Skip to content

Commit

Permalink
Merge pull request #198 from raphaelquast/dev
Browse files Browse the repository at this point in the history
merge for v7.3.2
  • Loading branch information
raphaelquast authored Dec 4, 2023
2 parents a982253 + d2f3e79 commit 7136149
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 91 deletions.
12 changes: 11 additions & 1 deletion eomaps/_data_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,12 @@ def _select_vals(self, val, qs, slices=None):
else:
val = np.asanyarray(val)

if len(val.shape) == 2 and qx is not None and qy is not None:
if (
len(val.shape) == 2
and qx is not None
and qy is not None
and slices is not None
):
(x0, x1, y0, y1) = slices
ret = val[y0:y1, x0:x1]
else:
Expand Down Expand Up @@ -895,6 +900,11 @@ def get_props(self, *args, **kwargs):
else:
slices, blocksize = None, None

# remember last selection and slices (required in case explicit
# colors are provided since they must be selected accordingly)
self._last_qs = qs
self._last_slices = slices

self._current_data = dict(
xorig=self._select_vals(self.xorig, qs, slices),
yorig=self._select_vals(self.yorig, qs, slices),
Expand Down
2 changes: 1 addition & 1 deletion eomaps/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "7.3.1"
__version__ = "7.3.2"
21 changes: 12 additions & 9 deletions eomaps/_webmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,12 +584,15 @@ def _do_add_layer(self, m, layer, **kwargs):


class _WebServiceCollection:
def __init__(self, m, service_type="wmts", url=None):
def __init__(self, m, service_type="wmts", url=None, **kwargs):
self._m = m
self._service_type = service_type
if url is not None:
self._url = url

# additional kwargs that will be passed to owslib.WebMapService()
self._service_kwargs = kwargs.copy()

def __getitem__(self, key):
return self.add_layer.__dict__[key]

Expand Down Expand Up @@ -626,28 +629,28 @@ def findlayer(self, name):
return [i for i in self.layers if name.lower() in i.lower()]

@staticmethod
def _get_wmts(url):
def _get_wmts(url, **kwargs):
# TODO expose useragent

# lazy import used to avoid long import times
from owslib.wmts import WebMapTileService

return WebMapTileService(url)
return WebMapTileService(url, **kwargs)

@staticmethod
def _get_wms(url):
def _get_wms(url, **kwargs):
# TODO expose useragent

# lazy import used to avoid long import times
from owslib.wms import WebMapService

return WebMapService(url)
return WebMapService(url, **kwargs)

@property
@lru_cache()
def add_layer(self):
if self._service_type == "wmts":
wmts = self._get_wmts(self._url)
wmts = self._get_wmts(self._url, **self._service_kwargs)
layers = dict()
for key in wmts.contents.keys():
layername = _sanitize(key)
Expand All @@ -665,7 +668,7 @@ def add_layer(self):
layers[layername] = wmtslayer

elif self._service_type == "wms":
wms = self._get_wms(self._url)
wms = self._get_wms(self._url, **self._service_kwargs)
layers = dict()
for key in wms.contents.keys():
layername = _sanitize(key)
Expand Down Expand Up @@ -821,14 +824,14 @@ def _fetch_layers(self):
url = self._url
if url is not None:
if self._service_type == "wms":
wms = self._get_wms(url)
wms = self._get_wms(url, **self._service_kwargs)
layer_names = list(wms.contents.keys())
for lname in layer_names:
self._layers["layer_" + _sanitize(lname)] = _WMSLayer(
self._m, wms, lname
)
elif self._service_type == "wmts":
wmts = self._get_wmts(url)
wmts = self._get_wmts(url, **self._service_kwargs)
layer_names = list(wmts.contents.keys())
for lname in layer_names:
self._layers["layer_" + _sanitize(lname)] = _WMTSLayer(
Expand Down
81 changes: 38 additions & 43 deletions eomaps/eomaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,8 @@ def _handle_backends():

active_backend = plt.get_backend()

if active_backend in ["module://matplotlib_inline.backend_inline"]:
plt.ioff()

if not Maps._backend_warning_shown and not BlitManager._snapshot_on_update:
_log.info(
"EOmaps disables matplotlib's interactive mode (e.g. 'plt.ioff()') "
f"for the backend {plt.get_backend()}.\n"
"Call `m.snapshot()` to print a static snapshot of the map "
"to a Jupyter Notebook cell (or an IPython console)!"
)

Maps._backend_warning_shown = True

# to avoid flickering in the layout editor in jupyter notebooks
elif active_backend in ["module://ipympl.backend_nbagg"]:
if active_backend in ["module://ipympl.backend_nbagg"]:
plt.ioff()
else:
if Maps._use_interactive_mode is True:
Expand Down Expand Up @@ -3390,19 +3377,18 @@ def show(self, clear=True):
show_layer : Set the currently visible layer.
"""

if not plt.isinteractive():
try:
__IPYTHON__
except NameError:
plt.show()
try:
__IPYTHON__
except NameError:
plt.show()
else:
active_backend = plt.get_backend()
# print a snapshot to the active ipython cell in case the
# inline-backend is used
if active_backend in ["module://matplotlib_inline.backend_inline"]:
self.BM.update(clear_snapshot=clear)
else:
active_backend = plt.get_backend()
# print a snapshot to the active ipython cell in case the
# inline-backend is used
if active_backend in ["module://matplotlib_inline.backend_inline"]:
self.BM.update(clear_snapshot=clear)
else:
plt.show()
plt.show()

def snapshot(self, *layer, transparent=False, clear=False):
"""
Expand Down Expand Up @@ -3476,9 +3462,13 @@ def snapshot(self, *layer, transparent=False, clear=False):
else:
sn = self._get_snapshot()
try:
from IPython.display import display
from IPython.display import display_png, clear_output

if clear:
clear_output(wait=True)
# use display_png to avoid issues with transparent snapshots
display_png(Image.fromarray(sn, "RGBA"), raw=False)

display(Image.fromarray(sn, "RGBA"), display_id=True, clear=clear)
except Exception:
_log.exception(
"Unable to display the snapshot... is the script "
Expand Down Expand Up @@ -4090,6 +4080,8 @@ def _init_figure(self, ax=None, plot_crs=None, **kwargs):
_handle_backends()

self._f = plt.figure(**kwargs)
# to hide canvas header in jupyter notebooks (default figure label)
self._f.canvas.header_visible = False

# override Figure.savefig with Maps.savefig but keep original
# method accessible via Figure._mpl_orig_savefig
Expand Down Expand Up @@ -4215,16 +4207,17 @@ def _init_figure(self, ax=None, plot_crs=None, **kwargs):
if self.parent._layout_editor is None:
self.parent._layout_editor = LayoutEditor(self.parent, modifier="alt+l")

if newfig:
# we only need to call show if a new figure has been created!
if (
# plt.isinteractive() or
plt.get_backend()
== "module://ipympl.backend_nbagg"
):
# make sure to call show only if we use an interactive backend...
# or within the ipympl backend (otherwise it will block subsequent code!)
plt.show()
active_backend = plt.get_backend()
# we only need to call show if a new figure has been created!
if newfig and active_backend == "module://ipympl.backend_nbagg":
# make sure to call show only if we use an interactive backend...
# or within the ipympl backend (otherwise it will block subsequent code!)
plt.show()

if active_backend == "module://matplotlib_inline.backend_inline":
# close the figure to avoid duplicated (empty) plots created
# by the inline-backend manager in jupyter notebooks
plt.close(self.f)

def _get_ax_label(self):
return "map"
Expand Down Expand Up @@ -4567,7 +4560,7 @@ def _classify_data(
bins = [vmin, *bins]

if vmax > max(bins):
bins[np.argmax(bins)] = vmax
bins = [*bins, vmax]

cbcmap = cmap
norm = mpl.colors.BoundaryNorm(bins, cmap.N)
Expand Down Expand Up @@ -4826,7 +4819,9 @@ def _plot_map(

def _sel_c_transp(self, c):
return self._data_manager._select_vals(
c.T if self._data_manager._z_transposed else c
c.T if self._data_manager._z_transposed else c,
qs=self._data_manager._last_qs,
slices=self._data_manager._last_slices,
)

def _handle_explicit_colors(self, color):
Expand Down Expand Up @@ -5645,11 +5640,8 @@ def set_frame(self, rounded=0, **kwargs):
>>> path_effects=[pe.withStroke(linewidth=7, foreground="m")])
"""
self.redraw("__SPINES__")

for key in ("fc", "facecolor"):
self.redraw("__BG__")

if key in kwargs:
self.ax.patch.set_facecolor(kwargs.pop(key))

Expand Down Expand Up @@ -5712,3 +5704,6 @@ def cb(*args, **kwargs):

self.BM._before_fetch_bg_actions.append(cb)
self.ax._EOmaps_rounded_spine_attached = True

self.redraw("__SPINES__")
self.redraw("__BG__")
67 changes: 39 additions & 28 deletions eomaps/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,13 @@ def modifier_pressed(self, val):
self._modifier_pressed = val
self.m.cb.execute_callbacks(not val)

if self._modifier_pressed:
self.m.BM._disable_draw = True
self.m.BM._disable_update = True
else:
self.m.BM._disable_draw = False
self.m.BM._disable_update = False

@property
def ms(self):
return [self.m.parent, *self.m.parent._children]
Expand Down Expand Up @@ -1493,7 +1500,7 @@ def apply_layout(self, layout):
# check if all relevant axes are specified in the layout
valid_keys = set(self.get_layout())
if valid_keys != set(layout):
warnings.warn(
_log.warning(
"EOmaps: The the layout does not match the expected structure! "
"Layout might not be properly restored. "
"Invalid or missing keys:\n"
Expand Down Expand Up @@ -1549,6 +1556,9 @@ def __init__(self, m):
List of the artists to manage
"""
self._disable_draw = False
self._disable_update = False

self._m = m

self._artists = dict()
Expand Down Expand Up @@ -2109,12 +2119,11 @@ def _do_fetch_bg(self, layer, bbox=None):
return

if renderer:
if not self._m.parent._layout_editor._modifier_pressed:
for art in allartists:
if art not in self._hidden_artists:
art.draw(renderer)
art.stale = False
self._bg_layers[layer] = renderer.copy_from_bbox(bbox)
for art in allartists:
if art not in self._hidden_artists:
art.draw(renderer)
art.stale = False
self._bg_layers[layer] = renderer.copy_from_bbox(bbox)

def fetch_bg(self, layer=None, bbox=None):
"""
Expand All @@ -2132,8 +2141,6 @@ def fetch_bg(self, layer=None, bbox=None):
The default is None.
"""
if self._m.parent._layout_editor._modifier_pressed:
return

if layer is None:
layer = self.bg_layer
Expand Down Expand Up @@ -2161,28 +2168,31 @@ def _disconnect_draw(self):

def on_draw(self, event):
"""Callback to register with 'draw_event'."""

if self._disable_draw:
return

cv = self.canvas
_log.log(5, "draw")
loglevel = _log.getEffectiveLevel()

try:
if (
"RendererBase._draw_disabled"
in cv.get_renderer().draw_image.__qualname__
):
# TODO this fixes issues when saving figues with a "tight" bbox, e.g.:
# m.savefig(bbox_inches='tight', pad_inches=0.1)

# This workaround is necessary but the implementation is suboptimal since
# it relies on the __qualname__ to identify if the
# `matplotlib.backend_bases.RendererBase._draw_disabled()` context is active
# The reason why the "_draw_disabled" context has to be handled explicitly
# is because otherwise empty backgrounds would be fetched (and cached) by
# the draw-event and the export would result in an empty figure.
if hasattr(cv, "get_renderer") and not cv.is_saving():

renderer = cv.get_renderer()
if renderer is None:
# don't run on_draw if no renderer is available
return
except AttributeError:
# return on AttributeError to handle backends that don't expose the renderer
else:
# don't run on_draw if no renderer is available
# (this is true for svg export where mpl export routines
# are used to avoid issues)
if loglevel <= 5:
_log.log(5, " not drawing")

return

if loglevel <= 5:
_log.log(5, "draw")

if event is not None:
if event.canvas != cv:
raise RuntimeError
Expand Down Expand Up @@ -2226,7 +2236,8 @@ def on_draw(self, event):

except Exception:
# we need to catch exceptions since QT does not like them...
pass
if loglevel <= 5:
_log.log(5, "There was an error during draw!", exc_info=True)

def add_artist(self, art, layer=None):
"""
Expand Down Expand Up @@ -2657,7 +2668,7 @@ def update(
If True, clear the active cell before plotting a snapshot of the figure.
The default is True.
"""
if self._m.parent._layout_editor._modifier_pressed:
if self._disable_update:
# don't update during layout-editing
return

Expand Down
Loading

0 comments on commit 7136149

Please sign in to comment.