Skip to content

Commit

Permalink
interactive downsampling large vector fields
Browse files Browse the repository at this point in the history
  • Loading branch information
iuryt committed Jul 18, 2024
1 parent 51a03c8 commit ac5a86d
Showing 1 changed file with 120 additions and 1 deletion.
121 changes: 120 additions & 1 deletion doc/reference/xarray/vectorfield.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"source": [
"import numpy as np\n",
"import xarray as xr\n",
"import holoviews as hv\n",
"import cartopy.crs as ccrs"
]
},
Expand Down Expand Up @@ -113,12 +114,130 @@
"ds.hvplot.vectorfield(x='x', y='y', angle='angle', mag='mag',\n",
" hover=False, geo=True, coastline=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Large Data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The visualization of vector fields from large datasets often presents a challenge. Direct plotting methods can quickly consume excessive memory, leading to crashes or unresponsive applications. To address this issue, we introduce a dynamic downsampling technique that enables interactive exploration of vector fields without sacrificing performance. We first create a `sample_data` that contains 4,000,000 points."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"xs, ys, U, V, crs = sample_data(shape=(2000, 2000))\n",
"\n",
"mag = np.sqrt(U**2 + V**2)\n",
"angle = (np.pi/2.) - np.arctan2(U/mag, V/mag)\n",
"\n",
"ds = xr.Dataset({'mag': 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",
" attrs={'crs': crs})\n",
"ds"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we just try to call `ds.hvplot.vectorfield` this is probably returning `MemoryError`. The alternative is to dynamically downsample the data based on the visible range. This helps manage memory consumption when dealing with large datasets, especially when plotting vector fields."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def create_quiver(x_range=None, y_range=None, nmax=10):\n",
" \"\"\"\n",
" Creates a HoloViews vector field plot from a dataset, dynamically downsampling \n",
" data based on the visible range to optimize memory usage.\n",
"\n",
" Args:\n",
" x_range (tuple, optional): Range of x values to include. Defaults to None (full range).\n",
" y_range (tuple, optional): Range of y values to include. Defaults to None (full range).\n",
" nmax (int, optional): Maximum number of points along each axis after coarsening. \n",
" Defaults to 10.\n",
"\n",
" Returns:\n",
" HoloViews DynamicMap: A dynamic vector field plot that updates based on the visible range.\n",
" \"\"\"\n",
"\n",
" if x_range is None or y_range is None:\n",
" # No range provided, downsample the entire dataset for initial display\n",
" xs, ys = ds.x.size, ds.y.size # Get dataset dimensions\n",
" ix, iy = xs // nmax, ys // nmax # Calculate downsampling intervals\n",
"\n",
" ix = max(1, ix) # Ensure interval is at least 1\n",
" iy = max(1, iy)\n",
"\n",
" sub = ds.coarsen(x=ix, y=iy, side=\"center\", boundary=\"trim\").mean() # Downsample\n",
" else:\n",
" # Select data within the specified range\n",
" sub = ds.sel(x=slice(*x_range), y=slice(*y_range))\n",
"\n",
" # Downsample the selected data\n",
" xs, ys = sub.x.size, sub.y.size\n",
" ix, iy = xs // nmax, ys // nmax\n",
" ix = max(1, ix)\n",
" iy = max(1, iy)\n",
" sub = sub.coarsen(x=ix, y=iy, side=\"center\", boundary=\"trim\").mean()\n",
"\n",
" # Create the vector field plot\n",
" quiver = sub.hvplot.vectorfield(\n",
" x=\"x\",\n",
" y=\"y\",\n",
" mag=\"mag\",\n",
" angle=\"angle\",\n",
" hover=False,\n",
" ).opts(magnitude=\"mag\")\n",
"\n",
" return quiver\n",
"\n",
"\n",
"# Create interactive plot components\n",
"range_xy = hv.streams.RangeXY() # Stream to capture range changes\n",
"filtered = hv.DynamicMap(create_quiver, streams=[range_xy]) # Dynamic plot\n",
"range_xy.source = filtered # Link stream to the plot\n",
"filtered # Display the plot"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "coringa",
"language": "python",
"name": "coringa"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"pygments_lexer": "ipython3"
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.15"
}
},
"nbformat": 4,
Expand Down

0 comments on commit ac5a86d

Please sign in to comment.