Releases: raphaelquast/EOmaps
EOmaps v4.1.1
A bugfix release that brings some nice updates for the colorbar.
🌈 updates for the colorbar
- ⭐ Colorbars now have proper extension-arrows to indicate values outside the colorbar-range
- ⭐
m.add_colorbar()
supports some new arguments to further customize the colorbar:histogram_size
: set the relative height of the histogram in relation to the height of the colorbar
(use 0 for a plain colorbar and 999 for a plain histogram)extend_frac
: set the relative size of the extension-arrowsadd_extend_arrows
: toggle drawing extension-arrows
(by default arrows are only drawn if there are values outside the [vmin
,vmax
] range)
🌦️ changes
- setting vmin/vmax no longer clips data-values
(e.g. callbacks now always retrieve actual data-values independent of vmin/vmax)
🔨 fixes
- fix setting zorder for WebMap layers
- make sure the default zorder for
m.plot_map()
is 1 for all shapes - fix test-action issues (use mamba + updated version of conda-incubator)
- fix adding static annotations by dataset-ID with
m.add_annotation()
- fix some issues with draggable axes
- fix sorting of callback-execution order
EOmaps v4.1
A minor release that brings an awesome new feature and some bugfixes.
🔬 New feature: Inset-maps!
- Quickly create zoomed-in views on selected regions of a map with
m.new_inset_map()
Checkout the docs for more details: 🔬 Inset-maps - zoom-in on interesting areas
🔨 fixes
- allow using a scalar radius for calculating ellipse and rectangle points
- make sure the blit-manager always uses the correct figure object
- make histogram plot background visible (but set boundary color to none)
- fix wrong error-catching for layer-slider
- fix issues with colored histograms for discrete colormaps
EOmaps v4.0
A new major release that brings some nice new features, a lot of updates and some outstanding api-changes.
🌩 changes
❗ There are breaking changes to EOmaps v3.x ❗
🌞 For a quick-guide on how to port existing scripts to v4.x see: ⚙️ port script from v3.x to v4.x
[or click on the text below for details!]
🔸 m.plot_specs
and m.set_plot_specs(...)
have been removed
- "vmin", "vmax" and "cmap" are now set when calling
m.plot_map(...)
- "density", "tick_precision", "histbins" and "label" are now set when calling
m.add_colorbar(...)
- "cpos" and "cpos_radius" are now set with
m.set_data_specs(...)
🔸 voroni_diagram
is now correctly called voronoi_diagram
This just fixes the typo in the name.
# --- OLD ---
m.set_shape.voroni_diagram()
# --- NEW ---
m.set_shape.voronoi_diagram()
🔸 The data-specs xcoord
and ycoord
have been renamed to x
and y
This change is optional and will only raise a depreciation warning for now...
The old naming-convention will however be removed in future releases so it's highly recommended to use the new (shorter and more intuitive🙂) x
and y
variable names.
# --- OLD ---
m.set_data(data=..., xcoord=..., ycoord=..., ...)
m.data_specs.xcoord
# --- NEW ---
m.set_data(data=..., x=..., y=..., ...)
m.data_specs.x
🔸 Custom callback functions now have a slightly different call-signature
This removes the contra-intuitive "binding" of functions to the
Maps
-objects and ensures that class-methods can be used as callbacks without unwanted side-effects.
- The first argument is no longer identified automatically as the
Maps
-object!
(if you need access to the underlyingMaps
-object, simply pass it as an argument!)
m = Maps()
def cb(m, **kwargs):
pos = kwargs["pos"]
print("the Maps-object:", m)
print("the click-position is", pos)
m.cb.click.attach(cb, m=m)
👾 [click to show] how to get back the old behaviour
To get back the old behavior you have to "bind" the callback functions to the Maps-object, e.g:
m = Maps()
def cb(self, **kwargs):
...
m.cb.click.attach(cb.__get__(m))
or simply pass the Maps-object as kwarg, e.g.:
m = Maps()
def cb(self, **kwargs):
...
m.cb.click.attach(cb self=m)
🌳 NEW
- ⭐ The Sentinel-2 cloudless WebMap service can now be used via
m.add_wms.s2_cloudless
- 🌟 It is now possible to set "coordinate-only" datasets!
- This is particularly useful if you want to manually assign colors
m.set_data(None, [1,2,3], [1,2,3]) m.plot_map(fc=["r", "g", "b"])
🚀 there's a new plot shape! m.set_shape.raster
A fast way to plot 2D datasets.
[click to show] 🔸 details
- it's quite similar to
plt.imshow
(e.g. a QuadMesh is used to speed up plotting of 2D datasets) - the differences to
shade_raster
are:- the whole dataset is always plotted (so for very very large datasets
shade_raster
is much faster!) - it supports manual color specifications (
shade_raster
does not)
- the whole dataset is always plotted (so for very very large datasets
- the differences between
rectangles
andraster
are:raster
does not take the curvature of the edges into accountraster
determines the pixel-size based on neighboring pixels,rectangles
allows arbitrary pixel-dimensions
🌈 there have been some major improvements for manual color specifications!
Checkout the 🌎 Customizing the plot section of the docs for details!
Colors can now be set manually with all shapes (except shade
shapes) using
m.plot_map(fc=[...])
(or facecolor=
or color=
)!
[click to show] 🔸 Possible ways to specify colors.
- a single value (RGB/RGBA tuple, a matplotlib color-name or a hex-color)
- a tuple of 3/4 arrays in the same shape as the coordinates (identified as RGB/RGBA values)
- a list/array of RGB tuples, e.g.
[(1, 0, 0.25), (0.3, 0.4, 0.5), ....]
- a list/array of RGBA tuples, e.g.:
[(1, 0, 0.25, 0.15), (0.3, 0.4, 0.5, 0.25), ....]
- a list/array of matplotlib named-colors, e.g.
["r", "olive", "darkblue", ...]
- a list/array of hex-colors, e.g.:
['#ff0040', '#4c6680', ...]
For example:
m = Maps()
m.set_data(None, [1,2,3,4,5], [1,2,3,4,5])
# use named colors
m.plot_map(ec="k", fc=["r", "olive", "darkblue", "orange", "indigo"])
# or RGB tuples
m.plot_map(color=[(1, 0, 0), (.4, .5, .6), (.2, .7, .2), (.45, .12, .98), (.94, .45, .56)])
# or a single color for all datapoints
m.plot_map(facecolor="g", edgecolor="r")
# or use 3 individual arrays that should be identified as RGB values
m.plot_map(fc=([0.1,0.2,0.3,0.4,0.5], [0.1,0.2,0.3,0.4,0.5], [0.1,0.2,0.3,0.4,0.5])
☁️ minor (non-breaking) changes
- the default
radius_crs
for themark
callback is now determined based on theradius_crs
assigned in the plot-shape
... this definition allows usingm.cb.pick.attach.mark(buffer=3)
directly without having to worry about the crs
(previouslyin
, e.g. the input-crs was used by default) - the background patch of the compass is now by default set to
None
🔨 fixes
- fix issues with manual color specifications for various plot-shapes
(e.g. when providing explicit color-arrays viam.plot_map(color=[...])
) - fix issues with shapes close to crs-bounds
- support estimation of different x- and y- radius for 2D datasets
- warn if datapoints are masked or if datapoints are outside the CRS-bounds
- cache shape transformers (so they are not re-initialized all the time)
EOmaps v3.5
🚀 updates
⭐ EOmaps now properly handles encoded datasets!
- This saves a lot of memory and provides a huge speedup when plotting integer-encoded datasets!
- If you plot GeoTIFFs or NetCDFs with the functions
Maps.read_data
,Maps.from_file
orm.new_layer_from_file
, the data is now kept in the encoded dtype and conversions are only performed "on demand" (e.g. when adding colorbars or in pick-callbacks)- (if you really want to immediately convert all data-values, use
mask_and_scale=True
)
- (if you really want to immediately convert all data-values, use
- The encoding information can be get/set via
m.data_specs.encoding
orm.set_data_specs(encoding=...)
m = Maps()
m.set_data(data=[1,2,3], xcoord=[1,2,3], ycoord=[1,2,3], encoding=dict(scale_factor=0.01, add_offset=1))
# the "decoding" of the values is evaluated via "add_offset" + "scale_factor" * x
# e.g.: in this case the actual data-values are : [1.01, 1.02, 1.03]
🌳 New
-
⭐ The colorbar can now be used as a dynamic shade indicator with
m.add_colorbar(dynamic_shade_indicator=True)
- it is dynamically updated based on the distribution of shaded pixels in the current field of view.
(only possible withm.set_shape.shade_raster()
orm.set_shape.shade_points()
)
- it is dynamically updated based on the distribution of shaded pixels in the current field of view.
-
⭐ There is now a way to use
pick
callbacks on datasets without plotting the data first.- To make a "pick-only" dataset, use
m.set_data(...)
to assign the dataset and then
callm.make_dataset_pickable()
to initialize all required information to make the dataset pickable. - This is useful if you want to indicate certain informations "on click" without plotting the data
- To make a "pick-only" dataset, use
⚙️ changes
- The default plot-shape is now determined based on the size of the assigned dataset.
- <500k datapoints:
m.set_shape.ellipses()
- >500k datapoints:
m.set_shape.shade_raster()
- <500k datapoints:
Maps.from_file
andm.new_layer_from_file
now no longer attempt multiple shapes for plotting in case the first attempt fails
(the default shape is used if no explicit shape-name is provided)
🔨 fixes
- Fix typo in
m.add_colorbar
- Fix some typos in the docs
- Fix unnecessary dtype conversions in "shade_raster" and "shade_points"
- Avoid dtype conversions when reading NetCDFs and GeoTIFFs
EOmaps v3.4.1
[hotfix release to fix issues with multiple maps in one figure]
... EOmaps v3.4
A release that brings a lot of updates on speed and memory management and some very nice (but possibly breaking) changes compared previous versions of EOmaps.
❗ IMPORTANT CHANGES ❗
⭐ Starting with EOmaps v3.4 all callbacks and colorbars are layer-specific !
This means that callbacks only trigger if the layer of the associated Maps
object is visible!
(...and colorbars are only visible if the associated layer is visible)
-
To trigger callbacks or add features & datasets independent of the visible layer, use
m.all.cb. ...
(or attach them to aMaps
object on the"all"
layer) -
Note:
pick
callbacks now always react to the visible collection!
(except for the ones on the"all"
layer)m = Maps(layer=0) m.cb.click.attach.annotate() # this callback is ONLY executed if the layer 0 is visible m1 = m.new_layer(layer=1) m1.cb.click.attach.mark() # this callback is ONLY executed if the layer 1 is visible m.all.cb.click.attach.annotate() # this callback is executed independent of the visible layer!
🍃 removed arguments
- the obsolete
"orientation"
argument has been removed fromMaps(...)
(it set the colorbar-orientation which is now specified viam.add_colorbar(orientation=...)
🌳 NEW
- ⭐
m.show()
can be used to make the associated layer visible. (a shortcut form.show_layer(m.layer)
- ⭐
m.BM.on_layer(...)
can be used to trigger functions if the visible layer changes. - 🌟 WebMap layers are now lazily evaluated and only added to the map if the corresponding layer is actually visible.
- 🌟 [experimental feature] memory-mapping can now be used to avoid using up a lot of ram for very large datasets
- Intermediate datasets are stored as memory-mapped files in a temp-folder on disk to release memory
- By default memory-mapping is disabled! (to activate it, use:
m.plot_map(memmap=False)
)
🌦️ changes
- Adding data from files (e.g.
m.from_file
orm.new_layer_from_file
) now always uses"shade_raster"
as the default plot-shape (since EOmaps v3.3.2, raster-shading works perfectly fine with re-projected rasters as well) - If a file with >2M data-points is plotted, only "shade" shapes are attempted by default to avoid overloading memory.
- only one colorbar is allowed for
Maps
objects (use multiple objects for multiple colorbars)
🔨 fixes
- Fix several issues with memory-leaks and garbage-collection of objects
- Fix autoscale_fraction not recognized when using
preset="bw"
inm.add_scalebar
- Maps objects are now properly garbage-collected
- Fix auto-scaling of scalebars for very small scales
Maps.from_file
now properly handlespathlib.Path
objects- Fix utility widget start-layer should be the currently visible layer
- Fix pick-events should only identify points on visible layers
- Fix
m.add_colorbar(log=True)
for horizontal colorbars - Fix colorbar limit autoscaling
- Fix logo size changes on zoom
- Remove obsolete
layer
kwarg fromm.add_logo
- Fix incorrect color-normalization for
shade_raster
orshade_points
ifvmin/vmax
outside the data-range are used
(thanks to @maxhollmann)
🔥 hotfix EOmaps v3.4.1
- fix issues with delayed WebMap services on multiple maps in one figure
- fix issues with
m.all
for multiple maps in one figure
EOmaps v3.4
A release that brings a lot of updates on speed and memory management and some very nice (but possibly breaking) changes compared previous versions of EOmaps.
❗ IMPORTANT CHANGES ❗
⭐ Starting with EOmaps v3.4 all callbacks and colorbars are layer-specific !
This means that callbacks only trigger if the layer of the associated Maps
object is visible!
(...and colorbars are only visible if the associated layer is visible)
-
To trigger callbacks or add features & datasets independent of the visible layer, use
m.all.cb. ...
(or attach them to aMaps
object on the"all"
layer) -
Note:
pick
callbacks now always react to the visible collection!
(except for the ones on the"all"
layer)m = Maps(layer=0) m.cb.click.attach.annotate() # this callback is ONLY executed if the layer 0 is visible m1 = m.new_layer(layer=1) m1.cb.click.attach.mark() # this callback is ONLY executed if the layer 1 is visible m.all.cb.click.attach.annotate() # this callback is executed independent of the visible layer!
🍃 removed arguments
- the obsolete
"orientation"
argument has been removed fromMaps(...)
(it set the colorbar-orientation which is now specified viam.add_colorbar(orientation=...)
🌳 NEW
- ⭐
m.show()
can be used to make the associated layer visible. (a shortcut form.show_layer(m.layer)
- ⭐
m.BM.on_layer(...)
can be used to trigger functions if the visible layer changes. - 🌟 WebMap layers are now lazily evaluated and only added to the map if the corresponding layer is actually visible.
- 🌟 [experimental feature] memory-mapping can now be used to avoid using up a lot of ram for very large datasets
- Intermediate datasets are stored as memory-mapped files in a temp-folder on disk to release memory
- By default memory-mapping is disabled! (to activate it, use:
m.plot_map(memmap=False)
)
🌦️ changes
- Adding data from files (e.g.
m.from_file
orm.new_layer_from_file
) now always uses"shade_raster"
as the default plot-shape (since EOmaps v3.3.2, raster-shading works perfectly fine with re-projected rasters as well) - If a file with >2M data-points is plotted, only "shade" shapes are attempted by default to avoid overloading memory.
- only one colorbar is allowed for
Maps
objects (use multiple objects for multiple colorbars)
🔨 fixes
- Fix several issues with memory-leaks and garbage-collection of objects
- Fix autoscale_fraction not recognized when using
preset="bw"
inm.add_scalebar
- Maps objects are now properly garbage-collected
- Fix auto-scaling of scalebars for very small scales
Maps.from_file
now properly handlespathlib.Path
objects- Fix utility widget start-layer should be the currently visible layer
- Fix pick-events should only identify points on visible layers
- Fix
m.add_colorbar(log=True)
for horizontal colorbars - Fix colorbar limit autoscaling
- Fix logo size changes on zoom
- Remove obsolete
layer
kwarg fromm.add_logo
- Fix incorrect color-normalization for
shade_raster
orshade_points
ifvmin/vmax
outside the data-range are used
(thanks to @maxhollmann)
EOmaps v3.3.2
A minor bugfix release that brings some nice updates for raster-shading!
🌳 NEW
- ⭐ Raster-shading with
m.set_shape.shade_raster()
can now finally be used with re-projected datasets as well!- The previous limitation
plot_crs == data_crs
is now gone for good 🥳
- The previous limitation
🔨 fixes
- fix issues for
m.util.layer_slider
when switching between xyz-WebMap layers if axis-extent changed - fix glitches of dynamic artists during pan/zoom
- fix image parsing in github-pages jekyll parser
EOmaps v3.3.1
A minor bugfix release (that also brings some miscellaneous convenience functions)
🌳 NEW
(⭐: new feature, 🍃: new functionality for existing feature)
- ⭐ there's a new function
m.subplots_adjust()
forMaps
andMapsGrid
objects to quickly set the margins of the plots as well as the horizontal and vertical spacing between subplots:m = Maps() m.subplots_adjust(left=0.2, right=0.8, top=0.9, bottom=0.1)
(these are just shortcuts formg = MapsGrid() mg.subplots_adjust(left=0.2, right=0.8, top=0.9, bottom=0.1, hspace=0.05, wspace=0.15)
m.figure.gridspec.update()
+m.redraw()
) - 🍃
m.add_colorbar
now has an additional kwarglog=True/False
to make the y-axis of the histogram logarithmic. - 🍃
m.add_scalebar
now provides style-presets viapreset="<preset-name>"
- at the moment there's only 1 preset... more to come in future releases!
"bw"
: a simple black-and-white style without a background
🔨 fixes
- fix
m.savefig
with different dpi-settings requres a re-draw - fix
m.plot_map
withdynamic=True
does not require a update - incorporated some updates to ensure that layers are only re-drawn if necessary
- make sure cached backgrounds are always re-drawn if new artists are added
- fix annotation in example 9 (still used old syntax)
EOmaps v3.3
A release with some nice new features and a lot of usability updates and fixes.
❗ note that there is a breaking change compared to <v3.2 (only affecting the ambiguous "layer" kwarg of dynamic artists (see 🌦️ changes below for details) )
🌳 NEW
(⭐: new feature, 🍃: new functionalities for existing features)
- ⭐ There's a new pre-defined WebMap service:
m.add_wms.GEBCO
that provides nice underwater topography (https://www.gebco.net/) - ⭐ Theres a new function
m.redraw()
that can be used to force a re-draw of the entire figure - ⭐ shortcuts for
mg.redraw
andmg.util
have been added toMapsGrid
- 🍃
m.add_wms. ... <layer>.set_extent_to_bbox()
now supports a new kwargshrink
which can be used to set the extent to a "shrinked" bbox (useful to avoid request-errors for tiles outside the bbox) - 🍃
m.add_colorbar
can now be used to add individual colorbars for different plot-layers
(the colorbars will always reflect the currently displayed layer) - 🍃the
peek_layer
callback can now be used to either view one (or more) layers or to overlay one (or more) layers on top of the current background layer. - 🍃 some major improvements have been implemented for fetching WebTiles from xyz-TileServer links.
m.add_wms.get_service
now supports using customwms
,wmts
,restAPI
orxyz
services
🌦️ changes
- the ambiguous (and misleading)
layer
kwarg has finally been removed from dynamic artists.
(note this "layer" was NOT referring to the actual plot-layer but to the stacking of dynamic artists!)layer
now always refers to the background layer name and not to the stack-order of dynamic artists!- ❗ the plot-order of multiple artists on the same layer is now determined by matplotlib's
zorder
property.
- ❕ old:m.cb.click.attach.mark(layer=5)
➡️ new:m.cb.click.attach.mark(zorder=5)
- ❕ old:m.cb.click.attach.annotate(layer=5)
➡️ new:m.cb.click.attach.annotate(zorder=5)
- ❕ old:m.BM.add_artist(art, layer=5)
➡️ new:m.BM.add_artist(art)
+art.set_zorder(5)
- all examples have been updated accordingly
🔨 fixes
- fix _onrelease() missing 1 required positional argument
- fix issues with
nbagg
andipympl
backends (e.g. jupyter notebooks) - fix
plt.show
should only be called if we're in an interactive backend! - fix some issues with the scalebar and colorbar
- re-work of
draggable_axes
- fix maxzoom for stamen_watercolor layer
EOmaps v3.2
A release with some nice new features and a lot of fixes & improvements.
... Note: many parts of the 📚 documentation have been updated with small code-examples and images!
🌳 New
- ⭐
m.add_annotation
andm.add_marker
now support adding multiple objects in one go! - ⭐ raster-shading with datashader now supports 2D arrays for values and coordinates (e.g. curvilinear QuadMeshes)
- ⭐ there's a new function
m.show_layer(name)
that provides a shortcut for switching the currently displayed layer - ⭐ layer-names can now be arbitrary strings! (e.g.
Maps(layer=...)
orm.plot_map(layer=...)
)- ❗ The layer-name
"all"
, has a special meaning: all features on this layer will be visible in ALL other layers!
- ❗ The layer-name
⭐ 🦜 Utility widgets !
EOmaps now has a slot for utility widgets that provides some nice tools to simplify common tasks.
- Utilities are accessible via
m.util.<...>
At the moment, there are 2 utilities that simplify switching between layers:
- ⭐
m.util.layer_selector()
: get a "legend-like" object with buttons that can be used to switch between layers - ⭐
m.util.layer_slider()
: get a slider that can be used to switch between layers
Checkout the 🦜 Utility widgets section in the docs and the updated example: 🛰 WebMap services and layer-switching
⭐🌈 Updates for the scalebar
The scalebar has been re-worked for a much improved "out-of-the-box" usability.
- By default, the scalebar is now automatically re-scaled on pan/zoom events based on the current extent of the map.
- the new
autoscale_fraction
argument can be used to set the relative size of the (autoscaled) scalebar - the new
auto_position
argument can be used to set the position targeted for automatic re-positioning on pan/zoom events.
- the new
- The background patch is now automatically scaled to enclose the labels.
- When dragging the scalebar with the mouse, it is now immediately released if you release the mouse-button.
m.add_scalebar() # get a scalebar that autoscales itself on pan/zoom events
m.add_scaleblar(scale=10000) # get a scalebar with a fixed segment-separation of 10km
🌦️ changes
- some changes to
m.new_layer
:- It now supports the additional
layer
kwarg - ❗ By default ONLY the "plot-shape" is now copied to the new layer.
- this avoids side-effects from unintentional copying of plot-specs (
vmin
vmax
etc.) - you can still copy plot-specs by using
m.new_layer(copy_plot_specs=True)
- this avoids side-effects from unintentional copying of plot-specs (
- It now supports the additional
Maps.from_file
andMaps.read_file
andm.new_layer_from_file
now support using already opened NetCDF and GeoTIFF files
⚙️ fixes
- fix treatment of colorbar orientation in
m.figure.set_colorbar_position
- fix reprojection of wms-layers with a native crs specified as "EPSG:3857"
- fix sorting of layer-names
- avoid identification of pixel-ID if no pick-callback is attached
- fix label-axis should not respond to navigation events
- fix adding multiple markers in one go
- fallback to WSG84 boundary in
wms_layer.set_bbox_to_extent()