Skip to content

Commit

Permalink
Merge pull request #78 from raphaelquast/dev
Browse files Browse the repository at this point in the history
merge for v4.1.1
  • Loading branch information
raphaelquast authored May 27, 2022
2 parents 43eaaca + 108b27e commit 8e9db5a
Show file tree
Hide file tree
Showing 18 changed files with 448 additions and 137 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/testMaps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,15 @@ jobs:
# checkout the repository
- uses: actions/checkout@v2
# install miniconda environment
- uses: conda-incubator/setup-miniconda@v2
- uses: conda-incubator/setup-miniconda@v2.1.1
with:
environment-file: tests/test_env.yml

# use mamba to speed up installation
mamba-version: "*"
channels: conda-forge
channel-priority: true

activate-environment: testMaps

show-channel-urls: true
Expand Down
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,11 @@ docs/_build
docs/debug.log
docs/.vscode
docs/generated
docs/_tables
.spyproject
EOmaps.egg-info
.pytest_cache
logos
tests/Images
tests/.ipynb_checkpoints
docs/_static/example_gifs_very_old
87 changes: 44 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
### A library to create interactive maps of geographical datasets.

<ul type="none">
<li>🌍 EOmaps provides a simple and intuitive interface to visualize and interact with geographical datasets</li>
<li>🌍 EOmaps provides a simple and intuitive interface to visualize and interact with geographical datasets.</li>
<ul type="none">
<li>⬥ Data can be provided as 1D or 2D <code>lists</code>, <code>numpy-arrays</code>, <code>pandas.DataFrames</code></li>
<li> &nbsp; &nbsp; &nbsp; or directly from GeoTIFFs, NetCDFs and csv-files.</li>
Expand All @@ -36,58 +36,33 @@
</ul>
</ul>
<br/>
<p align="center">
🌲🌳 Checkout the <a href=https://eomaps.readthedocs.io/en/latest><b>documentation</b></a> for more details and <a href=https://eomaps.readthedocs.io/en/latest/EOmaps_examples.html><b>examples</b></a> 🌳🌲
</p>

---

### ❗ update notice ❗
> There are breaking API changes between `EOmaps v3.x` and `EOmaps v4.0`
> To quickly update existing scripts, see: [⚙ Port script from EOmaps v3.x to v4.x](https://eomaps.readthedocs.io/en/latest/FAQ.html#port-script-from-eomaps-v3-x-to-v4-x)
<details>
<summary>[click to show] a quick summary of the API changes</summary>

- the following properties and functions have been removed:
-`m.plot_specs.`
-`m.set_plot_specs()`
- Arguments are now directly passed to relevant functions:

```python
m = Maps
# m.set_plot_specs(cmap=..., vmin=..., vmax=..., cpos=..., cpos_radius=..., histbins=...)
# m.plot_specs.< > = ...
m.set_data(..., cpos=..., cpos_radius=...)
m.plot_map(cmap=..., vmin=..., vmax=...)
m.add_colorbar(histbins=...)
```


- 🔶 `m.set_shape.voroni_diagram` is renamed to `m.set_shape.voronoi_diagram`
- 🔷 custom callbacks are no longer bound to the Maps-object
- the call-signature of custom callbacks has changed to:
`def cb(self, *args, **kwargs) >> def cb(*args, **kwargs)`





</details>

---


## 🔨 Installation

To install EOmaps (and all its dependencies) via the `conda` package-manager, simply use:

```python
conda install -c conda-forge eomaps
```
For more information, have a look at the [installation instructions](https://eomaps.readthedocs.io/en/latest/general.html#installation) in the documentation!
... to get a huge speedup, use `mamba` to solve the dependencies!
```python
conda install -c conda-forge mamba
mamba install -c conda-forge eomaps
```
For more information, have a look at the [installation instructions](https://eomaps.readthedocs.io/en/latest/general.html#installation) or checkout the quickstart guide [🚀 from 0 to EOmaps](https://eomaps.readthedocs.io/en/latest/FAQ.html#from-0-to-eomaps-a-quickstart-guide)!
<br/>

## 📖 Documentation

Make sure to have a look at the <a href=https://eomaps.readthedocs.io/en/latest><b>🌳 documentation 🌳</b></a> which provides a lot of <a href=https://eomaps.readthedocs.io/en/latest/EOmaps_examples.html><b>examples</b></a> on how to create awesome interactive maps (incl. source code)!

## ✔️ Citation
Did EOmaps help in your research?
Expand All @@ -103,15 +78,41 @@ Open an [issue](https://github.com/raphaelquast/EOmaps/issues) or start a [discu
(I'm of course also happy about actual pull requests on features and bug-fixes!)

---------------
<table>
<tr>
<td valign="center">
<img src="https://github.com/raphaelquast/EOmaps/blob/dev/docs/_static/fig6.gif?raw=true" alt="EOmaps example 6">
</td>
<td valign="center">
<img src="https://github.com/raphaelquast/EOmaps/blob/dev/docs/_static/fig2.gif?raw=true" alt="EOmaps example 2">
</td>
</tr>
<tr>
<td valign="center">
<img src="https://github.com/raphaelquast/EOmaps/blob/dev/docs/_static/fig7.gif?raw=true" alt="EOmaps example 7">
</td>
<td valign="center">
<img src="https://github.com/raphaelquast/EOmaps/blob/dev/docs/_static/fig8.gif?raw=true" alt="EOmaps example 8">
</td>
</tr>
<tr>
<td valign="center">
<img src="https://github.com/raphaelquast/EOmaps/blob/dev/docs/_static/fig9.gif?raw=true" alt="EOmaps example 9">
</td>
<td valign="center">
<img src="https://github.com/raphaelquast/EOmaps/blob/dev/docs/_static/fig4.gif?raw=true" alt="EOmaps example 4">
</td>
</tr>
<tr>
<td valign="center">
<img src="https://github.com/raphaelquast/EOmaps/blob/dev/docs/_static/inset_maps.png?raw=true" alt="EOmaps inset-maps">
</td>
<td valign="center">
<img src="https://github.com/raphaelquast/EOmaps/blob/dev/docs/_static/fig3.png?raw=true" alt="EOmaps example 3">
</td>
</tr>
</table>

<p align="center">
<img src="https://github.com/raphaelquast/EOmaps/blob/dev/docs/_static/fig6.gif?raw=true" alt="EOmaps example image 2" width="46%">
<img src="https://github.com/raphaelquast/EOmaps/blob/dev/docs/_static/fig2.gif?raw=true" alt="EOmaps example image 1" width="50%">
<img src="https://github.com/raphaelquast/EOmaps/blob/dev/docs/_static/fig7.gif?raw=true" alt="EOmaps example image 3" width="48%">
<img src="https://github.com/raphaelquast/EOmaps/blob/dev/docs/_static/fig8.gif?raw=true" alt="EOmaps example image 1" width="48%">
<img src="https://github.com/raphaelquast/EOmaps/blob/dev/docs/_static/fig9.gif?raw=true" alt="EOmaps example image 1" width="48%">
<img src="https://github.com/raphaelquast/EOmaps/blob/dev/docs/_static/fig4.gif?raw=true" alt="EOmaps example image 1" width="48%">
</p>


## 🌳 Basic usage
Expand Down
Binary file modified docs/_static/fig1.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/_static/fig1.png
Binary file not shown.
Binary file modified docs/_static/fig2.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/_static/fig2.png
Binary file not shown.
Binary file modified docs/_static/fig3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/fig6.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/inset_maps.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 6 additions & 2 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@

Possible ways for specifying the crs for plotting are:

- If you provide an integer, it is identified as an epsg-code (e.g. ``4326``, ``3035``, etc.).
- If you provide an integer, it is identified as an epsg-code (e.g. ``4326``, ``3035``, etc.)

- 4326 hereby defaults to `PlateCarree` projection

- All other CRS usable for plotting are accessible via ``Maps.CRS``,
e.g.: ``crs=Maps.CRS.Orthographic()`` or ``crs=Maps.CRS.Equi7Grid_projection("EU")``.
e.g.: ``crs=Maps.CRS.Orthographic()``, ``crs=Maps.CRS.GOOGLE_MERCATOR`` or ``crs=Maps.CRS.Equi7Grid_projection("EU")``.
(``Maps.CRS`` is just an accessor for ``cartopy.crs``)

▤ Layers
Expand Down Expand Up @@ -1141,6 +1144,7 @@ To indicate rectangular areas in any given crs, simply use ``m.indicate_extent``
| Before adding a colorbar, you must plot the data using ``m.plot_map()``.
| A colorbar with a colored histogram on top can then be added to the map via ``m.add_colorbar``.

.. note::
Colorbars are only visible if the layer at which the data was plotted is visible!

Expand Down
7 changes: 4 additions & 3 deletions eomaps/_cb_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,11 @@ def _clear_temporary_artists(self):
def _sort_cbs(self, cbs):
if not cbs:
return set()
cbnames = set([i.rsplit("_", 1)[0] for i in cbs])

cbnames = set([i.rsplit("__", 1)[0].rsplit("_", 1)[0] for i in cbs])
sortp = self._cb_list + list(set(self._cb_list) ^ cbnames)
return sorted(list(cbs), key=lambda w: sortp.index(w.rsplit("_", 1)[0]))
return sorted(
list(cbs), key=lambda w: sortp.index(w.rsplit("__", 1)[0].rsplit("_", 1)[0])
)

def __repr__(self):
txt = "Attached callbacks:\n " + "\n ".join(
Expand Down
35 changes: 33 additions & 2 deletions eomaps/_containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,23 @@ def set_colorbar_position(self, pos=None, ratio=None, cb=None):
"""

if cb is None:
_, _, ax_cb, ax_cb_plot, orientation, _ = self._m._colorbar
(
_,
_,
ax_cb,
ax_cb_plot,
ax_cb_extend,
extend_frac,
orientation,
_,
) = self._m._colorbar
else:
_, _, ax_cb, ax_cb_plot, orientation, _ = cb
_, _, ax_cb, ax_cb_plot, ax_cb_extend, extend_frac, orientation, _ = cb

if orientation == "horizontal":
pcb = ax_cb.get_position()
pcbp = ax_cb_plot.get_position()

if pos is None:
pos = [pcb.x0, pcb.y0, pcb.width, pcb.height + pcbp.height]
if ratio is None:
Expand All @@ -160,6 +170,16 @@ def set_colorbar_position(self, pos=None, ratio=None, cb=None):
[pos[0], pos[1] + hcb, pos[2], hp],
)

# adjust colorbar extension arrows
if ax_cb_extend:
frac = (
ax_cb.bbox.transformed(ax_cb.figure.transFigure.inverted()).width
* extend_frac
)
ax_cb_extend.set_position(
[pos[0] - frac / 2, pos[1], pos[2] + frac, hcb],
)

elif orientation == "vertical":
pcb = ax_cb.get_position()
pcbp = ax_cb_plot.get_position()
Expand All @@ -177,6 +197,17 @@ def set_colorbar_position(self, pos=None, ratio=None, cb=None):
ax_cb_plot.set_position(
[pos[0], pos[1], wp, pos[3]],
)

# adjust colorbar extension arrows
if ax_cb_extend:
frac = (
ax_cb.bbox.transformed(ax_cb.figure.transFigure.inverted()).height
* extend_frac
)
ax_cb_extend.set_position(
[pos[0] + wp, pos[1] - frac / 2, wcb, pos[3] + frac],
)

else:
raise TypeError(f"EOmaps: '{orientation}' is not a valid orientation")

Expand Down
36 changes: 30 additions & 6 deletions eomaps/_webmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
pass

def __call__(self, layer=None, **kwargs):
def __call__(self, layer=None, zorder=0, **kwargs):
"""
Add the WMTS layer to the map
Expand All @@ -284,13 +284,17 @@ def __call__(self, layer=None, **kwargs):
- If None, the layer of the parent object is used.
The default is None.
zorder : float
The zorder of the artist (e.g. the stacking level of overlapping artists)
The default is 0
**kwargs :
additional kwargs passed to the WebMap service request.
(e.g. transparent=True, time='2020-02-05', etc.)
"""
from . import MapsGrid # do this here to avoid circular imports!

for m in self._m if isinstance(self._m, MapsGrid) else [self._m]:
self._zorder = zorder
self._kwargs = kwargs
if layer is None:
self._layer = m.layer
Expand All @@ -311,7 +315,11 @@ def _do_add_layer(self, m, l):
print(f"EOmaps: Adding wmts-layer: {self.name}")

art = m.figure.ax.add_wmts(
self._wms, self.name, wmts_kwargs=self._kwargs, interpolation="spline36"
self._wms,
self.name,
wmts_kwargs=self._kwargs,
interpolation="spline36",
zorder=self._zorder,
)

m.BM.add_bg_artist(art, l)
Expand All @@ -322,7 +330,7 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
pass

def __call__(self, layer=None, **kwargs):
def __call__(self, layer=None, zorder=0, **kwargs):
"""
Add the WMS layer to the map
Expand All @@ -335,6 +343,9 @@ def __call__(self, layer=None, **kwargs):
- If None, the layer of the parent object is used.
The default is None.
zorder : float
The zorder of the artist (e.g. the stacking level of overlapping artists)
The default is 0
**kwargs :
additional kwargs passed to the WebMap service request.
(e.g. transparent=True, time='2020-02-05', etc.)
Expand All @@ -343,6 +354,8 @@ def __call__(self, layer=None, **kwargs):

for m in self._m if isinstance(self._m, MapsGrid) else [self._m]:
self._kwargs = kwargs
self._zorder = zorder

if layer is None:
self._layer = m.layer
else:
Expand All @@ -364,7 +377,11 @@ def _do_add_layer(self, m, l, usem=None):
# actually add the layer to the map.
print(f"EOmaps: ... adding wms-layer {self.name}")
art = m.figure.ax.add_wms(
self._wms, self.name, wms_kwargs=self._kwargs, interpolation="spline36"
self._wms,
self.name,
wms_kwargs=self._kwargs,
interpolation="spline36",
zorder=self._zorder,
)

m.BM.add_bg_artist(art, l)
Expand Down Expand Up @@ -877,6 +894,7 @@ def __call__(
transparent=False,
alpha=1,
interpolation="spline36",
zorder=0,
**kwargs,
):
"""
Expand Down Expand Up @@ -904,6 +922,9 @@ def __call__(
required (e.g. if you don't use the native projection of the WMS)
changing this value will slow down re-projection but it can
provide a huge boost in image quality! The default is 750.
zorder : float
The zorder of the artist (e.g. the stacking level of overlapping artists)
The default is 0
**kwargs :
Additional kwargs passed to the cartopy-wrapper for
matplotlib's `imshow`.
Expand All @@ -920,14 +941,15 @@ def __call__(
if isinstance(self._m, MapsGrid):
for m in self._m:
self._reinit(m).__call__(
layer, transparent, alpha, interpolation, **kwargs
layer, transparent, alpha, interpolation, zorder, **kwargs
)
else:

self._kwargs = dict(
interpolation=interpolation, alpha=alpha, origin="lower"
)
self._kwargs.update(kwargs)
self._zorder = zorder

if self._layer == "all" or self._m.BM.bg_layer == self._layer:
# add the layer immediately if the layer is already active
Expand Down Expand Up @@ -959,7 +981,9 @@ def _do_add_layer(self, m, l):
# (only SlippyImageArtist has been subclassed)

self._raster_source.validate_projection(m.ax.projection)
img = SlippyImageArtist_NEW(m.ax, self._raster_source, **self._kwargs)
img = SlippyImageArtist_NEW(
m.ax, self._raster_source, zorder=self._zorder, **self._kwargs
)
with self._m.ax.hold_limits():
m.ax.add_image(img)
self._artist = img
Expand Down
Loading

0 comments on commit 8e9db5a

Please sign in to comment.