Skip to content

Commit deb508a

Browse files
authored
Merge pull request #267 from raphaelquast/dev
Merge for v8.4
2 parents 4789ab5 + ce93690 commit deb508a

36 files changed

Lines changed: 747 additions & 444 deletions

.github/workflows/testMaps.yml

100644100755
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
# set operating systems to test
1414
os: [ubuntu-latest]
1515
# set python versions to test
16-
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
16+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
1717

1818
name: test_Maps ${{ matrix.os }} ${{ matrix.python-version }}
1919
steps:
302 KB
Loading
1.81 MB
Loading

docs/source/_static/version_switcher.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
"version": "dev",
99
"url": "https://eomaps.readthedocs.io/en/dev/"
1010
},
11+
{
12+
"version": "v8.4",
13+
"url": "https://eomaps.readthedocs.io/en/v8.4/"
14+
},
1115
{
1216
"version": "v8.3.3",
1317
"url": "https://eomaps.readthedocs.io/en/v8.3.3/"

docs/source/api/eomaps.eomaps.Maps.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Layers and Maps
4646

4747
Maps.new_map
4848
Maps.new_inset_map
49+
Maps.new_subplot
4950

5051

5152
.. autosummary::

docs/source/installation.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ In addition, you can use the following dependency-groups to activate only select
7272
- ``pip install eomaps[io]`` Add support for ``pandas``, ``xarray``, ``geopandas`` and ``rioxarray``
7373
- ``pip install eomaps[shade]`` Add capabilities to visualize extremely large datasets (via ``datashader``)
7474
- ``pip install eomaps[classify]`` Add support for ``mapclassify`` to classify datasets
75+
- ``pip install eomaps[docs]`` Install all required dependencies to build the docs
7576

7677
It is also possible to combine dependency-groups, e.g.: ``pip install eomaps[wms, gui]``.
7778

eomaps/_blit_manager.py

100644100755
Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ def cb(*args, **kwargs):
510510
if _log.getEffectiveLevel() <= 10:
511511
logmsg = (
512512
f"Adding {'persistent' if persistent else 'single-shot'} "
513-
f"layer change action for: '{layer}'"
513+
f"layer change action for: '{layer if layer else 'all layers'}': {getattr(func, '__qualname__', func)}"
514514
)
515515
_log.debug(logmsg)
516516

@@ -903,14 +903,14 @@ def _on_draw_cb(self, event):
903903
if loglevel <= 5:
904904
_log.log(5, "There was an error during draw!", exc_info=True)
905905

906-
def add_artist(self, art, layer=None):
906+
def add_artist(self, *artists, layer=None):
907907
"""
908908
Add a dynamic-artist to be managed.
909909
(Dynamic artists are re-drawn on every update!)
910910
911911
Parameters
912912
----------
913-
art : Artist
913+
artists : Artist
914914
915915
The artist to be added. Will be set to 'animated' (just
916916
to be safe). *art* must be in the figure associated with
@@ -922,38 +922,38 @@ def add_artist(self, art, layer=None):
922922
923923
The default is None in which case the layer of the base-Maps object is used.
924924
"""
925-
926-
if art.figure != self.figure:
927-
raise RuntimeError(
928-
"EOmaps: The artist does not belong to the figure"
929-
"of this Maps-object!"
930-
)
931-
932925
if layer is None:
933926
layer = self._m.layer
934927

935928
# make sure all layers are converted to string
936929
layer = str(layer)
937930

938-
self._artists.setdefault(layer, list())
931+
for art in artists:
932+
if art.figure != self.figure:
933+
raise RuntimeError(
934+
"EOmaps: The artist does not belong to the figure"
935+
"of this Maps-object!"
936+
)
939937

940-
if art in self._artists[layer]:
941-
return
942-
else:
943-
art.set_animated(True)
944-
self._artists[layer].append(art)
938+
self._artists.setdefault(layer, list())
945939

946-
if isinstance(art, plt.Axes):
947-
self._managed_axes.add(art)
940+
if art in self._artists[layer]:
941+
continue
942+
else:
943+
art.set_animated(True)
944+
self._artists[layer].append(art)
948945

949-
def add_bg_artist(self, art, layer=None, draw=True):
946+
if isinstance(art, plt.Axes):
947+
self._managed_axes.add(art)
948+
949+
def add_bg_artist(self, *artists, layer=None, draw=True):
950950
"""
951951
Add a background-artist to be managed.
952952
(Background artists are only updated on zoom-events... they are NOT animated!)
953953
954954
Parameters
955955
----------
956-
art : Artist
956+
artists : Artist
957957
The artist to be added. Will be set to 'animated' (just
958958
to be safe). *art* must be in the figure associated with
959959
the canvas this class is managing.
@@ -974,31 +974,32 @@ def add_bg_artist(self, art, layer=None, draw=True):
974974
# make sure all layer names are converted to string
975975
layer = str(layer)
976976

977-
if art.figure != self.figure:
978-
raise RuntimeError
977+
for art in artists:
978+
if art.figure != self.figure:
979+
raise RuntimeError
979980

980-
# put all artist of inset-maps on dedicated layers
981-
if (
982-
getattr(art, "axes", None) is not None
983-
and art.axes.get_label() == "inset_map"
984-
and not layer.startswith("__inset_")
985-
):
986-
layer = "__inset_" + str(layer)
981+
# put all artist of inset-maps on dedicated layers
982+
if (
983+
getattr(art, "axes", None) is not None
984+
and art.axes.get_label() == "inset_map"
985+
and not layer.startswith("__inset_")
986+
):
987+
layer = "__inset_" + str(layer)
987988

988-
if layer in self._bg_artists and art in self._bg_artists[layer]:
989-
_log.info(
990-
f"EOmaps: Background-artist '{art}' already added on layer '{layer}'"
991-
)
992-
return
989+
if layer in self._bg_artists and art in self._bg_artists[layer]:
990+
_log.info(
991+
f"EOmaps: Background-artist '{art}' already added on layer '{layer}'"
992+
)
993+
continue
993994

994-
art.set_animated(True)
995-
self._bg_artists.setdefault(layer, []).append(art)
995+
art.set_animated(True)
996+
self._bg_artists.setdefault(layer, []).append(art)
996997

997-
if isinstance(art, plt.Axes):
998-
self._managed_axes.add(art)
998+
if isinstance(art, plt.Axes):
999+
self._managed_axes.add(art)
9991000

1000-
# tag all relevant layers for refetch
1001-
self._refetch_layer(layer)
1001+
# tag all relevant layers for refetch
1002+
self._refetch_layer(layer)
10021003

10031004
for f in self._on_add_bg_artist:
10041005
f()

eomaps/_data_manager.py

100644100755
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -916,9 +916,9 @@ def on_fetch_bg(self, layer=None, bbox=None, check_redraw=True):
916916
self.m.ax.add_collection(coll, autolim=False)
917917

918918
if self.m._coll_dynamic:
919-
self.m.BM.add_artist(coll, self.layer)
919+
self.m.BM.add_artist(coll, layer=self.layer)
920920
else:
921-
self.m.BM.add_bg_artist(coll, self.layer)
921+
self.m.BM.add_bg_artist(coll, layer=self.layer)
922922

923923
self.m._coll = coll
924924

eomaps/_maps_base.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -990,7 +990,15 @@ def edit_layout(self, filepath=None):
990990
@wraps(GridSpec.update)
991991
def subplots_adjust(self, **kwargs):
992992
"""Adjust the margins of subplots."""
993-
self.parent._gridspec.update(**kwargs)
993+
with self.delay_draw():
994+
for m in (self.parent, *self.parent._children):
995+
try:
996+
m.ax.get_gridspec().update(**kwargs)
997+
except AttributeError:
998+
# TODO fix this properly
999+
# ignore gridspecs that don't provide an update method
1000+
# (like GridSpecFromSubplotSpec)
1001+
pass
9941002
# after changing margins etc. a redraw is required
9951003
# to fetch the updated background!
9961004

@@ -1220,6 +1228,38 @@ def _transf_lonlat_to_plot(self):
12201228
self.crs_plot,
12211229
)
12221230

1231+
def transform_plot_to_lonlat(self, x, y):
1232+
"""
1233+
Transform plot-coordinates to longitude and latitude values.
1234+
1235+
Parameters
1236+
----------
1237+
x, y : float or array-like
1238+
The coordinates values in the coordinate-system of the plot.
1239+
1240+
Returns
1241+
-------
1242+
lon, lat : The coordinates transformed to longitude and latitude values.
1243+
1244+
"""
1245+
return self._transf_plot_to_lonlat.transform(x, y)
1246+
1247+
def transform_lonlat_to_plot(self, lon, lat):
1248+
"""
1249+
Transform longitude and latitude values to plot coordinates.
1250+
1251+
Parameters
1252+
----------
1253+
lon, lat : float or array-like
1254+
The longitude and latitude values to transform.
1255+
1256+
Returns
1257+
-------
1258+
x, y : The coordinates transformed to the plot-coordinate system.
1259+
1260+
"""
1261+
return self._transf_lonlat_to_plot.transform(lon, lat)
1262+
12231263
def on_layer_activation(self, func, layer=None, persistent=False, **kwargs):
12241264
"""
12251265
Attach a callback that is executed if the associated layer is activated.

eomaps/_webmap.py

100644100755
Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from urllib3.exceptions import InsecureRequestWarning
1414
from io import BytesIO
1515
from pprint import PrettyPrinter
16+
from textwrap import dedent
1617

1718
from packaging import version
1819

@@ -171,7 +172,7 @@ def add_legend(self, style=None, img=None):
171172
if not self._m.BM._layer_visible(self._layer):
172173
legax.set_visible(False)
173174

174-
self._m.BM.add_artist(legax, self._layer)
175+
self._m.BM.add_artist(legax, layer=self._layer)
175176

176177
def cb_move(event):
177178
if not self._legend_picked:
@@ -336,6 +337,17 @@ def _set_style(self, style=None):
336337

337338
return style
338339

340+
def _get_layer_info_text(self):
341+
"""Get layer-specific info text of a given layer"""
342+
t = ""
343+
abstract = getattr(self.wms_layer, "abstract", None)
344+
if abstract:
345+
t += f"**Abstract**: <i>{abstract}</i>\n \n---- \n "
346+
347+
t += f"{dedent(getattr(self, '_EOmaps_info', ''))}"
348+
349+
return t
350+
339351

340352
class _WMTSLayer(_WebMapLayer):
341353
def __init__(self, *args, **kwargs):
@@ -440,7 +452,7 @@ def _do_add_layer(self, m, layer, **kwargs):
440452

441453
# attach the info to the artist so it can be identified by the companion widget
442454
if hasattr(self, "_EOmaps_info"):
443-
art._EOmaps_info = self._EOmaps_info
455+
art._EOmaps_info = self._get_layer_info_text()
444456
if hasattr(self, "_EOmaps_source_code"):
445457
art._EOmaps_source_code = self._EOmaps_source_code
446458

@@ -581,12 +593,10 @@ def _do_add_layer(self, m, layer, **kwargs):
581593
art = self._add_wms(
582594
m.ax, self._wms, self.name, interpolation="spline36", **kwargs
583595
)
584-
585596
art.set_label(f"WebMap service: {self.name}")
586-
587597
# attach the info to the artist so it can be identified by the companion widget
588598
if hasattr(self, "_EOmaps_info"):
589-
art._EOmaps_info = self._EOmaps_info
599+
art._EOmaps_info = self._get_layer_info_text()
590600
if hasattr(self, "_EOmaps_source_code"):
591601
art._EOmaps_source_code = self._EOmaps_source_code
592602

@@ -1396,7 +1406,7 @@ def draw(self, renderer, *args, **kwargs):
13961406
# only re-fetch tiles if the extent has changed
13971407
located_images = self.raster_source.fetch_raster(
13981408
ax.projection,
1399-
extent=[x1, x2, y1, y2],
1409+
extent=list(map(float, [x1, x2, y1, y2])),
14001410
target_resolution=(window_extent.width, window_extent.height),
14011411
)
14021412
self.cache = located_images
@@ -1410,6 +1420,12 @@ def draw(self, renderer, *args, **kwargs):
14101420
# (otherwise the path might still correspond to a previous extent)
14111421
clippath._adjust_location()
14121422

1423+
if clippath.get_path().vertices.size == 0:
1424+
# in case the clip-path is an empty-path don't draw.
1425+
# This is used to allow clipped-webmaps outside the
1426+
# current field-of-view
1427+
return
1428+
14131429
self.set_clip_path(
14141430
clippath.get_path(),
14151431
transform=self.axes.projection._as_mpl_transform(self.axes),

0 commit comments

Comments
 (0)