Skip to content

Commit

Permalink
Add WindBarbs to Matplotlib Backend (#651)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrew Huang <ahuang@Andrews-MacBook-Pro.local>
  • Loading branch information
ahuang11 and Andrew Huang committed Jul 6, 2023
1 parent 118568e commit f114de0
Show file tree
Hide file tree
Showing 13 changed files with 520 additions and 9 deletions.
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)

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

0 comments on commit f114de0

Please sign in to comment.