lets-plot 4.8.1rc1__cp311-cp311-manylinux2014_x86_64.manylinux_2_17_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.
- lets_plot/__init__.py +382 -0
- lets_plot/_global_settings.py +192 -0
- lets_plot/_kbridge.py +197 -0
- lets_plot/_type_utils.py +133 -0
- lets_plot/_version.py +6 -0
- lets_plot/bistro/__init__.py +16 -0
- lets_plot/bistro/_plot2d_common.py +106 -0
- lets_plot/bistro/corr.py +448 -0
- lets_plot/bistro/im.py +196 -0
- lets_plot/bistro/joint.py +192 -0
- lets_plot/bistro/qq.py +207 -0
- lets_plot/bistro/residual.py +341 -0
- lets_plot/bistro/waterfall.py +332 -0
- lets_plot/export/__init__.py +6 -0
- lets_plot/export/ggsave_.py +172 -0
- lets_plot/frontend_context/__init__.py +8 -0
- lets_plot/frontend_context/_configuration.py +140 -0
- lets_plot/frontend_context/_dynamic_configure_html.py +115 -0
- lets_plot/frontend_context/_frontend_ctx.py +16 -0
- lets_plot/frontend_context/_html_contexts.py +223 -0
- lets_plot/frontend_context/_intellij_python_json_ctx.py +38 -0
- lets_plot/frontend_context/_isolated_webview_panel_ctx.py +81 -0
- lets_plot/frontend_context/_json_contexts.py +39 -0
- lets_plot/frontend_context/_jupyter_notebook_ctx.py +82 -0
- lets_plot/frontend_context/_mime_types.py +7 -0
- lets_plot/frontend_context/_static_html_page_ctx.py +76 -0
- lets_plot/frontend_context/_static_svg_ctx.py +26 -0
- lets_plot/frontend_context/_webbr_html_page_ctx.py +29 -0
- lets_plot/frontend_context/sandbox.py +5 -0
- lets_plot/geo_data/__init__.py +19 -0
- lets_plot/geo_data/core.py +335 -0
- lets_plot/geo_data/geocoder.py +988 -0
- lets_plot/geo_data/geocodes.py +512 -0
- lets_plot/geo_data/gis/__init__.py +0 -0
- lets_plot/geo_data/gis/fluent_dict.py +201 -0
- lets_plot/geo_data/gis/geocoding_service.py +42 -0
- lets_plot/geo_data/gis/geometry.py +91 -0
- lets_plot/geo_data/gis/json_request.py +232 -0
- lets_plot/geo_data/gis/json_response.py +308 -0
- lets_plot/geo_data/gis/request.py +492 -0
- lets_plot/geo_data/gis/response.py +247 -0
- lets_plot/geo_data/livemap_helper.py +65 -0
- lets_plot/geo_data/to_geo_data_frame.py +141 -0
- lets_plot/geo_data/type_assertion.py +34 -0
- lets_plot/geo_data_internals/__init__.py +4 -0
- lets_plot/geo_data_internals/constants.py +13 -0
- lets_plot/geo_data_internals/utils.py +33 -0
- lets_plot/mapping.py +115 -0
- lets_plot/package_data/lets-plot.min.js +3 -0
- lets_plot/plot/__init__.py +64 -0
- lets_plot/plot/_global_theme.py +14 -0
- lets_plot/plot/annotation.py +290 -0
- lets_plot/plot/coord.py +242 -0
- lets_plot/plot/core.py +1071 -0
- lets_plot/plot/expand_limits_.py +78 -0
- lets_plot/plot/facet.py +210 -0
- lets_plot/plot/font_features.py +71 -0
- lets_plot/plot/geom.py +9146 -0
- lets_plot/plot/geom_extras.py +53 -0
- lets_plot/plot/geom_function_.py +219 -0
- lets_plot/plot/geom_imshow_.py +393 -0
- lets_plot/plot/geom_livemap_.py +343 -0
- lets_plot/plot/ggbunch_.py +96 -0
- lets_plot/plot/gggrid_.py +139 -0
- lets_plot/plot/ggtb_.py +81 -0
- lets_plot/plot/guide.py +231 -0
- lets_plot/plot/label.py +187 -0
- lets_plot/plot/marginal_layer.py +181 -0
- lets_plot/plot/plot.py +245 -0
- lets_plot/plot/pos.py +344 -0
- lets_plot/plot/sampling.py +338 -0
- lets_plot/plot/sandbox_.py +26 -0
- lets_plot/plot/scale.py +3580 -0
- lets_plot/plot/scale_colormap_mpl.py +300 -0
- lets_plot/plot/scale_convenience.py +155 -0
- lets_plot/plot/scale_identity_.py +653 -0
- lets_plot/plot/scale_position.py +1342 -0
- lets_plot/plot/series_meta.py +209 -0
- lets_plot/plot/stat.py +585 -0
- lets_plot/plot/subplots.py +331 -0
- lets_plot/plot/subplots_util.py +24 -0
- lets_plot/plot/theme_.py +790 -0
- lets_plot/plot/theme_set.py +418 -0
- lets_plot/plot/tooltip.py +486 -0
- lets_plot/plot/util.py +267 -0
- lets_plot/settings_utils.py +244 -0
- lets_plot/tilesets.py +429 -0
- lets_plot-4.8.1rc1.dist-info/METADATA +221 -0
- lets_plot-4.8.1rc1.dist-info/RECORD +97 -0
- lets_plot-4.8.1rc1.dist-info/WHEEL +6 -0
- lets_plot-4.8.1rc1.dist-info/licenses/LICENSE +21 -0
- lets_plot-4.8.1rc1.dist-info/licenses/licenses/LICENSE.FreeType +166 -0
- lets_plot-4.8.1rc1.dist-info/licenses/licenses/LICENSE.ImageMagick +106 -0
- lets_plot-4.8.1rc1.dist-info/licenses/licenses/LICENSE.expat +21 -0
- lets_plot-4.8.1rc1.dist-info/licenses/licenses/LICENSE.fontconfig +200 -0
- lets_plot-4.8.1rc1.dist-info/top_level.txt +2 -0
- lets_plot_kotlin_bridge.cpython-311-x86_64-linux-gnu.so +0 -0
|
@@ -0,0 +1,343 @@
|
|
|
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 enum import Enum
|
|
6
|
+
from typing import Union, Optional, List
|
|
7
|
+
|
|
8
|
+
from lets_plot._global_settings import MAPTILES_KIND, MAPTILES_URL, MAPTILES_THEME, MAPTILES_ATTRIBUTION, \
|
|
9
|
+
GEOCODING_PROVIDER_URL, GEOCODING_ROUTE, \
|
|
10
|
+
TILES_RASTER_ZXY, TILES_VECTOR_LETS_PLOT, MAPTILES_MIN_ZOOM, MAPTILES_MAX_ZOOM, TILES_SOLID, \
|
|
11
|
+
MAPTILES_SOLID_FILL_COLOR, TILES_CHESSBOARD
|
|
12
|
+
from lets_plot._global_settings import has_global_value, get_global_val
|
|
13
|
+
from .geom import _geom
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
import pandas
|
|
17
|
+
except ImportError:
|
|
18
|
+
pandas = None
|
|
19
|
+
|
|
20
|
+
# from ..geo_data.livemap_helper import _prepare_location
|
|
21
|
+
# from ..geo_data.livemap_helper import _prepare_parent
|
|
22
|
+
# from ..geo_data.livemap_helper import _prepare_tiles
|
|
23
|
+
|
|
24
|
+
__all__ = ['geom_livemap']
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def geom_livemap(*,
|
|
28
|
+
location=None,
|
|
29
|
+
zoom=None,
|
|
30
|
+
projection=None,
|
|
31
|
+
tiles=None,
|
|
32
|
+
show_coord_pick_tools=None,
|
|
33
|
+
data_size_zoomin=None,
|
|
34
|
+
const_size_zoomin=None,
|
|
35
|
+
**other_args):
|
|
36
|
+
"""
|
|
37
|
+
Display an interactive map.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
location : list
|
|
42
|
+
Initial position of the map. If not set, display the United States.
|
|
43
|
+
There are [lon1, lat1, lon2, lat2,..., lonN, latN]:
|
|
44
|
+
lon1, lon2,..., lonN are longitudes in degrees (positive in the Eastern hemisphere);
|
|
45
|
+
lat1, lat2,..., latN are latitudes in degrees (positive in the Northern hemisphere).
|
|
46
|
+
zoom : int
|
|
47
|
+
Zoom of the map in the range 1 - 15.
|
|
48
|
+
projection : str, default='epsg3857'
|
|
49
|
+
The map projection. There are: 'epsg3857' for Mercator projection;
|
|
50
|
+
'epsg4326' for Equirectangular projection. ``projection`` only works
|
|
51
|
+
with vector map tiles (i.e. Lets-Plot map tiles).
|
|
52
|
+
tiles : str
|
|
53
|
+
Tile provider:
|
|
54
|
+
|
|
55
|
+
- pass a predefined constant from the ``tilesets`` module (Lets-Plot's vector tiles, e.g. `LETS_PLOT_COLOR <https://lets-plot.org/python/pages/api/lets_plot.tilesets.LETS_PLOT_COLOR.html>`__, or external raster tiles, e.g. `OPEN_TOPO_MAP <https://lets-plot.org/python/pages/api/lets_plot.tilesets.OPEN_TOPO_MAP.html>`__);
|
|
56
|
+
- pass a URL for a standard raster ZXY tile provider with {z}, {x} and {y} wildcards (e.g. 'http://my.tile.com/{z}/{x}/{y}.png') if the required tileset not present in the module;
|
|
57
|
+
- pass the result of a call to a `maptiles_zxy() <https://lets-plot.org/python/pages/api/lets_plot.maptiles_zxy.html>`__ function if further customisation is required (e.g. attribution or zoom).
|
|
58
|
+
|
|
59
|
+
More information about tiles can be found here:
|
|
60
|
+
https://lets-plot.org/python/pages/basemap_tiles.html
|
|
61
|
+
show_coord_pick_tools : bool, default=False
|
|
62
|
+
Show buttons "copy location" and "draw geometry".
|
|
63
|
+
data_size_zoomin : int, default=0
|
|
64
|
+
Control how zooming-in of the map widget increases size of geometry objects (circles, lines etc.) on map
|
|
65
|
+
when the size is set by means of mapping between the data and the ``size`` aesthetic.
|
|
66
|
+
|
|
67
|
+
0 - size never increases;
|
|
68
|
+
|
|
69
|
+
-1 - size will be increasing without limits;
|
|
70
|
+
|
|
71
|
+
n - a number of zooming-in steps (counting from the initial state of the map widget)
|
|
72
|
+
when size of objects will be increasing. Farther zooming will no longer affect the size.
|
|
73
|
+
|
|
74
|
+
const_size_zoomin : int, default=-1
|
|
75
|
+
Control how zooming-in of the map widget increases size of geometry objects (circles, lines etc.) on map
|
|
76
|
+
when the size is not linked to a data (i.e. constant size).
|
|
77
|
+
|
|
78
|
+
0 - size never increases;
|
|
79
|
+
|
|
80
|
+
-1 - size will be increasing without limits;
|
|
81
|
+
|
|
82
|
+
n - a number of zooming-in steps (counting from the initial state of the map widget)
|
|
83
|
+
when size of objects will be increasing. Farther zooming will no longer affect the size.
|
|
84
|
+
|
|
85
|
+
other_args
|
|
86
|
+
Other arguments passed on to the layer.
|
|
87
|
+
|
|
88
|
+
Returns
|
|
89
|
+
-------
|
|
90
|
+
``LayerSpec``
|
|
91
|
+
Geom object specification.
|
|
92
|
+
|
|
93
|
+
Notes
|
|
94
|
+
-----
|
|
95
|
+
``geom_livemap()`` draws a map, which can be dragged and zoomed.
|
|
96
|
+
|
|
97
|
+
----
|
|
98
|
+
|
|
99
|
+
By default the livemap area has a non-zero inset. You can get rid of this with the theme: ``theme(plot_inset=0)``.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
When drawing a path with two points, the shortest route is taken. To create a longer arc, add intermediate points.
|
|
104
|
+
|
|
105
|
+
Examples
|
|
106
|
+
--------
|
|
107
|
+
.. jupyter-execute::
|
|
108
|
+
:linenos:
|
|
109
|
+
:emphasize-lines: 3
|
|
110
|
+
|
|
111
|
+
from lets_plot import *
|
|
112
|
+
LetsPlot.setup_html()
|
|
113
|
+
ggplot() + geom_livemap()
|
|
114
|
+
|
|
115
|
+
|
|
|
116
|
+
|
|
117
|
+
.. jupyter-execute::
|
|
118
|
+
:linenos:
|
|
119
|
+
:emphasize-lines: 10
|
|
120
|
+
|
|
121
|
+
from lets_plot import *
|
|
122
|
+
from lets_plot import tilesets
|
|
123
|
+
LetsPlot.setup_html()
|
|
124
|
+
data = {
|
|
125
|
+
'city': ['New York City', 'Prague'],
|
|
126
|
+
'lon': [-73.7997, 14.418540],
|
|
127
|
+
'lat': [40.6408, 50.073658],
|
|
128
|
+
}
|
|
129
|
+
ggplot(data, aes(x='lon', y='lat')) + \\
|
|
130
|
+
geom_livemap(projection='epsg4326', tiles=tilesets.LETS_PLOT_DARK) + \\
|
|
131
|
+
geom_path(color='white', geodesic=True) + \\
|
|
132
|
+
geom_point(color='white', tooltips=layer_tooltips().line('@city')) + \\
|
|
133
|
+
ggtitle("The shortest path between New York and Prague")
|
|
134
|
+
|
|
135
|
+
|
|
|
136
|
+
|
|
137
|
+
.. jupyter-execute::
|
|
138
|
+
:linenos:
|
|
139
|
+
:emphasize-lines: 9
|
|
140
|
+
|
|
141
|
+
from lets_plot import *
|
|
142
|
+
LetsPlot.setup_html()
|
|
143
|
+
data = {
|
|
144
|
+
'x': [-170, 170, -170, 0, 170],
|
|
145
|
+
'y': [10, 10, -10, -10, -10],
|
|
146
|
+
'route': ['A', 'A', 'B', 'B', 'B'],
|
|
147
|
+
}
|
|
148
|
+
ggplot(data) + \\
|
|
149
|
+
geom_livemap(zoom=1, location=[180, 0]) + \\
|
|
150
|
+
geom_path(aes('x', 'y', color='route'), size=1) + \\
|
|
151
|
+
scale_color_manual(values=['red', 'green'],
|
|
152
|
+
labels={'A': "'x': [-170, 170]",
|
|
153
|
+
'B': "'x': [-170, 0, 170]"}) + \\
|
|
154
|
+
ggtitle("A path that crosses the antimeridian")
|
|
155
|
+
|
|
156
|
+
"""
|
|
157
|
+
if 'symbol' in other_args:
|
|
158
|
+
print("WARN: The parameter 'symbol' is no longer supported. "
|
|
159
|
+
"Use separate geom_point() or geom_pie() geometry layers to display markers on the map.")
|
|
160
|
+
other_args.pop('symbol')
|
|
161
|
+
|
|
162
|
+
deprecated_params = set.intersection(
|
|
163
|
+
{'data', 'mapping', 'map', 'map_join', 'ontop', 'stat', 'position', 'show_legend', 'sampling', 'tooltips'},
|
|
164
|
+
other_args
|
|
165
|
+
)
|
|
166
|
+
if len(deprecated_params) > 0:
|
|
167
|
+
print(f"WARN: These parameters are not supported and will be ignored: {str(deprecated_params):s}. "
|
|
168
|
+
"Specify a separate geometry layer to display data on the livemap.")
|
|
169
|
+
|
|
170
|
+
for param in deprecated_params:
|
|
171
|
+
other_args.pop(param)
|
|
172
|
+
|
|
173
|
+
if location is not None:
|
|
174
|
+
location = _prepare_location(location)
|
|
175
|
+
|
|
176
|
+
tiles = _prepare_tiles(tiles)
|
|
177
|
+
geocoding = _prepare_geocoding()
|
|
178
|
+
|
|
179
|
+
return _geom('livemap',
|
|
180
|
+
mapping=None,
|
|
181
|
+
data=None,
|
|
182
|
+
stat=None,
|
|
183
|
+
position=None,
|
|
184
|
+
show_legend=None,
|
|
185
|
+
sampling=None,
|
|
186
|
+
tooltips=None,
|
|
187
|
+
map=None, map_join=None,
|
|
188
|
+
location=location,
|
|
189
|
+
zoom=zoom,
|
|
190
|
+
projection=projection,
|
|
191
|
+
tiles=tiles,
|
|
192
|
+
geocoding=geocoding,
|
|
193
|
+
show_coord_pick_tools=show_coord_pick_tools,
|
|
194
|
+
data_size_zoomin=data_size_zoomin,
|
|
195
|
+
const_size_zoomin=const_size_zoomin,
|
|
196
|
+
**other_args
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
LOCATION_COORDINATE_COLUMNS = {'lon', 'lat'}
|
|
201
|
+
LOCATION_RECTANGLE_COLUMNS = {'lonmin', 'latmin', 'lonmax', 'latmax'}
|
|
202
|
+
LOCATION_LIST_ERROR_MESSAGE = "Expected: location = [double lon1, double lat1, ... , double lonN, double latN]"
|
|
203
|
+
LOCATION_DATAFRAME_ERROR_MESSAGE = "Expected: location = DataFrame with [{}] or [{}] columns" \
|
|
204
|
+
.format(', '.join(LOCATION_COORDINATE_COLUMNS), ', '.join(LOCATION_RECTANGLE_COLUMNS))
|
|
205
|
+
|
|
206
|
+
OPTIONS_MAPTILES_KIND = 'kind'
|
|
207
|
+
OPTIONS_MAPTILES_URL = 'url'
|
|
208
|
+
OPTIONS_MAPTILES_THEME = 'theme'
|
|
209
|
+
OPTIONS_MAPTILES_ATTRIBUTION = 'attribution'
|
|
210
|
+
OPTIONS_MAPTILES_MIN_ZOOM = 'min_zoom'
|
|
211
|
+
OPTIONS_MAPTILES_MAX_ZOOM = 'max_zoom'
|
|
212
|
+
OPTIONS_MAPTILES_FILL_COLOR = 'fill_color'
|
|
213
|
+
OPTIONS_GEOCODING_PROVIDER_URL = 'url'
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class RegionKind(Enum):
|
|
217
|
+
region_ids = 'region_ids'
|
|
218
|
+
region_name = 'region_name'
|
|
219
|
+
coordinates = 'coordinates'
|
|
220
|
+
data_frame = 'data_frame'
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _prepare_geocoding():
|
|
224
|
+
if has_global_value(GEOCODING_PROVIDER_URL):
|
|
225
|
+
return {
|
|
226
|
+
OPTIONS_GEOCODING_PROVIDER_URL: get_global_val(GEOCODING_PROVIDER_URL) + GEOCODING_ROUTE
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return {}
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _prepare_tiles(tiles: Optional[Union[str, dict]]) -> Optional[dict]:
|
|
233
|
+
if isinstance(tiles, str):
|
|
234
|
+
return {
|
|
235
|
+
OPTIONS_MAPTILES_KIND: TILES_RASTER_ZXY,
|
|
236
|
+
OPTIONS_MAPTILES_URL: tiles
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if isinstance(tiles, dict):
|
|
240
|
+
if tiles.get(MAPTILES_KIND) == TILES_RASTER_ZXY:
|
|
241
|
+
_warn_deprecated_tiles(tiles)
|
|
242
|
+
return {
|
|
243
|
+
OPTIONS_MAPTILES_KIND: TILES_RASTER_ZXY,
|
|
244
|
+
OPTIONS_MAPTILES_URL: tiles[MAPTILES_URL],
|
|
245
|
+
OPTIONS_MAPTILES_ATTRIBUTION: tiles[MAPTILES_ATTRIBUTION],
|
|
246
|
+
OPTIONS_MAPTILES_MIN_ZOOM: tiles[MAPTILES_MIN_ZOOM],
|
|
247
|
+
OPTIONS_MAPTILES_MAX_ZOOM: tiles[MAPTILES_MAX_ZOOM],
|
|
248
|
+
}
|
|
249
|
+
elif tiles.get(MAPTILES_KIND) == TILES_VECTOR_LETS_PLOT:
|
|
250
|
+
return {
|
|
251
|
+
OPTIONS_MAPTILES_KIND: TILES_VECTOR_LETS_PLOT,
|
|
252
|
+
OPTIONS_MAPTILES_URL: tiles[MAPTILES_URL],
|
|
253
|
+
OPTIONS_MAPTILES_THEME: tiles[MAPTILES_THEME],
|
|
254
|
+
OPTIONS_MAPTILES_ATTRIBUTION: tiles[MAPTILES_ATTRIBUTION],
|
|
255
|
+
}
|
|
256
|
+
elif tiles.get(MAPTILES_KIND) == TILES_SOLID:
|
|
257
|
+
return {
|
|
258
|
+
OPTIONS_MAPTILES_KIND: TILES_SOLID,
|
|
259
|
+
OPTIONS_MAPTILES_FILL_COLOR: tiles[MAPTILES_SOLID_FILL_COLOR]
|
|
260
|
+
}
|
|
261
|
+
elif tiles.get(MAPTILES_KIND) == TILES_CHESSBOARD:
|
|
262
|
+
return {
|
|
263
|
+
OPTIONS_MAPTILES_KIND: TILES_CHESSBOARD
|
|
264
|
+
}
|
|
265
|
+
else:
|
|
266
|
+
raise ValueError("Unsupported 'tiles' kind: " + tiles.get(MAPTILES_KIND))
|
|
267
|
+
|
|
268
|
+
if tiles is not None:
|
|
269
|
+
raise ValueError("Unsupported 'tiles' parameter type: " + type(tiles))
|
|
270
|
+
|
|
271
|
+
# tiles are not set for this livemap - try to get global tiles config
|
|
272
|
+
if has_global_value(MAPTILES_KIND):
|
|
273
|
+
if not has_global_value(MAPTILES_URL):
|
|
274
|
+
raise ValueError('URL for tiles service is not set')
|
|
275
|
+
|
|
276
|
+
if get_global_val(MAPTILES_KIND) == TILES_RASTER_ZXY:
|
|
277
|
+
_warn_deprecated_tiles(None)
|
|
278
|
+
return {
|
|
279
|
+
OPTIONS_MAPTILES_KIND: TILES_RASTER_ZXY,
|
|
280
|
+
OPTIONS_MAPTILES_URL: get_global_val(MAPTILES_URL),
|
|
281
|
+
OPTIONS_MAPTILES_ATTRIBUTION: get_global_val(MAPTILES_ATTRIBUTION) if has_global_value(
|
|
282
|
+
MAPTILES_ATTRIBUTION) else None,
|
|
283
|
+
OPTIONS_MAPTILES_MIN_ZOOM: get_global_val(MAPTILES_MIN_ZOOM) if has_global_value(
|
|
284
|
+
MAPTILES_MIN_ZOOM) else None,
|
|
285
|
+
OPTIONS_MAPTILES_MAX_ZOOM: get_global_val(MAPTILES_MAX_ZOOM) if has_global_value(
|
|
286
|
+
MAPTILES_MAX_ZOOM) else None,
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if get_global_val(MAPTILES_KIND) == TILES_VECTOR_LETS_PLOT:
|
|
290
|
+
return {
|
|
291
|
+
OPTIONS_MAPTILES_KIND: TILES_VECTOR_LETS_PLOT,
|
|
292
|
+
OPTIONS_MAPTILES_URL: get_global_val(MAPTILES_URL),
|
|
293
|
+
OPTIONS_MAPTILES_THEME: get_global_val(MAPTILES_THEME) if has_global_value(MAPTILES_THEME) else None,
|
|
294
|
+
OPTIONS_MAPTILES_ATTRIBUTION: get_global_val(MAPTILES_ATTRIBUTION) if has_global_value(
|
|
295
|
+
MAPTILES_ATTRIBUTION) else None,
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if get_global_val(MAPTILES_KIND) == TILES_SOLID:
|
|
299
|
+
return {
|
|
300
|
+
OPTIONS_MAPTILES_KIND: TILES_SOLID,
|
|
301
|
+
OPTIONS_MAPTILES_FILL_COLOR: get_global_val(MAPTILES_SOLID_FILL_COLOR),
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
raise ValueError('Tile provider is not set.')
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def _warn_deprecated_tiles(tiles: Union[dict, None]):
|
|
308
|
+
if tiles is None:
|
|
309
|
+
maptiles_url = get_global_val(MAPTILES_URL)
|
|
310
|
+
else:
|
|
311
|
+
maptiles_url = tiles[MAPTILES_URL]
|
|
312
|
+
|
|
313
|
+
# Check if the current tiles should be deprecated and print a deprecation message. Otherwise, return.
|
|
314
|
+
return
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def _prepare_location(location: Union[str, List[float]]) -> Optional[dict]:
|
|
318
|
+
if location is None:
|
|
319
|
+
return None
|
|
320
|
+
|
|
321
|
+
value = location
|
|
322
|
+
# if isinstance(location, Geocoder):
|
|
323
|
+
# kind = RegionKind.region_ids
|
|
324
|
+
# value = location.unique_ids()
|
|
325
|
+
|
|
326
|
+
if isinstance(location, str):
|
|
327
|
+
kind = RegionKind.region_name
|
|
328
|
+
|
|
329
|
+
elif isinstance(location, list):
|
|
330
|
+
if len(location) == 0 or len(location) % 2 != 0:
|
|
331
|
+
raise ValueError(LOCATION_LIST_ERROR_MESSAGE)
|
|
332
|
+
kind = RegionKind.coordinates
|
|
333
|
+
|
|
334
|
+
elif pandas and isinstance(location, pandas.DataFrame):
|
|
335
|
+
if not LOCATION_COORDINATE_COLUMNS.issubset(location.columns) and not LOCATION_RECTANGLE_COLUMNS.issubset(
|
|
336
|
+
location.columns):
|
|
337
|
+
raise ValueError(LOCATION_DATAFRAME_ERROR_MESSAGE)
|
|
338
|
+
kind = RegionKind.data_frame
|
|
339
|
+
|
|
340
|
+
else:
|
|
341
|
+
raise ValueError('Wrong location type: ' + location.__str__())
|
|
342
|
+
|
|
343
|
+
return {'type': kind.value, 'data': value}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Copyright (c) 2025. 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 numbers import Number
|
|
5
|
+
from typing import List, Tuple
|
|
6
|
+
|
|
7
|
+
from ._global_theme import _get_global_theme
|
|
8
|
+
from .subplots import SupPlotsLayoutSpec
|
|
9
|
+
from .subplots import SupPlotsSpec
|
|
10
|
+
from .subplots_util import _strip_theme_if_global
|
|
11
|
+
|
|
12
|
+
__all__ = ['ggbunch']
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def ggbunch(plots: List,
|
|
16
|
+
regions: List[Tuple[float, float, float, float, float, float]]
|
|
17
|
+
) -> SupPlotsSpec:
|
|
18
|
+
"""
|
|
19
|
+
Combine several plots into a single figure with custom layout.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
plots : List
|
|
24
|
+
A list where each element is one of:
|
|
25
|
+
|
|
26
|
+
- a plot specification
|
|
27
|
+
- a subplots specification
|
|
28
|
+
- None
|
|
29
|
+
|
|
30
|
+
regions : List[Tuple]
|
|
31
|
+
Layout parameters for each plot. Each region is specified as
|
|
32
|
+
(x, y, width, height, dx, dy) where:
|
|
33
|
+
|
|
34
|
+
- x, y: Position of the plot's top-left corner in relative coordinates ([0,0] is top-left corner, [1,1] is bottom-right corner of the container).
|
|
35
|
+
- width, height: Size of the plot relative to container dimensions (1 equal to the full container width/height).
|
|
36
|
+
- dx, dy: Pixel offsets to move the region (defaults to 0).
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
|
+
``SupPlotsSpec``
|
|
41
|
+
A specification describing the combined figure with all plots and their layout.
|
|
42
|
+
|
|
43
|
+
Examples
|
|
44
|
+
--------
|
|
45
|
+
.. jupyter-execute::
|
|
46
|
+
:linenos:
|
|
47
|
+
:emphasize-lines: 10-14
|
|
48
|
+
|
|
49
|
+
import numpy as np
|
|
50
|
+
from lets_plot import *
|
|
51
|
+
LetsPlot.setup_html()
|
|
52
|
+
np.random.seed(42)
|
|
53
|
+
data = {'x': np.random.gamma(2.0, size=100)}
|
|
54
|
+
p1 = ggplot(data, aes(x='x')) + \\
|
|
55
|
+
geom_histogram(aes(color='x', fill='x'))
|
|
56
|
+
p2 = ggplot(data, aes(x='x')) + \\
|
|
57
|
+
geom_density() + theme_bw() + theme(axis='blank', panel_grid='blank')
|
|
58
|
+
ggbunch(
|
|
59
|
+
[p1, p2],
|
|
60
|
+
[(0, 0, 1, 1),
|
|
61
|
+
(0.5, 0.1, 0.3, 0.3)]
|
|
62
|
+
) + ggsize(400, 300)
|
|
63
|
+
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
if not len(plots):
|
|
67
|
+
raise ValueError("Supplots list is empty.")
|
|
68
|
+
|
|
69
|
+
# Validate provided regions
|
|
70
|
+
for i, region in enumerate(regions):
|
|
71
|
+
if len(region) not in (4, 6):
|
|
72
|
+
raise ValueError(f"Region {i} must have 4 or 6 values, got {len(region)}")
|
|
73
|
+
if not all(isinstance(x, Number) for x in region):
|
|
74
|
+
raise ValueError(f"Region {i} contains non-numeric values: {region}")
|
|
75
|
+
|
|
76
|
+
# Validate size is positive
|
|
77
|
+
if any(x <= 0 for x in region[2:4]):
|
|
78
|
+
raise ValueError(f"Region {i} sizes must be positive: {region}")
|
|
79
|
+
|
|
80
|
+
# Convert regions tuples to lists
|
|
81
|
+
regions_list = [list(r) for r in regions]
|
|
82
|
+
layout = SupPlotsLayoutSpec(
|
|
83
|
+
name="free",
|
|
84
|
+
regions=regions_list
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
figures = [_strip_theme_if_global(fig) for fig in plots]
|
|
88
|
+
|
|
89
|
+
figure_spec = SupPlotsSpec(figures=figures, layout=layout)
|
|
90
|
+
|
|
91
|
+
# Apply global theme if defined
|
|
92
|
+
global_theme_options = _get_global_theme()
|
|
93
|
+
if global_theme_options is not None:
|
|
94
|
+
figure_spec += global_theme_options
|
|
95
|
+
|
|
96
|
+
return figure_spec
|
|
@@ -0,0 +1,139 @@
|
|
|
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
|
+
|
|
6
|
+
from ._global_theme import _get_global_theme
|
|
7
|
+
from .subplots import SupPlotsLayoutSpec
|
|
8
|
+
from .subplots import SupPlotsSpec
|
|
9
|
+
from .subplots_util import _strip_theme_if_global
|
|
10
|
+
|
|
11
|
+
__all__ = ['gggrid']
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def gggrid(plots: list, ncol: int = None, *,
|
|
15
|
+
sharex: str = None,
|
|
16
|
+
sharey: str = None,
|
|
17
|
+
widths: list = None,
|
|
18
|
+
heights: list = None,
|
|
19
|
+
hspace: float = None,
|
|
20
|
+
vspace: float = None,
|
|
21
|
+
fit: bool = None,
|
|
22
|
+
align: bool = None,
|
|
23
|
+
guides: str = None
|
|
24
|
+
) -> SupPlotsSpec:
|
|
25
|
+
"""
|
|
26
|
+
Combine several plots on one figure, organized in a regular grid.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
plots : list
|
|
31
|
+
A list where each element is a plot specification, a subplot specification, or None.
|
|
32
|
+
Use None to fill in empty cells in the grid.
|
|
33
|
+
ncol : int
|
|
34
|
+
Number of columns in the grid.
|
|
35
|
+
If not specified, shows plots horizontally, in one row.
|
|
36
|
+
sharex, sharey : bool or str, default=False
|
|
37
|
+
Controls sharing of axis limits between subplots in the grid.
|
|
38
|
+
|
|
39
|
+
- 'all'/True - share limits between all subplots.
|
|
40
|
+
- 'none'/False - do not share limits between subplots.
|
|
41
|
+
- 'row' - share limits between subplots in the same row.
|
|
42
|
+
- 'col' - share limits between subplots in the same column.
|
|
43
|
+
|
|
44
|
+
widths : list of numbers
|
|
45
|
+
Relative width of each column in the grid, left to right.
|
|
46
|
+
heights : list of numbers
|
|
47
|
+
Relative height of each row in the grid, top-down.
|
|
48
|
+
hspace : float, default=4.0
|
|
49
|
+
Cell horizontal spacing in px.
|
|
50
|
+
vspace : float, default=4.0
|
|
51
|
+
Cell vertical spacing in px.
|
|
52
|
+
fit : bool, default=True
|
|
53
|
+
Whether to stretch each plot to match the aspect ratio of its cell (``fit=True``),
|
|
54
|
+
or to preserve the original aspect ratio of plots (``fit=False``).
|
|
55
|
+
align : bool, default=False
|
|
56
|
+
If True, align inner areas (i.e. "geom" bounds) of plots.
|
|
57
|
+
However, cells containing other (sub)grids are not participating in the plot "inner areas" layouting.
|
|
58
|
+
guides : str, default='auto'
|
|
59
|
+
Specifies how guides (legends and colorbars) should be treated in the layout.
|
|
60
|
+
|
|
61
|
+
- 'collect' - collect guides from all subplots, removing duplicates.
|
|
62
|
+
- 'keep' - keep guides in their original subplots; do not collect at this level.
|
|
63
|
+
- 'auto' - allow guides to be collected if an upper-level layout uses ``guides='collect'``; otherwise, keep them in subplots.
|
|
64
|
+
|
|
65
|
+
Duplicates are identified by comparing visual properties:
|
|
66
|
+
|
|
67
|
+
- For legends: title, labels, and all aesthetic values (colors, shapes, sizes, etc.).
|
|
68
|
+
- For colorbars: title, domain limits, breaks, and color gradient.
|
|
69
|
+
|
|
70
|
+
Returns
|
|
71
|
+
-------
|
|
72
|
+
``SupPlotsSpec``
|
|
73
|
+
The grid specification.
|
|
74
|
+
|
|
75
|
+
Examples
|
|
76
|
+
--------
|
|
77
|
+
.. jupyter-execute::
|
|
78
|
+
:linenos:
|
|
79
|
+
:emphasize-lines: 11, 14
|
|
80
|
+
|
|
81
|
+
import numpy as np
|
|
82
|
+
from lets_plot import *
|
|
83
|
+
LetsPlot.setup_html()
|
|
84
|
+
np.random.seed(42)
|
|
85
|
+
n = 100
|
|
86
|
+
x = np.arange(n)
|
|
87
|
+
y = np.random.normal(size=n)
|
|
88
|
+
w, h = 200, 150
|
|
89
|
+
p = ggplot({'x': x, 'y': y}, aes(x='x', y='y')) + ggsize(w, h)
|
|
90
|
+
plot_list=[
|
|
91
|
+
gggrid([p+geom_point(), p+geom_histogram(bins=3)]),
|
|
92
|
+
p+geom_line()
|
|
93
|
+
]
|
|
94
|
+
gggrid(plot_list, ncol=1) + ggsize(400, 300)
|
|
95
|
+
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
if not len(plots):
|
|
99
|
+
raise ValueError("Supplots list is empty.")
|
|
100
|
+
|
|
101
|
+
if ncol is None:
|
|
102
|
+
ncol = len(plots)
|
|
103
|
+
nrow = 1
|
|
104
|
+
else:
|
|
105
|
+
extended_list = plots + [None] * (ncol - 1)
|
|
106
|
+
nrow = len(extended_list) // ncol
|
|
107
|
+
length = ncol * nrow
|
|
108
|
+
plots = extended_list[0:length]
|
|
109
|
+
|
|
110
|
+
if sharex is not None and type(sharex) != str:
|
|
111
|
+
sharex = 'all' if sharex else 'none'
|
|
112
|
+
if sharey is not None and type(sharey) != str:
|
|
113
|
+
sharey = 'all' if sharey else 'none'
|
|
114
|
+
|
|
115
|
+
layout = SupPlotsLayoutSpec(
|
|
116
|
+
name="grid",
|
|
117
|
+
ncol=ncol,
|
|
118
|
+
nrow=nrow,
|
|
119
|
+
sharex=sharex,
|
|
120
|
+
sharey=sharey,
|
|
121
|
+
widths=widths,
|
|
122
|
+
heights=heights,
|
|
123
|
+
hspace=hspace,
|
|
124
|
+
vspace=vspace,
|
|
125
|
+
fit=fit,
|
|
126
|
+
align=align,
|
|
127
|
+
guides=guides
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
figures = [_strip_theme_if_global(fig) for fig in plots]
|
|
131
|
+
|
|
132
|
+
figure_spec = SupPlotsSpec(figures=figures, layout=layout)
|
|
133
|
+
|
|
134
|
+
# Apply global theme if defined
|
|
135
|
+
global_theme_options = _get_global_theme()
|
|
136
|
+
if global_theme_options is not None:
|
|
137
|
+
figure_spec += global_theme_options
|
|
138
|
+
|
|
139
|
+
return figure_spec
|
lets_plot/plot/ggtb_.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2024. 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 .core import FeatureSpec
|
|
6
|
+
|
|
7
|
+
__all__ = ['ggtb']
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def ggtb(size_basis=None, size_zoomin=None) -> FeatureSpec:
|
|
11
|
+
"""
|
|
12
|
+
Add a toolbar to a chart.
|
|
13
|
+
|
|
14
|
+
This function adds a toolbar containing three tool-buttons (pan, rubber-band zoom,
|
|
15
|
+
and center-point zoom) to a chart. Each tool uses mouse-drag for its
|
|
16
|
+
specific functionality. Additionally, the mouse wheel can be used for zooming
|
|
17
|
+
in and out, regardless of the selected tool.
|
|
18
|
+
|
|
19
|
+
The toolbar includes:
|
|
20
|
+
|
|
21
|
+
- Pan: Drag to move the plot.
|
|
22
|
+
- Rubber-band zoom: Drag to define a rectangular area to zoom into.
|
|
23
|
+
- Center-point zoom: Drag up or down to zoom in or out from a center point.
|
|
24
|
+
- Reset button: Click to reset the plot and tools to their original state.
|
|
25
|
+
|
|
26
|
+
Double-clicking anywhere on the plot resets it to its original coordinates,
|
|
27
|
+
regardless of whether a tool is selected or not.
|
|
28
|
+
|
|
29
|
+
Limitations:
|
|
30
|
+
|
|
31
|
+
- The toolbar does not work with interactive maps.
|
|
32
|
+
- The toolbar cannot be used with plots using a polar coordinate system.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
size_zoomin : int, default=0
|
|
37
|
+
Control how zooming in affects the size of geometry objects on the plot. Currently, works only with
|
|
38
|
+
the geom_point layer and layers based on it (geom_jitter, geom_sina, etc.).
|
|
39
|
+
|
|
40
|
+
0 - size never increases;
|
|
41
|
+
|
|
42
|
+
-1 - size will be increasing without limits;
|
|
43
|
+
|
|
44
|
+
n - the number of times the size of objects will increase (relative to the initial state of the plot).
|
|
45
|
+
Farther zooming will no longer affect the size.
|
|
46
|
+
|
|
47
|
+
size_basis : {'x', 'y', 'min', 'max'}, default='max'
|
|
48
|
+
Defines the axis along which the scaling factor for geometry objects will be calculated.
|
|
49
|
+
|
|
50
|
+
'x' - size changes only when zooming in/out along x-axis;
|
|
51
|
+
|
|
52
|
+
'y' - size changes only when zooming in/out along y-axis;
|
|
53
|
+
|
|
54
|
+
'min' - size changes when zooming in/out along any axis, but the change is determined by the axis
|
|
55
|
+
with the minimum zoom factor;
|
|
56
|
+
|
|
57
|
+
'max' - size changes when zooming in/out along any axis, but the change is determined by the axis
|
|
58
|
+
with the maximum zoom factor.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
``FeatureSpec``
|
|
63
|
+
Toolbar feature specification.
|
|
64
|
+
|
|
65
|
+
Examples
|
|
66
|
+
--------
|
|
67
|
+
.. jupyter-execute::
|
|
68
|
+
:linenos:
|
|
69
|
+
:emphasize-lines: 8
|
|
70
|
+
|
|
71
|
+
import numpy as np
|
|
72
|
+
from lets_plot import *
|
|
73
|
+
LetsPlot.setup_html()
|
|
74
|
+
x = np.linspace(-2 * np.pi, 2 * np.pi, 100)
|
|
75
|
+
y = np.sin(x)
|
|
76
|
+
ggplot({'x': x, 'y': y}, aes(x='x', y='y')) + \\
|
|
77
|
+
geom_point() + \\
|
|
78
|
+
ggtb()
|
|
79
|
+
|
|
80
|
+
"""
|
|
81
|
+
return FeatureSpec(kind='ggtoolbar', name=None, size_basis=size_basis, size_zoomin=size_zoomin)
|