matplotlib-map-utils 3.1.1__py3-none-any.whl → 4.0.0__py3-none-any.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.
@@ -35,6 +35,7 @@ from ..validation import functions as sbf
35
35
 
36
36
  _DEFAULT_BAR, _DEFAULT_LABELS, _DEFAULT_UNITS, _DEFAULT_TEXT, _DEFAULT_AOB = sbd._DEFAULTS_SB["md"]
37
37
 
38
+
38
39
  ### CLASSES ###
39
40
 
40
41
  class ScaleBar(matplotlib.artist.Artist):
@@ -205,9 +206,17 @@ class ScaleBar(matplotlib.artist.Artist):
205
206
  # THANK YOU to matplotlib-scalebar for figuring this out
206
207
  # Note that we never specify the renderer - the axis takes care of it!
207
208
  def draw(self, renderer, *args, **kwargs):
209
+ # Prefer renderer dpi for class-based artists so exports stay sharp
210
+ # when savefig(dpi=...) differs from the figure construction dpi.
211
+ _bar = copy.deepcopy(self._bar)
212
+ if _bar.get("raster_dpi", None) is None:
213
+ _raster_dpi, _ = _resolve_raster_dpi(
214
+ _bar, self.axes.get_figure(), renderer=renderer
215
+ )
216
+ _bar["raster_dpi"] = _raster_dpi
208
217
  # Can re-use the drawing function we already established, but return the object instead
209
218
  sb_artist = scale_bar(ax=self.axes, style=self._style, location=self._location, draw=False,
210
- bar=self._bar, units=self._units,
219
+ bar=_bar, units=self._units,
211
220
  labels=self._labels, text=self._text, aob=self._aob,
212
221
  zorder=self._zorder)
213
222
  # This handles the actual drawing
@@ -251,6 +260,22 @@ def scale_bar(ax, draw=True, style: Literal["ticks","boxes"]="boxes",
251
260
  aob: None | bool | sbt._TYPE_AOB=None,
252
261
  zorder: int=99,
253
262
  return_aob: bool=True,):
263
+ # For the default function mode, dispatch to the Artist class so final
264
+ # rasterization happens at draw-time with the active renderer dpi.
265
+ if draw == True and return_aob == True:
266
+ _ = ax.add_artist(
267
+ ScaleBar(
268
+ style=style,
269
+ location=location,
270
+ bar=bar,
271
+ units=units,
272
+ labels=labels,
273
+ text=text,
274
+ aob=aob,
275
+ zorder=zorder,
276
+ )
277
+ )
278
+ return
254
279
 
255
280
  ##### VALIDATION #####
256
281
  _style = sbf._validate(sbt._VALIDATE_PRIMARY, "style", style)
@@ -272,6 +297,12 @@ def scale_bar(ax, draw=True, style: Literal["ticks","boxes"]="boxes",
272
297
  _text = sbf._validate_dict(text, copy.deepcopy(_DEFAULT_TEXT), sbt._VALIDATE_TEXT, return_clean=True) # this one has to be a deepcopy due to dictionary immutability
273
298
  _aob = sbf._validate_dict(aob, _DEFAULT_AOB, sbt._VALIDATE_AOB, return_clean=True)
274
299
 
300
+ # Raster controls for the temporary rendered image.
301
+ # These are kept explicit so output quality is not coupled to external rc state.
302
+ _fig = ax.get_figure()
303
+ _raster_dpi, _raster_dpi_scale = _resolve_raster_dpi(_bar, _fig)
304
+ _raster_dpi = _raster_dpi * _raster_dpi_scale
305
+
275
306
  ##### CONFIGURING TEXT #####
276
307
  # First need to convert each string font size (if any) to a point size
277
308
  for d in [_text, _labels, _units]:
@@ -290,7 +321,7 @@ def scale_bar(ax, draw=True, style: Literal["ticks","boxes"]="boxes",
290
321
  # First, ensuring matplotlib knows the correct dimensions for everything
291
322
  # as we need it to be accurate to calculate out the plots!
292
323
  if draw:
293
- ax.get_figure().draw_without_rendering()
324
+ _fig.draw_without_rendering()
294
325
 
295
326
  # Getting the config for the bar (length, text, divs, etc.)
296
327
  bar_max, bar_length, units_label, major_div, minor_div = _config_bar(ax, _bar)
@@ -308,7 +339,7 @@ def scale_bar(ax, draw=True, style: Literal["ticks","boxes"]="boxes",
308
339
  units_label = _units["label"]
309
340
 
310
341
  # Creating a temporary figure and axis for rendering later
311
- fig_temp, ax_temp = _temp_figure(ax)
342
+ fig_temp, ax_temp = _temp_figure(ax, dpi=_raster_dpi)
312
343
 
313
344
  ##### BAR CONSTRUCTION #####
314
345
 
@@ -472,7 +503,14 @@ def scale_bar(ax, draw=True, style: Literal["ticks","boxes"]="boxes",
472
503
 
473
504
  # Placing the image in an OffsetBox, while rotating if desired
474
505
  # We have to set the zoom level to be relative to the DPI as well (image is in pixels)
475
- offset_img = matplotlib.offsetbox.OffsetImage(img_scale_bar, origin="upper", zoom=72/fig_temp.dpi)
506
+ offset_img = matplotlib.offsetbox.OffsetImage(
507
+ img_scale_bar,
508
+ origin="upper",
509
+ zoom=72/fig_temp.dpi,
510
+ interpolation=_bar.get("interpolation", "none"),
511
+ dpi_cor=_bar.get("dpi_cor", True),
512
+ resample=_bar.get("resample", False),
513
+ )
476
514
  # If desired, we can just return the rendered image in the final OffsetImage
477
515
  # This will override any aob or draw selections! Only the OffsetImage is returned!
478
516
  if return_aob==False:
@@ -1087,15 +1125,18 @@ def _format_numeric(val, fmt, integer_override=True):
1087
1125
  return f"{val:{fmt}}"
1088
1126
 
1089
1127
  # A small function for creating a temporary figure based on a provided axis
1090
- def _temp_figure(ax, axis=False, visible=False):
1128
+ def _temp_figure(ax, axis=False, visible=False, dpi=None):
1091
1129
  # Getting the figure of the provided axis
1092
1130
  fig = ax.get_figure()
1131
+ # If no dpi is passed, fall back to the figure dpi
1132
+ if dpi is None:
1133
+ dpi = fig.dpi
1093
1134
  # Getting the dimensions of the axis
1094
1135
  ax_bbox = ax.patch.get_window_extent()
1095
1136
  # Converting to inches and rounding up
1096
1137
  ax_dim = math.ceil(max(ax_bbox.height, ax_bbox.width) / fig.dpi)
1097
1138
  # Creating a new temporary figure
1098
- fig_temp, ax_temp = matplotlib.pyplot.subplots(1,1, figsize=(ax_dim*1.5, ax_dim*1.5), dpi=fig.dpi)
1139
+ fig_temp, ax_temp = matplotlib.pyplot.subplots(1,1, figsize=(ax_dim*1.5, ax_dim*1.5), dpi=dpi)
1099
1140
  # Turning off the x and y labels if desired
1100
1141
  if axis == False:
1101
1142
  ax_temp.axis("off")
@@ -1270,9 +1311,9 @@ def _render_as_image(fig, ax, artist, rotation, add=True, remove=True, close=Tru
1270
1311
  # If needed, adding the artist to the axis
1271
1312
  if add == True:
1272
1313
  ax.add_artist(artist)
1273
- # Draw the figure, but without showing it, to place all the elements
1274
- fig.draw_without_rendering()
1275
- # Sets the canvas for the figure to AGG (Anti-Grain Geometry)
1314
+ # Render directly with Agg; a prior draw_without_rendering() can override
1315
+ # temporary figure DPI in some wrappers (e.g., UltraPlot), which makes
1316
+ # raster_dpi ineffective.
1276
1317
  canvas = FigureCanvasAgg(fig)
1277
1318
  # Draws the figure onto the canvas
1278
1319
  canvas.draw()
@@ -1291,4 +1332,15 @@ def _render_as_image(fig, ax, artist, rotation, add=True, remove=True, close=Tru
1291
1332
  if close == True:
1292
1333
  matplotlib.pyplot.close(fig)
1293
1334
  # Returning the image
1294
- return img
1335
+ return img
1336
+
1337
+
1338
+ def _resolve_raster_dpi(bar, fig, renderer=None):
1339
+ """
1340
+ Resolve base raster DPI and raster scale for temporary rendering.
1341
+ """
1342
+ raster_dpi = bar.get("raster_dpi", None)
1343
+ if raster_dpi is None:
1344
+ raster_dpi = renderer.dpi if renderer is not None else fig.dpi
1345
+ raster_dpi_scale = bar.get("raster_dpi_scale", 1)
1346
+ return raster_dpi, raster_dpi_scale
@@ -35,7 +35,12 @@ _BAR_XS = {
35
35
  "tick_loc":"above",
36
36
  "basecolors":["black"],
37
37
  "tickcolors":["black"],
38
- "tickwidth":0.5 # changed
38
+ "tickwidth":0.5, # changed
39
+ "interpolation":"none",
40
+ "dpi_cor":True,
41
+ "resample":False,
42
+ "raster_dpi":None,
43
+ "raster_dpi_scale":1,
39
44
  }
40
45
 
41
46
  # Labels
@@ -107,7 +112,12 @@ _BAR_SM = {
107
112
  "tick_loc":"above",
108
113
  "basecolors":["black"],
109
114
  "tickcolors":["black"],
110
- "tickwidth":0.75 # changed
115
+ "tickwidth":0.75, # changed
116
+ "interpolation":"none",
117
+ "dpi_cor":True,
118
+ "resample":False,
119
+ "raster_dpi":None,
120
+ "raster_dpi_scale":1,
111
121
  }
112
122
 
113
123
  # Labels
@@ -179,7 +189,12 @@ _BAR_MD = {
179
189
  "tick_loc":"above",
180
190
  "basecolors":["black"],
181
191
  "tickcolors":["black"],
182
- "tickwidth":1.5 # changed
192
+ "tickwidth":1.5, # changed
193
+ "interpolation":"none",
194
+ "dpi_cor":True,
195
+ "resample":False,
196
+ "raster_dpi":None,
197
+ "raster_dpi_scale":1,
183
198
  }
184
199
 
185
200
  # Labels
@@ -251,7 +266,12 @@ _BAR_LG = {
251
266
  "tick_loc":"above",
252
267
  "basecolors":["black"],
253
268
  "tickcolors":["black"],
254
- "tickwidth":3 # changed
269
+ "tickwidth":3, # changed
270
+ "interpolation":"none",
271
+ "dpi_cor":True,
272
+ "resample":False,
273
+ "raster_dpi":None,
274
+ "raster_dpi_scale":1,
255
275
  }
256
276
 
257
277
  # Labels
@@ -323,7 +343,12 @@ _BAR_XL = {
323
343
  "tick_loc":"above",
324
344
  "basecolors":["black"],
325
345
  "tickcolors":["black"],
326
- "tickwidth":5 # changed
346
+ "tickwidth":5, # changed
347
+ "interpolation":"none",
348
+ "dpi_cor":True,
349
+ "resample":False,
350
+ "raster_dpi":None,
351
+ "raster_dpi_scale":1,
327
352
  }
328
353
 
329
354
  # Labels
@@ -379,4 +404,4 @@ _DEFAULTS_SB = {
379
404
  "md":[_BAR_MD, _LABELS_MD, _UNITS_MD, _TEXT_MD, _AOB_MD],
380
405
  "lg":[_BAR_LG, _LABELS_LG, _UNITS_LG, _TEXT_LG, _AOB_LG],
381
406
  "xl":[_BAR_XL, _LABELS_XL, _UNITS_XL, _TEXT_XL, _AOB_XL],
382
- }
407
+ }
@@ -99,6 +99,11 @@ class _TYPE_BAR(TypedDict, total=False):
99
99
  basecolors: list | tuple | str # a color or list of colors to use for the bottom bar
100
100
  tickcolors: list | tuple | str # a color or list of colors to use for the ticks
101
101
  tickwidth: float | int # the line thickness of the bottom bar and ticks
102
+ interpolation: str | None # interpolation method used by OffsetImage; e.g. "none", "nearest", "bilinear"
103
+ dpi_cor: bool # whether OffsetImage should be corrected for renderer dpi (matplotlib default behavior)
104
+ resample: bool # whether OffsetImage should use image resampling during scaling
105
+ raster_dpi: float | int | None # explicit dpi for temporary rasterization step, None uses figure/renderer dpi
106
+ raster_dpi_scale: float | int # multiplier applied to raster_dpi for supersampling
102
107
 
103
108
 
104
109
  class _TYPE_LABELS(TypedDict, total=False):
@@ -195,6 +200,11 @@ _VALIDATE_BAR = {
195
200
  "basecolors":{"func":vf._validate_iterable, "kwargs":{"func":matplotlib.rcsetup.validate_color}}, # ticks only: any color value for matplotlib
196
201
  "tickcolors":{"func":vf._validate_iterable, "kwargs":{"func":matplotlib.rcsetup.validate_color}}, # ticks only: any color value for matplotlib
197
202
  "tickwidth":{"func":vf._validate_range, "kwargs":{"min":0, "max":None, "none_ok":True}}, # ticks only: between 0 and inf
203
+ "interpolation":{"func":vf._validate_type, "kwargs":{"match":str, "none_ok":True}},
204
+ "dpi_cor":{"func":vf._validate_type, "kwargs":{"match":bool}},
205
+ "resample":{"func":vf._validate_type, "kwargs":{"match":bool}},
206
+ "raster_dpi":{"func":vf._validate_range, "kwargs":{"min":1, "max":None, "none_ok":True}},
207
+ "raster_dpi_scale":{"func":vf._validate_range, "kwargs":{"min":0.0001, "max":None, "none_ok":True}},
198
208
  }
199
209
 
200
210
  _VALID_LABELS_STYLE = get_args(_TYPE_LABELS.__annotations__["style"])
@@ -272,4 +282,4 @@ _VALIDATE_AOB = {
272
282
  "frameon":{"func":vf._validate_type, "kwargs":{"match":bool}}, # any bool
273
283
  "bbox_to_anchor":{"func":vf._skip_validation}, # NOTE: currently unvalidated, use at your own risk!
274
284
  "bbox_transform":{"func":vf._skip_validation}, # NOTE: currently unvalidated, use at your own risk!
275
- }
285
+ }
@@ -0,0 +1,105 @@
1
+ Metadata-Version: 2.4
2
+ Name: matplotlib-map-utils
3
+ Version: 4.0.0
4
+ Summary: A suite of tools for creating maps in matplotlib
5
+ Author-email: David Moss <davidmoss1221@gmail.com>
6
+ Project-URL: Homepage, https://github.com/moss-xyz/matplotlib-map-utils/
7
+ Project-URL: Bug Tracker, https://github.com/moss-xyz/matplotlib-map-utils/issues
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: GNU General Public License (GPL)
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Framework :: Matplotlib
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: matplotlib>=3.9.0
16
+ Requires-Dist: cartopy>=0.23.0
17
+ Requires-Dist: great-circle-calculator>=1.3.1
18
+ Dynamic: license-file
19
+
20
+ ![matplotlib_map_utils logo](docs/assets/index/mmu_logo_w_elements.png)
21
+
22
+ ---
23
+
24
+ **Documentation:** Available at [https://moss-xyz.github.io/matplotlib-map-utils/](https://moss-xyz.github.io/matplotlib-map-utils/)
25
+
26
+ **Source Code:** [Available on GitHub](https://github.com/moss-xyz/matplotlib-map-utils)
27
+
28
+ **Feedback:** I welcome any and all feedback! See the *Development Notes* below for more details.
29
+
30
+ **Current Version:** `v4.0.0`, featuring a brand-new documentation site!
31
+
32
+ ---
33
+
34
+ ### 👋 Introduction
35
+
36
+ `matplotlib_map_utils` is a package that that assists with the creation of maps using [`matplotlib`](https://matplotlib.org/stable/).
37
+
38
+ As of `v3.x` (the current version), this includes the ability to easily create three common map elements:
39
+
40
+ * <span style="color: orange; font-weight: bold;">North arrows</span>, which automatically point to true north,
41
+
42
+ * <span style="color: orange; font-weight: bold;">Scale bars</span>, available in different styles and automatic unit conversion, and
43
+
44
+ * <span style="color: orange; font-weight: bold;">Inset maps</span>, including both detail and extent-style plots.
45
+
46
+ The three elements listed above are all intended to be high-resolution, easily modifiable, and context-aware relative to your specific plot.
47
+
48
+ This package also contains a single utility object:
49
+
50
+ * <span style='color: orange; font-weight: bold; font-family: var(--md-code-font-family);'>USA</span>, a class that helps filter for states and territories within the USA based on given characteristics, used primarily for building queries based on FIPS codes or names.
51
+
52
+ Together, these allow for the (relatively) easy creation of a map such as the following:
53
+
54
+ ![Map with all common elements added](docs/assets/index/bigmap_w_elements.png)
55
+
56
+ ---
57
+
58
+ ### 💾 Installation
59
+
60
+ This package is available on PyPi, and can be installed like so:
61
+
62
+ ```bash
63
+ pip install matplotlib-map-utils
64
+ # or
65
+ uv add matplotlib-map-utils
66
+ ```
67
+
68
+ The requirements for this package are:
69
+
70
+ * `python >= 3.10` (due to the use of the pipe operator to concatenate dictionaries and types)
71
+
72
+ * `matplotlib >= 3.9` (might work with lower versions but not guaranteed)
73
+
74
+ * `cartopy >= 0.23` (due to earlier bug with calling `copy()` on `CRS` objects)
75
+
76
+ ---
77
+
78
+ ### Quick Start and Usage Guides
79
+
80
+ For a primer on how to import the package and use the primary functions and methods to create elements, see the [Quick Start guide](https://moss_xyz.github.io/matplotlib_map_utils/quick).
81
+
82
+ Each part of the package also has a dedicated page that lays out usage and customisation options in more detail:
83
+
84
+ - 🧭 [__North Arrows__](https://moss_xyz.github.io/matplotlib_map_utils/north_arrows)
85
+ - 📏 [__Scale Bars__](https://moss_xyz.github.io/matplotlib_map_utils/scale_bars)
86
+ - 🗺️ [__Inset Maps__](https://moss_xyz.github.io/matplotlib_map_utils/inset_maps)
87
+ - 🛠️ [__Utilities__](https://moss_xyz.github.io/matplotlib_map_utils/utilities)
88
+
89
+ Finally, the [Package Information page](https://moss_xyz.github.io/matplotlib_map_utils/package) provides additional context around the development of and overall structure of the package.
90
+
91
+ ---
92
+
93
+ ### Support and Contributions
94
+
95
+ If you notice something is not working as intended or if you'd like to add a feature yourself, I welcome PRs - just be sure to be descriptive as to what you are changing and why, including code examples!
96
+
97
+ If you are having issues using this script, feel free to leave a post explaining your issue, and I will try and assist, though I have no guaranteed SLAs as this is just a hobby project.
98
+
99
+ I am open to contributions, especially to help tackle the roadmap above!
100
+
101
+ ---
102
+
103
+ ### ⚖️ License
104
+
105
+ I know nothing about licensing, so I went with the GPL license. If that is incompatible with any of the dependencies, please let me know.
@@ -2,11 +2,11 @@ matplotlib_map_utils/__init__.py,sha256=2mL2sZOjfxC--EthFMTMuYh1uvozz-9PzM4EDprD
2
2
  matplotlib_map_utils/core/__init__.py,sha256=mIn7x-LZlvNaYMcmjZXwnKNTirv3Vv2lAJodwRg_AdU,471
3
3
  matplotlib_map_utils/core/inset_map.py,sha256=iJISV0gZ3OmhO-DzC5z5kH5qL8fpdqmHn5OkdhdtzAY,41561
4
4
  matplotlib_map_utils/core/north_arrow.py,sha256=UDn0TBnLuhuONbibb_XT8C2HNSY6ONLCQgadR19WpmI,22846
5
- matplotlib_map_utils/core/scale_bar.py,sha256=kM9WMwdpKJuShl8BkzsRcFhc0y-Kxu8wJpriz8iVYzk,67064
5
+ matplotlib_map_utils/core/scale_bar.py,sha256=RPVFhQ1I5Z6fqc31JRdlUgcxxfoJQ9FKkRrK1fjgokQ,68993
6
6
  matplotlib_map_utils/defaults/__init__.py,sha256=_pegE5kv_sb0ansSF4XpWBRwboaP4zUjWY1KIGbK-TE,119
7
7
  matplotlib_map_utils/defaults/inset_map.py,sha256=RNwaZqWjDjdNwPgmqx_cN9lQQ6DW_Db61peaeMRCPlc,1569
8
8
  matplotlib_map_utils/defaults/north_arrow.py,sha256=uZb1RsUWxFTHywm8HATj_9iPF_GjCs_Z2HOn0JchjTY,8571
9
- matplotlib_map_utils/defaults/scale_bar.py,sha256=422U5hBtLpXrWZuj7vOnZNmIWI_KnOgDIwRX__m4GCY,8345
9
+ matplotlib_map_utils/defaults/scale_bar.py,sha256=H_4shk1AwJkEj9IXk7BRdEsT0aaGm6FHWr57bzU1PMA,8972
10
10
  matplotlib_map_utils/scratch/map_utils.py,sha256=j8dOX9uuotl9rRCAXapFLHycUwVE4nzIrqWYOGG2Lgg,19653
11
11
  matplotlib_map_utils/scratch/north_arrow_old_classes.py,sha256=1xKQ6yUghX4BWzIv8GsGBHDDPJ8B0Na7ixdw2jgtTqw,50993
12
12
  matplotlib_map_utils/utils/__init__.py,sha256=uUy0kUMMGrDpvo88J_OLk2dQI-UwCXclccaEyk8x5R0,41
@@ -16,9 +16,9 @@ matplotlib_map_utils/validation/__init__.py,sha256=0fL3N63jxjRwTU44b7-6ZYZJfOT_0
16
16
  matplotlib_map_utils/validation/functions.py,sha256=IIT9DiPKVv_ZHUTC8FwXJPt2pzdQI-8zhx6SHqto65E,13020
17
17
  matplotlib_map_utils/validation/inset_map.py,sha256=C5e_zOBKHqVNgufhwoIxu1OhlvXoaj70WxreW4BSfnA,6019
18
18
  matplotlib_map_utils/validation/north_arrow.py,sha256=6D-uLiMmre0E9JwjR0BTWNZJyCqPuL0b3HGZ91UHoXw,10442
19
- matplotlib_map_utils/validation/scale_bar.py,sha256=dYhiuqBV8wkMmFsR8p4RMbfBmN1DU--5cWU-Om9m7UY,18162
20
- matplotlib_map_utils-3.1.1.dist-info/licenses/LICENSE,sha256=aFLFZg6LEJFpTlNQ8su3__jw4GfV-xWBmC1cePkKZVw,35802
21
- matplotlib_map_utils-3.1.1.dist-info/METADATA,sha256=AZQKlt58icL88wIRhSJwyEdU6XhEDwcr-zpiwBBsoQQ,63423
22
- matplotlib_map_utils-3.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
- matplotlib_map_utils-3.1.1.dist-info/top_level.txt,sha256=6UyDpxsnMhSOd9a-abQe0lLJveybJyYtUHMdX7zXgKA,21
24
- matplotlib_map_utils-3.1.1.dist-info/RECORD,,
19
+ matplotlib_map_utils/validation/scale_bar.py,sha256=DAPTK1BHJXAQQE4Zii4a2Dt7boBtgy4f5dDp4NSUxog,19097
20
+ matplotlib_map_utils-4.0.0.dist-info/licenses/LICENSE,sha256=aFLFZg6LEJFpTlNQ8su3__jw4GfV-xWBmC1cePkKZVw,35802
21
+ matplotlib_map_utils-4.0.0.dist-info/METADATA,sha256=RpGTjxrbQvDY3_hB66nSt0PScxdE7zQ6cGK-P-2c2TA,4613
22
+ matplotlib_map_utils-4.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
23
+ matplotlib_map_utils-4.0.0.dist-info/top_level.txt,sha256=6UyDpxsnMhSOd9a-abQe0lLJveybJyYtUHMdX7zXgKA,21
24
+ matplotlib_map_utils-4.0.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (82.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5