Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WindBarbs to Matplotlib Backend #651

Merged
merged 15 commits into from
Jul 6, 2023
2 changes: 1 addition & 1 deletion examples/gallery/bokeh/orthographic_vectorfield.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"\n",
"xs, ys, U, V, crs = sample_data()\n",
"mag = np.sqrt(U**2 + V**2)\n",
"angle = (np.pi/2.) - np.arctan2(U/mag, V/mag)\n",
"angle = np.pi / 2 - np.arctan2(-V, -U)\n",
"vectorfield = gv.VectorField((xs, ys, angle, mag), crs=crs)"
]
},
Expand Down
2 changes: 1 addition & 1 deletion examples/gallery/bokeh/vectorfield_example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"\n",
"xs, ys, U, V, crs = sample_data()\n",
"mag = np.sqrt(U**2 + V**2)\n",
"angle = (np.pi/2.) - np.arctan2(U/mag, V/mag)\n",
"angle = np.pi / 2 - np.arctan2(-V, -U)\n",
"tiles = gv.tile_sources.OSM\n",
"vectorfield = gv.VectorField((xs, ys, angle, mag), crs=crs)"
]
Expand Down
2 changes: 1 addition & 1 deletion examples/gallery/matplotlib/orthographic_vectorfield.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"\n",
"xs, ys, U, V, crs = sample_data()\n",
"mag = np.sqrt(U**2 + V**2)\n",
"angle = (np.pi/2.) - np.arctan2(U/mag, V/mag)\n",
"angle = np.pi / 2 - np.arctan2(-V, -U)\n",
"vectorfield = gv.VectorField((xs, ys, angle, mag), crs=crs)"
]
},
Expand Down
2 changes: 1 addition & 1 deletion examples/gallery/matplotlib/vectorfield_example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"\n",
"xs, ys, U, V, crs = sample_data()\n",
"mag = np.sqrt(U**2 + V**2)\n",
"angle = (np.pi/2.) - np.arctan2(U/mag, V/mag)\n",
"angle = np.pi / 2 - np.arctan2(-V, -U)\n",
"tiles = gv.tile_sources.OSM\n",
"vectorfield = gv.VectorField((xs, ys, angle, mag), crs=crs)"
]
Expand Down
90 changes: 90 additions & 0 deletions examples/gallery/matplotlib/wind_barbs_example.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import geoviews as gv\n",
"\n",
"gv.extension('matplotlib')\n",
"\n",
"gv.output(fig='svg', size=200)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Define data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"lat = np.arange(60, 37.5, -2.5)\n",
"lon = np.arange(270, 292.5, 2.5)\n",
"uwnd = np.array(\n",
" [\n",
" [2, 0, -2, -2, -3, -3, -3, -2, -1],\n",
" [2, 0, -2, -2, -2, -2, -2, -1, 1],\n",
" [2, -1, -2, -2, -2, -1, 0, 1, 3],\n",
" [3, 0, -3, -5, -5, -4, -4, -2, 0],\n",
" [8, 4, 0, -3, -5, -6, -6, -6, -5],\n",
" [12, 10, 8, 5, 3, 0, -2, -2, -2],\n",
" [13, 14, 16, 16, 14, 12, 10, 9, 10],\n",
" [13, 18, 22, 24, 25, 24, 23, 22, 23],\n",
" [20, 25, 29, 32, 33, 32, 32, 33, 34],\n",
" ]\n",
")\n",
"vwwnd = np.array(\n",
" [\n",
" [3, 1, 0, -1, -1, 0, 1, 3, 4],\n",
" [-2, -3, -3, -2, 0, 2, 4, 6, 8],\n",
" [-6, -6, -4, -1, 2, 5, 7, 10, 12],\n",
" [-12, -10, -6, -1, 4, 7, 10, 12, 14],\n",
" [-17, -15, -10, -4, 2, 6, 9, 12, 16],\n",
" [-20, -18, -14, -8, -2, 2, 5, 10, 16],\n",
" [-17, -16, -13, -9, -6, -3, 1, 7, 15],\n",
" [-11, -10, -8, -6, -6, -5, -2, 6, 15],\n",
" [-5, -3, -2, -2, -4, -5, -2, 6, 15],\n",
" ]\n",
")\n",
"\n",
"wind_barbs = gv.WindBarbs.from_uv((lon, lat, uwnd, vwwnd)).opts(\n",
" fig_size=250, length=6.5, padding=1\n",
")\n",
"coastline = gv.feature.coastline()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plot"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"wind_barbs * coastline"
]
}
],
"metadata": {
"language_info": {
"name": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
2 changes: 1 addition & 1 deletion geoviews/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
_Element, Feature, Tiles, WMTS, LineContours, FilledContours,
Text, Image, Points, Path, Polygons, Shape, Dataset, RGB,
Contours, Graph, TriMesh, Nodes, EdgePaths, QuadMesh, VectorField,
HexTiles, Labels, Rectangles, Segments
HexTiles, Labels, Rectangles, Segments, WindBarbs
)
from .util import load_tiff, from_xarray # noqa (API import)
from .operation import project # noqa (API import)
Expand Down
2 changes: 1 addition & 1 deletion geoviews/element/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
WMTS, Points, Image, Text, LineContours, RGB,
FilledContours, Path, Polygons, Shape, Dataset,
Contours, TriMesh, Graph, Nodes, EdgePaths, QuadMesh,
VectorField, Labels, HexTiles, Rectangles, Segments)
VectorField, Labels, HexTiles, Rectangles, Segments, WindBarbs)


class GeoConversion(ElementConversion):
Expand Down
3 changes: 2 additions & 1 deletion geoviews/element/comparison.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from holoviews.element.comparison import Comparison as HvComparison

from .geo import Image, Points, LineContours, FilledContours
from .geo import Image, Points, LineContours, FilledContours, WindBarbs

class Comparison(HvComparison):

Expand All @@ -13,6 +13,7 @@ def register(cls):
cls.equality_type_funcs[Points] = cls.compare_dataset
cls.equality_type_funcs[LineContours] = cls.compare_dataset
cls.equality_type_funcs[FilledContours] = cls.compare_dataset
cls.equality_type_funcs[WindBarbs] = cls.compare_dataset
return cls.equality_type_funcs


Expand Down
40 changes: 39 additions & 1 deletion geoviews/element/geo.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
QuadMesh as HvQuadMesh, Points as HvPoints,
VectorField as HvVectorField, HexTiles as HvHexTiles,
Labels as HvLabels, Rectangles as HvRectangles,
Segments as HvSegments
Segments as HvSegments, Geometry as HvGeometry,
)
from holoviews.element.selection import Selection2DExpr


from shapely.geometry.base import BaseGeometry
from shapely.geometry import (
Expand Down Expand Up @@ -340,6 +342,42 @@ class VectorField(_Element, HvVectorField):
Dimension('Magnitude')], bounds=(1, None))


class WindBarbs(_Element, Selection2DExpr, HvGeometry):
"""
"""

group = param.String(default='WindBarbs', constant=True)

vdims = param.List(default=[Dimension('Angle', cyclic=True, range=(0,2*np.pi)),
Dimension('Magnitude')], bounds=(2, None))

@classmethod
def from_uv(cls, data, kdims=None, vdims=None, **params):
if isinstance(data, tuple):
xs, ys, us, vs = data
else:
us = data[vdims[0]]
vs = data[vdims[1]]

uv_magnitudes = np.hypot(us, vs) # unscaled
radians = np.pi / 2 - np.arctan2(-vs, -us)
ahuang11 marked this conversation as resolved.
Show resolved Hide resolved

if isinstance(data, tuple):
reorganized_data = (xs, ys, radians, uv_magnitudes)
else:
# calculations on this data could mutate the original data
# here we do not do any calculations; we only store the data
reorganized_data = {}
for kdim in kdims:
reorganized_data[kdim] = data[kdim]
reorganized_data["Angle"] = radians
reorganized_data["Magnitude"] = uv_magnitudes
for vdim in vdims[2:]:
reorganized_data[vdim] = data[vdim]
vdims = ["Angle", "Magnitude"] + vdims[2:]
return cls(reorganized_data, kdims=kdims, vdims=vdims, **params)


class Image(_Element, HvImage):
"""
Image represents a 2D array of some quantity with
Expand Down
14 changes: 13 additions & 1 deletion geoviews/plotting/mpl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
Image, Points, Feature, WMTS, Tiles, Text, LineContours,
FilledContours, is_geographic, Path, Polygons, Shape, RGB,
Contours, Nodes, EdgePaths, Graph, TriMesh, QuadMesh, VectorField,
HexTiles, Labels, Rectangles, Segments
HexTiles, Labels, Rectangles, Segments, WindBarbs
)
from ...util import geo_mesh, poly_types
from ..plot import ProjectionPlot
Expand All @@ -39,6 +39,7 @@
project_points, project_path, project_graph, project_quadmesh,
project_geom
)
from .chart import WindBarbsPlot



Expand Down Expand Up @@ -327,6 +328,16 @@ class GeoVectorFieldPlot(GeoPlot, VectorFieldPlot):
_project_operation = project_points


class GeoWindBarbsPlot(GeoPlot, WindBarbsPlot):
"""
Draws a wind barbs plot from the data in a WindBarbs Element.
"""

apply_ranges = param.Boolean(default=True)

_project_operation = project_points


class GeometryPlot(GeoPlot):

def init_artists(self, ax, plot_args, plot_kwargs):
Expand Down Expand Up @@ -567,6 +578,7 @@ def draw_annotation(self, axis, data, crs, opts):
Points: GeoPointPlot,
Labels: GeoLabelsPlot,
VectorField: GeoVectorFieldPlot,
WindBarbs: GeoWindBarbsPlot,
Text: GeoTextPlot,
Layout: LayoutPlot,
NdLayout: LayoutPlot,
Expand Down
Loading