core-lens 0.1.dev154__tar.gz → 0.1.dev159__tar.gz

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 (92) hide show
  1. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/PKG-INFO +1 -1
  2. core_lens-0.1.dev159/src/core_lens/__main__.py +36 -0
  3. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/_version.py +2 -2
  4. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/base/namespaces/plot.py +102 -4
  5. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/base/namespaces/stats.py +29 -45
  6. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_main.py +5 -1
  7. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_plot.py +2 -2
  8. core_lens-0.1.dev154/src/core_lens/__main__.py +0 -14
  9. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/.github/ISSUE_TEMPLATE/blank-proposal.yaml +0 -0
  10. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/.github/ISSUE_TEMPLATE/bug-report.yaml +0 -0
  11. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/.github/ISSUE_TEMPLATE/feature-request.yaml +0 -0
  12. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/.github/pull_request_template.md +0 -0
  13. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/.github/workflows/ci.yml +0 -0
  14. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/.github/workflows/gh-pages.yml +0 -0
  15. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/.github/workflows/pre-release.yml +0 -0
  16. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/.github/workflows/release.yml +0 -0
  17. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/.gitignore +0 -0
  18. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/.gitmessage +0 -0
  19. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/.pre-commit-config.yaml +0 -0
  20. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/.python-version +0 -0
  21. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/CONTRIBUTING.md +0 -0
  22. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/LICENSE +0 -0
  23. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/README.md +0 -0
  24. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/SKILLS.md +0 -0
  25. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/benchmarks/README.md +0 -0
  26. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/benchmarks/bench_aoi.py +0 -0
  27. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/benchmarks/bench_export.py +0 -0
  28. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/benchmarks/bench_polars_utils.py +0 -0
  29. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/benchmarks/bench_result.py +0 -0
  30. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/benchmarks/bench_schema.py +0 -0
  31. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/benchmarks/bench_season.py +0 -0
  32. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/benchmarks/bench_spatial.py +0 -0
  33. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/benchmarks/bench_view.py +0 -0
  34. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/benchmarks/run_all.sh +0 -0
  35. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/docs/Makefile +0 -0
  36. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/docs/make.bat +0 -0
  37. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/docs/source/concepts.md +0 -0
  38. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/docs/source/conf.py +0 -0
  39. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/docs/source/export.md +0 -0
  40. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/docs/source/index.rst +0 -0
  41. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/docs/source/intro.md +0 -0
  42. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/docs/source/logging.md +0 -0
  43. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/docs/source/plots.md +0 -0
  44. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/docs/source/plugins.md +0 -0
  45. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/docs/source/queries.md +0 -0
  46. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/docs/source/quickstart.md +0 -0
  47. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/docs/source/stats.md +0 -0
  48. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/examples/demo_mws.py +0 -0
  49. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/examples/demo_tehsil.py +0 -0
  50. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/hooks/mypy.sh +0 -0
  51. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/hooks/no-parquet-outside-fixtures.sh +0 -0
  52. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/hooks/pytest.sh +0 -0
  53. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/pyproject.toml +0 -0
  54. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/__init__.py +0 -0
  55. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/aoi.py +0 -0
  56. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/base/__init__.py +0 -0
  57. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/base/entity.py +0 -0
  58. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/base/namespaces/__init__.py +0 -0
  59. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/base/result.py +0 -0
  60. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/base/view.py +0 -0
  61. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/entities/__init__.py +0 -0
  62. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/entities/mws.py +0 -0
  63. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/entities/tehsil.py +0 -0
  64. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/entities/waterbody.py +0 -0
  65. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/export/__init__.py +0 -0
  66. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/export/formats.py +0 -0
  67. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/py.typed +0 -0
  68. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/schema/__init__.py +0 -0
  69. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/schema/detection.py +0 -0
  70. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/schema/profile.py +0 -0
  71. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/utils/__init__.py +0 -0
  72. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/utils/paths.py +0 -0
  73. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/utils/polars_utils.py +0 -0
  74. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/utils/season.py +0 -0
  75. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/src/core_lens/utils/spatial.py +0 -0
  76. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/fixtures/generate_fixtures.py +0 -0
  77. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/conftest.py +0 -0
  78. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_aoi.py +0 -0
  79. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_entities.py +0 -0
  80. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_entity.py +0 -0
  81. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_export.py +0 -0
  82. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_polars_utils.py +0 -0
  83. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_profile.py +0 -0
  84. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_result.py +0 -0
  85. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_schema_detection.py +0 -0
  86. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_schema_profile.py +0 -0
  87. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_season.py +0 -0
  88. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_season_config.py +0 -0
  89. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_spatial.py +0 -0
  90. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_stats.py +0 -0
  91. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/tests/unit/test_view.py +0 -0
  92. {core_lens-0.1.dev154 → core_lens-0.1.dev159}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: core-lens
3
- Version: 0.1.dev154
3
+ Version: 0.1.dev159
4
4
  Summary: Query, analyse, and visualise CoreStack's microwatershed and Earth science data through a clean, composable Python API.
5
5
  Project-URL: Homepage, https://github.com/ApoorvaKashyap/core-lens
6
6
  Project-URL: Issues, https://github.com/ApoorvaKashyap/core-lens/issues
@@ -0,0 +1,36 @@
1
+ from . import __version__
2
+
3
+
4
+ def hello() -> str:
5
+ hello_str = """Hello from core-lens!
6
+
7
+ The following primary capabilities are available:
8
+ - AoI: Construct Area of Interest queries (e.g., `AoI(district="Godda")`)
9
+ - Result: Lazy evaluation and computation graph materialisation
10
+
11
+ Analytics (via `result.stats`):
12
+ - anomaly(): Timeseries and cross-sectional anomaly detection
13
+ - change(): Absolute, percentage, and trend changes over time
14
+ - similarity(): Multi-feature similarity search across entities
15
+ - test(): Statistical hypothesis testing
16
+ - correlate(): Feature correlation analysis
17
+
18
+ Visualisation (via `result.plot`):
19
+ - choropleth(): Interactive Lonboard spatial mapping
20
+ - timeseries(): Temporal data visualisation
21
+ - scatter(): Scatter plots for variable comparison
22
+ - distribution(): Histograms and density plots
23
+ - correlation(): Correlation heatmaps between variables
24
+ - heatmap(): 2D density/binned heatmaps
25
+ - matrix(): Scatter matrix/pair plots
26
+ """
27
+ return hello_str
28
+
29
+
30
+ def version() -> str:
31
+ return str(__version__)
32
+
33
+
34
+ if __name__ == "__main__":
35
+ print(hello())
36
+ print(f"Version: {version()}")
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.1.dev154'
22
- __version_tuple__ = version_tuple = (0, 1, 'dev154')
21
+ __version__ = version = '0.1.dev159'
22
+ __version_tuple__ = version_tuple = (0, 1, 'dev159')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -27,7 +27,6 @@ class SubplotOn(Enum):
27
27
 
28
28
 
29
29
  if TYPE_CHECKING:
30
- import lonboard
31
30
  from bokeh.plotting import figure as BokehFigure
32
31
  from core_lens.base.result import Result
33
32
 
@@ -224,6 +223,102 @@ def _apply_theme(fig: Any, result: "Result", title: str) -> None:
224
223
  fig.add_layout(subtitle)
225
224
 
226
225
 
226
+ class MapWithLegend:
227
+ """Wrapper around lonboard.Map that adds a legend for Jupyter and HTML exports."""
228
+
229
+ def __init__(
230
+ self,
231
+ map_widget: Any,
232
+ cmap: Any,
233
+ v_min: float,
234
+ v_max: float,
235
+ column_name: str,
236
+ ) -> None:
237
+ self._map = map_widget
238
+ self._cmap = cmap
239
+ self._v_min = v_min
240
+ self._v_max = v_max
241
+ self._column_name = column_name
242
+
243
+ def __getattr__(self, name: str) -> Any:
244
+ return getattr(self._map, name)
245
+
246
+ def _generate_legend_div(self, absolute: bool = True) -> str:
247
+ import matplotlib.colors as mcolors
248
+ import numpy as np
249
+
250
+ stops = 5
251
+ style = (
252
+ "position:absolute; bottom:35px; left:20px; z-index:999; "
253
+ if absolute
254
+ else ""
255
+ )
256
+ style += (
257
+ "background:white; padding:8px 12px; border-radius:4px; "
258
+ "box-shadow:0 1px 4px rgba(0,0,0,.3); font-family:sans-serif; font-size:12px;"
259
+ )
260
+
261
+ html = [
262
+ f'<div style="{style}">',
263
+ f'<b style="margin-bottom:4px;display:inline-block;">{self._column_name}</b><br>',
264
+ ]
265
+
266
+ if np.isnan(self._v_min) or np.isnan(self._v_max) or self._v_min >= self._v_max:
267
+ html.append('<span style="color:gray;">No Data</span>')
268
+ else:
269
+ for i in range(stops):
270
+ frac = (stops - 1 - i) / (
271
+ stops - 1
272
+ ) # Reverse order so highest is on top
273
+ val = self._v_min + frac * (self._v_max - self._v_min)
274
+ rgba = self._cmap(frac)
275
+ hex_color = mcolors.to_hex(rgba)
276
+ html.append(
277
+ f'<div style="margin-top:2px;">'
278
+ f'<span style="background:{hex_color};width:12px;height:12px;'
279
+ f"display:inline-block;margin-right:8px;vertical-align:middle;"
280
+ f'border:1px solid #ccc;"></span>'
281
+ f'<span style="vertical-align:middle;">{val:.2f}</span></div>'
282
+ )
283
+ html.append("</div>")
284
+ return "".join(html)
285
+
286
+ def _ipython_display_(self) -> None:
287
+ import ipywidgets # type: ignore[import-untyped]
288
+ from IPython.display import display
289
+
290
+ legend_div = self._generate_legend_div(absolute=False)
291
+ legend_html = ipywidgets.HTML(legend_div)
292
+
293
+ display(ipywidgets.VBox([legend_html, self._map])) # type: ignore[no-untyped-call]
294
+
295
+ def to_html(
296
+ self, filename: str | None = None, title: str | None = None
297
+ ) -> str | None:
298
+ """Export the map to a static HTML string or file, injecting the legend."""
299
+ # lonboard.Map to_html doesn't accept title in all versions,
300
+ # so we conditionally pass it if it's not None or we can just omit title if we aren't sure.
301
+ # But wait, we can just use `self._map.to_html()`
302
+ if title is not None:
303
+ try:
304
+ html_str = self._map.to_html(title=title)
305
+ except TypeError:
306
+ html_str = self._map.to_html()
307
+ else:
308
+ html_str = self._map.to_html()
309
+
310
+ legend_div = self._generate_legend_div(absolute=True)
311
+
312
+ # Inject right before closing </body> tag
313
+ html_str = html_str.replace("</body>", legend_div + "</body>")
314
+
315
+ if filename is not None:
316
+ with open(filename, "w", encoding="utf-8") as f:
317
+ f.write(html_str)
318
+ return None
319
+ return str(html_str)
320
+
321
+
227
322
  class PlotNamespace:
228
323
  """Visualisation namespace for :class:`~core_lens.base.result.Result`.
229
324
 
@@ -239,7 +334,7 @@ class PlotNamespace:
239
334
 
240
335
  def choropleth(
241
336
  self, column: str, subplot_on: SubplotOn | None = None
242
- ) -> "lonboard.Map":
337
+ ) -> "MapWithLegend":
243
338
  """Render an interactive choropleth map using Lonboard.
244
339
 
245
340
  If the Result does not already have geometry, it will be attached
@@ -319,13 +414,16 @@ class PlotNamespace:
319
414
  else:
320
415
  norm_values = (values - v_min) / (v_max - v_min)
321
416
 
322
- cmap = mpl.colormaps["plasma"]
417
+ cmap = mpl.colormaps["plasma_r"]
323
418
 
324
419
  layer = lonboard.PolygonLayer(
325
420
  arrow_table,
326
421
  get_fill_color=apply_continuous_cmap(norm_values, cmap),
422
+ get_line_color=[211, 211, 211, 255],
423
+ line_width_min_pixels=0.5,
327
424
  )
328
- return lonboard.Map(layers=[layer])
425
+ map_widget = lonboard.Map(layers=[layer])
426
+ return MapWithLegend(map_widget, cmap, v_min, v_max, column)
329
427
 
330
428
  def timeseries(
331
429
  self,
@@ -489,18 +489,24 @@ class StatsNamespace:
489
489
  )
490
490
 
491
491
  if method in (ChangeMethod.ABSOLUTE, ChangeMethod.PERCENTAGE):
492
+ join_keys = [key]
493
+ if "season" in df.columns:
494
+ join_keys.append("season")
495
+
492
496
  from_df = (
493
497
  df.filter(pl.col(year_col) == from_period)
494
- .select([key, column])
498
+ .select(join_keys + [column])
495
499
  .rename({column: "value_from"})
496
500
  )
497
501
  to_df = (
498
502
  df.filter(pl.col(year_col) == to_period)
499
- .select([key, column])
503
+ .select(join_keys + [column])
500
504
  .rename({column: "value_to"})
501
505
  )
502
- joined = from_df.join(to_df, on=key, how="inner").with_columns(
506
+ joined = from_df.join(to_df, on=join_keys, how="inner").with_columns(
503
507
  [
508
+ pl.lit(from_period).alias("year_from").cast(pl.Int32),
509
+ pl.lit(to_period).alias("year_to").cast(pl.Int32),
504
510
  (pl.col("value_to") - pl.col("value_from")).alias("change"),
505
511
  (
506
512
  (pl.col("value_to") - pl.col("value_from"))
@@ -509,7 +515,16 @@ class StatsNamespace:
509
515
  ).alias("pct_change"),
510
516
  ]
511
517
  )
512
- data = joined
518
+
519
+ final_cols = join_keys + [
520
+ "year_from",
521
+ "year_to",
522
+ "value_from",
523
+ "value_to",
524
+ "change",
525
+ "pct_change",
526
+ ]
527
+ data = joined.select(final_cols)
513
528
 
514
529
  else: # trend
515
530
  period_df = df.filter(
@@ -532,6 +547,8 @@ class StatsNamespace:
532
547
  rows.append(
533
548
  {
534
549
  key: eid,
550
+ "year_from": int(from_period),
551
+ "year_to": int(to_period),
535
552
  "slope": float(cast(float, slope)),
536
553
  "r_squared": float(cast(float, r_val) ** 2),
537
554
  "direction": (
@@ -859,12 +876,9 @@ class StatsNamespace:
859
876
  df = self._r.df()
860
877
  key = self._r.key_cols[0]
861
878
 
862
- min_year: int | None = None
863
- max_year: int | None = None
864
-
865
879
  # --- Build feature DataFrame ------------------------------------------
866
880
  # Universe of entity keys from result.data.
867
- feat = df.select([key]).unique()
881
+ feat = df.select([key])
868
882
 
869
883
  for col_name, spec in columns.items():
870
884
  if spec is None:
@@ -884,23 +898,6 @@ class StatsNamespace:
884
898
  resolution_str, filter_dict = spec
885
899
  filter_dict = dict(filter_dict) if filter_dict else {}
886
900
 
887
- if "year" in filter_dict:
888
- yr = filter_dict["year"]
889
- y0: int | None = None
890
- y1: int | None = None
891
-
892
- if isinstance(yr, (list, tuple)) and len(yr) >= 2:
893
- y0, y1 = int(yr[0]), int(yr[1])
894
- elif isinstance(yr, int):
895
- y0, y1 = yr, yr
896
-
897
- if y0 is not None:
898
- if min_year is None or y0 < min_year:
899
- min_year = y0
900
- if y1 is not None:
901
- if max_year is None or y1 > max_year:
902
- max_year = y1
903
-
904
901
  entity = self._r.entity
905
902
  path: str | None
906
903
  if resolution_str == "static":
@@ -1026,26 +1023,13 @@ class StatsNamespace:
1026
1023
  dists[tidx] = float("inf") # exclude target itself
1027
1024
  top_idx = np.argsort(dists)[:top_n]
1028
1025
 
1029
- if min_year is None and max_year is None:
1030
- year_col = self._year_col()
1031
- if year_col and year_col in df.columns:
1032
- yr_min = df[year_col].min()
1033
- yr_max = df[year_col].max()
1034
- if yr_min is not None and yr_max is not None:
1035
- min_year = int(cast(int, yr_min))
1036
- max_year = int(cast(int, yr_max))
1037
-
1038
- output_dict: dict[str, Any] = {
1039
- key: [ids[i] for i in top_idx],
1040
- "similarity_score": [float(1.0 / (1.0 + dists[i])) for i in top_idx],
1041
- "rank": list(range(1, len(top_idx) + 1)),
1042
- }
1043
-
1044
- if min_year is not None and max_year is not None:
1045
- output_dict["year_from"] = [min_year] * len(top_idx)
1046
- output_dict["year_to"] = [max_year] * len(top_idx)
1047
-
1048
- data = pl.DataFrame(output_dict)
1026
+ data = pl.DataFrame(
1027
+ {
1028
+ key: [ids[i] for i in top_idx],
1029
+ "similarity_score": [float(1.0 / (1.0 + dists[i])) for i in top_idx],
1030
+ "rank": list(range(1, len(top_idx) + 1)),
1031
+ }
1032
+ )
1049
1033
  metadata: dict[str, Any] = {
1050
1034
  "method": method.value if method is not None else None,
1051
1035
  "target": target,
@@ -8,7 +8,11 @@ def test_version() -> None:
8
8
  def test_hello() -> None:
9
9
  from core_lens.__main__ import hello
10
10
 
11
- assert hello() == "Hello from core-lens!"
11
+ msg = hello()
12
+ assert msg.startswith("Hello from core-lens!")
13
+ assert "AoI: Construct Area of Interest queries" in msg
14
+ assert "Analytics (via `result.stats`):" in msg
15
+ assert "Visualisation (via `result.plot`):" in msg
12
16
 
13
17
 
14
18
  def test_version_type() -> None:
@@ -9,7 +9,7 @@ from typing import Any
9
9
  from core_lens.base.entity import BaseEntity
10
10
  from core_lens.base.result import Result
11
11
  from core_lens.schema.profile import Resolution, SchemaProfile
12
- from core_lens.base.namespaces.plot import SubplotOn
12
+ from core_lens.base.namespaces.plot import SubplotOn, MapWithLegend
13
13
 
14
14
 
15
15
  class DummyEntity(BaseEntity):
@@ -79,7 +79,7 @@ def test_choropleth_basic(dummy_result: Result) -> None:
79
79
  """Test choropleth creates a lonboard Map correctly."""
80
80
  plot_map = dummy_result.plot.choropleth("value")
81
81
 
82
- assert isinstance(plot_map, lonboard.Map)
82
+ assert isinstance(plot_map, MapWithLegend)
83
83
  assert len(plot_map.layers) == 1
84
84
  layer = plot_map.layers[0]
85
85
  assert isinstance(layer, lonboard.PolygonLayer)
@@ -1,14 +0,0 @@
1
- from . import __version__
2
-
3
-
4
- def hello() -> str:
5
- return "Hello from core-lens!"
6
-
7
-
8
- def version() -> str:
9
- return str(__version__)
10
-
11
-
12
- if __name__ == "__main__":
13
- print(hello())
14
- print(f"Version: {version()}")
File without changes
File without changes
File without changes
File without changes