Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
1 change: 1 addition & 0 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@
'reference/xarray/line': 'ref/api/manual/hvplot.hvPlot.line',
'reference/xarray/quadmesh': 'ref/api/manual/hvplot.hvPlot.quadmesh',
'reference/xarray/rgb': 'ref/api/manual/hvplot.hvPlot.rgb',
'reference/xarray/barbs': 'ref/api/manual/hvplot.hvPlot.barbs',
'reference/xarray/vectorfield': 'ref/api/manual/hvplot.hvPlot.vectorfield',
'reference/xarray/violin': 'ref/api/manual/hvplot.hvPlot.violin',
# When the pandas section was renamed tabular:
Expand Down
79 changes: 79 additions & 0 deletions doc/gallery/gridded/barbs.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "c73d803c-a005-496f-9812-7eb414ce6449",
"metadata": {},
"source": [
"# Wind Barbs\n",
"\n",
"A wind barbs plot showing wind speed and direction using meteorological wind barb symbols.\n",
"\n",
":::{note}\n",
"Wind barb plots require `geoviews` to be installed.\n",
":::"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ac5ea091-6484-4fc8-9852-d48acd90cc74",
"metadata": {},
"outputs": [],
"source": [
"import hvplot.xarray # noqa\n",
"import numpy as np\n",
"import xarray as xr\n",
"\n",
"def sample_wind_data(shape=(20, 30)):\n",
" x = np.linspace(311.9, 391.1, shape[1])\n",
" y = np.linspace(-23.6, 24.8, shape[0])\n",
" x2d, y2d = np.meshgrid(x, y)\n",
" u = 10 * (2 * np.cos(2 * np.deg2rad(x2d) + 3 * np.deg2rad(y2d + 30)) ** 2)\n",
" v = 20 * np.cos(6 * np.deg2rad(x2d))\n",
" return x, y, u, v\n",
"\n",
"xs, ys, U, V = sample_wind_data()\n",
"# Calculate magnitude and angle for wind barbs\n",
"mag = np.sqrt(U**2 + V**2)\n",
"angle = (np.pi/2.) - np.arctan2(U/mag, V/mag)\n",
"\n",
"ds = xr.Dataset({\n",
" 'speed': xr.DataArray(mag, dims=('y', 'x'), coords={'y': ys, 'x': xs}),\n",
" 'angle': xr.DataArray(angle, dims=('y', 'x'), coords={'y': ys, 'x': xs})\n",
"})\n",
"\n",
"ds.hvplot.barbs(\n",
" x='x',\n",
" y='y',\n",
" angle='angle',\n",
" mag='speed',\n",
" color='speed',\n",
" cmap='viridis',\n",
" colorbar=True,\n",
" title='Wind Barbs Plot',\n",
" width=700,\n",
" height=400\n",
").opts(magnitude='speed')"
]
},
{
"cell_type": "markdown",
"id": "4f0cd955-3e03-42a5-b581-f828036e1716",
"metadata": {},
"source": [
":::{seealso}\n",
"- [Wind Barbs reference documentation](../../ref/api/manual/hvplot.hvPlot.barbs.ipynb).\n",
":::"
]
}
],
"metadata": {
"language_info": {
"name": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
2 changes: 2 additions & 0 deletions doc/ref/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ This section documents all the plotting methods of the `hvPlot` class, which as

hvPlot.area
hvPlot.bar
hvPlot.barbs
hvPlot.barh
hvPlot.box
hvPlot.bivariate
Expand Down Expand Up @@ -123,6 +124,7 @@ hvPlot's structure is based on Pandas' plotting API and as such provides special

hvplot.hvPlot.area <manual/hvplot.hvPlot.area>
hvplot.hvPlot.bar <manual/hvplot.hvPlot.bar>
hvplot.hvPlot.barbs <manual/hvplot.hvPlot.barbs>
hvplot.hvPlot.barh <manual/hvplot.hvPlot.barh>
hvplot.hvPlot.box <manual/hvplot.hvPlot.box>
hvplot.hvPlot.bivariate <manual/hvplot.hvPlot.bivariate>
Expand Down
157 changes: 157 additions & 0 deletions doc/ref/api/manual/hvplot.hvPlot.barbs.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# hvPlot.barbs\n",
"\n",
"```{eval-rst}\n",
".. currentmodule:: hvplot\n",
"\n",
".. automethod:: hvPlot.barbs\n",
"```\n",
"\n",
":::{note}\n",
"Wind barb plots require `geoviews` to be installed.\n",
":::\n",
"\n",
"## Backend-specific styling options\n",
"\n",
"```{eval-rst}\n",
".. backend-styling-options:: barbs\n",
"```\n",
"\n",
"## Examples\n",
"\n",
"### Basic wind barbs plot\n",
"\n",
"In this example we create a simple DataFrame with 4 columns `x`, `y`, `angle` and `speed`. `x` and `y` represent the location of the wind barbs. `angle` defines the wind direction expressed in radians (meteorological convention: direction FROM which the wind is blowing, with 0 being North). `speed` defines the wind speed magnitude."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import hvplot.pandas\n",
"import pandas as pd\n",
"import numpy as np\n",
"\n",
"df = pd.DataFrame(dict(\n",
" x=[0, -1, 0, 1, 0, 1, 1, -1, -1],\n",
" y=[0, 0, -1, 0, 1, 1, -1, -1, 1],\n",
" angle=[0, 0, np.pi/2, np.pi, 3*np.pi/2, np.pi/4, np.pi/3, np.pi/6, np.pi/8],\n",
" speed=[0, 5, 10, 15, 20, 50, 75, 100, 150],\n",
"))\n",
"\n",
"df.hvplot.barbs(\n",
" x=\"x\", y=\"y\", angle=\"angle\", mag=\"speed\",\n",
" data_aspect=1, padding=0.2, width=400, height=400,\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Xarray example\n",
"\n",
"In this example we show how to create a barb plot using Xarray data with hvPlot."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import hvplot.xarray # noqa\n",
"import numpy as np\n",
"import xarray as xr\n",
"\n",
"def sample_wind_data(shape=(20, 30)):\n",
" x = np.linspace(311.9, 391.1, shape[1])\n",
" y = np.linspace(-23.6, 24.8, shape[0])\n",
" x2d, y2d = np.meshgrid(x, y)\n",
" u = 10 * (2 * np.cos(2 * np.deg2rad(x2d) + 3 * np.deg2rad(y2d + 30)) ** 2)\n",
" v = 20 * np.cos(6 * np.deg2rad(x2d))\n",
" return x, y, u, v\n",
"\n",
"xs, ys, U, V = sample_wind_data()\n",
"mag = np.sqrt(U**2 + V**2)\n",
"angle = (np.pi/2.) - np.arctan2(U/mag, V/mag)\n",
"ds = xr.Dataset({\n",
" 'speed': xr.DataArray(mag, dims=('y', 'x'), coords={'y': ys, 'x': xs}),\n",
" 'angle': xr.DataArray(angle, dims=('y', 'x'), coords={'y': ys, 'x': xs})\n",
"})\n",
"\n",
"ds.hvplot.barbs(\n",
" x='x', y='y', angle='angle', mag='speed',\n",
" width=700, height=400, scale=0.3\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Geographic example with Xarray\n",
"\n",
"The `xarray.Dataset` constructed in this example has a `'crs'` key in its `attrs` dictionary, which lets us simply set `geo=True` to turn this plot into a correctly projected geographic plot overlaid on web map tiles."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import cartopy.crs as ccrs\n",
"import hvplot.xarray # noqa\n",
"import numpy as np\n",
"import xarray as xr\n",
"\n",
"def sample_data(shape=(20, 30)):\n",
" \"\"\"\n",
" Return ``(x, y, u, v, crs)`` of some vector data computed mathematically.\n",
" The returned crs will be a rotated pole CRS, meaning that the vectors\n",
" will be unevenly spaced in regular PlateCarree space.\n",
" \"\"\"\n",
" crs = ccrs.RotatedPole(pole_longitude=177.5, pole_latitude=37.5)\n",
"\n",
" x = np.linspace(311.9, 391.1, shape[1])\n",
" y = np.linspace(-23.6, 24.8, shape[0])\n",
" x2d, y2d = np.meshgrid(x, y)\n",
" u = 10 * (2 * np.cos(2 * np.deg2rad(x2d) + 3 * np.deg2rad(y2d + 30)) ** 2)\n",
" v = 20 * np.cos(6 * np.deg2rad(x2d))\n",
" return x, y, u, v, crs\n",
"\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",
"ds = xr.Dataset(\n",
" {\n",
" 'speed': xr.DataArray(mag, dims=('y', 'x'), coords={'y': ys, 'x': xs}),\n",
" 'angle': xr.DataArray(angle, dims=('y', 'x'), coords={'y': ys, 'x': xs})\n",
" },\n",
" attrs={'crs': crs},\n",
")\n",
"\n",
"ds.hvplot.barbs(\n",
" x=\"x\", y=\"y\", angle=\"angle\", mag=\"speed\",\n",
" geo=True, tiles=\"CartoLight\", width=700, height=400\n",
").opts(\"WindBarbs\", scale=0.3)"
]
}
],
"metadata": {
"language_info": {
"name": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
36 changes: 33 additions & 3 deletions hvplot/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@
)
from .utilities import hvplot_extension

try:
from geoviews import WindBarbs
except ImportError:
WindBarbs = None

renderer = hv.renderer('bokeh')


Expand Down Expand Up @@ -574,7 +579,9 @@ class HoloViewsConverter:
_geom_types = ['paths', 'polygons']

_geo_types = sorted(
_gridded_types + _geom_types + ['points', 'vectorfield', 'labels', 'hexbin', 'bivariate']
_gridded_types
+ _geom_types
+ ['points', 'barbs', 'vectorfield', 'labels', 'hexbin', 'bivariate']
)

_stats_types = ['hist', 'kde', 'violin', 'box', 'density']
Expand Down Expand Up @@ -647,8 +654,6 @@ class HoloViewsConverter:
'yformatter',
'xlabel',
'ylabel',
'xlim',
'ylim',
'xticks',
'yticks',
'cticks',
Expand Down Expand Up @@ -745,6 +750,7 @@ class HoloViewsConverter:
'area': ['x', 'y', 'y2', 'stacked'],
'bar': ['x', 'y', 'stacked'],
'barh': ['x', 'y', 'stacked'],
'barbs': ['x', 'y', 'angle', 'mag', 'scale'],
'box': ['x', 'y'],
'errorbars': ['x', 'y', 'yerr1', 'yerr2'],
'bivariate': ['x', 'y', 'bandwidth', 'cut', 'filled', 'levels'],
Expand Down Expand Up @@ -777,6 +783,7 @@ class HoloViewsConverter:
'area': Area,
'bar': Bars,
'barh': Bars,
'barbs': WindBarbs,
'bivariate': Bivariate,
'box': BoxWhisker,
'contour': Contours,
Expand Down Expand Up @@ -3275,6 +3282,29 @@ def contourf(self, x=None, y=None, z=None, data=None):
else:
return contourf

def barbs(self, x=None, y=None, angle=None, mag=None, data=None):
self._error_if_unavailable('barbs')
data, x, y, _ = self._process_gridded_args(data, x, y, z=None)

if not (x and y):
x, y = list(k for k, v in data.coords.items() if v.size > 1)

angle = self.kwds.get('angle')
mag = self.kwds.get('mag')
z = [angle, mag] + self.hover_cols
redim = self._merge_redim({z[1]: self._dim_ranges['c']})
params = dict(self._relabel)

element = self._get_element('barbs')
cur_opts, compat_opts = self._get_compat_opts('WindBarbs')
if self.geo:
params['crs'] = self.crs

return redim_(
element(data, [x, y], z, **params),
**redim,
).apply(self._set_backends_opts, cur_opts=cur_opts, compat_opts=compat_opts)

def vectorfield(self, x=None, y=None, angle=None, mag=None, data=None):
self._error_if_unavailable('vectorfield')
data, x, y, _ = self._process_gridded_args(data, x, y, z=None)
Expand Down
Loading
Loading