Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
180 commits
Select commit Hold shift + click to select a range
79da780
major refactor of the Maps class into mixin classes
raphaelquast Feb 5, 2026
0312df0
avoid usage of deprecated Maps.set_classify_specs and Maps.CLASSIFIERS
raphaelquast Feb 5, 2026
e83ec92
fix typo
raphaelquast Feb 5, 2026
d8f9b10
add final button release event to test to avoid blocking
raphaelquast Feb 5, 2026
8f95654
make sure numpy numbers are properly recognized
raphaelquast Feb 5, 2026
b1fb538
fix typo
raphaelquast Feb 5, 2026
cbaadfb
fix broadcasting for draw-circle callbacks
raphaelquast Feb 5, 2026
e157749
minor
raphaelquast Feb 5, 2026
4b1a51e
rename add_features.py to add_mixin.py
raphaelquast Feb 5, 2026
349baff
minor
raphaelquast Feb 5, 2026
f4ce68b
add refetch_wms_on_size_change and the associated cx to WebMapContainer
raphaelquast Feb 5, 2026
0dd388f
fix new method for getting clipboard-kwargs
raphaelquast Feb 5, 2026
76dbee8
make sure shared callback events trigger each map only once
raphaelquast Feb 5, 2026
bee6344
allow specifying a list of buffer-factors for the mark-callback
raphaelquast Feb 5, 2026
19cc5c0
use layer=None as default kwarg for Maps
raphaelquast Feb 5, 2026
946e494
introduce new MapsGrid definition based on MultiCaller class
raphaelquast Feb 5, 2026
c860a18
update MapsGrid tests
raphaelquast Feb 5, 2026
eff1902
fix import
raphaelquast Feb 5, 2026
710ec54
make _proxy a helper funktion
raphaelquast Feb 5, 2026
c16af23
more refactoring (CallbackMixin and DataMixin)
raphaelquast Feb 5, 2026
54a315b
move related properties to AddMixin
raphaelquast Feb 5, 2026
ad3c9fa
add mixin modules
raphaelquast Feb 5, 2026
b01e71e
make codespell happy
raphaelquast Feb 6, 2026
68be39f
maintain execution oder of submitted permanent layer-activation callb…
raphaelquast Feb 6, 2026
21ac0a1
execute on-layer callback immediately if the layer is currently visible
raphaelquast Feb 6, 2026
dd29ae0
move set_frame method to the Maps class
raphaelquast Feb 6, 2026
e91a604
minor
raphaelquast Feb 6, 2026
58f3a3a
add missing import
raphaelquast Feb 6, 2026
af84078
introduce LazyCaller and LazyLayerNamespace
raphaelquast Feb 6, 2026
90e329a
fix MapsGrid Maps must assign parent properly
raphaelquast Feb 6, 2026
1b5fec7
remove python 3.9 (EOL) and add 3.14 to unittests
raphaelquast Feb 6, 2026
02ed5ba
make sure mixins folder is properly packaged
raphaelquast Feb 6, 2026
f6a90a6
remove usages of set_classify_specs
raphaelquast Feb 6, 2026
8a13920
make sure all maps-objects get to the same _edit_annotations property
raphaelquast Feb 6, 2026
11615ef
minor
raphaelquast Feb 6, 2026
c1ff1ea
minor
raphaelquast Feb 6, 2026
c440aae
collections are automatically over-written, no need to make them temp…
raphaelquast Feb 13, 2026
25d4d80
switch to new "add_text" method
raphaelquast Feb 13, 2026
97af464
remove duplicated endpoint when calculating geod-circle vertices
raphaelquast Feb 13, 2026
3b30d41
update tools mixin
raphaelquast Feb 14, 2026
3e2d426
move weakref.proxy call to CallbackContainer class
raphaelquast Feb 13, 2026
c9eda02
add explicit "force_data_redraw" parameter to Maps.redraw
raphaelquast Feb 13, 2026
72046c1
let each Maps-object handle its own artists and bg_artists
raphaelquast Feb 14, 2026
0ad8d5d
fix mapsgrid init must set proper parent
raphaelquast Feb 14, 2026
604a719
minor fix for docs
raphaelquast Feb 14, 2026
a161fab
introduce new Hooks class for better control over attached "hooks"
raphaelquast Feb 14, 2026
335c5a2
minor
raphaelquast Feb 14, 2026
f15a2ba
fix typos
raphaelquast Feb 14, 2026
2808572
fix definition of util accessor
raphaelquast Feb 14, 2026
c8d94a2
update hook-implementation and add "layer_activation" hooks
raphaelquast Feb 16, 2026
b012d66
minor (removal of not needed imports and calls
raphaelquast Feb 16, 2026
e4c93d4
hide private layer-names from LayerNamespace auto-completion
raphaelquast Feb 16, 2026
45c9932
make sure logos are plotted on **SPINES** layer by default
raphaelquast Feb 16, 2026
4673ee6
add workaround for resampling issue with transparent logo-parts
raphaelquast Feb 16, 2026
9556355
add new example on how to use "agg filters"
raphaelquast Feb 16, 2026
8e5ac3f
make pre-commit happy
raphaelquast Feb 16, 2026
96711a8
minor
raphaelquast Feb 16, 2026
dd5865d
improve performance of scalebars
raphaelquast Feb 16, 2026
3d94cba
don't inherit the shape for new layers by default
raphaelquast Feb 16, 2026
342b228
minor
raphaelquast Feb 16, 2026
fe20b4b
update example
raphaelquast Feb 16, 2026
f110000
make sure redraw kwargs are properly forwarded
raphaelquast Feb 16, 2026
a4f7526
minor
raphaelquast Feb 16, 2026
0be34a5
remove gdal based clipping and _invert clipping for geo-dataframes
raphaelquast Feb 16, 2026
53b821f
fix clipping extent for reprojected crs
raphaelquast Feb 16, 2026
2543cb9
add (very) basic test to run through clipping methods at least once
raphaelquast Feb 16, 2026
e528eb2
make pre-commit happy
raphaelquast Feb 16, 2026
83d287c
make sure companion widget key is properly forwarded to widget event
raphaelquast Feb 17, 2026
4b396fb
add basic unittest for companion widget
raphaelquast Feb 17, 2026
7c6e469
update test dependencies
raphaelquast Feb 17, 2026
a19bceb
make pre-commit happy
raphaelquast Feb 17, 2026
ef2dbc8
fix Qt properties should be accessed via the classes not instances
raphaelquast Feb 17, 2026
b53bf1a
make sure existing app is properly re-used if it is already running
raphaelquast Feb 17, 2026
babc6f1
make pre-commit happy
raphaelquast Feb 17, 2026
5091243
fix test dependencies
raphaelquast Feb 17, 2026
aa436cb
add _get_hooks method to Hooks class
raphaelquast Feb 17, 2026
48a3f67
use Hooks._get_hooks in companion widget to identify pending actions
raphaelquast Feb 17, 2026
0937ef2
fix typos for PyQt events
raphaelquast Feb 17, 2026
ec6f737
minor
raphaelquast Feb 17, 2026
04e71ab
make sure hook-actions accept kwargs
raphaelquast Feb 17, 2026
6f1c7fc
fix hooks for companion widget
raphaelquast Feb 17, 2026
02c7bbd
require pyside <6.9 in environment.yml (used for testing)
raphaelquast Feb 17, 2026
af26fda
perform unittests on PyQt5 for now
raphaelquast Feb 17, 2026
dbdac63
add missing pytest-qt dependency for tests and test on arbitrary pyqt
raphaelquast Feb 17, 2026
d92b3ef
don't instantiate QApplication on import
raphaelquast Feb 17, 2026
3cbfa71
remove companion tests for now - they create segfaults!
raphaelquast Feb 17, 2026
c64f1ac
use pytest-xdist also in github actions to speed up tests
raphaelquast Feb 17, 2026
6f5a682
fix workflow pytest-xdist call
raphaelquast Feb 17, 2026
c6370fa
fix typo
raphaelquast Feb 17, 2026
4559e87
remove quick-chckeck if first value of array is truthful
raphaelquast Feb 17, 2026
9a05bcd
remove _clear_all_temp_artists implementation (tbd for v9)
raphaelquast Feb 17, 2026
896cc28
make the BlitManager a private property (m.BM -> m._bm)
raphaelquast Feb 17, 2026
44202a3
update examples
raphaelquast Feb 17, 2026
ecb20fe
remove m.data property
raphaelquast Feb 17, 2026
b8c00ea
minor
raphaelquast Feb 18, 2026
d5e097d
make sure using m.add_title updates the title rather than re-creating it
raphaelquast Feb 19, 2026
7c6f299
make sure webmap layers are created even if webmaps are added lazily
raphaelquast Feb 19, 2026
e643019
add explicit LazyMaps and MultiMaps classes
raphaelquast Feb 19, 2026
79dfbc2
avoid setting the extent on plot if a lazy layer is fetched
raphaelquast Feb 19, 2026
8c02e10
remove __setitem__ for ChildAccessor
raphaelquast Feb 20, 2026
77a55c4
remove obsolete _children property on Maps objects
raphaelquast Feb 20, 2026
a5185fd
minor
raphaelquast Feb 21, 2026
0757a0d
add explicit "name" property to maps objects
raphaelquast Feb 22, 2026
47f29cb
make m.new_layer return a LazyMaps object if the layer is not visible
raphaelquast Feb 22, 2026
222be1e
remove obsolete lazy wms layer functionalities
raphaelquast Feb 22, 2026
b1515fb
remove obsolete layer specifications for companion widget wms features
raphaelquast Feb 22, 2026
8e715c3
make sure removing a layer from the namespace does not re-create it
raphaelquast Feb 23, 2026
b79de06
avoid costly initialization of ne-features class
raphaelquast Feb 24, 2026
dc2940d
initialize drawer only on attribute-access (to avoid costly initializ…
raphaelquast Feb 24, 2026
9fc3e03
fix getitem for LayerNamespace if non-string values are passed
raphaelquast Feb 24, 2026
1694fad
remove deprecated kwargs for m.copy
raphaelquast Feb 24, 2026
e543bbc
move LayerNamespace property to MapsLayerBase
raphaelquast Feb 24, 2026
0b042de
call add/remove artist hooks only on public methods
raphaelquast Feb 24, 2026
b64a3d5
minor
raphaelquast Feb 25, 2026
59f9bd7
minor - add type-hints for LayerNamespace
raphaelquast Feb 25, 2026
86ff5f0
remove LazyCaller and LazyMaps in favor of using an explicit decorator
raphaelquast Feb 25, 2026
aa1d20c
remove lazy attrs
raphaelquast Feb 25, 2026
25e74e3
pass return values through m.on_layer_activation if method is evaluated
raphaelquast Feb 25, 2026
e68c500
remove lazy attrs property
raphaelquast Feb 25, 2026
239f171
add _submit_on_activation decorator to relevant methods
raphaelquast Feb 25, 2026
3d200f6
minor - update code shown in companion-widget for webmaps
raphaelquast Feb 25, 2026
9f2a7c4
make sure the layer is shown before indicating contours
raphaelquast Feb 25, 2026
263e226
avoid dtype conversion for shade_points if masked arrays are used
raphaelquast Feb 25, 2026
dd4aa32
remove typo
raphaelquast Feb 25, 2026
d0054a6
remove unnecessarily passed cb_cls attribute
raphaelquast Feb 25, 2026
df7ed92
add _get_gdf_path_boundary intermediate method
raphaelquast Mar 5, 2026
e8e49b4
get rid of irrelevant pyproj.geod warnings about returning back_azimuth
raphaelquast Mar 5, 2026
0d84cb2
add "dynamic" kwarg to m.add_line
raphaelquast Mar 5, 2026
1e80206
add inherit_data/shape/classification kwargs to m.new_inset_map
raphaelquast Mar 5, 2026
01a2b1e
make sure multicaller properly handles subclass __getattribute__
raphaelquast Mar 5, 2026
b0856af
make sure layer-callbacks are immediately executed on the "all" layer
raphaelquast Mar 5, 2026
0c43cd0
add _from_parent helper decorator
raphaelquast Mar 5, 2026
9a99384
update readthedocs.yml to use latest versions
raphaelquast Apr 19, 2026
c713e4a
allow setting default "lazyness" of method
raphaelquast Apr 19, 2026
52377a2
move "execute_callbacks" property to CallbackMixin
raphaelquast Apr 19, 2026
b6f4c83
ensure lon/lat are at least 1D arrays for geod_circles
raphaelquast Apr 19, 2026
80c57ec
implement fix for not yet fetched images
raphaelquast Apr 19, 2026
e76203e
add WeakOrderedCollection to ensure insert-order on weakrefs
raphaelquast Apr 19, 2026
876c96b
remove cb_container and callbacks modules in favor of callback_contai…
raphaelquast Apr 19, 2026
7dc6df9
minor
raphaelquast Apr 19, 2026
e3ee77f
set default lazyness for methods
raphaelquast Apr 19, 2026
97e54a3
minor fix typo
raphaelquast Apr 19, 2026
a82c03d
draw "all" layer artists below explicit layer artists
raphaelquast Apr 19, 2026
3110f57
update example
raphaelquast Apr 19, 2026
4ad85a0
update examples
raphaelquast Apr 19, 2026
4e405ec
update unittests
raphaelquast Apr 19, 2026
5f073ad
set default lazyness for set_shape
raphaelquast Apr 19, 2026
2feab37
define explicit "add_peek_layer" method
raphaelquast Apr 19, 2026
99fbfac
set _coll_dynamic property
raphaelquast Apr 19, 2026
51143f4
allow indexing for Maps-objects to create/access layers
raphaelquast Apr 19, 2026
dc49fe4
turn Maps.lazy property into a contextmanager
raphaelquast Apr 19, 2026
c9914d0
fix typo
raphaelquast Apr 19, 2026
3b0c958
add call to "after_fetch_bg" hook
raphaelquast Apr 19, 2026
4db87cc
update peek widget
raphaelquast Apr 19, 2026
a5e8c51
update callbacks widget
raphaelquast Apr 19, 2026
6ac4c60
update multiple-maps example
raphaelquast Apr 19, 2026
b25399e
run layer-change actionson fetch_bg
raphaelquast Apr 19, 2026
688c5a8
remove call to "_do_on_layer_change" in "_combine_bgs"
raphaelquast Apr 19, 2026
2b51b27
add explicit typing info for ne-features
raphaelquast Apr 19, 2026
53f44fd
minor
raphaelquast Apr 19, 2026
ffc0650
minor
raphaelquast Apr 19, 2026
40bbd7c
fix typos
raphaelquast Apr 19, 2026
7fbee4f
remove no longer existing members from autodoc
raphaelquast Apr 19, 2026
c7e11eb
update doc dependencies
raphaelquast Apr 19, 2026
756b0fa
use python 3.12 for docs
raphaelquast Apr 19, 2026
0ea6893
decrease pydata-sphinx-theme version
raphaelquast Apr 19, 2026
6916b1a
fix minor doc issue
raphaelquast Apr 19, 2026
966c2ac
remove no longer existing properties from docs
raphaelquast Apr 19, 2026
615bf3f
update docs
raphaelquast Apr 19, 2026
8c0a0de
update docs
raphaelquast Apr 19, 2026
87bdf30
rename "draw" module to "drawer"
raphaelquast Apr 19, 2026
93af423
fix docs issue
raphaelquast Apr 19, 2026
a3ef5c6
fix recursion of draw-property
raphaelquast Apr 19, 2026
0387f7d
remove obsolete method
raphaelquast Apr 20, 2026
777676c
update unittests to reflect default lazyness state of methods
raphaelquast Apr 20, 2026
31055c2
update unittest to reflect custom callback signature
raphaelquast Apr 20, 2026
6fd93e2
fix keypress callbacks assigned to "any" key
raphaelquast Apr 20, 2026
2201c0f
make sure non-existing layers are not shown with m.show_layer
raphaelquast Apr 20, 2026
5c9f4b9
flush events after click in unittests
raphaelquast Apr 20, 2026
35e53d0
use format() instead of str() to avoid issues with IntEnum in python …
raphaelquast Apr 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/testMaps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
# set operating systems to test
os: [ubuntu-latest]
# set python versions to test
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]

name: test_Maps ${{ matrix.os }} ${{ matrix.python-version }}
steps:
Expand All @@ -34,7 +34,7 @@ jobs:
shell: bash -l {0}
run: |
pip install -e .[test]
python -m pytest -v --cov=eomaps --cov-report=xml
python -m pytest -v --cov=eomaps --cov-report=xml -n auto
- name: Upload Image Comparison Artefacts
if: ${{ failure() }}
uses: actions/upload-artifact@v4
Expand Down
4 changes: 2 additions & 2 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ sphinx:
configuration: docs/source/conf.py

build:
os: "ubuntu-20.04"
os: "ubuntu-lts-latest"
tools:
python: "mambaforge-22.9"
python: "miniforge3-latest"

conda:
environment: docs/docs_env.yml
Expand Down
12 changes: 6 additions & 6 deletions docs/docs_env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ channels:

dependencies:

- python =3.11
- python =3.12

# --------------for building the docs
- docutils =0.20.1
- sphinx =8.0.2
- docutils =0.22.4
- sphinx =9.1.0
- sphinx-copybutton =0.5.2
- myst-nb =1.1.1
- sphinx-design =0.6.1
- pydata-sphinx-theme
- myst-nb =1.4.0
- sphinx-design =0.7.0
- pydata-sphinx-theme =0.16.1
- myst-sphinx-gallery = 0.2.2


Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 2 additions & 4 deletions docs/source/api/eomaps.eomaps.Maps.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Properties

Maps.f
Maps.ax
Maps.l
Maps.ll
Maps.layer
Maps.crs_plot

Expand All @@ -29,9 +31,7 @@ Properties
:template: obj_with_attributes_no_toc.rst
:nosignatures:

Maps.data
Maps.data_specs
Maps.classify_specs
Maps.colorbar


Expand Down Expand Up @@ -144,7 +144,6 @@ Data visualization
Maps.set_data
Maps.set_shape
Maps.set_classify
Maps.set_classify_specs

.. autosummary::
:toctree: ../generated
Expand Down Expand Up @@ -229,7 +228,6 @@ Miscellaneous
:nosignatures:

Maps.config
Maps.BM

.. autosummary::
:toctree: ../generated
Expand Down
7 changes: 0 additions & 7 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,24 +84,17 @@ def setup(app):

Maps.cb.click.__name__ = "click"
Maps.cb.click.attach.__name__ = "attach"
Maps.cb.click.get.__name__ = "get"

Maps.cb.pick.__name__ = "pick"
Maps.cb.pick.attach.__name__ = "attach"
Maps.cb.pick.get.__name__ = "get"

Maps.cb.keypress.__name__ = "keypress"
Maps.cb.keypress.attach.__name__ = "attach"
Maps.cb.keypress.get.__name__ = "get"

Maps.cb.move.__name__ = "move"
Maps.cb.move.attach.__name__ = "attach"
Maps.cb.move.get.__name__ = "get"

Maps.BM.__name__ = "BM"

Maps.data_specs.__name__ = "data_specs"
Maps.classify_specs.__name__ = "classify_specs"


# -- Project information
Expand Down
16 changes: 1 addition & 15 deletions docs/source/gen_autodoc_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,6 @@

from eomaps import Maps, widgets

# TODO there must be a better way than this...
# BM needs to be a property otherwise there are problems with jupyter notebooks
# In order to make BM still accessible to sphinx, override it prior to generating
# the autodoc-files
from eomaps._blit_manager import BlitManager

Maps.BM = BlitManager


def get_autosummary(
currentmodule="eomaps.eomaps",
Expand Down Expand Up @@ -75,9 +67,7 @@ def make_feature_toctree_file():
"read_file",
"util",
"add_wms",
"BM",
"data_specs",
"classify_specs",
):
members.extend(get_members(Maps, key, False))
for key in ("add_feature", "cb"):
Expand All @@ -89,8 +79,6 @@ def make_feature_toctree_file():
"cb.keypress.attach",
):
members.extend(get_members(Maps, key, True))
for key in ("cb.click.get", "cb.pick.get", "cb.move.get", "cb.keypress.get"):
members.extend(get_members(Maps, key, False))

# create a page that will be used for sphinx-autodoc to create stub-files
s = ":orphan:\n\n"
Expand All @@ -103,9 +91,7 @@ def make_feature_toctree_file():
s += get_autosummary("eomaps.compass", ["Compass"], "custom-class-template")
s += get_autosummary("eomaps.scalebar", ["ScaleBar"], "custom-class-template")
s += get_autosummary(
"eomaps.callbacks",
["ClickCallbacks", "PickCallbacks", "KeypressCallbacks"],
"custom-class-template",
"eomaps.callback_methods", ["_CallbackMixin"], "custom-class-template"
)

s += get_autosummary(
Expand Down
132 changes: 23 additions & 109 deletions docs/source/user_guide/how_to_use/api_basics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,12 @@ You can create as many layers as you need! The following image explains how it w
If you use methods that are **NOT provided by EOmaps**, the corresponding artists will always appear on the ``"base"`` layer by default!
(e.g. ``cartopy`` or ``matplotlib`` methods accessible via ``m.ax.`` or ``m.f.`` like ``m.ax.plot(...)``)

In most cases this behavior is sufficient... for more complicated use-cases, artists must be explicitly added to the **Blit Manager** (``m.BM``) so that ``EOmaps`` can handle drawing accordingly.
In most cases this behavior is sufficient... for more complicated use-cases, artists must be explicitly added to the ``Maps`` object so that ``EOmaps`` can handle drawing accordingly.

To put the artists on dedicated layers, use one of the the following options:

- For artists that are dynamically updated on each event, use ``m.BM.add_artist(artist, layer=...)``
- For "background" artists that only require updates on pan/zoom/resize, use ``m.BM.add_bg_artist(artist, layer=...)``
- For artists that are dynamically updated on each event, use ``m.add_artist(artist)``
- For "background" artists that only require updates on pan/zoom/resize, use ``m.add_bg_artist(artist)``


.. code-block:: python
Expand All @@ -195,9 +195,9 @@ You can create as many layers as you need! The following image explains how it w
(l1, ) = m.ax.plot([0, 1], [0, 1], lw=5, c="r", transform=m.ax.transAxes)
(l2, ) = m.ax.plot([0, 1], [1, 0], lw=5, c="r", transform=m.ax.transAxes)

m.BM.add_bg_artist(l1, layer="mylayer")
m.BM.add_bg_artist(l2, layer="mylayer")
m.show_layer("mylayer")
m.l.mylayer.add_bg_artist(l1)
m.l.mylayer.add_bg_artist(l2)
m.l.mylayer.show()

.. _combine_layers:

Expand Down Expand Up @@ -276,7 +276,7 @@ The visible layer can be a **single layer-name**, or a **combination of multiple
:icon: info
:color: info

.. currentmodule:: eomaps.callbacks.ClickCallbacks
.. currentmodule:: eomaps.callback_methods._CallbackMixin

If you want to interactively overlay a part of the screen with a different layer, have a look at :py:meth:`peek_layer` callbacks!

Expand Down Expand Up @@ -642,23 +642,22 @@ Dynamic updates of figures
**************************

As soon as a :py:class:`Maps`-object is attached to a figure, EOmaps will handle re-drawing of the figure!
Therefore **dynamically updated** artists must be added to the "blit-manager" (``m.BM``) to ensure
Therefore **dynamically updated** artists must be added to the ``Maps``-object to ensure
that they are correctly updated.

- use ``m.BM.add_artist(artist, layer=...)`` if the artist should be re-drawn on **any event** in the figure
- use ``m.BM.add_bg_artist(artist, layer=...)`` if the artist should **only** be re-drawn if the extent of the map changes
- use ``m.add_artist(artist, layer=...)`` if the artist should be re-drawn on **any event** in the figure
- use ``m.add_bg_artist(artist, layer=...)`` if the artist should **only** be re-drawn if the extent of the map changes

.. note::

In most cases it is sufficient to simply add the whole axes-object as artist via ``m.BM.add_artist(...)``.
In most cases it is sufficient to simply add the whole axes-object as artist via ``m.add_artist(...)``.

This ensures that all artists of the axes are updated as well!


Here's an example to show how it works:



.. grid:: 1 1 1 2

.. grid-item::
Expand All @@ -685,7 +684,7 @@ Here's an example to show how it works:
# Since we want to dynamically update the data on the axis, it must be
# added to the BlitManager to ensure that the artists are properly updated.
# (EOmaps handles interactive re-drawing of the figure)
m.BM.add_artist(ax, layer=m.layer)
m.add_artist(ax, layer=m.layer)

# plot some static data on the axis
ax.plot([10, 20, 30, 40, 50], [10, 20, 30, 40, 50])
Expand All @@ -710,9 +709,9 @@ MapsGrid objects

.. note::

While :py:class:`MapsGrid` objects provide some convenience, starting with EOmaps v6.x,
the preferred way of combining multiple maps and/or matplotlib axes in a figure
is by using one of the options presented in the previous sections!
Starting with EOmaps v9.0 MapsGrid objects support the full range of functionalities
offered by single Maps objects.


A :py:class:`MapsGrid` creates a grid of :py:class:`Maps` objects (and/or ordinary ``matplotlib`` axes),
and provides convenience-functions to perform actions on all maps of the figure.
Expand All @@ -722,120 +721,35 @@ and provides convenience-functions to perform actions on all maps of the figure.

from eomaps import MapsGrid
mg = MapsGrid(r=2, c=2, crs=4326)
# you can then access the individual Maps-objects via:
# you can then access the individual Maps-objects via the ``m_<i>_<j>`` properties
# (useful for auto-completion)
mg.m_0_0.add_feature.preset.ocean()
mg.m_0_1.add_feature.preset.land()
mg.m_1_0.add_feature.preset.urban_areas()
mg.m_1_1.add_feature.preset.rivers_lake_centerlines()

m_0_0_ocean = mg.m_0_0.new_layer("ocean")
m_0_0_ocean.add_feature.preset.ocean()
# or via 1d or 2d indexing
mg[0, 1].add_feature.preset.land()
mg[1, 0].add_feature.preset.urban_areas()
mg[3].add_feature.preset.rivers_lake_centerlines()

# functions executed on MapsGrid objects will be executed on all Maps-objects:
mg.add_feature.preset.coastline()
mg.add_compass()
mg.add_gridlines(10, c="lightblue")

# to perform more complex actions on all Maps-objects, simply loop over the MapsGrid object
for m in mg:
m.add_gridlines(10, c="lightblue")
mg.l.ocean.add_feature.preset.ocean()

# set the margins of the plot-grid
mg.subplots_adjust(left=0.1, right=0.9, bottom=0.05, top=0.95, hspace=0.1, wspace=0.05)


Make sure to checkout the :ref:`layout_editor` which greatly simplifies the arrangement of multiple axes within a figure!

Custom grids and mixed axes
+++++++++++++++++++++++++++

Fully customized grid-definitions can be specified by providing ``m_inits`` and/or ``ax_inits`` dictionaries
of the following structure:

- The keys of the dictionary are used to identify the objects
- The values of the dictionary are used to identify the position of the associated axes
- The position can be either an integer ``N``, a tuple of integers or slices ``(row, col)``
- Axes that span over multiple rows or columns, can be specified via ``slice(start, stop)``

.. code-block:: python

dict(
name1 = N # position the axis at the Nth grid cell (counting first)
name2 = (row, col), # position the axis at the (row, col) grid-cell
name3 = (row, slice(col_start, col_end)) # span the axis over multiple columns
name4 = (slice(row_start, row_end), col) # span the axis over multiple rows
)

- ``m_inits`` is used to initialize :py:class:`Maps` objects
- ``ax_inits`` is used to initialize ordinary ``matplotlib`` axes

The individual :py:class:`Maps` objects and ``matplotlib-Axes`` are then accessible via:

.. code-block:: python
:name: test_mapsgrid_custom

from eomaps import MapsGrid
mg = MapsGrid(2, 3,
m_inits=dict(ocean=(0, 0), land=(0, 2)),
ax_inits=dict(someplot=(1, slice(0, 3)))
)
# Maps object with the name "left"
mg.m_ocean.add_feature.preset.ocean()
# the Maps object with the name "right"
mg.m_land.add_feature.preset.land()

# the ordinary matplotlib-axis with the name "someplot"
mg.ax_someplot.plot([1,2,3], marker="o")
mg.subplots_adjust(left=0.1, right=0.9, bottom=0.2, top=0.9)

❗ NOTE: if ``m_inits`` and/or ``ax_inits`` are provided, ONLY the explicitly defined objects are initialized!


- The initialization of the axes is based on matplotlib's `GridSpec <https://matplotlib.org/stable/api/_as_gen/matplotlib.gridspec.GridSpec.html>`_ functionality.
All additional keyword-arguments (``width_ratios, height_ratios, etc.``) are passed to the initialization of the ``GridSpec`` object.

- To specify unique ``crs`` for each :py:class:`Maps` object, provide a dictionary of ``crs`` specifications.

.. code-block:: python
:name: test_mapsgrid_custom_02

from eomaps import MapsGrid
# initialize a grid with 2 Maps objects and 1 ordinary matplotlib axes
mg = MapsGrid(2, 2,
m_inits=dict(top_row=(0, slice(0, 2)),
bottom_left=(1, 0)),
crs=dict(top_row=4326,
bottom_left=3857),
ax_inits=dict(bottom_right=(1, 1)),
width_ratios=(1, 2),
height_ratios=(2, 1))

# a map extending over the entire top-row of the grid (in epsg=4326)
mg.m_top_row.add_feature.preset.coastline()

# a map in the bottom left corner of the grid (in epsg=3857)
mg.m_bottom_left.add_feature.preset.ocean()

# an ordinary matplotlib axes in the bottom right corner of the grid
mg.ax_bottom_right.plot([1, 2, 3], marker="o")
mg.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9)


.. currentmodule:: eomaps.mapsgrid

.. autosummary::
:nosignatures:

MapsGrid
MapsGrid.join_limits
MapsGrid.share_click_events
MapsGrid.share_pick_events
MapsGrid.set_data
MapsGrid.set_classify_specs
MapsGrid.add_wms
MapsGrid.add_feature
MapsGrid.add_annotation
MapsGrid.add_marker
MapsGrid.add_gdf


Syntax and Autocompletion
Expand Down
Loading
Loading