lets-plot 4.5.0__cp313-cp313-macosx_10_15_x86_64.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.

Potentially problematic release.


This version of lets-plot might be problematic. Click here for more details.

Files changed (89) hide show
  1. lets_plot/__init__.py +283 -0
  2. lets_plot/_global_settings.py +191 -0
  3. lets_plot/_kbridge.py +36 -0
  4. lets_plot/_type_utils.py +110 -0
  5. lets_plot/_version.py +6 -0
  6. lets_plot/bistro/__init__.py +16 -0
  7. lets_plot/bistro/_plot2d_common.py +93 -0
  8. lets_plot/bistro/corr.py +447 -0
  9. lets_plot/bistro/im.py +165 -0
  10. lets_plot/bistro/joint.py +192 -0
  11. lets_plot/bistro/qq.py +207 -0
  12. lets_plot/bistro/residual.py +341 -0
  13. lets_plot/bistro/waterfall.py +250 -0
  14. lets_plot/export/__init__.py +6 -0
  15. lets_plot/export/ggsave_.py +133 -0
  16. lets_plot/frontend_context/__init__.py +8 -0
  17. lets_plot/frontend_context/_configuration.py +144 -0
  18. lets_plot/frontend_context/_frontend_ctx.py +16 -0
  19. lets_plot/frontend_context/_html_contexts.py +117 -0
  20. lets_plot/frontend_context/_intellij_python_json_ctx.py +38 -0
  21. lets_plot/frontend_context/_json_contexts.py +39 -0
  22. lets_plot/frontend_context/_jupyter_notebook_ctx.py +119 -0
  23. lets_plot/frontend_context/_mime_types.py +7 -0
  24. lets_plot/frontend_context/_static_html_page_ctx.py +27 -0
  25. lets_plot/frontend_context/_static_svg_ctx.py +26 -0
  26. lets_plot/frontend_context/_webbr_html_page_ctx.py +29 -0
  27. lets_plot/frontend_context/sandbox.py +5 -0
  28. lets_plot/geo_data/__init__.py +18 -0
  29. lets_plot/geo_data/core.py +331 -0
  30. lets_plot/geo_data/geocoder.py +977 -0
  31. lets_plot/geo_data/geocodes.py +512 -0
  32. lets_plot/geo_data/gis/__init__.py +0 -0
  33. lets_plot/geo_data/gis/fluent_dict.py +201 -0
  34. lets_plot/geo_data/gis/geocoding_service.py +42 -0
  35. lets_plot/geo_data/gis/geometry.py +91 -0
  36. lets_plot/geo_data/gis/json_request.py +232 -0
  37. lets_plot/geo_data/gis/json_response.py +308 -0
  38. lets_plot/geo_data/gis/request.py +492 -0
  39. lets_plot/geo_data/gis/response.py +247 -0
  40. lets_plot/geo_data/livemap_helper.py +65 -0
  41. lets_plot/geo_data/to_geo_data_frame.py +141 -0
  42. lets_plot/geo_data/type_assertion.py +34 -0
  43. lets_plot/geo_data_internals/__init__.py +4 -0
  44. lets_plot/geo_data_internals/constants.py +13 -0
  45. lets_plot/geo_data_internals/utils.py +33 -0
  46. lets_plot/mapping.py +115 -0
  47. lets_plot/package_data/lets-plot.min.js +2 -0
  48. lets_plot/plot/__init__.py +62 -0
  49. lets_plot/plot/_global_theme.py +14 -0
  50. lets_plot/plot/annotation.py +233 -0
  51. lets_plot/plot/coord.py +242 -0
  52. lets_plot/plot/core.py +943 -0
  53. lets_plot/plot/expand_limits_.py +78 -0
  54. lets_plot/plot/facet.py +206 -0
  55. lets_plot/plot/font_features.py +71 -0
  56. lets_plot/plot/geom.py +7897 -0
  57. lets_plot/plot/geom_extras.py +53 -0
  58. lets_plot/plot/geom_function_.py +216 -0
  59. lets_plot/plot/geom_imshow_.py +401 -0
  60. lets_plot/plot/geom_livemap_.py +330 -0
  61. lets_plot/plot/gggrid_.py +141 -0
  62. lets_plot/plot/ggtb_.py +56 -0
  63. lets_plot/plot/guide.py +229 -0
  64. lets_plot/plot/label.py +187 -0
  65. lets_plot/plot/marginal_layer.py +181 -0
  66. lets_plot/plot/plot.py +237 -0
  67. lets_plot/plot/pos.py +344 -0
  68. lets_plot/plot/sampling.py +338 -0
  69. lets_plot/plot/sandbox_.py +26 -0
  70. lets_plot/plot/scale.py +3552 -0
  71. lets_plot/plot/scale_colormap_mpl.py +297 -0
  72. lets_plot/plot/scale_convenience.py +155 -0
  73. lets_plot/plot/scale_identity_.py +658 -0
  74. lets_plot/plot/scale_position.py +1336 -0
  75. lets_plot/plot/series_meta.py +123 -0
  76. lets_plot/plot/stat.py +581 -0
  77. lets_plot/plot/subplots.py +322 -0
  78. lets_plot/plot/theme_.py +681 -0
  79. lets_plot/plot/theme_set.py +393 -0
  80. lets_plot/plot/tooltip.py +486 -0
  81. lets_plot/plot/util.py +226 -0
  82. lets_plot/settings_utils.py +244 -0
  83. lets_plot/tilesets.py +364 -0
  84. lets_plot-4.5.0.dist-info/LICENSE +21 -0
  85. lets_plot-4.5.0.dist-info/METADATA +186 -0
  86. lets_plot-4.5.0.dist-info/RECORD +89 -0
  87. lets_plot-4.5.0.dist-info/WHEEL +5 -0
  88. lets_plot-4.5.0.dist-info/top_level.txt +2 -0
  89. lets_plot_kotlin_bridge.cpython-313-darwin.so +0 -0
@@ -0,0 +1,93 @@
1
+ #
2
+ # Copyright (c) 2023. JetBrains s.r.o.
3
+ # Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4
+ #
5
+ from ..plot.core import DummySpec, aes
6
+ from ..plot.geom import *
7
+ from ..plot.marginal_layer import ggmarginal
8
+
9
+ _BINS_DEF = 30
10
+ _COLOR_DEF = "pen"
11
+
12
+ _MARGINAL_ALPHA = .1
13
+
14
+
15
+ def _get_bin_params_2d(xs, ys, binwidth, bins):
16
+ if isinstance(bins, int):
17
+ bins = [bins, bins]
18
+ if isinstance(binwidth, int) or isinstance(binwidth, float):
19
+ binwidth = [binwidth, binwidth]
20
+ if binwidth is not None or bins is not None or len(xs) == 0:
21
+ return binwidth, bins
22
+ binwidth_x = (max(xs) - min(xs)) / _BINS_DEF
23
+ binwidth_y = (max(ys) - min(ys)) / _BINS_DEF
24
+ binwidth_max = max(binwidth_x, binwidth_y)
25
+
26
+ return [binwidth_max, binwidth_max], bins
27
+
28
+
29
+ def _get_geom2d_layer(geom_kind, binwidth2d, bins2d, color, color_by, size, alpha, show_legend):
30
+ if geom_kind == 'point':
31
+ return geom_point(color=color, size=size, alpha=alpha, show_legend=show_legend)
32
+ if geom_kind == 'tile':
33
+ return geom_bin2d(
34
+ aes(fill=('..count..' if color_by is None else color_by)),
35
+ bins=bins2d, binwidth=binwidth2d,
36
+ color=color, size=size, alpha=alpha,
37
+ show_legend=show_legend
38
+ )
39
+ if geom_kind == 'density2d':
40
+ return geom_density2d(
41
+ aes(color=('..group..' if color_by is None else color_by)),
42
+ color=color, size=size, alpha=alpha,
43
+ show_legend=show_legend
44
+ )
45
+ if geom_kind == 'density2df':
46
+ return geom_density2df(
47
+ aes(fill=('..group..' if color_by is None else color_by)),
48
+ color=color, size=size, alpha=alpha,
49
+ show_legend=show_legend
50
+ )
51
+ if geom_kind == 'none':
52
+ return None
53
+ raise Exception("Unknown geom '{0}'".format(geom_kind))
54
+
55
+
56
+ def _get_marginal_layers(marginal, binwidth2d, bins2d, color, color_by, show_legend):
57
+ marginal_color = None if color_by is not None else (color or _COLOR_DEF)
58
+
59
+ def bin_param_to_1d(param2d, side):
60
+ if param2d is None:
61
+ return None
62
+ else:
63
+ if side in ['t', 'b']:
64
+ return param2d[0]
65
+ else:
66
+ return param2d[1]
67
+
68
+ def _get_marginal_layer(geom_kind, side, size):
69
+ if geom_kind in ['dens', 'density']:
70
+ layer = geom_area(stat='density', position='identity', color=marginal_color, fill=marginal_color,
71
+ alpha=_MARGINAL_ALPHA, show_legend=show_legend)
72
+ elif geom_kind in ['hist', 'histogram']:
73
+ binwidth = bin_param_to_1d(binwidth2d, side)
74
+ bins = bin_param_to_1d(bins2d, side)
75
+ layer = geom_histogram(bins=bins, binwidth=binwidth,
76
+ color=marginal_color, fill=marginal_color, alpha=_MARGINAL_ALPHA,
77
+ show_legend=show_legend)
78
+ elif geom_kind in ['box', 'boxplot']:
79
+ layer = geom_boxplot(color=marginal_color, fill=marginal_color, alpha=_MARGINAL_ALPHA, show_legend=show_legend)
80
+ else:
81
+ raise Exception("Unknown geom '{0}'".format(geom_kind))
82
+
83
+ return ggmarginal(side, size=size, layer=layer)
84
+
85
+ result = DummySpec()
86
+ for layer_description in filter(bool, marginal.split(",")):
87
+ params = layer_description.strip().split(":")
88
+ geom_kind, sides = params[0].strip(), params[1].strip()
89
+ size = float(params[2].strip()) if len(params) > 2 else None
90
+ for side in sides:
91
+ result += _get_marginal_layer(geom_kind, side, size)
92
+
93
+ return result
@@ -0,0 +1,447 @@
1
+ # Copyright (c) 2020. JetBrains s.r.o.
2
+ # Use of this source code is governed by the MIT license that can be found in the LICENSE file.
3
+ #
4
+
5
+ """Correlation matrix implementation module"""
6
+ from typing import Any
7
+
8
+ from lets_plot.plot.util import is_pandas_data_frame
9
+
10
+ try:
11
+ import numpy
12
+ except ImportError:
13
+ numpy = None
14
+
15
+ try:
16
+ import pandas
17
+ except ImportError:
18
+ pandas = None
19
+
20
+ from lets_plot.plot.core import PlotSpec
21
+
22
+ __all__ = ['corr_plot']
23
+
24
+
25
+ def _is_corr_matrix(data: Any):
26
+ if is_pandas_data_frame(data):
27
+ if data.shape[0] != data.shape[1]:
28
+ return False
29
+
30
+ if not (all(col_type == 'float64' for col_type in data.dtypes)):
31
+ return False
32
+
33
+ for column in data:
34
+ import math
35
+ if not all(math.isnan(v) or (1.0 >= v >= -1.0) for v in data[column]):
36
+ return False
37
+
38
+ return True
39
+
40
+ elif isinstance(data, dict):
41
+ m = len(data.keys())
42
+ for column in data.values():
43
+ if not isinstance(column, (list, tuple)):
44
+ return False
45
+
46
+ if len(column) != m:
47
+ return False
48
+
49
+ import math
50
+ for v in column:
51
+ if not isinstance(v, float):
52
+ return False
53
+
54
+ if math.isnan(v):
55
+ return True
56
+
57
+ if 1.0 >= v >= -1.0:
58
+ return True
59
+
60
+ return False
61
+
62
+ return True
63
+ else:
64
+ return False
65
+
66
+
67
+ class corr_plot:
68
+ """
69
+ This class is intended to build correlation matrix plot.
70
+
71
+ Notes
72
+ -----
73
+ To hide axis tooltips, set 'blank' or the result of `element_blank()`
74
+ to the `axis_tooltip`, `axis_tooltip_x` or `axis_tooltip_y` parameter of the `theme()`.
75
+
76
+ Examples
77
+ --------
78
+ .. jupyter-execute::
79
+ :linenos:
80
+ :emphasize-lines: 7
81
+
82
+ import numpy as np
83
+ from lets_plot import *
84
+ from lets_plot.bistro.corr import *
85
+ LetsPlot.setup_html()
86
+ np.random.seed(42)
87
+ data = {var: np.random.poisson(size=10) for var in 'abcdef'}
88
+ corr_plot(data).tiles().build()
89
+
90
+ |
91
+
92
+ .. jupyter-execute::
93
+ :linenos:
94
+ :emphasize-lines: 7-9
95
+
96
+ import numpy as np
97
+ from lets_plot import *
98
+ from lets_plot.bistro.corr import *
99
+ LetsPlot.setup_html()
100
+ np.random.seed(42)
101
+ data = {var: np.random.uniform(size=10) for var in 'abcd'}
102
+ corr_plot(data).tiles(type='upper', diag=True)\\
103
+ .labels(type='upper', diag=True, map_size=True, color='black')\\
104
+ .palette_RdBu().build()
105
+
106
+ |
107
+
108
+ .. jupyter-execute::
109
+ :linenos:
110
+ :emphasize-lines: 7-9
111
+
112
+ import numpy as np
113
+ from lets_plot import *
114
+ from lets_plot.bistro.corr import *
115
+ LetsPlot.setup_html()
116
+ np.random.seed(42)
117
+ data = {var: np.random.normal(size=10) for var in 'abcdef'}
118
+ corr_plot(data, flip=False, threshold=.4).points().labels()\\
119
+ .palette_gradient(low='#d73027', mid='#ffffbf', high='#1a9850')\\
120
+ .build()
121
+
122
+ """
123
+
124
+ def _duplicate(self):
125
+ dup = corr_plot(
126
+ data=self._data,
127
+ show_legend=self._show_legend,
128
+ flip=self._reverse_y,
129
+ threshold=self.threshold
130
+ )
131
+
132
+ dup._color_scale = self._color_scale
133
+ dup._fill_scale = self._fill_scale
134
+ dup._points_params = self._points_params
135
+ dup._tiles_params = self._tiles_params
136
+ dup._labels_params = self._labels_params
137
+ dup._labels_map_size = self._labels_map_size
138
+ dup._palette = self._palette
139
+ dup._low = self._low
140
+ dup._mid = self._mid
141
+ dup._high = self._high
142
+
143
+ return dup
144
+
145
+ def __init__(self, data, show_legend=True, flip=True, threshold=None):
146
+ """
147
+ Parameters
148
+ ----------
149
+ data : dict or Pandas or Polars `DataFrame`
150
+ Correlation matrix or data (correlation will be calculated for each variable pair).
151
+ Data will be recognized as correlation matrix if it has a square shape and all values are
152
+ in range -1.0..+1.0 or NaN.
153
+ show_legend : bool, default=True
154
+ If True legend is shown.
155
+ flip : bool, default=True
156
+ If True the y axis is flipped.
157
+ threshold : float, default=0.0
158
+ Minimal correlation abs value to be included in result.
159
+ Accept values between 0 and 1.
160
+
161
+ """
162
+
163
+ self._data = data
164
+ self._show_legend = show_legend
165
+ self._reverse_y = flip if flip else False
166
+ self.threshold = threshold
167
+ self._color_scale = None
168
+ self._fill_scale = None
169
+ self._points_params = None
170
+ self._tiles_params = None
171
+ self._labels_params = None
172
+ self._labels_map_size = None
173
+ self._palette = None
174
+ self._low = None
175
+ self._mid = None
176
+ self._high = None
177
+
178
+ def points(self, type=None, diag=None):
179
+ """
180
+ Method defines correlation matrix layer drawn by points to the plot.
181
+
182
+ Parameters
183
+ ----------
184
+ type : {'upper', 'lower', 'full'}
185
+ Type of matrix. Default - contextual.
186
+ diag : bool
187
+ Determines whether to fill the main diagonal with values or not.
188
+ Default - contextual.
189
+
190
+ Returns
191
+ -------
192
+ `corr_plot`
193
+ Correlation plot specification.
194
+ """
195
+ return self._duplicate()._set_points(type, diag)
196
+
197
+ def labels(self, type=None, diag=None, map_size=None, color=None):
198
+ """
199
+ Method defines correlation matrix layer drawn with geom_text to the plot.
200
+
201
+ Parameters
202
+ ----------
203
+ type : {'upper', 'lower', 'full'}
204
+ Type of matrix. Default - contextual.
205
+ diag : bool
206
+ Determines whether to fill the main diagonal with values or not.
207
+ Default - contextual.
208
+ map_size : bool
209
+ If True, then absolute value of correlation is mapped to text size.
210
+ If False - the text size is constant. Default - contextual.
211
+ color : str
212
+ Set text color.
213
+ For more info see `Color and Fill <https://lets-plot.org/python/pages/aesthetics.html#color-and-fill>`__.
214
+ Default - contextual.
215
+
216
+ Returns
217
+ -------
218
+ `corr_plot`
219
+ Correlation plot specification.
220
+ """
221
+ return self._duplicate()._set_labels(type, diag, map_size, color)
222
+
223
+ def tiles(self, type=None, diag=None):
224
+ """
225
+ Method defines correlation matrix layer drawn as square tiles to the plot.
226
+
227
+ Parameters
228
+ ----------
229
+ type : {'upper', 'lower', 'full'}
230
+ Type of matrix. Default - contextual.
231
+ diag : bool
232
+ Determines whether to fill the main diagonal with values or not.
233
+ Default - contextual.
234
+
235
+ Returns
236
+ -------
237
+ `corr_plot`
238
+ Correlation plot specification.
239
+ """
240
+ return self._duplicate()._set_tiles(type, diag)
241
+
242
+ def palette_gradient(self, low, mid, high):
243
+ """
244
+ Set `scale_color_gradient2()` and `scale_fill_gradient()` for corr plot.
245
+
246
+ Parameters
247
+ ----------
248
+ low : str
249
+ Color for low end of gradient (correlation -1).
250
+ mid : str
251
+ Color for mid point (correlation 0).
252
+ high : str
253
+ Color for high end of gradient (correlation 1).
254
+
255
+ Returns
256
+ -------
257
+ `corr_plot`
258
+ Correlation plot specification.
259
+ """
260
+ return self._duplicate()._set_gradient_palette(low, mid, high)
261
+
262
+ def palette_BrBG(self):
263
+ """
264
+ Set `scale_color_brewer()` with BrBG palette for corr plot.
265
+
266
+ Returns
267
+ -------
268
+ `corr_plot`
269
+ Correlation plot specification.
270
+ """
271
+ return self._set_brewer_palette('BrBG')
272
+
273
+ def palette_PiYG(self):
274
+ """
275
+ Set `scale_color_brewer()` with PiYG palette for corr plot.
276
+
277
+ Returns
278
+ -------
279
+ `corr_plot`
280
+ Correlation plot specification.
281
+ """
282
+ return self._duplicate()._set_brewer_palette('PiYG')
283
+
284
+ def palette_PRGn(self):
285
+ """
286
+ Set `scale_color_brewer()` with PRGn palette for corr plot.
287
+
288
+ Returns
289
+ -------
290
+ `corr_plot`
291
+ Correlation plot specification.
292
+ """
293
+ return self._duplicate()._set_brewer_palette('PRGn')
294
+
295
+ def palette_PuOr(self):
296
+ """
297
+ Set `scale_color_brewer()` with PuOr palette for corr plot.
298
+
299
+ Returns
300
+ -------
301
+ `corr_plot`
302
+ Correlation plot specification.
303
+ """
304
+ return self._duplicate()._set_brewer_palette('PuOr')
305
+
306
+ def palette_RdBu(self):
307
+ """
308
+ Set `scale_color_brewer()` with RdBu palette for corr plot.
309
+
310
+ Returns
311
+ -------
312
+ `corr_plot`
313
+ Correlation plot specification.
314
+ """
315
+ return self._duplicate()._set_brewer_palette('RdBu')
316
+
317
+ def palette_RdGy(self):
318
+ """
319
+ Set `scale_color_brewer()` with RdGy palette for corr plot.
320
+
321
+ Returns
322
+ -------
323
+ `corr_plot`
324
+ Correlation plot specification.
325
+ """
326
+ return self._duplicate()._set_brewer_palette('RdGy')
327
+
328
+ def palette_RdYlBu(self):
329
+ """
330
+ Set `scale_color_brewer()` with RdYlBu palette for corr plot.
331
+
332
+ Returns
333
+ -------
334
+ `corr_plot`
335
+ Correlation plot specification.
336
+ """
337
+ return self._duplicate()._set_brewer_palette('RdYlBu')
338
+
339
+ def palette_RdYlGn(self):
340
+ """
341
+ Set `scale_color_brewer()` with RdYlGn palette for corr plot.
342
+
343
+ Returns
344
+ -------
345
+ `corr_plot`
346
+ Correlation plot specification.
347
+ """
348
+ return self._duplicate()._set_brewer_palette('RdYlGn')
349
+
350
+ def palette_Spectral(self):
351
+ """
352
+ Set `scale_color_brewer()` with Spectral palette for corr plot.
353
+
354
+ Returns
355
+ -------
356
+ `corr_plot`
357
+ Correlation plot specification.
358
+ """
359
+ return self._duplicate()._set_brewer_palette('Spectral')
360
+
361
+ def _set_points(self, type=None, diag=None):
362
+ self._points_params = {'type': type, 'diag': diag, 'threshold': self.threshold}
363
+ return self
364
+
365
+ def _set_labels(self, type=None, diag=None, map_size=None, color=None):
366
+ self._labels_params = {'type': type, 'diag': diag, 'color': color, 'threshold': self.threshold}
367
+ self._labels_map_size = map_size
368
+ return self
369
+
370
+ def _set_tiles(self, type=None, diag=None):
371
+ self._tiles_params = {'type': type, 'diag': diag, 'threshold': self.threshold}
372
+ return self
373
+
374
+ def _set_gradient_palette(self, low, mid, high):
375
+ self._palette = 'gradient'
376
+ self._low = low
377
+ self._mid = mid
378
+ self._high = high
379
+ return self
380
+
381
+ def _set_brewer_palette(self, palette):
382
+ self._palette = palette
383
+ self._low = None
384
+ self._mid = None
385
+ self._high = None
386
+ return self
387
+
388
+ def build(self) -> PlotSpec:
389
+ """
390
+ This method creates PlotSpec object.
391
+
392
+ Returns
393
+ -------
394
+ `PlotSpec`
395
+ Plot specification.
396
+ """
397
+
398
+ if self._points_params is not None:
399
+ point_params = {
400
+ 'type': self._points_params['type'],
401
+ 'diag': self._points_params['diag']
402
+ }
403
+ else:
404
+ point_params = None
405
+
406
+ if self._labels_params is not None:
407
+ label_params = {
408
+ 'type': self._labels_params['type'],
409
+ 'diag': self._labels_params['diag'],
410
+ 'color': self._labels_params['color'],
411
+ 'map_size': self._labels_map_size
412
+ }
413
+ else:
414
+ label_params = None
415
+
416
+ if self._tiles_params is not None:
417
+ tile_params = {
418
+ 'type': self._tiles_params['type'],
419
+ 'diag': self._tiles_params['diag']
420
+ }
421
+ else:
422
+ tile_params = None
423
+
424
+ data = self._data
425
+ if _is_corr_matrix(data):
426
+ coefficients = True
427
+ else:
428
+ if is_pandas_data_frame(data):
429
+ data = data.corr(numeric_only=True)
430
+ coefficients = True
431
+ else:
432
+ coefficients = False
433
+
434
+ return PlotSpec(data=data, mapping=None, scales=[], layers=[], bistro={
435
+ 'name': 'corr',
436
+ 'coefficients': coefficients,
437
+ 'show_legend': self._show_legend,
438
+ 'flip': self._reverse_y,
439
+ 'threshold': self.threshold,
440
+ 'palette': self._palette,
441
+ 'low': self._low,
442
+ 'mid': self._mid,
443
+ 'high': self._high,
444
+ 'point_params': point_params,
445
+ 'tile_params': tile_params,
446
+ 'label_params': label_params
447
+ })
lets_plot/bistro/im.py ADDED
@@ -0,0 +1,165 @@
1
+ #
2
+ # Copyright (c) 2019. JetBrains s.r.o.
3
+ # Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4
+ #
5
+ from typing import Any
6
+
7
+ from lets_plot._type_utils import is_ndarray
8
+ from lets_plot.plot.geom_imshow_ import geom_imshow
9
+ from lets_plot.plot.plot import ggplot, GGBunch
10
+ from lets_plot.plot.scale_position import scale_x_continuous, scale_y_continuous
11
+ from lets_plot.plot.theme_ import theme
12
+
13
+ __all__ = ['image_matrix']
14
+
15
+
16
+ def image_matrix(image_data_array, cmap=None, *, norm=None, vmin=None, vmax=None, scale=1) -> GGBunch:
17
+ """
18
+ Display a set of images in a grid.
19
+ Dimensions of the grid are determined by the shape of the input Numpy 2D array.
20
+
21
+ Each element of the input 2D array is an 2D or 3D Numpy array itself
22
+ specifying either a grayscale image (2D array) or a color RGB(A) image (3D array).
23
+ For more information on image arrays please see the documentation of geom_imshow() function.
24
+
25
+ Parameters
26
+ ----------
27
+ image_data_array : `ndarray`
28
+ 2D `numpy.ndarray` containing images.
29
+ cmap : str, optional
30
+ Name of colormap. For example "viridis", "magma", "plasma", "inferno", or any other colormap
31
+ which is supported by the Palettable package (https://github.com/jiffyclub/palettable)
32
+ This parameter is ignored for RGB(A) images.
33
+ norm : bool, optional, default=True
34
+ True - luminance values in grey-scale image will be scaled to [0-255] range using a linear scaler.
35
+ False - disables scaling of luminance values in grey-scale image.
36
+ This parameter is ignored for RGB(A) images.
37
+ vmin, vmax : number, optional
38
+ Define the data range used for luminance normalization in grey-scale images.
39
+ This parameter is ignored for RGB(A) images or if parameter `norm=False`.
40
+ scale : float, default=1.0
41
+ Specify the image size magnification factor.
42
+
43
+ Returns
44
+ -------
45
+ `GGBunch`
46
+ Plot bunch object.
47
+
48
+ Examples
49
+ --------
50
+ .. jupyter-execute::
51
+ :linenos:
52
+ :emphasize-lines: 9
53
+
54
+ import numpy as np
55
+ from lets_plot import *
56
+ from lets_plot.bistro.im import *
57
+ LetsPlot.setup_html()
58
+ np.random.seed(42)
59
+ image = np.random.randint(256, size=(64, 64, 3))
60
+ matrix = np.empty((2, 3), dtype=object)
61
+ matrix.fill(image)
62
+ image_matrix(matrix)
63
+
64
+ |
65
+
66
+ .. jupyter-execute::
67
+ :linenos:
68
+ :emphasize-lines: 12
69
+
70
+ import numpy as np
71
+ from lets_plot import *
72
+ from lets_plot.bistro.im import *
73
+ LetsPlot.setup_html()
74
+ rows, cols = 3, 3
75
+ matrix = np.empty((rows, cols), dtype=object)
76
+ for r in range(rows):
77
+ for c in range(cols):
78
+ w, h = 32 + 16 * c, 32 + 16 * r
79
+ matrix[r][c] = 256 * np.linspace(np.linspace(0, .5, w), \\
80
+ np.linspace(.5, .5, w), h)
81
+ image_matrix(matrix, norm=False, scale=1.5)
82
+
83
+ """
84
+
85
+ if not is_ndarray(image_data_array):
86
+ raise Exception("Invalid image_data_array: 2d ndarray is expacted but was {}".format(type(image_data_array)))
87
+
88
+ if image_data_array.ndim != 2:
89
+ raise Exception("Invalid image_data_array: 2-dimentional ndarray is expacted but was {}-dimentional".format(
90
+ image_data_array.ndim))
91
+
92
+ rows, cols = image_data_array.shape
93
+ if cols * rows <= 0:
94
+ return
95
+
96
+ w_max = 0
97
+ h_max = 0
98
+ for row in range(rows):
99
+ for col in range(cols):
100
+ image_data = image_data_array[row][col]
101
+ if image_data is None:
102
+ continue
103
+
104
+ _assert_image_data(image_data)
105
+ h, w = image_data.shape[0:2]
106
+ h, w = _expand_h_w(h, w, scale)
107
+ w_max = max(w_max, w)
108
+ h_max = max(h_max, h)
109
+
110
+ # no gaps between image and plot edges
111
+ options = scale_x_continuous(expand=[0, 0])
112
+ options += scale_y_continuous(expand=[0, 0])
113
+
114
+ # show no axis
115
+ options += theme(axis_line='blank', axis_title='blank', axis_ticks='blank', axis_text='blank')
116
+
117
+ ggbunch = GGBunch()
118
+
119
+ for row in range(rows):
120
+ for col in range(cols):
121
+ image_data = image_data_array[row][col]
122
+ if image_data is None:
123
+ continue
124
+
125
+ h, w = image_data.shape[0:2]
126
+ h, w = _expand_h_w(h, w, scale)
127
+ p = ggplot() + geom_imshow(
128
+ image_data=image_data,
129
+ cmap=cmap,
130
+ norm=norm,
131
+ vmin=vmin,
132
+ vmax=vmax,
133
+ show_legend=False
134
+ )
135
+ p += options
136
+ ggbunch.add_plot(p, col * w_max, row * h_max, w, h)
137
+
138
+ return ggbunch
139
+
140
+
141
+ def _assert_image_data(image_data: Any) -> None:
142
+ try:
143
+ import numpy as np
144
+ if not isinstance(image_data, np.ndarray):
145
+ raise Exception("Invalid image_data: ndarray is expacted but was {}".format(type(image_data)))
146
+
147
+ if image_data.ndim not in (2, 3):
148
+ raise Exception(
149
+ "Invalid image_data: 2d or 3d array is expacted but was {}-dimentional".format(image_data.ndim))
150
+ except ImportError:
151
+ pass
152
+
153
+
154
+ def _expand_h_w(h, w, scale):
155
+ if scale:
156
+ h *= scale
157
+ w *= scale
158
+
159
+ # Mininum plot geom area size: 50 x 50
160
+ h = 50 if h < 50 else h
161
+ w = 50 if w < 50 else w
162
+
163
+ # Currently plot has not customizable 10px padding on the right and the bottom
164
+ # return h + 10, w + 10
165
+ return h, w