core-lens 0.1.dev159__tar.gz → 0.1.dev161__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 (91) hide show
  1. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/PKG-INFO +1 -1
  2. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/_version.py +2 -2
  3. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/base/namespaces/plot.py +60 -19
  4. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/.github/ISSUE_TEMPLATE/blank-proposal.yaml +0 -0
  5. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/.github/ISSUE_TEMPLATE/bug-report.yaml +0 -0
  6. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/.github/ISSUE_TEMPLATE/feature-request.yaml +0 -0
  7. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/.github/pull_request_template.md +0 -0
  8. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/.github/workflows/ci.yml +0 -0
  9. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/.github/workflows/gh-pages.yml +0 -0
  10. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/.github/workflows/pre-release.yml +0 -0
  11. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/.github/workflows/release.yml +0 -0
  12. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/.gitignore +0 -0
  13. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/.gitmessage +0 -0
  14. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/.pre-commit-config.yaml +0 -0
  15. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/.python-version +0 -0
  16. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/CONTRIBUTING.md +0 -0
  17. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/LICENSE +0 -0
  18. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/README.md +0 -0
  19. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/SKILLS.md +0 -0
  20. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/benchmarks/README.md +0 -0
  21. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/benchmarks/bench_aoi.py +0 -0
  22. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/benchmarks/bench_export.py +0 -0
  23. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/benchmarks/bench_polars_utils.py +0 -0
  24. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/benchmarks/bench_result.py +0 -0
  25. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/benchmarks/bench_schema.py +0 -0
  26. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/benchmarks/bench_season.py +0 -0
  27. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/benchmarks/bench_spatial.py +0 -0
  28. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/benchmarks/bench_view.py +0 -0
  29. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/benchmarks/run_all.sh +0 -0
  30. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/docs/Makefile +0 -0
  31. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/docs/make.bat +0 -0
  32. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/docs/source/concepts.md +0 -0
  33. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/docs/source/conf.py +0 -0
  34. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/docs/source/export.md +0 -0
  35. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/docs/source/index.rst +0 -0
  36. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/docs/source/intro.md +0 -0
  37. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/docs/source/logging.md +0 -0
  38. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/docs/source/plots.md +0 -0
  39. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/docs/source/plugins.md +0 -0
  40. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/docs/source/queries.md +0 -0
  41. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/docs/source/quickstart.md +0 -0
  42. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/docs/source/stats.md +0 -0
  43. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/examples/demo_mws.py +0 -0
  44. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/examples/demo_tehsil.py +0 -0
  45. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/hooks/mypy.sh +0 -0
  46. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/hooks/no-parquet-outside-fixtures.sh +0 -0
  47. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/hooks/pytest.sh +0 -0
  48. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/pyproject.toml +0 -0
  49. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/__init__.py +0 -0
  50. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/__main__.py +0 -0
  51. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/aoi.py +0 -0
  52. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/base/__init__.py +0 -0
  53. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/base/entity.py +0 -0
  54. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/base/namespaces/__init__.py +0 -0
  55. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/base/namespaces/stats.py +0 -0
  56. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/base/result.py +0 -0
  57. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/base/view.py +0 -0
  58. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/entities/__init__.py +0 -0
  59. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/entities/mws.py +0 -0
  60. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/entities/tehsil.py +0 -0
  61. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/entities/waterbody.py +0 -0
  62. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/export/__init__.py +0 -0
  63. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/export/formats.py +0 -0
  64. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/py.typed +0 -0
  65. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/schema/__init__.py +0 -0
  66. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/schema/detection.py +0 -0
  67. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/schema/profile.py +0 -0
  68. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/utils/__init__.py +0 -0
  69. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/utils/paths.py +0 -0
  70. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/utils/polars_utils.py +0 -0
  71. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/utils/season.py +0 -0
  72. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/src/core_lens/utils/spatial.py +0 -0
  73. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/fixtures/generate_fixtures.py +0 -0
  74. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/conftest.py +0 -0
  75. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_aoi.py +0 -0
  76. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_entities.py +0 -0
  77. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_entity.py +0 -0
  78. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_export.py +0 -0
  79. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_main.py +0 -0
  80. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_plot.py +0 -0
  81. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_polars_utils.py +0 -0
  82. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_profile.py +0 -0
  83. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_result.py +0 -0
  84. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_schema_detection.py +0 -0
  85. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_schema_profile.py +0 -0
  86. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_season.py +0 -0
  87. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_season_config.py +0 -0
  88. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_spatial.py +0 -0
  89. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_stats.py +0 -0
  90. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/tests/unit/test_view.py +0 -0
  91. {core_lens-0.1.dev159 → core_lens-0.1.dev161}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: core-lens
3
- Version: 0.1.dev159
3
+ Version: 0.1.dev161
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
@@ -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.dev159'
22
- __version_tuple__ = version_tuple = (0, 1, 'dev159')
21
+ __version__ = version = '0.1.dev161'
22
+ __version_tuple__ = version_tuple = (0, 1, 'dev161')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -233,12 +233,16 @@ class MapWithLegend:
233
233
  v_min: float,
234
234
  v_max: float,
235
235
  column_name: str,
236
+ clamped_min: bool = False,
237
+ clamped_max: bool = False,
236
238
  ) -> None:
237
239
  self._map = map_widget
238
240
  self._cmap = cmap
239
241
  self._v_min = v_min
240
242
  self._v_max = v_max
241
243
  self._column_name = column_name
244
+ self._clamped_min = clamped_min
245
+ self._clamped_max = clamped_max
242
246
 
243
247
  def __getattr__(self, name: str) -> Any:
244
248
  return getattr(self._map, name)
@@ -273,12 +277,19 @@ class MapWithLegend:
273
277
  val = self._v_min + frac * (self._v_max - self._v_min)
274
278
  rgba = self._cmap(frac)
275
279
  hex_color = mcolors.to_hex(rgba)
280
+
281
+ prefix = ""
282
+ if i == stops - 1 and self._clamped_min:
283
+ prefix = "< "
284
+ elif i == 0 and self._clamped_max:
285
+ prefix = "> "
286
+
276
287
  html.append(
277
288
  f'<div style="margin-top:2px;">'
278
289
  f'<span style="background:{hex_color};width:12px;height:12px;'
279
290
  f"display:inline-block;margin-right:8px;vertical-align:middle;"
280
291
  f'border:1px solid #ccc;"></span>'
281
- f'<span style="vertical-align:middle;">{val:.2f}</span></div>'
292
+ f'<span style="vertical-align:middle;">{prefix}{val:.2f}</span></div>'
282
293
  )
283
294
  html.append("</div>")
284
295
  return "".join(html)
@@ -333,7 +344,11 @@ class PlotNamespace:
333
344
  self.result = result
334
345
 
335
346
  def choropleth(
336
- self, column: str, subplot_on: SubplotOn | None = None
347
+ self,
348
+ column: str,
349
+ subplot_on: SubplotOn | None = None,
350
+ v_min: float | None = None,
351
+ v_max: float | None = None,
337
352
  ) -> "MapWithLegend":
338
353
  """Render an interactive choropleth map using Lonboard.
339
354
 
@@ -407,23 +422,33 @@ class PlotNamespace:
407
422
 
408
423
  with warnings.catch_warnings():
409
424
  warnings.simplefilter("ignore", category=RuntimeWarning)
410
- v_min, v_max = np.nanmin(values), np.nanmax(values)
425
+ actual_min, actual_max = np.nanmin(values), np.nanmax(values)
426
+
427
+ calc_v_min = float(v_min) if v_min is not None else float(actual_min)
428
+ calc_v_max = float(v_max) if v_max is not None else float(actual_max)
411
429
 
412
- if np.isnan(v_min) or np.isnan(v_max) or v_min >= v_max:
430
+ clamped_min = v_min is not None and actual_min < v_min
431
+ clamped_max = v_max is not None and actual_max > v_max
432
+
433
+ if np.isnan(calc_v_min) or np.isnan(calc_v_max) or calc_v_min >= calc_v_max:
413
434
  norm_values = np.where(np.isnan(values), np.nan, 0.0)
414
435
  else:
415
- norm_values = (values - v_min) / (v_max - v_min)
436
+ norm_values = np.clip(
437
+ (values - calc_v_min) / (calc_v_max - calc_v_min), 0.0, 1.0
438
+ )
416
439
 
417
440
  cmap = mpl.colormaps["plasma_r"]
418
441
 
419
442
  layer = lonboard.PolygonLayer(
420
443
  arrow_table,
421
444
  get_fill_color=apply_continuous_cmap(norm_values, cmap),
422
- get_line_color=[211, 211, 211, 255],
423
- line_width_min_pixels=0.5,
445
+ get_line_color=[255, 255, 255, 180],
446
+ line_width_min_pixels=0.25,
424
447
  )
425
448
  map_widget = lonboard.Map(layers=[layer])
426
- return MapWithLegend(map_widget, cmap, v_min, v_max, column)
449
+ return MapWithLegend(
450
+ map_widget, cmap, calc_v_min, calc_v_max, column, clamped_min, clamped_max
451
+ )
427
452
 
428
453
  def timeseries(
429
454
  self,
@@ -536,11 +561,19 @@ class PlotNamespace:
536
561
  color=color,
537
562
  size=5,
538
563
  )
539
- elif key_col in pdf.columns:
540
- for i, entity in enumerate(pdf[key_col].unique()):
541
- row = pdf[pdf[key_col] == entity]
564
+ elif key_col in df.columns:
565
+ entities = df.get_column(key_col).unique().to_list()
566
+ for i, entity in enumerate(entities):
567
+ entity_df = df.filter(pl.col(key_col) == entity)
568
+ source_data = {}
569
+ for c in hover_cols:
570
+ if c in entity_df.columns:
571
+ lst = entity_df.get_column(c).to_list()
572
+ if entity_df.schema[c].is_numeric():
573
+ lst = [float("nan") if v is None else v for v in lst]
574
+ source_data[c] = lst
575
+ source = ColumnDataSource(source_data) # type: ignore[arg-type]
542
576
  color = _color_for(i)
543
- source = _src(row)
544
577
  fig.line(
545
578
  x=x,
546
579
  y=y_col,
@@ -651,8 +684,6 @@ class PlotNamespace:
651
684
  entities = unique_entities.limit(top_n).to_list()
652
685
  df = df.join(pl.DataFrame({key_col: entities}), on=key_col, how="inner")
653
686
 
654
- df_pd = df.to_pandas()
655
-
656
687
  def _make_scatter(y_col: str) -> "BokehFigure":
657
688
  from bokeh.models import ColumnDataSource
658
689
 
@@ -664,11 +695,21 @@ class PlotNamespace:
664
695
  tools="pan,wheel_zoom,box_zoom,reset,save,hover",
665
696
  tooltips=[(c, f"@{{{c}}}") for c in hover_cols],
666
697
  )
667
- for i, entity in enumerate(df_pd[key_col].unique()):
668
- row = df_pd[df_pd[key_col] == entity]
669
- source = ColumnDataSource(
670
- {c: row[c].tolist() for c in hover_cols if c in row.columns}
671
- )
698
+
699
+ entities = df.get_column(key_col).unique().to_list()
700
+ for i, entity in enumerate(entities):
701
+ row = df.filter(pl.col(key_col) == entity)
702
+
703
+ # Replace None with NaN for numeric columns to prevent Bokeh JS rendering crashes
704
+ source_data = {}
705
+ for c in hover_cols:
706
+ if c in row.columns:
707
+ lst = row.get_column(c).to_list()
708
+ if row.schema[c].is_numeric():
709
+ lst = [float("nan") if v is None else v for v in lst]
710
+ source_data[c] = lst
711
+
712
+ source = ColumnDataSource(source_data) # type: ignore[arg-type]
672
713
  fig.scatter(
673
714
  x=x,
674
715
  y=y_col,
File without changes
File without changes
File without changes
File without changes