MatplotLibAPI 3.2.19__tar.gz → 3.2.20__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/.github/workflows/ci.yml +2 -2
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/BoxViolin.py +4 -2
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Wordcloud.py +13 -33
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/PKG-INFO +1 -1
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/pyproject.toml +1 -1
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/scripts/generate_sample_data.py +1 -8
- matplotlibapi-3.2.20/tests/__init__.py +1 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/conftest.py +3 -5
- matplotlibapi-3.2.20/tests/test_wordcloud.py +77 -0
- matplotlibapi-3.2.19/tests/__init__.py +0 -0
- matplotlibapi-3.2.19/tests/test_wordcloud.py +0 -38
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/.github/workflows/python-publish.yml +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/.gitignore +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/AGENTS.md +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/LICENSE +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Area.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Bar.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Bubble.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Composite.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Heatmap.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Histogram.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Network.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Pie.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Pivot.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Sankey.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/StyleTemplate.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Sunburst.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Table.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Timeserie.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Treemap.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/Waffle.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/__init__.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/_typing.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/_visualization_utils.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/MatplotLibAPI/accessor.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/README.md +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/SECURITY.md +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/SUGGESTIONS.md +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_area.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_bar.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_box_violin.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_bubble.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_dependencies.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_heatmap.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_histogram.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_network.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_pie.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_pivot.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_sankey.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_smoke.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_sunburst.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_table.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_timeseries.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_treemap.py +0 -0
- {matplotlibapi-3.2.19 → matplotlibapi-3.2.20}/tests/test_waffle.py +0 -0
|
@@ -31,12 +31,12 @@ jobs:
|
|
|
31
31
|
|
|
32
32
|
- name: Run style checks
|
|
33
33
|
run: |
|
|
34
|
-
pydocstyle
|
|
34
|
+
pydocstyle .
|
|
35
35
|
black --check .
|
|
36
36
|
|
|
37
37
|
- name: Run static type analysis
|
|
38
38
|
run: |
|
|
39
|
-
pyright
|
|
39
|
+
pyright .
|
|
40
40
|
|
|
41
41
|
- name: Run tests with coverage
|
|
42
42
|
run: |
|
|
@@ -33,10 +33,12 @@ def aplot_box_violin(
|
|
|
33
33
|
validate_dataframe(pd_df, cols=cols)
|
|
34
34
|
plot_ax = _get_axis(ax)
|
|
35
35
|
|
|
36
|
+
common_kwargs = {"data": pd_df, "x": by, "y": column, "palette": style.palette}
|
|
37
|
+
|
|
36
38
|
if violin:
|
|
37
|
-
sns.violinplot(
|
|
39
|
+
sns.violinplot(**common_kwargs, hue=by, legend=False, ax=plot_ax)
|
|
38
40
|
else:
|
|
39
|
-
sns.boxplot(
|
|
41
|
+
sns.boxplot(**common_kwargs, hue=by, legend=False, ax=plot_ax)
|
|
40
42
|
|
|
41
43
|
plot_ax.set_facecolor(style.background_color)
|
|
42
44
|
plot_ax.set_ylabel(string_formatter(column))
|
|
@@ -25,33 +25,6 @@ WORDCLOUD_STYLE_TEMPLATE = StyleTemplate(
|
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
def _normalize_weights(weights: Sequence[float], base_size: int) -> np.ndarray:
|
|
29
|
-
"""Normalize weights to a range of font sizes.
|
|
30
|
-
|
|
31
|
-
Parameters
|
|
32
|
-
----------
|
|
33
|
-
weights : Sequence[float]
|
|
34
|
-
Sequence of weights representing word importance.
|
|
35
|
-
base_size : int
|
|
36
|
-
Base font size used as the lower bound for scaling.
|
|
37
|
-
|
|
38
|
-
Returns
|
|
39
|
-
-------
|
|
40
|
-
numpy.ndarray
|
|
41
|
-
Array of font sizes corresponding to the provided weights.
|
|
42
|
-
"""
|
|
43
|
-
numeric_weights = np.asarray(weights, dtype=float)
|
|
44
|
-
if numeric_weights.size == 0:
|
|
45
|
-
return np.array([], dtype=float)
|
|
46
|
-
min_weight = numeric_weights.min()
|
|
47
|
-
max_weight = numeric_weights.max()
|
|
48
|
-
if min_weight == max_weight:
|
|
49
|
-
return np.full_like(numeric_weights, fill_value=base_size, dtype=float)
|
|
50
|
-
|
|
51
|
-
min_size, max_size = base_size, base_size * 4
|
|
52
|
-
return np.interp(numeric_weights, (min_weight, max_weight), (min_size, max_size))
|
|
53
|
-
|
|
54
|
-
|
|
55
28
|
def _filter_stopwords(
|
|
56
29
|
words: Iterable[str], stopwords: Optional[Iterable[str]]
|
|
57
30
|
) -> np.ndarray:
|
|
@@ -232,20 +205,21 @@ def _plot_words(
|
|
|
232
205
|
frequency_map = {
|
|
233
206
|
string_formatter(word): weight for word, weight in zip(words, weights)
|
|
234
207
|
}
|
|
208
|
+
min_font_size = style.font_mapping[min(style.font_mapping.keys())]
|
|
209
|
+
max_font_size = style.font_mapping[max(style.font_mapping.keys())]
|
|
235
210
|
|
|
236
|
-
font_sizes = _normalize_weights(weights, base_size=style.font_size)
|
|
237
211
|
wc = WordCloud(
|
|
238
212
|
width=width,
|
|
239
213
|
height=height,
|
|
240
214
|
background_color=style.background_color,
|
|
241
215
|
colormap=colormaps.get_cmap(style.palette),
|
|
242
|
-
min_font_size=
|
|
243
|
-
max_font_size=
|
|
216
|
+
min_font_size=min_font_size,
|
|
217
|
+
max_font_size=max_font_size,
|
|
244
218
|
random_state=random_state,
|
|
245
219
|
mask=resolved_mask,
|
|
246
220
|
).generate_from_frequencies(frequency_map)
|
|
247
221
|
|
|
248
|
-
ax.imshow(wc, interpolation="bilinear")
|
|
222
|
+
ax.imshow(wc.to_array(), interpolation="bilinear")
|
|
249
223
|
|
|
250
224
|
if title:
|
|
251
225
|
ax.set_title(title, color=style.font_color, fontsize=style.font_size * 1.5)
|
|
@@ -261,7 +235,7 @@ def aplot_wordcloud(
|
|
|
261
235
|
max_words: int = MAX_RESULTS,
|
|
262
236
|
stopwords: Optional[Iterable[str]] = None,
|
|
263
237
|
random_state: Optional[int] = None,
|
|
264
|
-
ax: Optional[Axes] = None,
|
|
238
|
+
ax: Optional[Axes | np.ndarray[Any, np.dtype[Any]]] = None,
|
|
265
239
|
mask: Optional[np.ndarray] = None,
|
|
266
240
|
) -> Axes:
|
|
267
241
|
"""Plot a word cloud on the provided axes.
|
|
@@ -284,7 +258,7 @@ def aplot_wordcloud(
|
|
|
284
258
|
Words to exclude from the visualization. Defaults to ``None``.
|
|
285
259
|
random_state : int, optional
|
|
286
260
|
Seed for word placement. Defaults to ``None``.
|
|
287
|
-
ax : matplotlib.axes.Axes, optional
|
|
261
|
+
ax : matplotlib.axes.Axes or numpy.ndarray, optional
|
|
288
262
|
Axes to draw on. Defaults to ``None`` which uses the current axes.
|
|
289
263
|
mask : numpy.ndarray, optional
|
|
290
264
|
Two-dimensional mask array defining the drawable region of the word cloud.
|
|
@@ -299,9 +273,15 @@ def aplot_wordcloud(
|
|
|
299
273
|
------
|
|
300
274
|
AttributeError
|
|
301
275
|
If required columns are missing from the DataFrame.
|
|
276
|
+
TypeError
|
|
277
|
+
If ``ax`` is not a ``matplotlib.axes.Axes`` instance.
|
|
302
278
|
"""
|
|
303
279
|
if ax is None:
|
|
304
280
|
ax = cast(Axes, plt.gca())
|
|
281
|
+
elif isinstance(ax, np.ndarray):
|
|
282
|
+
raise TypeError("ax must be a single matplotlib Axes instance, not an array.")
|
|
283
|
+
elif not isinstance(ax, Axes):
|
|
284
|
+
raise TypeError("ax must be a matplotlib Axes instance.")
|
|
305
285
|
|
|
306
286
|
words, weights = _prepare_word_frequencies(
|
|
307
287
|
pd_df=pd_df,
|
|
@@ -97,7 +97,7 @@ def generate_treemap_data():
|
|
|
97
97
|
}
|
|
98
98
|
df = pd.DataFrame(data)
|
|
99
99
|
# For treemap, we need a path-like structure. We will create it here.
|
|
100
|
-
df["path"] = df["parent"]
|
|
100
|
+
df["path"] = df["parent"].str.cat(df["location"], sep="/")
|
|
101
101
|
df["path"] = df["path"].str.lstrip("/")
|
|
102
102
|
df.to_csv("data/treemap.csv", index=False)
|
|
103
103
|
|
|
@@ -169,7 +169,6 @@ def generate_wordcloud_data():
|
|
|
169
169
|
|
|
170
170
|
def generate_bar_data():
|
|
171
171
|
"""Generate and save sample data for bar and stacked bar charts."""
|
|
172
|
-
|
|
173
172
|
data = {
|
|
174
173
|
"product": ["Gadget", "Gadget", "Gadget", "Widget", "Widget", "Widget"],
|
|
175
174
|
"region": ["North", "South", "West", "North", "South", "West"],
|
|
@@ -181,7 +180,6 @@ def generate_bar_data():
|
|
|
181
180
|
|
|
182
181
|
def generate_histogram_data():
|
|
183
182
|
"""Generate and save sample data for histogram and KDE plots."""
|
|
184
|
-
|
|
185
183
|
data = {
|
|
186
184
|
"waiting_time_minutes": [
|
|
187
185
|
5,
|
|
@@ -212,7 +210,6 @@ def generate_histogram_data():
|
|
|
212
210
|
|
|
213
211
|
def generate_box_violin_data():
|
|
214
212
|
"""Generate and save sample data for box and violin plots."""
|
|
215
|
-
|
|
216
213
|
data = {
|
|
217
214
|
"department": [
|
|
218
215
|
"Engineering",
|
|
@@ -243,7 +240,6 @@ def generate_box_violin_data():
|
|
|
243
240
|
|
|
244
241
|
def generate_heatmap_and_correlation_data():
|
|
245
242
|
"""Generate and save sample data for heatmaps and correlation matrices."""
|
|
246
|
-
|
|
247
243
|
data = {
|
|
248
244
|
"month": ["Jan", "Jan", "Feb", "Feb", "Mar", "Mar", "Apr", "Apr"],
|
|
249
245
|
"channel": [
|
|
@@ -269,7 +265,6 @@ def generate_heatmap_and_correlation_data():
|
|
|
269
265
|
|
|
270
266
|
def generate_area_data():
|
|
271
267
|
"""Generate and save sample data for area charts."""
|
|
272
|
-
|
|
273
268
|
data = {
|
|
274
269
|
"quarter": ["Q1", "Q2", "Q3", "Q4", "Q1", "Q2", "Q3", "Q4"],
|
|
275
270
|
"segment": [
|
|
@@ -290,7 +285,6 @@ def generate_area_data():
|
|
|
290
285
|
|
|
291
286
|
def generate_pie_waffle_data():
|
|
292
287
|
"""Generate and save sample data for pie, donut, and waffle charts."""
|
|
293
|
-
|
|
294
288
|
data = {
|
|
295
289
|
"device": ["Desktop", "Mobile", "Tablet", "Other"],
|
|
296
290
|
"sessions": [5200, 8900, 1300, 600],
|
|
@@ -302,7 +296,6 @@ def generate_pie_waffle_data():
|
|
|
302
296
|
|
|
303
297
|
def generate_sankey_data():
|
|
304
298
|
"""Generate and save sample data for Sankey diagrams."""
|
|
305
|
-
|
|
306
299
|
data = {
|
|
307
300
|
"source": ["Homepage", "Homepage", "Landing Page", "Landing Page", "Cart"],
|
|
308
301
|
"target": ["Landing Page", "Product", "Product", "Signup", "Checkout"],
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Public test for MatplotLibAPI."""
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import Any, Callable
|
|
5
|
+
from typing import Any, Callable, Generator
|
|
6
6
|
|
|
7
7
|
import pandas as pd
|
|
8
8
|
import pytest
|
|
@@ -13,7 +13,6 @@ from scripts import generate_sample_data
|
|
|
13
13
|
@pytest.fixture(scope="session")
|
|
14
14
|
def sample_data_dir(tmp_path_factory: pytest.TempPathFactory) -> Path:
|
|
15
15
|
"""Generate sample CSV files in an isolated directory for tests."""
|
|
16
|
-
|
|
17
16
|
base_dir = tmp_path_factory.mktemp("sample_data")
|
|
18
17
|
cwd = os.getcwd()
|
|
19
18
|
os.chdir(base_dir)
|
|
@@ -28,7 +27,7 @@ def sample_data_dir(tmp_path_factory: pytest.TempPathFactory) -> Path:
|
|
|
28
27
|
@pytest.fixture(scope="session")
|
|
29
28
|
def load_sample_df(
|
|
30
29
|
sample_data_dir: Path,
|
|
31
|
-
) -> Callable[
|
|
30
|
+
) -> Callable[..., pd.DataFrame]:
|
|
32
31
|
"""Return a loader that reads generated sample CSVs into dataframes."""
|
|
33
32
|
|
|
34
33
|
def _loader(filename: str, **kwargs: Any) -> pd.DataFrame:
|
|
@@ -38,9 +37,8 @@ def load_sample_df(
|
|
|
38
37
|
|
|
39
38
|
|
|
40
39
|
@pytest.fixture(autouse=True)
|
|
41
|
-
def close_matplotlib_figures() -> None:
|
|
40
|
+
def close_matplotlib_figures() -> Generator[None, None, None]:
|
|
42
41
|
"""Close any matplotlib figures created during a test."""
|
|
43
|
-
|
|
44
42
|
yield
|
|
45
43
|
|
|
46
44
|
import matplotlib.pyplot as plt
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Tests for word cloud visualizations."""
|
|
2
|
+
|
|
3
|
+
import matplotlib.pyplot as plt
|
|
4
|
+
from matplotlib.figure import Figure
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from MatplotLibAPI.Wordcloud import (
|
|
8
|
+
aplot_wordcloud,
|
|
9
|
+
create_circular_mask,
|
|
10
|
+
fplot_wordcloud,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_fplot_wordcloud(load_sample_df):
|
|
15
|
+
"""Render a word cloud figure from sample data."""
|
|
16
|
+
|
|
17
|
+
df = load_sample_df("wordcloud.csv")
|
|
18
|
+
|
|
19
|
+
fig = fplot_wordcloud(
|
|
20
|
+
pd_df=df, text_column="country", weight_column="population", random_state=42
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
assert isinstance(fig, Figure)
|
|
24
|
+
default_mask = create_circular_mask(size=300)
|
|
25
|
+
image = fig.axes[0].images[0].get_array()
|
|
26
|
+
assert image is not None
|
|
27
|
+
assert tuple(image.shape[:2]) == default_mask.shape
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_fplot_wordcloud_with_mask(load_sample_df):
|
|
31
|
+
"""Render a word cloud using a circular mask to constrain placement."""
|
|
32
|
+
|
|
33
|
+
df = load_sample_df("wordcloud.csv")
|
|
34
|
+
mask = create_circular_mask(size=200)
|
|
35
|
+
|
|
36
|
+
fig = fplot_wordcloud(
|
|
37
|
+
pd_df=df,
|
|
38
|
+
text_column="country",
|
|
39
|
+
weight_column="population",
|
|
40
|
+
random_state=0,
|
|
41
|
+
mask=mask,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
image = fig.axes[0].images[0].get_array()
|
|
45
|
+
assert image is not None
|
|
46
|
+
assert tuple(image.shape[:2]) == mask.shape
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_aplot_wordcloud(load_sample_df):
|
|
50
|
+
"""Render a word cloud onto an existing axes object."""
|
|
51
|
+
|
|
52
|
+
df = load_sample_df("wordcloud.csv")
|
|
53
|
+
fig, ax = plt.subplots()
|
|
54
|
+
|
|
55
|
+
result_ax = aplot_wordcloud(
|
|
56
|
+
ax=ax,
|
|
57
|
+
pd_df=df,
|
|
58
|
+
text_column="country",
|
|
59
|
+
weight_column="population",
|
|
60
|
+
random_state=42,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
assert result_ax is not None
|
|
64
|
+
assert ax is result_ax
|
|
65
|
+
image = result_ax.images[0].get_array()
|
|
66
|
+
assert image is not None
|
|
67
|
+
assert image.shape[0] > 0 and image.shape[1] > 0
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_create_circular_mask():
|
|
71
|
+
"""Verify circular mask generation."""
|
|
72
|
+
|
|
73
|
+
mask = create_circular_mask(size=100, radius=40)
|
|
74
|
+
assert mask.shape == (100, 100)
|
|
75
|
+
assert mask.dtype == np.uint8
|
|
76
|
+
assert np.sum(mask == 0) > 0
|
|
77
|
+
assert np.sum(mask == 255) > 0
|
|
File without changes
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
"""Tests for word cloud visualizations."""
|
|
2
|
-
|
|
3
|
-
from matplotlib.figure import Figure
|
|
4
|
-
|
|
5
|
-
from MatplotLibAPI.Wordcloud import create_circular_mask, fplot_wordcloud
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def test_fplot_wordcloud(load_sample_df):
|
|
9
|
-
"""Render a word cloud figure from sample data."""
|
|
10
|
-
|
|
11
|
-
df = load_sample_df("wordcloud.csv")
|
|
12
|
-
|
|
13
|
-
fig = fplot_wordcloud(
|
|
14
|
-
pd_df=df, text_column="country", weight_column="population", random_state=42
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
assert isinstance(fig, Figure)
|
|
18
|
-
default_mask = create_circular_mask()
|
|
19
|
-
image = fig.axes[0].images[0].get_array()
|
|
20
|
-
assert tuple(image.shape[:2]) == default_mask.shape
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def test_fplot_wordcloud_with_mask(load_sample_df):
|
|
24
|
-
"""Render a word cloud using a circular mask to constrain placement."""
|
|
25
|
-
|
|
26
|
-
df = load_sample_df("wordcloud.csv")
|
|
27
|
-
mask = create_circular_mask(size=200)
|
|
28
|
-
|
|
29
|
-
fig = fplot_wordcloud(
|
|
30
|
-
pd_df=df,
|
|
31
|
-
text_column="country",
|
|
32
|
-
weight_column="population",
|
|
33
|
-
random_state=0,
|
|
34
|
-
mask=mask,
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
image = fig.axes[0].images[0].get_array()
|
|
38
|
-
assert tuple(image.shape[:2]) == mask.shape
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|