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.
Files changed (97) hide show
  1. lets_plot/__init__.py +382 -0
  2. lets_plot/_global_settings.py +192 -0
  3. lets_plot/_kbridge.py +197 -0
  4. lets_plot/_type_utils.py +133 -0
  5. lets_plot/_version.py +6 -0
  6. lets_plot/bistro/__init__.py +16 -0
  7. lets_plot/bistro/_plot2d_common.py +106 -0
  8. lets_plot/bistro/corr.py +448 -0
  9. lets_plot/bistro/im.py +196 -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 +332 -0
  14. lets_plot/export/__init__.py +6 -0
  15. lets_plot/export/ggsave_.py +172 -0
  16. lets_plot/frontend_context/__init__.py +8 -0
  17. lets_plot/frontend_context/_configuration.py +140 -0
  18. lets_plot/frontend_context/_dynamic_configure_html.py +115 -0
  19. lets_plot/frontend_context/_frontend_ctx.py +16 -0
  20. lets_plot/frontend_context/_html_contexts.py +223 -0
  21. lets_plot/frontend_context/_intellij_python_json_ctx.py +38 -0
  22. lets_plot/frontend_context/_isolated_webview_panel_ctx.py +81 -0
  23. lets_plot/frontend_context/_json_contexts.py +39 -0
  24. lets_plot/frontend_context/_jupyter_notebook_ctx.py +82 -0
  25. lets_plot/frontend_context/_mime_types.py +7 -0
  26. lets_plot/frontend_context/_static_html_page_ctx.py +76 -0
  27. lets_plot/frontend_context/_static_svg_ctx.py +26 -0
  28. lets_plot/frontend_context/_webbr_html_page_ctx.py +29 -0
  29. lets_plot/frontend_context/sandbox.py +5 -0
  30. lets_plot/geo_data/__init__.py +19 -0
  31. lets_plot/geo_data/core.py +335 -0
  32. lets_plot/geo_data/geocoder.py +988 -0
  33. lets_plot/geo_data/geocodes.py +512 -0
  34. lets_plot/geo_data/gis/__init__.py +0 -0
  35. lets_plot/geo_data/gis/fluent_dict.py +201 -0
  36. lets_plot/geo_data/gis/geocoding_service.py +42 -0
  37. lets_plot/geo_data/gis/geometry.py +91 -0
  38. lets_plot/geo_data/gis/json_request.py +232 -0
  39. lets_plot/geo_data/gis/json_response.py +308 -0
  40. lets_plot/geo_data/gis/request.py +492 -0
  41. lets_plot/geo_data/gis/response.py +247 -0
  42. lets_plot/geo_data/livemap_helper.py +65 -0
  43. lets_plot/geo_data/to_geo_data_frame.py +141 -0
  44. lets_plot/geo_data/type_assertion.py +34 -0
  45. lets_plot/geo_data_internals/__init__.py +4 -0
  46. lets_plot/geo_data_internals/constants.py +13 -0
  47. lets_plot/geo_data_internals/utils.py +33 -0
  48. lets_plot/mapping.py +115 -0
  49. lets_plot/package_data/lets-plot.min.js +3 -0
  50. lets_plot/plot/__init__.py +64 -0
  51. lets_plot/plot/_global_theme.py +14 -0
  52. lets_plot/plot/annotation.py +290 -0
  53. lets_plot/plot/coord.py +242 -0
  54. lets_plot/plot/core.py +1071 -0
  55. lets_plot/plot/expand_limits_.py +78 -0
  56. lets_plot/plot/facet.py +210 -0
  57. lets_plot/plot/font_features.py +71 -0
  58. lets_plot/plot/geom.py +9146 -0
  59. lets_plot/plot/geom_extras.py +53 -0
  60. lets_plot/plot/geom_function_.py +219 -0
  61. lets_plot/plot/geom_imshow_.py +393 -0
  62. lets_plot/plot/geom_livemap_.py +343 -0
  63. lets_plot/plot/ggbunch_.py +96 -0
  64. lets_plot/plot/gggrid_.py +139 -0
  65. lets_plot/plot/ggtb_.py +81 -0
  66. lets_plot/plot/guide.py +231 -0
  67. lets_plot/plot/label.py +187 -0
  68. lets_plot/plot/marginal_layer.py +181 -0
  69. lets_plot/plot/plot.py +245 -0
  70. lets_plot/plot/pos.py +344 -0
  71. lets_plot/plot/sampling.py +338 -0
  72. lets_plot/plot/sandbox_.py +26 -0
  73. lets_plot/plot/scale.py +3580 -0
  74. lets_plot/plot/scale_colormap_mpl.py +300 -0
  75. lets_plot/plot/scale_convenience.py +155 -0
  76. lets_plot/plot/scale_identity_.py +653 -0
  77. lets_plot/plot/scale_position.py +1342 -0
  78. lets_plot/plot/series_meta.py +209 -0
  79. lets_plot/plot/stat.py +585 -0
  80. lets_plot/plot/subplots.py +331 -0
  81. lets_plot/plot/subplots_util.py +24 -0
  82. lets_plot/plot/theme_.py +790 -0
  83. lets_plot/plot/theme_set.py +418 -0
  84. lets_plot/plot/tooltip.py +486 -0
  85. lets_plot/plot/util.py +267 -0
  86. lets_plot/settings_utils.py +244 -0
  87. lets_plot/tilesets.py +429 -0
  88. lets_plot-4.8.1rc1.dist-info/METADATA +221 -0
  89. lets_plot-4.8.1rc1.dist-info/RECORD +97 -0
  90. lets_plot-4.8.1rc1.dist-info/WHEEL +6 -0
  91. lets_plot-4.8.1rc1.dist-info/licenses/LICENSE +21 -0
  92. lets_plot-4.8.1rc1.dist-info/licenses/licenses/LICENSE.FreeType +166 -0
  93. lets_plot-4.8.1rc1.dist-info/licenses/licenses/LICENSE.ImageMagick +106 -0
  94. lets_plot-4.8.1rc1.dist-info/licenses/licenses/LICENSE.expat +21 -0
  95. lets_plot-4.8.1rc1.dist-info/licenses/licenses/LICENSE.fontconfig +200 -0
  96. lets_plot-4.8.1rc1.dist-info/top_level.txt +2 -0
  97. lets_plot_kotlin_bridge.cpython-311-x86_64-linux-gnu.so +0 -0
@@ -0,0 +1,308 @@
1
+ import json
2
+ from enum import Enum
3
+ from functools import partial
4
+ from typing import Dict, List, Optional, Union
5
+
6
+ from .fluent_dict import FluentDict
7
+ from .geometry import Ring
8
+ from .response import Multipolygon, GeoPoint, GeoRect, Boundary, Polygon
9
+ from .response import Response, ResponseBuilder, SuccessResponse, AmbiguousResponse
10
+ from .response import Status, LevelKind, Answer, GeocodedFeature, AmbiguousFeature, Namesake, NamesakeParent, \
11
+ FeatureBuilder
12
+
13
+
14
+ class ResponseField(Enum):
15
+ status = 'status'
16
+ message = 'message'
17
+ data = 'data'
18
+ answers = 'answers'
19
+ features = 'features'
20
+ geocoded_data = 'good_features'
21
+ incorrect_data = 'bad_features'
22
+ level = 'level'
23
+ position = 'position'
24
+ query = 'query'
25
+ name = 'name'
26
+ highlights = 'highlights'
27
+ limit = 'limit'
28
+ centroid = 'centroid'
29
+ boundary = 'boundary'
30
+ boundary_type = 'type'
31
+ geo_object_id = 'id'
32
+ boundary_lon = 'lon'
33
+ boundary_lat = 'lat'
34
+ boundary_coordinates = 'coordinates'
35
+ centroid_lon = 'lon'
36
+ centroid_lat = 'lat'
37
+ min_lon = 'min_lon'
38
+ min_lat = 'min_lat'
39
+ max_lon = 'max_lon'
40
+ max_lat = 'max_lat'
41
+ total_namesake_count = 'total_namesake_count'
42
+ namesake_examples = 'namesake_examples'
43
+ namesake_name = 'name'
44
+ namesake_parents = 'parents'
45
+ namesake_parent_name = 'name'
46
+ namesake_parent_level = 'level'
47
+
48
+
49
+ class GeometryKind(Enum):
50
+ point = 'Point'
51
+ polygon = 'Polygon'
52
+ multipolygon = 'MultiPolygon'
53
+
54
+
55
+ class ResponseParser:
56
+
57
+ @staticmethod
58
+ def parse(response_json: Dict) -> Response:
59
+ response = ResponseBuilder()
60
+ response_dict = FluentDict(response_json) \
61
+ .visit_enum(ResponseField.status, Status, response.set_status) \
62
+ .visit_str(ResponseField.message, response.set_message)
63
+
64
+ if response.status == Status.error:
65
+ return response.build()
66
+
67
+ data_dict = FluentDict(response_dict.get(ResponseField.data)) \
68
+ .visit_enum_existing(ResponseField.level, LevelKind, response.set_level)
69
+
70
+ if response.status == Status.success:
71
+ data_dict.visit(ResponseField.answers, partial(ResponseParser._parse_answers, response=response))
72
+ elif response.status == Status.ambiguous:
73
+ data_dict.visit(ResponseField.features, partial(ResponseParser._parse_ambiguous_features, response=response))
74
+ else:
75
+ raise ValueError('Unknown response kind')
76
+
77
+ return response.build()
78
+
79
+ @staticmethod
80
+ def _parse_answers(answers_json: List[Dict], response: ResponseBuilder):
81
+ answers: List[Answer] = []
82
+ for answer_json in answers_json:
83
+ features_json = answer_json.get(ResponseField.features.value, [])
84
+ geocoded_features: List[GeocodedFeature] = []
85
+ for feature_json in features_json:
86
+ feature = FeatureBuilder()
87
+
88
+ FluentDict(feature_json) \
89
+ .visit_str(ResponseField.geo_object_id, feature.set_id) \
90
+ .visit_str(ResponseField.name, feature.set_name) \
91
+ .visit_str_list_optional(ResponseField.highlights, feature.set_highlights) \
92
+ .visit_str_existing(ResponseField.boundary, lambda json: feature.set_boundary(GeoJson().parse_geometry(json))) \
93
+ .visit_object_optional(ResponseField.centroid, lambda json: feature.set_centroid(ResponseParser._parse_point(json))) \
94
+ .visit_object_optional(ResponseField.limit, lambda json: feature.set_limit(ResponseParser._parse_rect(json))) \
95
+ .visit_object_optional(ResponseField.position, lambda json: feature.set_position(ResponseParser._parse_rect(json)))
96
+
97
+ geocoded_features.append(feature.build_geocoded())
98
+ answers.append(Answer(geocoded_features))
99
+
100
+ response.set_answers(answers)
101
+
102
+ @staticmethod
103
+ def _parse_ambiguous_features(features_json: List[Dict], response: ResponseBuilder):
104
+ ambiguous_features: List[AmbiguousFeature] = []
105
+ for feature_json in features_json:
106
+ feature = FeatureBuilder()
107
+ FluentDict(feature_json) \
108
+ .visit_str(ResponseField.query, feature.set_query) \
109
+ .visit_int(ResponseField.total_namesake_count, feature.set_total_namesake_count) \
110
+ .visit_objects(ResponseField.namesake_examples, lambda json: feature.add_namesake(ResponseParser._parse_namesake(json)))
111
+
112
+ ambiguous_features.append(feature.build_ambiguous())
113
+
114
+ response.set_ambiguous_features(ambiguous_features)
115
+
116
+ @staticmethod
117
+ def _parse_point(centroid_dict: FluentDict) -> GeoPoint:
118
+ return GeoPoint(
119
+ centroid_dict.get(ResponseField.centroid_lon),
120
+ centroid_dict.get(ResponseField.centroid_lat)
121
+ )
122
+
123
+ @staticmethod
124
+ def _parse_rect(rect_dict: FluentDict) -> GeoRect:
125
+ return GeoRect(
126
+ rect_dict.get(ResponseField.min_lon),
127
+ rect_dict.get(ResponseField.min_lat),
128
+ rect_dict.get(ResponseField.max_lon),
129
+ rect_dict.get(ResponseField.max_lat),
130
+ )
131
+
132
+ @staticmethod
133
+ def _parse_namesake(namesake_dict: FluentDict):
134
+ return Namesake(
135
+ namesake_dict.get(ResponseField.namesake_name),
136
+ namesake_dict.get_objects(ResponseField.namesake_parents)
137
+ .map(
138
+ lambda parent: NamesakeParent(
139
+ parent.get(ResponseField.namesake_parent_name),
140
+ parent.get_enum(ResponseField.namesake_parent_level, LevelKind)))
141
+ .list()
142
+ )
143
+
144
+
145
+ class ResponseFormatter:
146
+
147
+ @staticmethod
148
+ def format(response: Response) -> Dict:
149
+ if isinstance(response, SuccessResponse):
150
+ return FluentDict() \
151
+ .put(ResponseField.status, Status.success.value) \
152
+ .put(ResponseField.message, response.message) \
153
+ .put(ResponseField.data, FluentDict()
154
+ .put(ResponseField.level, response.level.value)
155
+ .put(ResponseField.answers, list(map(ResponseFormatter._format_answer, response.answers)))) \
156
+ .to_dict()
157
+ elif isinstance(response, AmbiguousResponse):
158
+ return FluentDict() \
159
+ .put(ResponseField.status, Status.ambiguous.value) \
160
+ .put(ResponseField.message, response.message) \
161
+ .put(ResponseField.data, FluentDict()
162
+ .put(ResponseField.level, response.level.value)
163
+ .put(ResponseField.features, list(map(ResponseFormatter._format_ambiguous_feature, response.features)))) \
164
+ .to_dict()
165
+
166
+ @staticmethod
167
+ def _format_answer(answer: Answer) -> Dict:
168
+ features = []
169
+ for feature in answer.features:
170
+ features.append(
171
+ FluentDict() \
172
+ .put(ResponseField.geo_object_id, feature.id) \
173
+ .put(ResponseField.name, feature.name) \
174
+ .put(ResponseField.boundary, ResponseFormatter._format_boundary(feature.boundary)) \
175
+ .put(ResponseField.centroid, ResponseFormatter._format_centroid(feature.centroid)) \
176
+ .put(ResponseField.limit, ResponseFormatter._format_rect(feature.limit)) \
177
+ .put(ResponseField.position, ResponseFormatter._format_rect(feature.position)) \
178
+ .to_dict()
179
+ )
180
+
181
+ return FluentDict() \
182
+ .put(ResponseField.features, features) \
183
+ .to_dict()
184
+
185
+
186
+ @staticmethod
187
+ def _format_centroid(point: Optional[GeoPoint]) -> Optional[Dict]:
188
+ if point is None:
189
+ return None
190
+
191
+ return FluentDict() \
192
+ .put(ResponseField.centroid_lon, point.lon) \
193
+ .put(ResponseField.centroid_lat, point.lat) \
194
+ .to_dict()
195
+
196
+ @staticmethod
197
+ def _format_rect(rect: Optional[GeoRect]) -> Optional[Dict]:
198
+ if rect is None:
199
+ return None
200
+
201
+ return FluentDict() \
202
+ .put(ResponseField.min_lon, rect.start_lon) \
203
+ .put(ResponseField.min_lat, rect.min_lat) \
204
+ .put(ResponseField.max_lon, rect.end_lon) \
205
+ .put(ResponseField.max_lat, rect.max_lat) \
206
+ .to_dict()
207
+
208
+ @staticmethod
209
+ def _format_boundary(boundary: Optional[Boundary]) -> Optional[str]:
210
+ if boundary is None:
211
+ return None
212
+
213
+ return GeoJson.format_geometry(boundary)
214
+
215
+ @staticmethod
216
+ def _format_ambiguous_feature(feaure: AmbiguousFeature) -> Dict:
217
+ return FluentDict() \
218
+ .put(ResponseField.query, feaure.query) \
219
+ .put(ResponseField.total_namesake_count, feaure.total_namesake_count) \
220
+ .put(ResponseField.namesake_examples, list(map(ResponseFormatter._format_namesake, feaure.namesake_examples))) \
221
+ .to_dict()
222
+
223
+ @staticmethod
224
+ def _format_namesake(namesake: Namesake) -> Dict:
225
+ return FluentDict() \
226
+ .put(ResponseField.namesake_name, namesake.name) \
227
+ .put(ResponseField.namesake_parents, list(map(ResponseFormatter._format_namesake_parent, namesake.parents))) \
228
+ .to_dict()
229
+
230
+ @staticmethod
231
+ def _format_namesake_parent(parent: NamesakeParent) -> Dict:
232
+ return FluentDict() \
233
+ .put(ResponseField.namesake_parent_name, parent.name) \
234
+ .put(ResponseField.namesake_parent_level, parent.level) \
235
+ .to_dict()
236
+
237
+
238
+ class GeoJson:
239
+
240
+ def __init__(self):
241
+ self.lon_list: List[float] = []
242
+ self.lat_list: List[float] = []
243
+
244
+ @staticmethod
245
+ def parse_geometry(geometry_line: str) -> Union[Multipolygon, Polygon, GeoPoint]:
246
+ geoJson = GeoJson()
247
+ return geoJson._do_parse(geometry_line)
248
+
249
+ @staticmethod
250
+ def format_geometry(boundary: Boundary) -> str:
251
+ if isinstance(boundary.geometry, GeoPoint):
252
+ return json.dumps({
253
+ ResponseField.boundary_type.value: GeometryKind.point.value,
254
+ ResponseField.boundary_coordinates.value: [boundary.geometry.lon, boundary.geometry.lat]
255
+ })
256
+
257
+ if isinstance(boundary.geometry, Polygon):
258
+ return json.dumps({
259
+ ResponseField.boundary_type.value: GeometryKind.polygon.value,
260
+ ResponseField.boundary_coordinates.value: GeoJson._format_polygon(boundary.geometry)
261
+ })
262
+
263
+ if isinstance(boundary.geometry, Multipolygon):
264
+ return json.dumps({
265
+ ResponseField.boundary_type.value: GeometryKind.polygon.value,
266
+ ResponseField.boundary_coordinates.value: [GeoJson._format_polygon(poly) for poly in boundary.geometry.polygons]
267
+ })
268
+
269
+ @staticmethod
270
+ def _format_polygon(polygon: Polygon):
271
+ poly = []
272
+ for ring in polygon.rings:
273
+ poly.append([[p.lon, p.lat] for p in ring.points])
274
+ return poly
275
+
276
+ def _do_parse(self, geometry_line: str) -> Union[Multipolygon, Polygon, GeoPoint]:
277
+ geometry_data: dict = json.loads(geometry_line)
278
+ geometry_type: GeometryKind = GeometryKind(geometry_data[ResponseField.boundary_type.value])
279
+
280
+ if geometry_type == GeometryKind.point:
281
+ return self._parse_point(geometry_data)
282
+
283
+ if geometry_type == GeometryKind.polygon:
284
+ return self._parse_polygon(geometry_data[ResponseField.boundary_coordinates.value])
285
+
286
+ if geometry_type == GeometryKind.multipolygon:
287
+ return self._parse_multipolygon(geometry_data[ResponseField.boundary_coordinates.value])
288
+
289
+ raise ValueError('Invalid geometry type')
290
+
291
+ def _parse_multipolygon(self, geometry_data: List[List[List[List[float]]]]) -> Multipolygon:
292
+ return Multipolygon([self._parse_polygon(p) for p in geometry_data])
293
+
294
+ def _parse_polygon(self, geometry_data: List[List[List[float]]]) -> Polygon:
295
+ rings: List[Ring] = []
296
+ for ring in geometry_data:
297
+ rings.append(Ring([GeoPoint(p[0], p[1]) for p in ring]))
298
+ return Polygon(rings)
299
+
300
+ def _parse_point(self, geometry_data: dict) -> GeoPoint:
301
+ return GeoPoint(
302
+ lon=geometry_data[ResponseField.boundary_lon.value],
303
+ lat=geometry_data[ResponseField.boundary_lat.value]
304
+ )
305
+
306
+ def _add_point(self, lon: float, lat: float) -> None:
307
+ self.lon_list.append(lon)
308
+ self.lat_list.append(lat)