Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 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
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
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
3 changes: 0 additions & 3 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,7 @@ def setup(app):
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
10 changes: 0 additions & 10 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 Down
130 changes: 22 additions & 108 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 @@ -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
1 change: 0 additions & 1 deletion docs/source/user_guide/miscellaneous/api_misc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ Some additional functions and properties that might come in handy:
Maps.on_layer_activation
Maps.set_extent_to_location
Maps.get_crs
Maps.BM
Maps.join_limits
Maps.snapshot
Maps.refetch_wms_on_size_change
Expand Down
Loading
Loading