MatplotLibAPI 3.2.18__py3-none-any.whl → 3.2.20__py3-none-any.whl

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.
@@ -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(data=pd_df, x=by, y=column, palette=style.palette, ax=plot_ax)
39
+ sns.violinplot(**common_kwargs, hue=by, legend=False, ax=plot_ax)
38
40
  else:
39
- sns.boxplot(data=pd_df, x=by, y=column, palette=style.palette, ax=plot_ax)
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:
@@ -131,6 +104,40 @@ def _prepare_word_frequencies(
131
104
  return words, weights
132
105
 
133
106
 
107
+ def create_circular_mask(size: int = 300, radius: Optional[int] = None) -> np.ndarray:
108
+ """Construct a binary mask with a circular opening for a word cloud.
109
+
110
+ Parameters
111
+ ----------
112
+ size : int, optional
113
+ Width and height of the mask in pixels. Defaults to ``300``.
114
+ radius : int, optional
115
+ Radius of the circular opening in pixels. Defaults to ``size // 2``.
116
+
117
+ Returns
118
+ -------
119
+ numpy.ndarray
120
+ Two-dimensional array suitable for the ``mask`` argument of
121
+ ``wordcloud.WordCloud`` where ``0`` values define the drawable region.
122
+
123
+ Raises
124
+ ------
125
+ ValueError
126
+ If ``size`` or ``radius`` are non-positive.
127
+ """
128
+ if size <= 0:
129
+ raise ValueError("size must be a positive integer.")
130
+
131
+ resolved_radius = radius if radius is not None else size // 2
132
+ if resolved_radius <= 0:
133
+ raise ValueError("radius must be a positive integer.")
134
+
135
+ center = (size - 1) / 2
136
+ x, y = np.ogrid[:size, :size]
137
+ mask_region = (x - center) ** 2 + (y - center) ** 2 > resolved_radius**2
138
+ return 255 * mask_region.astype(np.uint8)
139
+
140
+
134
141
  def _plot_words(
135
142
  ax: Axes,
136
143
  words: Sequence[str],
@@ -138,6 +145,7 @@ def _plot_words(
138
145
  style: StyleTemplate,
139
146
  title: Optional[str],
140
147
  random_state: Optional[int],
148
+ mask: Optional[np.ndarray],
141
149
  ) -> Axes:
142
150
  """Render words on the provided axes with sizes proportional to weights.
143
151
 
@@ -179,25 +187,39 @@ def _plot_words(
179
187
 
180
188
  canvas.draw()
181
189
  ax_bbox = ax.get_window_extent()
182
- width = max(int(ax_bbox.width), 1)
183
- height = max(int(ax_bbox.height), 1)
190
+ resolved_mask = create_circular_mask() if mask is None else np.asarray(mask)
191
+ if resolved_mask is not None and resolved_mask.ndim != 2:
192
+ raise ValueError("mask must be a 2D array.")
193
+
194
+ width = (
195
+ max(int(ax_bbox.width), 1)
196
+ if resolved_mask is None
197
+ else max(int(resolved_mask.shape[1]), 1)
198
+ )
199
+ height = (
200
+ max(int(ax_bbox.height), 1)
201
+ if resolved_mask is None
202
+ else max(int(resolved_mask.shape[0]), 1)
203
+ )
184
204
 
185
205
  frequency_map = {
186
206
  string_formatter(word): weight for word, weight in zip(words, weights)
187
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())]
188
210
 
189
- font_sizes = _normalize_weights(weights, base_size=style.font_size)
190
211
  wc = WordCloud(
191
212
  width=width,
192
213
  height=height,
193
214
  background_color=style.background_color,
194
215
  colormap=colormaps.get_cmap(style.palette),
195
- min_font_size=int(font_sizes.min(initial=style.font_size)),
196
- max_font_size=int(font_sizes.max(initial=style.font_size * 4)),
216
+ min_font_size=min_font_size,
217
+ max_font_size=max_font_size,
197
218
  random_state=random_state,
219
+ mask=resolved_mask,
198
220
  ).generate_from_frequencies(frequency_map)
199
221
 
200
- ax.imshow(wc, interpolation="bilinear")
222
+ ax.imshow(wc.to_array(), interpolation="bilinear")
201
223
 
202
224
  if title:
203
225
  ax.set_title(title, color=style.font_color, fontsize=style.font_size * 1.5)
@@ -213,7 +235,8 @@ def aplot_wordcloud(
213
235
  max_words: int = MAX_RESULTS,
214
236
  stopwords: Optional[Iterable[str]] = None,
215
237
  random_state: Optional[int] = None,
216
- ax: Optional[Axes] = None,
238
+ ax: Optional[Axes | np.ndarray[Any, np.dtype[Any]]] = None,
239
+ mask: Optional[np.ndarray] = None,
217
240
  ) -> Axes:
218
241
  """Plot a word cloud on the provided axes.
219
242
 
@@ -235,8 +258,11 @@ def aplot_wordcloud(
235
258
  Words to exclude from the visualization. Defaults to ``None``.
236
259
  random_state : int, optional
237
260
  Seed for word placement. Defaults to ``None``.
238
- ax : matplotlib.axes.Axes, optional
261
+ ax : matplotlib.axes.Axes or numpy.ndarray, optional
239
262
  Axes to draw on. Defaults to ``None`` which uses the current axes.
263
+ mask : numpy.ndarray, optional
264
+ Two-dimensional mask array defining the drawable region of the word cloud.
265
+ Defaults to a circular mask generated by :func:`create_circular_mask`.
240
266
 
241
267
  Returns
242
268
  -------
@@ -247,9 +273,15 @@ def aplot_wordcloud(
247
273
  ------
248
274
  AttributeError
249
275
  If required columns are missing from the DataFrame.
276
+ TypeError
277
+ If ``ax`` is not a ``matplotlib.axes.Axes`` instance.
250
278
  """
251
279
  if ax is None:
252
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.")
253
285
 
254
286
  words, weights = _prepare_word_frequencies(
255
287
  pd_df=pd_df,
@@ -259,7 +291,13 @@ def aplot_wordcloud(
259
291
  stopwords=stopwords,
260
292
  )
261
293
  return _plot_words(
262
- ax, words, weights, style=style, title=title, random_state=random_state
294
+ ax,
295
+ words,
296
+ weights,
297
+ style=style,
298
+ title=title,
299
+ random_state=random_state,
300
+ mask=mask,
263
301
  )
264
302
 
265
303
 
@@ -275,6 +313,7 @@ def fplot_wordcloud(
275
313
  figsize: Tuple[float, float] = FIG_SIZE,
276
314
  save_path: Optional[str] = None,
277
315
  savefig_kwargs: Optional[Dict[str, Any]] = None,
316
+ mask: Optional[np.ndarray] = None,
278
317
  ) -> Figure:
279
318
  """Create a new figure with a word cloud.
280
319
 
@@ -298,6 +337,9 @@ def fplot_wordcloud(
298
337
  Seed for word placement. Defaults to ``None``.
299
338
  figsize : tuple of float, optional
300
339
  Figure size. Defaults to ``FIG_SIZE``.
340
+ mask : numpy.ndarray, optional
341
+ Two-dimensional mask array defining the drawable region of the word cloud.
342
+ Defaults to a circular mask generated by :func:`create_circular_mask`.
301
343
 
302
344
  Returns
303
345
  -------
@@ -325,6 +367,7 @@ def fplot_wordcloud(
325
367
  style=style,
326
368
  title=title,
327
369
  random_state=random_state,
370
+ mask=mask,
328
371
  )
329
372
  fig.patch.set_facecolor(style.background_color)
330
373
  fig.tight_layout()
MatplotLibAPI/__init__.py CHANGED
@@ -35,7 +35,12 @@ from .Timeserie import TIMESERIE_STYLE_TEMPLATE, aplot_timeserie, fplot_timeseri
35
35
  from .Sunburst import fplot_sunburst
36
36
  from .Treemap import TREEMAP_STYLE_TEMPLATE, fplot_treemap
37
37
  from .Waffle import aplot_waffle, fplot_waffle
38
- from .Wordcloud import WORDCLOUD_STYLE_TEMPLATE, aplot_wordcloud, fplot_wordcloud
38
+ from .Wordcloud import (
39
+ WORDCLOUD_STYLE_TEMPLATE,
40
+ aplot_wordcloud,
41
+ create_circular_mask,
42
+ fplot_wordcloud,
43
+ )
39
44
  from .accessor import DataFrameAccessor
40
45
 
41
46
  __all__ = [
@@ -54,6 +59,7 @@ __all__ = [
54
59
  "aplot_correlation_matrix",
55
60
  "aplot_area",
56
61
  "aplot_pie_donut",
62
+ "create_circular_mask",
57
63
  "aplot_waffle",
58
64
  "fplot_bubble",
59
65
  "fplot_network",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MatplotLibAPI
3
- Version: 3.2.18
3
+ Version: 3.2.20
4
4
  License-File: LICENSE
5
5
  Requires-Python: >=3.8
6
6
  Requires-Dist: kaleido
@@ -1,6 +1,6 @@
1
1
  MatplotLibAPI/Area.py,sha256=Y-tk6Di3Foj3yOGVbbOwDnPtL9rDh-VV2XTeaZcybgk,2095
2
2
  MatplotLibAPI/Bar.py,sha256=Y8mP_UWyU2h5T38L7j-Vnt0t9WSeCbV6Gw_-_48x3Bw,2243
3
- MatplotLibAPI/BoxViolin.py,sha256=zsyfUKYp6wKD30i-LWmwPxtOA7ljjh874xxES_GHZ8M,1947
3
+ MatplotLibAPI/BoxViolin.py,sha256=8nnXGyDwrjiNJOiJHEYEcJMqD6JIF5JT8aZ0y4AXgLY,2008
4
4
  MatplotLibAPI/Bubble.py,sha256=xByA6J89L1ye8oiinGQx1jd4PC0vPcBQhxFrKCEXtVM,12814
5
5
  MatplotLibAPI/Composite.py,sha256=k4elPk2mucw5oOH2S2GZV6mbHI9N4Nhpnte4mWLHObg,5902
6
6
  MatplotLibAPI/Heatmap.py,sha256=SRT8pCKtEaJ1PivxxzCuXp-OBu4ljno2PGB_XXvFxzY,3369
@@ -15,12 +15,12 @@ MatplotLibAPI/Table.py,sha256=jRdnQ0LNA5op65QJhXnXv_v7tBv1JEPLX7qHNd07_is,6448
15
15
  MatplotLibAPI/Timeserie.py,sha256=vN8Ed9eC6TcN02LAiSJRzbIW3ZNoBo8ip7lznnK5eG0,10198
16
16
  MatplotLibAPI/Treemap.py,sha256=VBBk6MpNXoQtnxFzR1YPhIx6Lz9b7yJNHBMbQDhvefM,4848
17
17
  MatplotLibAPI/Waffle.py,sha256=uplRhUBDWUhSwPnI_GzU1O2D_RQXW_0OJ51m01PFKLg,2517
18
- MatplotLibAPI/Wordcloud.py,sha256=sE6P8vCh8H6bQnaIr4LPW7fd3-OQootfOuM-9-htgv4,10016
19
- MatplotLibAPI/__init__.py,sha256=6Z51NTmLCoM7P-XPDGVQdtcXtz8S1zZzoByuX_nCpyw,2233
18
+ MatplotLibAPI/Wordcloud.py,sha256=uYH8amxRpMm0y60Ch9nkOl2yXNX-l01NZe2VGIwdZw8,11581
19
+ MatplotLibAPI/__init__.py,sha256=jyMVtJq3rGJ9GmM7mX1dhJcNCCJHJ2-IwtDClRgKBFg,2304
20
20
  MatplotLibAPI/_typing.py,sha256=Or3IPNceWKdyEk3CGXJb09FZR_fvT732oF0iWrx1ex8,598
21
21
  MatplotLibAPI/_visualization_utils.py,sha256=qIv7c0Mi3qK-saGxmKngw23uWxKFSAYjiH3uYTSr5Po,2215
22
22
  MatplotLibAPI/accessor.py,sha256=Wsje4q6bNa_-WAkljqTDWfbWpKcbAy2JKaHir9qZ9Ho,53038
23
- matplotlibapi-3.2.18.dist-info/METADATA,sha256=75mgiIyrEAbZsWAhIVTl6OzJax5iW6dANKSMdV1a4yE,5888
24
- matplotlibapi-3.2.18.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
25
- matplotlibapi-3.2.18.dist-info/licenses/LICENSE,sha256=hMErKLb6YZR3lRR5zr-vxeFkvY69QAaafgSpZ5-P1dQ,1067
26
- matplotlibapi-3.2.18.dist-info/RECORD,,
23
+ matplotlibapi-3.2.20.dist-info/METADATA,sha256=ocDaj9BvTZvdA3hs30komzhrlyfspk6MaZEVmq2q0Xw,5888
24
+ matplotlibapi-3.2.20.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
25
+ matplotlibapi-3.2.20.dist-info/licenses/LICENSE,sha256=hMErKLb6YZR3lRR5zr-vxeFkvY69QAaafgSpZ5-P1dQ,1067
26
+ matplotlibapi-3.2.20.dist-info/RECORD,,