lets-plot 4.3.3__cp312-cp312-win_amd64.whl → 4.4.0rc1__cp312-cp312-win_amd64.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.

lets_plot/__init__.py CHANGED
@@ -15,11 +15,13 @@ from ._global_settings import NO_JS, OFFLINE
15
15
  from .plot import *
16
16
  from .export import *
17
17
  from .frontend_context import *
18
+ from .mapping import *
18
19
  from .settings_utils import *
19
20
  from .plot._global_theme import _set_global_theme
20
21
 
21
22
  __all__ = (plot.__all__ +
22
23
  frontend_context.__all__ +
24
+ mapping.__all__ +
23
25
  settings_utils.__all__ +
24
26
  export.__all__ +
25
27
  ['LetsPlot'])
lets_plot/_type_utils.py CHANGED
@@ -39,6 +39,10 @@ def standardize_dict(value: Dict) -> Dict:
39
39
  return result
40
40
 
41
41
 
42
+ def is_pandas_data_frame(v) -> bool:
43
+ return pandas and isinstance(v, pandas.DataFrame)
44
+
45
+
42
46
  def is_polars_dataframe(v):
43
47
  return polars and isinstance(v, polars.DataFrame)
44
48
 
@@ -55,6 +59,10 @@ def is_float(v):
55
59
  return isinstance(v, float) or (numpy and isinstance(v, numpy.floating))
56
60
 
57
61
 
62
+ def is_ndarray(data) -> bool:
63
+ return numpy and isinstance(data, numpy.ndarray)
64
+
65
+
58
66
  def is_number(v):
59
67
  return is_int(v) or is_float(v)
60
68
 
lets_plot/_version.py CHANGED
@@ -3,4 +3,4 @@
3
3
  # Use of this source code is governed by the MIT license that can be found in the LICENSE file.
4
4
  #
5
5
  # see: https://www.python.org/dev/peps/pep-0440/#developmental-releases
6
- __version__ = '4.3.3'
6
+ __version__ = '4.4.0rc1'
@@ -6,9 +6,11 @@ from .im import *
6
6
  from .qq import *
7
7
  from .residual import *
8
8
  from .joint import *
9
+ from .waterfall import *
9
10
 
10
11
  __all__ = (im.__all__ +
11
12
  corr.__all__ +
12
13
  qq.__all__ +
13
14
  residual.__all__ +
14
- joint.__all__)
15
+ joint.__all__ +
16
+ waterfall.__all__)
lets_plot/bistro/corr.py CHANGED
@@ -5,7 +5,7 @@
5
5
  """Correlation matrix implementation module"""
6
6
  from typing import Any
7
7
 
8
- from lets_plot.plot.util import is_data_frame
8
+ from lets_plot.plot.util import is_pandas_data_frame
9
9
 
10
10
  try:
11
11
  import numpy
@@ -23,7 +23,7 @@ __all__ = ['corr_plot']
23
23
 
24
24
 
25
25
  def _is_corr_matrix(data: Any):
26
- if is_data_frame(data):
26
+ if is_pandas_data_frame(data):
27
27
  if data.shape[0] != data.shape[1]:
28
28
  return False
29
29
 
@@ -418,7 +418,7 @@ class corr_plot:
418
418
  if _is_corr_matrix(data):
419
419
  coefficients = True
420
420
  else:
421
- if is_data_frame(data):
421
+ if is_pandas_data_frame(data):
422
422
  data = data.corr(numeric_only=True)
423
423
  coefficients = True
424
424
  else:
lets_plot/bistro/im.py CHANGED
@@ -4,11 +4,11 @@
4
4
  #
5
5
  from typing import Any
6
6
 
7
+ from lets_plot._type_utils import is_ndarray
7
8
  from lets_plot.plot.geom_imshow_ import geom_imshow
8
9
  from lets_plot.plot.plot import ggplot, GGBunch
9
10
  from lets_plot.plot.scale_position import scale_x_continuous, scale_y_continuous
10
11
  from lets_plot.plot.theme_ import theme
11
- from lets_plot.plot.util import is_ndarray
12
12
 
13
13
  __all__ = ['image_matrix']
14
14
 
@@ -17,12 +17,12 @@ try:
17
17
  except ImportError:
18
18
  pl = None
19
19
 
20
- from ..plot.plot import ggplot
20
+ from ._plot2d_common import _get_bin_params_2d, _get_geom2d_layer, _get_marginal_layers
21
21
  from ..plot.core import DummySpec, aes
22
22
  from ..plot.geom import geom_hline
23
23
  from ..plot.label import ylab
24
+ from ..plot.plot import ggplot
24
25
  from ..plot.theme_ import *
25
- from ._plot2d_common import _get_bin_params_2d, _get_geom2d_layer, _get_marginal_layers
26
26
 
27
27
  __all__ = ['residual_plot']
28
28
 
@@ -114,7 +114,7 @@ def _get_stat_data(data, x, y, group_by, method, deg, span, seed, max_n):
114
114
  elif isinstance(data, pd.DataFrame):
115
115
  df = data.copy()
116
116
  elif pl is not None and isinstance(data, pl.DataFrame):
117
- df = pd.DataFrame(data.to_dict(False))
117
+ df = pd.DataFrame(data.to_dict(as_series=False))
118
118
  else:
119
119
  raise Exception("Unsupported type of data: {0}".format(data))
120
120
  df = df[(df[x].notna()) & df[y].notna()]
@@ -208,6 +208,11 @@ def residual_plot(data=None, x=None, y=None, *,
208
208
  `PlotSpec`
209
209
  Plot object specification.
210
210
 
211
+ Notes
212
+ -----
213
+ When using 'lm' and 'loess' methods,
214
+ this function requires the `statsmodels` and `scipy` libraries to be installed.
215
+
211
216
  Examples
212
217
  --------
213
218
  .. jupyter-execute::
@@ -0,0 +1,242 @@
1
+ # Copyright (c) 2024. 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
+ from lets_plot.plot.core import PlotSpec
5
+
6
+ __all__ = ['waterfall_plot']
7
+
8
+
9
+ def waterfall_plot(data, x, y, *,
10
+ measure=None, group=None,
11
+ color=None, fill=None, size=None, alpha=None, linetype=None,
12
+ width=None,
13
+ show_legend=None, relative_tooltips=None, absolute_tooltips=None,
14
+ sorted_value=None, threshold=None, max_values=None,
15
+ calc_total=None, total_title=None,
16
+ hline=None, hline_ontop=None,
17
+ connector=None,
18
+ label=None, label_format=None) -> PlotSpec:
19
+ """
20
+ A waterfall plot shows the cumulative effect of sequentially introduced positive or negative values.
21
+
22
+ Parameters
23
+ ----------
24
+ data : dict or Pandas or Polars `DataFrame`
25
+ The data to be displayed.
26
+ x : str
27
+ Name of a variable. All values should be distinct.
28
+ y : str
29
+ Name of a numeric variable.
30
+ measure : str
31
+ Kind of a calculation.
32
+ Values in 'measure' column could be:
33
+
34
+ 'absolute' - the value is shown as is;
35
+ 'relative' - the value is shown as a difference from the previous value;
36
+ 'total' - the value is shown as a cumulative sum of all previous values.
37
+
38
+ group : str
39
+ Grouping variable. Each group calculates its own statistics.
40
+ color : str
41
+ Color of the box boundary lines.
42
+ Use 'flow_type' to color lines by the direction of the flow.
43
+ fill : str
44
+ Fill color of the boxes.
45
+ Use 'flow_type' to color boxes by the direction of the flow.
46
+ size : float, default=0.0
47
+ Line width of the box boundary lines.
48
+ alpha : float
49
+ Transparency level of the boxes. Accept values between 0 and 1.
50
+ linetype : int or str
51
+ Type of the box boundary lines.
52
+ Codes and names: 0 = 'blank', 1 = 'solid', 2 = 'dashed',
53
+ 3 = 'dotted', 4 = 'dotdash', 5 = 'longdash', 6 = 'twodash'.
54
+ width : float, default=0.9
55
+ Width of the boxes. Typically range between 0 and 1.
56
+ Values that are greater than 1 lead to overlapping of the boxes.
57
+ show_legend : bool, default=False
58
+ True - show the legend.
59
+ relative_tooltips : `layer_tooltips` or str
60
+ Tooltips for boxes with relative values.
61
+ Result of the call to the `layer_tooltips()` function.
62
+ Specify appearance, style and content.
63
+ When 'none', tooltips are not shown.
64
+ When 'detailed', a more detailed (compared to the default) version of the tooltips is shown.
65
+ absolute_tooltips : `layer_tooltips` or str
66
+ Tooltips for boxes with absolute values.
67
+ Result of the call to the `layer_tooltips()` function.
68
+ Specify appearance, style and content.
69
+ When 'none', tooltips are not shown.
70
+ When 'detailed', a more detailed (compared to the default) version of the tooltips is shown.
71
+ sorted_value : bool, default=False
72
+ Sorts categories by absolute value of the changes.
73
+ threshold : float
74
+ Groups all categories under a certain threshold value into "Other" category.
75
+ max_values : int
76
+ Groups all categories with the smallest changes, except the first `max_values`, into "Other" category.
77
+ calc_total : bool, default=True
78
+ Setting the `calc_total` to True will put the final cumulative sum into a new separate box.
79
+ Taken into account only if the 'measure' column isn't provided.
80
+ total_title : str
81
+ The header of the last box with the final cumulative sum, if 'measure' column isn't provided.
82
+ Also used as a title in the legend for columns of type 'total'.
83
+ hline : str or dict
84
+ Horizontal line passing through 0.
85
+ Set 'blank' or result of `element_blank()` to draw nothing.
86
+ Set `element_line()` to specify parameters.
87
+ hline_ontop : bool, default=True
88
+ Option to place horizontal line over the other layers.
89
+ connector : str or dict
90
+ Line between neighbouring boxes connecting the end of the previous box and the beginning of the next box.
91
+ Set 'blank' or result of `element_blank()` to draw nothing.
92
+ Set `element_line()` to specify parameters.
93
+ label : str or dict
94
+ Label on the box. Shows change value.
95
+ Set 'blank' or result of `element_blank()` to draw nothing.
96
+ Set `element_text()` to specify parameters.
97
+ Use 'flow_type' for `color` parameter of the `element_text()` to color labels by the direction of the flow.
98
+ label_format : str
99
+ Format used to transform label mapping values to a string.
100
+ Examples:
101
+
102
+ - '.2f' -> '12.45'
103
+ - 'Num {}' -> 'Num 12.456789'
104
+ - 'TTL: {.2f}$' -> 'TTL: 12.45$'
105
+
106
+ For more info see https://lets-plot.org/python/pages/formats.html.
107
+
108
+ Returns
109
+ -------
110
+ `PlotSpec`
111
+ Plot object specification.
112
+
113
+ Notes
114
+ -----
115
+ Computed variables:
116
+
117
+ - ..x.. : category id.
118
+ - ..xlabel.. : category name.
119
+ - ..ymin.. : lower value of the change.
120
+ - ..ymax.. : upper value of the change.
121
+ - ..measure.. : kind of a calculation: absolute, relative or total.
122
+ - ..flow_type.. : direction of the flow: increasing, decreasing, or the result (total).
123
+ - ..initial.. : initial value of the change.
124
+ - ..value.. : current cumsum (result of the change) or absolute value (depending on the 'measure' column).
125
+ - ..dy.. : value of the change.
126
+
127
+ Examples
128
+ --------
129
+ .. jupyter-execute::
130
+ :linenos:
131
+ :emphasize-lines: 11
132
+
133
+ import numpy as np
134
+ from lets_plot import *
135
+ from lets_plot.bistro.waterfall import *
136
+ LetsPlot.setup_html()
137
+ categories = list("ABCDEF")
138
+ np.random.seed(42)
139
+ data = {
140
+ 'x': categories,
141
+ 'y': np.random.normal(size=len(categories))
142
+ }
143
+ waterfall_plot(data, 'x', 'y')
144
+
145
+ |
146
+
147
+ .. jupyter-execute::
148
+ :linenos:
149
+ :emphasize-lines: 12-18
150
+
151
+ import numpy as np
152
+ from lets_plot import *
153
+ from lets_plot.bistro.waterfall import *
154
+ LetsPlot.setup_html()
155
+ n, m = 10, 5
156
+ categories = list(range(n))
157
+ np.random.seed(42)
158
+ data = {
159
+ 'x': categories,
160
+ 'y': np.random.randint(2 * m + 1, size=len(categories)) - m
161
+ }
162
+ waterfall_plot(data, 'x', 'y', \\
163
+ threshold=2, \\
164
+ width=.7, size=1, fill="white", color='flow_type', \\
165
+ hline=element_line(linetype='solid'), hline_ontop=False, \\
166
+ connector=element_line(linetype='dotted'), \\
167
+ label=element_text(color='flow_type'), \\
168
+ total_title="Result", show_legend=True)
169
+
170
+ |
171
+
172
+ .. jupyter-execute::
173
+ :linenos:
174
+ :emphasize-lines: 11-20
175
+
176
+ import numpy as np
177
+ from lets_plot import *
178
+ from lets_plot.bistro.waterfall import *
179
+ LetsPlot.setup_html()
180
+ categories = list("ABCDEFGHIJKLMNOP")
181
+ np.random.seed(42)
182
+ data = {
183
+ 'x': categories,
184
+ 'y': np.random.uniform(-1, 1, size=len(categories))
185
+ }
186
+ waterfall_plot(data, 'x', 'y', sorted_value=True, max_values=5, calc_total=False, \\
187
+ relative_tooltips=layer_tooltips().title("Category: @..xlabel..")
188
+ .format("@..initial..", ".2~f")
189
+ .format("@..value..", ".2~f")
190
+ .format("@..dy..", ".2~f")
191
+ .line("@{..flow_type..}d from @..initial.. to @..value..")
192
+ .line("Difference: @..dy..")
193
+ .disable_splitting(), \\
194
+ size=1, alpha=.5, \\
195
+ label=element_text(color="black"), label_format=".4f")
196
+
197
+ |
198
+
199
+ .. jupyter-execute::
200
+ :linenos:
201
+ :emphasize-lines: 11
202
+
203
+ from lets_plot import *
204
+ from lets_plot.bistro.waterfall import *
205
+ LetsPlot.setup_html()
206
+ data = {
207
+ 'company': ["Badgersoft"] * 7 + ["AIlien Co."] * 7,
208
+ 'accounts': ["initial", "revenue", "costs", "Q1", "revenue", "costs", "Q2"] * 2,
209
+ 'values': [200, 200, -100, None, 250, -100, None, \\
210
+ 150, 50, -100, None, 100, -100, None],
211
+ 'measure': ['absolute', 'relative', 'relative', 'total', 'relative', 'relative', 'total'] * 2,
212
+ }
213
+ waterfall_plot(data, 'accounts', 'values', measure='measure', group='company') + \\
214
+ facet_wrap(facets='company', scales='free_x')
215
+
216
+ """
217
+ return PlotSpec(data=data, mapping=None, scales=[], layers=[], bistro={
218
+ 'name': 'waterfall',
219
+ 'x': x,
220
+ 'y': y,
221
+ 'measure': measure,
222
+ 'group': group,
223
+ 'color': color,
224
+ 'fill': fill,
225
+ 'size': size,
226
+ 'alpha': alpha,
227
+ 'linetype': linetype,
228
+ 'width': width,
229
+ 'show_legend': show_legend,
230
+ 'relative_tooltips': relative_tooltips,
231
+ 'absolute_tooltips': absolute_tooltips,
232
+ 'sorted_value': sorted_value,
233
+ 'threshold': threshold,
234
+ 'max_values': max_values,
235
+ 'calc_total': calc_total,
236
+ 'total_title': total_title,
237
+ 'hline': hline,
238
+ 'hline_ontop': hline_ontop,
239
+ 'connector': connector,
240
+ 'label': label,
241
+ 'label_format': label_format,
242
+ })
@@ -121,7 +121,11 @@ class BoundariesGeoDataFrame:
121
121
  geo_rings: List[ShapelyLinearRing] = [
122
122
  ShapelyLinearRing([(p.lon, p.lat) for p in ring.points]) for ring in polygon.rings
123
123
  ]
124
- return ShapelyPolygon(shell=geo_rings[0], holes=geo_rings[1:])
124
+
125
+ if len(geo_rings) == 0:
126
+ return ShapelyPolygon()
127
+ else:
128
+ return ShapelyPolygon(shell=geo_rings[0], holes=geo_rings[1:])
125
129
 
126
130
  def _geo_parse_point(self, geometry_data: GeoPoint) -> ShapelyPoint:
127
131
  return ShapelyPoint((geometry_data.lon, geometry_data.lat))
lets_plot/mapping.py CHANGED
@@ -1,6 +1,8 @@
1
1
  # Copyright (c) 2020. JetBrains s.r.o.
2
2
  # Use of this source code is governed by the MIT license that can be found in the LICENSE file.
3
3
 
4
+ __all__ = ['as_discrete']
5
+
4
6
 
5
7
  class MappingMeta:
6
8
  def __init__(self, variable, annotation, levels, **parameters):
@@ -18,7 +20,7 @@ class MappingMeta:
18
20
 
19
21
  def as_discrete(variable, label=None, order_by=None, order=None, levels=None):
20
22
  """
21
- The function is used to annotate a numeric data series as categorical data with the possibility of its ordering for the purposes of given visualization.
23
+ The function converts a column to a discrete scale and allows you to specify the order of its values.
22
24
 
23
25
  Parameters
24
26
  ----------
@@ -52,11 +54,10 @@ def as_discrete(variable, label=None, order_by=None, order=None, levels=None):
52
54
  --------
53
55
  .. jupyter-execute::
54
56
  :linenos:
55
- :emphasize-lines: 13
57
+ :emphasize-lines: 12
56
58
 
57
59
  import numpy as np
58
60
  from lets_plot import *
59
- from lets_plot.mapping import as_discrete
60
61
  LetsPlot.setup_html()
61
62
  n = 100
62
63
  np.random.seed(42)
@@ -72,11 +73,10 @@ def as_discrete(variable, label=None, order_by=None, order=None, levels=None):
72
73
 
73
74
  .. jupyter-execute::
74
75
  :linenos:
75
- :emphasize-lines: 12
76
+ :emphasize-lines: 11
76
77
 
77
78
  import numpy as np
78
79
  from lets_plot import *
79
- from lets_plot.mapping import as_discrete
80
80
  LetsPlot.setup_html()
81
81
  n = 100
82
82
  np.random.seed(42)
@@ -91,11 +91,10 @@ def as_discrete(variable, label=None, order_by=None, order=None, levels=None):
91
91
 
92
92
  .. jupyter-execute::
93
93
  :linenos:
94
- :emphasize-lines: 13-14
94
+ :emphasize-lines: 12-13
95
95
 
96
96
  import numpy as np
97
97
  from lets_plot import *
98
- from lets_plot.mapping import as_discrete
99
98
  LetsPlot.setup_html()
100
99
  n = 100
101
100
  np.random.seed(42)