matplotlib-map-utils 4.1.0__tar.gz → 4.1.1__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 (43) hide show
  1. {matplotlib_map_utils-4.1.0/matplotlib_map_utils.egg-info → matplotlib_map_utils-4.1.1}/PKG-INFO +2 -2
  2. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/README.md +1 -1
  3. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/__init__.py +16 -2
  4. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/core/inset_map.py +11 -11
  5. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/core/north_arrow.py +12 -12
  6. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/core/scale_bar.py +30 -24
  7. matplotlib_map_utils-4.1.1/matplotlib_map_utils/py.typed +0 -0
  8. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/validation/inset_map.py +21 -7
  9. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/validation/north_arrow.py +85 -16
  10. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/validation/scale_bar.py +115 -23
  11. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/validation/shared.py +36 -1
  12. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1/matplotlib_map_utils.egg-info}/PKG-INFO +2 -2
  13. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils.egg-info/SOURCES.txt +1 -0
  14. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/pyproject.toml +3 -1
  15. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/LICENSE +0 -0
  16. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/docs/assets/index/generator_logo.py +0 -0
  17. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/docs/assets/index/generator_map.py +0 -0
  18. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/docs/assets/inset_maps/generator.py +0 -0
  19. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/docs/assets/north_arrows/generator.py +0 -0
  20. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/docs/assets/quick/generator.py +0 -0
  21. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/docs/assets/scale_bars/generator.py +0 -0
  22. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/config.py +0 -0
  23. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/core/__init__.py +0 -0
  24. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/defaults/__init__.py +0 -0
  25. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/defaults/inset_map.py +0 -0
  26. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/defaults/north_arrow.py +0 -0
  27. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/defaults/scale_bar.py +0 -0
  28. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/scratch/map_utils.py +0 -0
  29. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/scratch/north_arrow_old_classes.py +0 -0
  30. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/utils/__init__.py +0 -0
  31. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/utils/usa.json +0 -0
  32. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/utils/usa.py +0 -0
  33. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils/validation/__init__.py +0 -0
  34. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils.egg-info/dependency_links.txt +0 -0
  35. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils.egg-info/requires.txt +0 -0
  36. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/matplotlib_map_utils.egg-info/top_level.txt +0 -0
  37. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/setup.cfg +0 -0
  38. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/site/assets/index/generator_logo.py +0 -0
  39. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/site/assets/index/generator_map.py +0 -0
  40. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/site/assets/inset_maps/generator.py +0 -0
  41. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/site/assets/north_arrows/generator.py +0 -0
  42. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/site/assets/quick/generator.py +0 -0
  43. {matplotlib_map_utils-4.1.0 → matplotlib_map_utils-4.1.1}/site/assets/scale_bars/generator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: matplotlib-map-utils
3
- Version: 4.1.0
3
+ Version: 4.1.1
4
4
  Summary: A suite of tools for creating maps in matplotlib
5
5
  Author-email: David Moss <davidmoss1221@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/moss-xyz/matplotlib-map-utils/
@@ -28,7 +28,7 @@ Dynamic: license-file
28
28
 
29
29
  **Feedback:** I welcome any and all feedback! See the *Development Notes* below for more details.
30
30
 
31
- **Current Version:** `v4.1.0`, featuring a brand-new documentation site and improved type validation! This DID introduce some breaking changes, see the documentation site for details!
31
+ **Current Version:** `v4.1.1`, which fixed a a few bugs (see [here](https://moss-xyz.github.io/matplotlib-map-utils/package/#release-notes) for details!)
32
32
 
33
33
  ---
34
34
 
@@ -8,7 +8,7 @@
8
8
 
9
9
  **Feedback:** I welcome any and all feedback! See the *Development Notes* below for more details.
10
10
 
11
- **Current Version:** `v4.1.0`, featuring a brand-new documentation site and improved type validation! This DID introduce some breaking changes, see the documentation site for details!
11
+ **Current Version:** `v4.1.1`, which fixed a a few bugs (see [here](https://moss-xyz.github.io/matplotlib-map-utils/package/#release-notes) for details!)
12
12
 
13
13
  ---
14
14
 
@@ -4,11 +4,25 @@ from .core.scale_bar import ScaleBar, scale_bar, dual_bars
4
4
  from .core.inset_map import InsetMap, inset_map, ExtentIndicator, indicate_extent, DetailIndicator, indicate_detail, inset_usa
5
5
  from typing import Literal
6
6
 
7
+ # TypedDicts describing the config dictionaries accepted by the objects/functions above.
8
+ # These power editor intellisense (key + value autocomplete) and can be used by callers
9
+ # to annotate their own config variables; runtime validation is still handled by pydantic.
10
+ from .validation.scale_bar import (ScaleBarBarDict, ScaleBarLabelsDict, ScaleBarUnitsDict,
11
+ ScaleBarTextDict, ScaleBarAobDict)
12
+ from .validation.north_arrow import (NorthArrowBaseDict, NorthArrowFancyDict, NorthArrowLabelDict,
13
+ NorthArrowShadowDict, NorthArrowPackDict, NorthArrowAobDict,
14
+ NorthArrowRotationDict)
15
+ from .validation.inset_map import InsetMapPlotDict
16
+
7
17
  # This defines what wildcard imports should import
8
- __all__ = ["NorthArrow", "north_arrow",
18
+ __all__ = ["NorthArrow", "north_arrow",
9
19
  "ScaleBar", "scale_bar", "dual_bars",
10
20
  "InsetMap","inset_map", "ExtentIndicator","indicate_extent", "DetailIndicator","indicate_detail", "inset_usa",
11
- "set_size"]
21
+ "set_size",
22
+ "ScaleBarBarDict", "ScaleBarLabelsDict", "ScaleBarUnitsDict", "ScaleBarTextDict", "ScaleBarAobDict",
23
+ "NorthArrowBaseDict", "NorthArrowFancyDict", "NorthArrowLabelDict", "NorthArrowShadowDict",
24
+ "NorthArrowPackDict", "NorthArrowAobDict", "NorthArrowRotationDict",
25
+ "InsetMapPlotDict"]
12
26
 
13
27
  from . import config
14
28
 
@@ -35,12 +35,12 @@ class InsetMap(matplotlib.artist.Artist):
35
35
  ## INITIALIZATION ##
36
36
  def __init__(self,
37
37
  size: str=None,
38
- location: Literal["upper right", "upper left", "lower left", "lower right", "center left", "center right", "lower center", "upper center", "center"]="lower left",
38
+ location: imt.Location="lower left",
39
39
  imsize: Any=None,
40
40
  pad: Any=None,
41
41
  coords: Any=None,
42
42
  transform=None,
43
- to_plot=None,
43
+ to_plot: None | list[imt.InsetMapPlotDict]=None,
44
44
  zorder: int=99,
45
45
  **kwargs):
46
46
  # Starting up the object with the base properties of a matplotlib Artist
@@ -199,7 +199,7 @@ class ExtentIndicator(matplotlib.artist.Artist):
199
199
 
200
200
  ## INITIALIZATION ##
201
201
  def __init__(self,
202
- to_return: Any=None,
202
+ to_return: None | imt.ExtentReturn=None,
203
203
  straighten: bool=True,
204
204
  pad: Any=0.05,
205
205
  plot: bool=True,
@@ -358,7 +358,7 @@ class DetailIndicator(matplotlib.artist.Artist):
358
358
 
359
359
  ## INITIALIZATION ##
360
360
  def __init__(self,
361
- to_return: Any=None,
361
+ to_return: None | imt.DetailReturn=None,
362
362
  straighten: bool=True,
363
363
  pad: Any=0.05,
364
364
  plot: bool=True,
@@ -544,9 +544,9 @@ class DetailIndicator(matplotlib.artist.Artist):
544
544
 
545
545
  # Function for creating an inset map, independent of the InsetMap object model
546
546
  # It is intended to be an easier-to-use API than the default inset_axes
547
- def inset_map(ax,
547
+ def inset_map(ax,
548
548
  size: str=None,
549
- location: Literal["upper right", "upper left", "lower left", "lower right", "center left", "center right", "lower center", "upper center", "center"]="upper right",
549
+ location: imt.Location="upper right",
550
550
  imsize: Any=None,
551
551
  pad: Any=None,
552
552
  coords: Any=None,
@@ -670,7 +670,7 @@ def indicate_extent(pax: matplotlib.axes.Axes,
670
670
  bax: matplotlib.axes.Axes,
671
671
  pcrs: Any,
672
672
  bcrs: Any,
673
- to_return: Any=None,
673
+ to_return: None | imt.ExtentReturn=None,
674
674
  straighten: bool=True,
675
675
  pad: Any=0.05,
676
676
  plot: bool=True,
@@ -755,11 +755,11 @@ def indicate_extent(pax: matplotlib.axes.Axes,
755
755
  # This will also, call extent_indicator too, as the two are linked
756
756
  # here, PAX means "parent axis" (where the indicator is plotted)
757
757
  # and IAX means "inset axis" (which contains the detail/zoomed-in section)
758
- def indicate_detail(pax: matplotlib.axes.Axes,
759
- iax: matplotlib.axes.Axes,
760
- pcrs: Any,
758
+ def indicate_detail(pax: matplotlib.axes.Axes,
759
+ iax: matplotlib.axes.Axes,
760
+ pcrs: Any,
761
761
  icrs: Any,
762
- to_return: Any=None,
762
+ to_return: None | imt.DetailReturn=None,
763
763
  straighten: bool=True,
764
764
  pad: Any=0.05,
765
765
  plot: bool=True,
@@ -34,11 +34,11 @@ from ..validation.shared import _del_keys
34
34
  class NorthArrow(matplotlib.artist.Artist):
35
35
 
36
36
  ## INITIALIZATION ##
37
- def __init__(self, size: str=None, location: Literal["upper right", "upper left", "lower left", "lower right", "center left", "center right", "lower center", "upper center", "center"]="upper right",
37
+ def __init__(self, size: str=None, location: nat.Location="upper right",
38
38
  scale: None | float | int=None,
39
- base: None | bool | dict = None, fancy: None | bool | dict = None,
40
- label: None | bool | dict = None, shadow: None | bool | dict = None,
41
- pack: None | dict = None, aob: None | dict = None, rotation: None | dict = None,
39
+ base: None | bool | nat.NorthArrowBaseDict = None, fancy: None | bool | nat.NorthArrowFancyDict = None,
40
+ label: None | bool | nat.NorthArrowLabelDict = None, shadow: None | bool | nat.NorthArrowShadowDict = None,
41
+ pack: None | nat.NorthArrowPackDict = None, aob: None | nat.NorthArrowAobDict = None, rotation: None | nat.NorthArrowRotationDict = None,
42
42
  zorder: int=99,):
43
43
  # Starting up the object with the base properties of a matplotlib Artist
44
44
  matplotlib.artist.Artist.__init__(self)
@@ -231,15 +231,15 @@ class NorthArrow(matplotlib.artist.Artist):
231
231
 
232
232
  # This function presents a way to draw the north arrow independent of the NorthArrow object model
233
233
  # and is actually used by the object model when draw() is called anyways
234
- def north_arrow(ax, draw=True, size: str=None, location: Literal["upper right", "upper left", "lower left", "lower right", "center left", "center right", "lower center", "upper center", "center"]="upper right",
234
+ def north_arrow(ax, draw=True, size: str=None, location: nat.Location="upper right",
235
235
  scale: None | float | int=None,
236
- base: None | bool | dict=None,
237
- fancy: None | bool | dict=None,
238
- label: None | bool | dict=None,
239
- shadow: None | bool | dict=None,
240
- pack: None | dict=None,
241
- aob: None | dict=None,
242
- rotation: None | dict=None,
236
+ base: None | bool | nat.NorthArrowBaseDict=None,
237
+ fancy: None | bool | nat.NorthArrowFancyDict=None,
238
+ label: None | bool | nat.NorthArrowLabelDict=None,
239
+ shadow: None | bool | nat.NorthArrowShadowDict=None,
240
+ pack: None | nat.NorthArrowPackDict=None,
241
+ aob: None | nat.NorthArrowAobDict=None,
242
+ rotation: None | nat.NorthArrowRotationDict=None,
243
243
  zorder: int=99,):
244
244
 
245
245
  if draw==True:
@@ -35,13 +35,13 @@ from ..validation.shared import _del_keys
35
35
  class ScaleBar(matplotlib.artist.Artist):
36
36
 
37
37
  ## INITIALIZATION ##
38
- def __init__(self, size: str=None, style: Literal["ticks","boxes"]="boxes",
39
- location: Literal["upper right", "upper left", "lower left", "lower right", "center left", "center right", "lower center", "upper center", "center"]="upper right",
40
- bar: None | bool | dict=None,
41
- units: None | bool | dict=None,
42
- labels: None | bool | dict=None,
43
- text: None | bool | dict=None,
44
- aob: None | bool | dict=None,
38
+ def __init__(self, size: str=None, style: sbt.ScaleBarStyle="boxes",
39
+ location: sbt.Location="upper right",
40
+ bar: None | bool | sbt.ScaleBarBarDict=None,
41
+ units: None | bool | sbt.ScaleBarUnitsDict=None,
42
+ labels: None | bool | sbt.ScaleBarLabelsDict=None,
43
+ text: None | bool | sbt.ScaleBarTextDict=None,
44
+ aob: None | bool | sbt.ScaleBarAobDict=None,
45
45
  zorder: int=99,
46
46
  ):
47
47
  # Starting up the object with the base properties of a matplotlib Artist
@@ -220,13 +220,13 @@ class ScaleBar(matplotlib.artist.Artist):
220
220
 
221
221
  ### DRAWING FUNCTIONS ###
222
222
 
223
- def scale_bar(ax, draw=True, size: str=None, style: Literal["ticks","boxes"]="boxes",
224
- location: Literal["upper right", "upper left", "lower left", "lower right", "center left", "center right", "lower center", "upper center", "center"]="upper right",
225
- bar: None | bool | dict=None,
226
- units: None | bool | dict=None,
227
- labels: None | bool | dict=None,
228
- text: None | bool | dict=None,
229
- aob: None | bool | dict=None,
223
+ def scale_bar(ax, draw=True, size: str=None, style: sbt.ScaleBarStyle="boxes",
224
+ location: sbt.Location="upper right",
225
+ bar: None | bool | sbt.ScaleBarBarDict=None,
226
+ units: None | bool | sbt.ScaleBarUnitsDict=None,
227
+ labels: None | bool | sbt.ScaleBarLabelsDict=None,
228
+ text: None | bool | sbt.ScaleBarTextDict=None,
229
+ aob: None | bool | sbt.ScaleBarAobDict=None,
230
230
  zorder: int=99,
231
231
  return_aob: bool=True,):
232
232
  # For the default function mode, dispatch to the Artist class so final
@@ -301,7 +301,7 @@ def scale_bar(ax, draw=True, size: str=None, style: Literal["ticks","boxes"]="bo
301
301
  segments = _config_seg(bar_max, bar_length/major_div, major_div, minor_div,
302
302
  _bar["minor_type"], _labels["style"],
303
303
  _labels["labels"], _labels["format"], _labels["format_int"])
304
-
304
+
305
305
  # Also setting the segment gap to be either the edgewidth or the tickwidth
306
306
  gap_width = _bar.get("edgewidth", _bar.get("edgewidth", 0))
307
307
 
@@ -320,7 +320,7 @@ def scale_bar(ax, draw=True, size: str=None, style: Literal["ticks","boxes"]="bo
320
320
  major_height = _bar["height"]*72
321
321
 
322
322
  # Initializing the bar with an invisible spacer, to align it with the text later
323
- # if all of these conditions are met, we do not need a spcer
323
+ # if all of these conditions are met, we do not need a spacer
324
324
  if _labels["style"] == "last_only" and major_div==1 and (minor_div==1 or minor_div==0):
325
325
  bar_artists = []
326
326
  # If we have minor divs, it will be equal to half the minor width
@@ -516,14 +516,14 @@ def scale_bar(ax, draw=True, size: str=None, style: Literal["ticks","boxes"]="bo
516
516
  # This is a convenience function for creating two scale bars, with different units, aligned with each other
517
517
  # The bars should be identical except for the units and the divisions
518
518
  # NOTE: still under development, will tidy up if there is usage of it
519
- def dual_bars(ax, draw=True, size: str=None, style: Literal["ticks","boxes"]="boxes",
520
- location: Literal["upper right", "upper left", "lower left", "lower right", "center left", "center right", "lower center", "upper center", "center"]="upper right",
519
+ def dual_bars(ax, draw=True, size: str=None, style: sbt.ScaleBarStyle="boxes",
520
+ location: sbt.Location="upper right",
521
521
  units_dual=["mi","km"], bar_maxes=[None,None], bar_lengths=[None,None], major_divs=[None, None], minor_divs=[None, None],
522
- bar: None | bool | dict=None,
523
- units: None | bool | dict=None,
524
- labels: None | bool | dict=None,
525
- text: None | bool | dict=None,
526
- aob: None | bool | dict=None,
522
+ bar: None | bool | sbt.ScaleBarBarDict=None,
523
+ units: None | bool | sbt.ScaleBarUnitsDict=None,
524
+ labels: None | bool | sbt.ScaleBarLabelsDict=None,
525
+ text: None | bool | sbt.ScaleBarTextDict=None,
526
+ aob: None | bool | sbt.ScaleBarAobDict=None,
527
527
  zorder: int=99,
528
528
  pad=0, sep=0,
529
529
  return_aob: bool=True
@@ -643,7 +643,13 @@ def _config_bar(ax, bar):
643
643
  # We've done most of the work here - just need to see if we want a minor div or not
644
644
  # If one is provided, override what we calculated above
645
645
  if bar["minor_div"] is not None:
646
- bar_minor_div = bar["minor_div"]
646
+ if bar["minor_div"] <= 1:
647
+ bar_minor_div = 1
648
+ else:
649
+ bar_minor_div = bar["minor_div"]
650
+ # Alternatively, if minor_type is "none", then we need to set to 1
651
+ if bar["minor_type"] == "none":
652
+ bar_minor_div = 1
647
653
 
648
654
  # Returning everything
649
655
  return bar_max, bar_length, units_label, bar_major_div, bar_minor_div
@@ -8,17 +8,18 @@
8
8
  # Geo packages
9
9
  import matplotlib.axes
10
10
  # Pydantic type validation
11
- from typing import Annotated, Union, Tuple, List, Optional, Literal, Any, Dict
11
+ from typing import Annotated, Union, Tuple, List, Optional, Literal, Any, Dict, TypedDict
12
12
  from pydantic import ConfigDict, BaseModel, Field, model_validator
13
- from .shared import MatplotlibColor, CRSInput, _get_size_key
13
+ from .shared import MatplotlibColor, CRSInput, _get_size_key, Location, ExtentReturn, DetailReturn
14
14
  from .. import config
15
15
  from ..defaults import inset_map as imd
16
16
 
17
17
  ### ALL ###
18
18
  # This code tells other packages what to import if not explicitly stated
19
19
  __all__ = [
20
- "InsetMapPlotModel", "InsetMapInsetModel",
20
+ "InsetMapPlotModel", "InsetMapInsetModel",
21
21
  "InsetMapExtentModel", "InsetMapDetailModel",
22
+ "InsetMapPlotDict",
22
23
  ]
23
24
 
24
25
  ### COMPONENT MODELS ###
@@ -30,7 +31,7 @@ class InsetMapPlotModel(BaseModel):
30
31
 
31
32
  class InsetMapInsetModel(BaseModel):
32
33
  model_config = ConfigDict(arbitrary_types_allowed=True)
33
- location: Literal["upper right", "upper left", "lower left", "lower right", "center left", "center right", "lower center", "upper center", "center"]
34
+ location: Location
34
35
  imsize: Optional[Union[Annotated[Union[float, int], Field(ge=0)], Tuple[Annotated[Union[float, int], Field(ge=0)], Annotated[Union[float, int], Field(ge=0)]]]] = None
35
36
  pad: Optional[Union[Annotated[Union[float, int], Field(ge=0)], Tuple[Annotated[Union[float, int], Field(ge=0)], Annotated[Union[float, int], Field(ge=0)]]]] = None
36
37
  coords: Optional[Tuple[Union[float, int], Union[float, int]]] = None
@@ -64,11 +65,24 @@ class InsetMapExtentModel(BaseModel):
64
65
  alpha: Annotated[Union[float, int], Field(ge=0)]
65
66
  linewidth: Annotated[Union[float, int], Field(ge=0)]
66
67
  zorder: int
67
- to_return: Optional[Literal["shape", "patch", "fig", "ax"]] = None
68
+ to_return: Optional[ExtentReturn] = None
68
69
 
69
70
  class InsetMapDetailModel(BaseModel):
70
71
  model_config = ConfigDict(arbitrary_types_allowed=True)
71
- to_return: Optional[Literal["connectors", "lines"]] = None
72
+ to_return: Optional[DetailReturn] = None
72
73
  connector_color: MatplotlibColor
73
74
  connector_width: Annotated[Union[float, int], Field(ge=0)]
74
- zorder: int
75
+ zorder: int
76
+
77
+ ### TYPED DICTS ###
78
+ # Inset-map objects take their settings as individual keyword arguments rather
79
+ # than nested config dicts, so (unlike ScaleBar/NorthArrow) there is no dict
80
+ # literal to complete - the enumerated kwargs are typed with the shared Literal
81
+ # aliases directly in core/inset_map.py. The one place a dict literal IS passed
82
+ # is each element of `to_plot`, so we expose a TypedDict for that shape. It is
83
+ # never validated at runtime (InsetMapPlotModel does that); it exists only so
84
+ # `to_plot=[{"data": ..., "kwargs": ...}]` autocompletes its keys.
85
+
86
+ class InsetMapPlotDict(TypedDict, total=False):
87
+ data: Any
88
+ kwargs: dict
@@ -8,24 +8,28 @@
8
8
  # Default packages
9
9
  import warnings
10
10
  # The types we use in this script
11
- from typing import Annotated, Union, Tuple, Optional, Literal, Any
11
+ from typing import Annotated, Union, Tuple, Optional, Literal, Any, TypedDict
12
12
  # Pydantic type validation
13
13
  from pydantic import ConfigDict, BaseModel, Field, BeforeValidator, model_validator
14
- from .shared import MatplotlibColor, Numpy2DArray, MatplotlibFontsize, CRSInput, _get_size_key
14
+ from .shared import (MatplotlibColor, Numpy2DArray, MatplotlibFontsize, CRSInput, _get_size_key,
15
+ Location, LabelPosition, HAlign, VAlign, FontFamily, FontStyle, FontWeight,
16
+ PackAlign, PackMode, RotationReference)
15
17
  from .. import config
16
18
  from ..defaults import north_arrow as nad
17
19
 
18
20
  ### ALL ###
19
21
  # This code tells other packages what to import if not explicitly stated
20
22
  __all__ = [
21
- "NorthArrowPrimaryModel", "NorthArrowBaseModel", "NorthArrowFancyModel",
22
- "NorthArrowLabelModel", "NorthArrowShadowModel", "NorthArrowPackModel",
23
- "NorthArrowAobModel", "NorthArrowRotationModel"
23
+ "NorthArrowPrimaryModel", "NorthArrowBaseModel", "NorthArrowFancyModel",
24
+ "NorthArrowLabelModel", "NorthArrowShadowModel", "NorthArrowPackModel",
25
+ "NorthArrowAobModel", "NorthArrowRotationModel",
26
+ "NorthArrowBaseDict", "NorthArrowFancyDict", "NorthArrowLabelDict", "NorthArrowShadowDict",
27
+ "NorthArrowPackDict", "NorthArrowAobDict", "NorthArrowRotationDict"
24
28
  ]
25
29
 
26
30
  ### COMPONENT MODELS ###
27
31
  class NorthArrowPrimaryModel(BaseModel):
28
- location: Literal["upper right", "upper left", "lower left", "lower right", "center left", "center right", "lower center", "upper center", "center"]
32
+ location: Location
29
33
  scale: Annotated[Optional[Union[float, int]], Field(ge=0)] = None
30
34
  zorder: int
31
35
 
@@ -74,14 +78,14 @@ class NorthArrowFancyModel(BaseModel):
74
78
  class NorthArrowLabelModel(BaseModel):
75
79
  model_config = ConfigDict(arbitrary_types_allowed=True)
76
80
  text: str
77
- position: Literal["top", "bottom", "left", "right"]
78
- ha: Literal["left", "center", "right"]
79
- va: Literal["baseline", "bottom", "center", "center_baseline", "top"]
81
+ position: LabelPosition
82
+ ha: HAlign
83
+ va: VAlign
80
84
  fontsize: MatplotlibFontsize
81
- fontfamily: Literal["serif", "sans-serif", "cursive", "fantasy", "monospace"]
82
- fontstyle: Literal["normal", "italic", "oblique"]
85
+ fontfamily: FontFamily
86
+ fontstyle: FontStyle
83
87
  color: MatplotlibColor
84
- fontweight: Literal["normal", "bold", "heavy", "light", "ultrabold", "ultralight"]
88
+ fontweight: FontWeight
85
89
  stroke_width: Annotated[Union[float, int], Field(ge=0)]
86
90
  stroke_color: MatplotlibColor
87
91
  rotation: Annotated[Union[float, int], Field(ge=-360, le=360)]
@@ -112,11 +116,11 @@ class NorthArrowShadowModel(BaseModel):
112
116
 
113
117
  class NorthArrowPackModel(BaseModel):
114
118
  sep: Annotated[Union[float, int], Field(ge=0)]
115
- align: Literal["top", "bottom", "left", "right", "center", "baseline"]
119
+ align: PackAlign
116
120
  pad: Annotated[Union[float, int], Field(ge=0)]
117
121
  width: Annotated[Optional[Union[float, int]], Field(ge=0)] = None
118
122
  height: Annotated[Optional[Union[float, int]], Field(ge=0)] = None
119
- mode: Literal["fixed", "expand", "equal"]
123
+ mode: PackMode
120
124
 
121
125
  @model_validator(mode='before')
122
126
  @classmethod
@@ -151,7 +155,7 @@ class NorthArrowRotationModel(BaseModel):
151
155
  model_config = ConfigDict(arbitrary_types_allowed=True)
152
156
  degrees: Annotated[Optional[Union[float, int]], Field(ge=-360, le=360)] = None
153
157
  crs: Optional[CRSInput] = None
154
- reference: Optional[Literal["axis", "data", "center"]] = None
158
+ reference: Optional[RotationReference] = None
155
159
  coords: Optional[Tuple[Union[float, int], Union[float, int]]] = None
156
160
 
157
161
  @model_validator(mode='before')
@@ -174,4 +178,69 @@ class NorthArrowRotationModel(BaseModel):
174
178
  raise ValueError("If degrees is None, crs, reference, and coords cannot be None: please provide a valid input for each of these variables instead")
175
179
  elif isinstance(self.degrees, (int, float)) and (self.crs is not None or self.reference is not None or self.coords is not None):
176
180
  warnings.warn("A value for degrees was supplied; values for crs, reference, and coords will be ignored")
177
- return self
181
+ return self
182
+
183
+ ### TYPED DICTS ###
184
+ # These mirror the user-facing fields of the models above, purely for editor
185
+ # intellisense (key + value autocomplete inside dict literals). They are never
186
+ # instantiated or validated at runtime - the plain dicts users pass still flow
187
+ # through the pydantic models above. total=False marks every key optional, since
188
+ # users supply partial configs. Literal-typed fields reuse the shared aliases so
189
+ # their allowed values stay in lockstep with the models.
190
+
191
+ class NorthArrowBaseDict(TypedDict, total=False):
192
+ coords: Any
193
+ facecolor: Any
194
+ edgecolor: Any
195
+ linewidth: float | int
196
+ zorder: int
197
+
198
+ class NorthArrowFancyDict(TypedDict, total=False):
199
+ coords: Any
200
+ facecolor: Any
201
+ zorder: int
202
+
203
+ class NorthArrowLabelDict(TypedDict, total=False):
204
+ text: str
205
+ position: LabelPosition
206
+ ha: HAlign
207
+ va: VAlign
208
+ fontsize: float | int | str
209
+ fontfamily: FontFamily
210
+ fontstyle: FontStyle
211
+ color: Any
212
+ fontweight: FontWeight
213
+ stroke_width: float | int
214
+ stroke_color: Any
215
+ rotation: float | int
216
+ zorder: int
217
+
218
+ class NorthArrowShadowDict(TypedDict, total=False):
219
+ offset: tuple
220
+ alpha: float | int
221
+ shadow_rgbFace: Any
222
+
223
+ class NorthArrowPackDict(TypedDict, total=False):
224
+ sep: float | int
225
+ align: PackAlign
226
+ pad: float | int
227
+ width: float | int
228
+ height: float | int
229
+ mode: PackMode
230
+
231
+ class NorthArrowAobDict(TypedDict, total=False):
232
+ facecolor: Any
233
+ edgecolor: Any
234
+ alpha: float | int
235
+ pad: float | int
236
+ borderpad: float | int
237
+ prop: float | int | str
238
+ frameon: bool
239
+ bbox_to_anchor: Any
240
+ bbox_transform: Any
241
+
242
+ class NorthArrowRotationDict(TypedDict, total=False):
243
+ degrees: float | int
244
+ crs: Any
245
+ reference: RotationReference
246
+ coords: Any
@@ -6,9 +6,11 @@
6
6
  ### IMPORTING PACKAGES ###
7
7
 
8
8
  # Pydantic type validation
9
- from typing import Annotated, Union, Tuple, List, Optional, Literal, Any
9
+ from typing import Annotated, Union, Tuple, List, Optional, Literal, Any, TypedDict
10
10
  from pydantic import ConfigDict, BaseModel, Field, BeforeValidator, model_validator
11
- from .shared import MatplotlibColor, MatplotlibFontsize, CRSInput, _validate_crs_input, _get_size_key
11
+ from .shared import (MatplotlibColor, MatplotlibFontsize, CRSInput, _validate_crs_input, _get_size_key,
12
+ ScaleBarStyle, Location, BarUnit, MinorType, TickLoc, LabelStyle, LabelsLoc, UnitsLoc,
13
+ FontFamily, FontStyle, FontWeight, RotationMode)
12
14
  from .. import config
13
15
  from ..defaults import scale_bar as sbd
14
16
 
@@ -16,7 +18,8 @@ from ..defaults import scale_bar as sbd
16
18
  # This code tells other packages what to import if not explicitly stated
17
19
  __all__ = [
18
20
  "preferred_divs", "convert_dict", "units_standard",
19
- "ScaleBarPrimaryModel", "ScaleBarBarModel", "ScaleBarLabelsModel", "ScaleBarUnitsModel", "ScaleBarTextModel", "ScaleBarAobModel"
21
+ "ScaleBarPrimaryModel", "ScaleBarBarModel", "ScaleBarLabelsModel", "ScaleBarUnitsModel", "ScaleBarTextModel", "ScaleBarAobModel",
22
+ "ScaleBarBarDict", "ScaleBarLabelsDict", "ScaleBarUnitsDict", "ScaleBarTextDict", "ScaleBarAobDict"
20
23
  ]
21
24
 
22
25
  ### CONSTANTS ###
@@ -73,8 +76,8 @@ units_standard = {
73
76
  ### COMPONENT MODELS ###
74
77
 
75
78
  class ScaleBarPrimaryModel(BaseModel):
76
- style: Literal["ticks","boxes"]
77
- location: Literal["upper right", "upper left", "lower left", "lower right", "center left", "center right", "lower center", "upper center", "center"]
79
+ style: ScaleBarStyle
80
+ location: Location
78
81
  zorder: int
79
82
 
80
83
  def _validate_scalebar_projection(v):
@@ -87,7 +90,7 @@ ScaleBarProjection = Annotated[Any, BeforeValidator(_validate_scalebar_projectio
87
90
  class ScaleBarBarModel(BaseModel):
88
91
  model_config = ConfigDict(arbitrary_types_allowed=True)
89
92
  projection: ScaleBarProjection
90
- unit: Optional[Literal["m","km","ft","yd","mi","nmi"]] = None
93
+ unit: Optional[BarUnit] = None
91
94
  rotation: Annotated[Optional[Union[float, int]], Field(ge=-360, le=360)] = None
92
95
  max: Annotated[Optional[Union[float, int]], Field(ge=0)] = None
93
96
  length: Annotated[Optional[Union[float, int]], Field(ge=0)] = None
@@ -96,12 +99,12 @@ class ScaleBarBarModel(BaseModel):
96
99
  major_div: Annotated[Optional[int], Field(ge=1)] = None
97
100
  minor_div: Annotated[Optional[int], Field(ge=0)] = None
98
101
  minor_frac: Annotated[Optional[Union[float, int]], Field(ge=0, le=1)] = None
99
- minor_type: Optional[Literal["all","first","none"]] = None
102
+ minor_type: Optional[MinorType] = None
100
103
  major_mult: Annotated[Optional[Union[float, int]], Field(ge=0)] = None
101
104
  facecolors: Optional[Union[MatplotlibColor, List[MatplotlibColor], Tuple[MatplotlibColor, ...]]] = None
102
105
  edgecolors: Optional[Union[MatplotlibColor, List[MatplotlibColor], Tuple[MatplotlibColor, ...]]] = None
103
106
  edgewidth: Annotated[Optional[Union[float, int]], Field(ge=0)] = None
104
- tick_loc: Optional[Literal["above","below","middle"]] = None
107
+ tick_loc: Optional[TickLoc] = None
105
108
  basecolors: Optional[Union[MatplotlibColor, List[MatplotlibColor], Tuple[MatplotlibColor, ...]]] = None
106
109
  tickcolors: Optional[Union[MatplotlibColor, List[MatplotlibColor], Tuple[MatplotlibColor, ...]]] = None
107
110
  tickwidth: Annotated[Optional[Union[float, int]], Field(ge=0)] = None
@@ -125,17 +128,17 @@ class ScaleBarLabelsModel(BaseModel):
125
128
  labels: Optional[Union[List[Any], Tuple[Any, ...]]] = None
126
129
  format: str
127
130
  format_int: bool
128
- style: Literal["major","first_last","last_only","minor_all","minor_first"]
129
- loc: Optional[Literal["above","below"]] = None
131
+ style: LabelStyle
132
+ loc: Optional[LabelsLoc] = None
130
133
  fontsize: Optional[MatplotlibFontsize] = None
131
134
  textcolors: Optional[Union[MatplotlibColor, List[MatplotlibColor], Tuple[MatplotlibColor, ...]]] = None
132
- fontfamily: Optional[Literal["serif", "sans-serif", "cursive", "fantasy", "monospace"]] = None
133
- fontstyle: Optional[Literal["normal", "italic", "oblique"]] = None
134
- fontweight: Optional[Literal["normal", "bold", "heavy", "light", "ultrabold", "ultralight"]] = None
135
+ fontfamily: Optional[FontFamily] = None
136
+ fontstyle: Optional[FontStyle] = None
137
+ fontweight: Optional[FontWeight] = None
135
138
  stroke_width: Annotated[Optional[Union[float, int]], Field(ge=0)] = None
136
139
  stroke_color: Optional[MatplotlibColor] = None
137
140
  rotation: Annotated[Optional[Union[float, int]], Field(ge=-360, le=360)] = None
138
- rotation_mode: Optional[Literal["anchor","default"]] = None
141
+ rotation_mode: Optional[RotationMode] = None
139
142
  sep: Annotated[Union[float, int], Field(ge=0)]
140
143
  pad: Annotated[Union[float, int], Field(ge=0)]
141
144
 
@@ -163,16 +166,16 @@ class ScaleBarLabelsModel(BaseModel):
163
166
  class ScaleBarUnitsModel(BaseModel):
164
167
  model_config = ConfigDict(arbitrary_types_allowed=True)
165
168
  label: Optional[str] = None
166
- loc: Optional[Literal["bar","text","opposite"]] = None
169
+ loc: Optional[UnitsLoc] = None
167
170
  fontsize: Optional[MatplotlibFontsize] = None
168
171
  textcolor: Optional[MatplotlibColor] = None
169
- fontfamily: Optional[Literal["serif", "sans-serif", "cursive", "fantasy", "monospace"]] = None
170
- fontstyle: Optional[Literal["normal", "italic", "oblique"]] = None
171
- fontweight: Optional[Literal["normal", "bold", "heavy", "light", "ultrabold", "ultralight"]] = None
172
+ fontfamily: Optional[FontFamily] = None
173
+ fontstyle: Optional[FontStyle] = None
174
+ fontweight: Optional[FontWeight] = None
172
175
  stroke_width: Annotated[Optional[Union[float, int]], Field(ge=0)] = None
173
176
  stroke_color: Optional[MatplotlibColor] = None
174
177
  rotation: Annotated[Optional[Union[float, int]], Field(ge=-360, le=360)] = None
175
- rotation_mode: Optional[Literal["anchor","default"]] = None
178
+ rotation_mode: Optional[RotationMode] = None
176
179
  sep: Annotated[Union[float, int], Field(ge=0)]
177
180
  pad: Annotated[Union[float, int], Field(ge=0)]
178
181
 
@@ -198,13 +201,13 @@ class ScaleBarTextModel(BaseModel):
198
201
  model_config = ConfigDict(arbitrary_types_allowed=True)
199
202
  fontsize: MatplotlibFontsize
200
203
  textcolor: Union[MatplotlibColor, List[MatplotlibColor], Tuple[MatplotlibColor, ...]]
201
- fontfamily: Literal["serif", "sans-serif", "cursive", "fantasy", "monospace"]
202
- fontstyle: Literal["normal", "italic", "oblique"]
203
- fontweight: Literal["normal", "bold", "heavy", "light", "ultrabold", "ultralight"]
204
+ fontfamily: FontFamily
205
+ fontstyle: FontStyle
206
+ fontweight: FontWeight
204
207
  stroke_width: Annotated[Union[float, int], Field(ge=0)]
205
208
  stroke_color: MatplotlibColor
206
209
  rotation: Annotated[Optional[Union[float, int]], Field(ge=-360, le=360)] = None
207
- rotation_mode: Optional[Literal["anchor","default"]] = None
210
+ rotation_mode: Optional[RotationMode] = None
208
211
 
209
212
  @model_validator(mode='before')
210
213
  @classmethod
@@ -235,3 +238,92 @@ class ScaleBarAobModel(BaseModel):
235
238
  size = data.pop('size', config.DEFAULT_SIZE)
236
239
  defaults = sbd._DEFAULTS_SB[_get_size_key(size)][4]
237
240
  return defaults | data
241
+
242
+ ### TYPED DICTS ###
243
+ # These mirror the user-facing fields of the models above, purely for editor
244
+ # intellisense (key + value autocomplete inside dict literals). They are never
245
+ # instantiated or validated at runtime - the plain dicts users pass still flow
246
+ # through the pydantic models above. total=False marks every key optional, since
247
+ # users supply partial configs. Literal-typed fields reuse the shared aliases so
248
+ # their allowed values stay in lockstep with the models.
249
+
250
+ class ScaleBarBarDict(TypedDict, total=False):
251
+ projection: Any
252
+ unit: BarUnit
253
+ rotation: float | int
254
+ max: float | int
255
+ length: float | int
256
+ height: float | int
257
+ reverse: bool
258
+ major_div: int
259
+ minor_div: int
260
+ minor_frac: float | int
261
+ minor_type: MinorType
262
+ major_mult: float | int
263
+ facecolors: Any
264
+ edgecolors: Any
265
+ edgewidth: float | int
266
+ tick_loc: TickLoc
267
+ basecolors: Any
268
+ tickcolors: Any
269
+ tickwidth: float | int
270
+ interpolation: str
271
+ dpi_cor: bool
272
+ resample: bool
273
+ raster_dpi: float | int
274
+ raster_dpi_scale: float | int
275
+
276
+ class ScaleBarLabelsDict(TypedDict, total=False):
277
+ labels: list | tuple
278
+ format: str
279
+ format_int: bool
280
+ style: LabelStyle
281
+ loc: LabelsLoc
282
+ fontsize: float | int | str
283
+ textcolors: Any
284
+ fontfamily: FontFamily
285
+ fontstyle: FontStyle
286
+ fontweight: FontWeight
287
+ stroke_width: float | int
288
+ stroke_color: Any
289
+ rotation: float | int
290
+ rotation_mode: RotationMode
291
+ sep: float | int
292
+ pad: float | int
293
+
294
+ class ScaleBarUnitsDict(TypedDict, total=False):
295
+ label: str
296
+ loc: UnitsLoc
297
+ fontsize: float | int | str
298
+ textcolor: Any
299
+ fontfamily: FontFamily
300
+ fontstyle: FontStyle
301
+ fontweight: FontWeight
302
+ stroke_width: float | int
303
+ stroke_color: Any
304
+ rotation: float | int
305
+ rotation_mode: RotationMode
306
+ sep: float | int
307
+ pad: float | int
308
+
309
+ class ScaleBarTextDict(TypedDict, total=False):
310
+ fontsize: float | int | str
311
+ textcolor: Any
312
+ fontfamily: FontFamily
313
+ fontstyle: FontStyle
314
+ fontweight: FontWeight
315
+ stroke_width: float | int
316
+ stroke_color: Any
317
+ rotation: float | int
318
+ rotation_mode: RotationMode
319
+
320
+ class ScaleBarAobDict(TypedDict, total=False):
321
+ facecolor: Any
322
+ edgecolor: Any
323
+ alpha: float | int
324
+ pad: float | int
325
+ borderpad: float | int
326
+ prop: float | int | str
327
+ frameon: bool
328
+ bbox_to_anchor: Any
329
+ bbox_transform: Any
@@ -6,9 +6,44 @@
6
6
  import numpy
7
7
  import pyproj
8
8
  import matplotlib.rcsetup
9
- from typing import Annotated, Any
9
+ from typing import Annotated, Any, Literal
10
10
  from pydantic import BeforeValidator
11
11
 
12
+ ### SHARED LITERAL ALIASES ###
13
+ # These name the enumerated value-sets used across the validation models.
14
+ # They are referenced by BOTH the pydantic models (for runtime validation) and
15
+ # the TypedDicts (for editor intellisense), so the allowed values can never drift
16
+ # between the two representations.
17
+
18
+ # Shared across components
19
+ Location = Literal["upper right", "upper left", "lower left", "lower right",
20
+ "center left", "center right", "lower center", "upper center", "center"]
21
+ FontFamily = Literal["serif", "sans-serif", "cursive", "fantasy", "monospace"]
22
+ FontStyle = Literal["normal", "italic", "oblique"]
23
+ FontWeight = Literal["normal", "bold", "heavy", "light", "ultrabold", "ultralight"]
24
+ RotationMode = Literal["anchor", "default"]
25
+
26
+ # scale_bar-specific
27
+ ScaleBarStyle = Literal["ticks", "boxes"]
28
+ BarUnit = Literal["m", "km", "ft", "yd", "mi", "nmi"]
29
+ MinorType = Literal["all", "first", "none"]
30
+ TickLoc = Literal["above", "below", "middle"]
31
+ LabelStyle = Literal["major", "first_last", "last_only", "minor_all", "minor_first"]
32
+ LabelsLoc = Literal["above", "below"]
33
+ UnitsLoc = Literal["bar", "text", "opposite"]
34
+
35
+ # north_arrow-specific
36
+ LabelPosition = Literal["top", "bottom", "left", "right"]
37
+ HAlign = Literal["left", "center", "right"]
38
+ VAlign = Literal["baseline", "bottom", "center", "center_baseline", "top"]
39
+ PackAlign = Literal["top", "bottom", "left", "right", "center", "baseline"]
40
+ PackMode = Literal["fixed", "expand", "equal"]
41
+ RotationReference = Literal["axis", "data", "center"]
42
+
43
+ # inset_map-specific
44
+ ExtentReturn = Literal["shape", "patch", "fig", "ax"]
45
+ DetailReturn = Literal["connectors", "lines"]
46
+
12
47
  def _validate_color(v):
13
48
  if v is None:
14
49
  return v
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: matplotlib-map-utils
3
- Version: 4.1.0
3
+ Version: 4.1.1
4
4
  Summary: A suite of tools for creating maps in matplotlib
5
5
  Author-email: David Moss <davidmoss1221@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/moss-xyz/matplotlib-map-utils/
@@ -28,7 +28,7 @@ Dynamic: license-file
28
28
 
29
29
  **Feedback:** I welcome any and all feedback! See the *Development Notes* below for more details.
30
30
 
31
- **Current Version:** `v4.1.0`, featuring a brand-new documentation site and improved type validation! This DID introduce some breaking changes, see the documentation site for details!
31
+ **Current Version:** `v4.1.1`, which fixed a a few bugs (see [here](https://moss-xyz.github.io/matplotlib-map-utils/package/#release-notes) for details!)
32
32
 
33
33
  ---
34
34
 
@@ -9,6 +9,7 @@ docs/assets/quick/generator.py
9
9
  docs/assets/scale_bars/generator.py
10
10
  matplotlib_map_utils/__init__.py
11
11
  matplotlib_map_utils/config.py
12
+ matplotlib_map_utils/py.typed
12
13
  matplotlib_map_utils.egg-info/PKG-INFO
13
14
  matplotlib_map_utils.egg-info/SOURCES.txt
14
15
  matplotlib_map_utils.egg-info/dependency_links.txt
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "matplotlib-map-utils"
7
- version = "4.1.0"
7
+ version = "4.1.1"
8
8
  authors = [
9
9
  { name="David Moss", email="davidmoss1221@gmail.com" },
10
10
  ]
@@ -29,6 +29,7 @@ exclude = ["matplotlib_map_utils.scratch*", "site*", "docs*"]
29
29
 
30
30
  [tool.setuptools.package-data]
31
31
  "matplotlib_map_utils.utils" = ["*.json"]
32
+ "matplotlib_map_utils" = ["py.typed"]
32
33
 
33
34
  [dependency-groups]
34
35
  dev = [
@@ -37,6 +38,7 @@ dev = [
37
38
  "ipykernel>=6.30.1",
38
39
  "jupyter>=1.1.1",
39
40
  "mapclassify>=2.8.1",
41
+ "marimo>=0.23.10",
40
42
  "matplotlib>=3.10.7",
41
43
  "notebook>=7.4.7",
42
44
  "pip>=25.2",