Skip to content

Commit 8e0b59c

Browse files
committed
Add QuiverItem for 2D vector field plots (closes #54)
New plot item displaying arrows at grid positions, similar to Matplotlib's quiver: - QuiverItem class (plotpy/items/quiver.py) with configurable arrow scale, head size, color, and auto-meshgrid from 1D inputs - Builder method make.quiver() and interactive plt.quiver() - Integrated with plot autoscale (initial zoom + middle-click reset) - Item icon for the item list widget - Test and release notes for v2.9.0
1 parent 5a449a4 commit 8e0b59c

File tree

15 files changed

+736
-14
lines changed

15 files changed

+736
-14
lines changed

doc/features/items/overview.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ The following image items are available:
4141
* :py:func:`.get_plot_qrect`
4242
* :py:func:`.get_image_from_plot`
4343

44+
Flow fields
45+
^^^^^^^^^^^
46+
47+
The following flow field items are available:
48+
49+
* :py:class:`.QuiverItem`: a flow field item with arrows
50+
4451
Grid
4552
^^^^
4653

doc/features/items/reference.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ Histograms
7171
.. autoclass:: plotpy.items.Histogram2DItem
7272
:members:
7373

74+
Flow fields
75+
^^^^^^^^^^^
76+
77+
.. autoclass:: plotpy.items.QuiverItem
78+
:members:
79+
7480
Grid
7581
^^^^
7682

doc/release_notes/release_2.09.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Version 2.9 #
2+
3+
## PlotPy Version 2.9.0 ##
4+
5+
💥 New features:
6+
7+
* Added `QuiverItem` for displaying 2D vector fields (quiver plots), similar to
8+
Matplotlib's `quiver`. This closes
9+
[Issue #54](https://github.com/PlotPyStack/PlotPy/issues/54):
10+
* New `QuiverItem` plot item class supporting X, Y, U, V arrays (1D or 2D)
11+
* Auto-meshgrid expansion when X, Y are 1D and U, V are 2D
12+
* Configurable arrow scale, head size, and color
13+
* New `make.quiver()` builder method for easy item creation
14+
* New `quiver()` function in the interactive plotting interface (`plotpy.pyplot`)
15+
* Integrated with plot autoscale (initial zoom and middle-click reset)
16+
* Item icon displayed in the item list widget

plotpy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
.. _GitHub: https://github.com/PierreRaybaut/plotpy
2121
"""
2222

23-
__version__ = "2.8.4"
23+
__version__ = "2.9.0"
2424
__VERSION__ = tuple([int(number) for number in __version__.split(".")])
2525

2626
# --- Important note: DATAPATH and LOCALEPATH are used by guidata.configtools

plotpy/builder/curvemarker.py

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
# pylint: disable=C0103
77

88
"""
9-
Curve/cursor/marker Item builder
10-
--------------------------------
9+
Curve/cursor/marker/... Item builder
10+
------------------------------------
1111
1212
This module provides a set of factory functions to simplify the creation of
13-
curve, cursor and marker items.
13+
curve, cursor, marker, histogram and flow field items.
1414
"""
1515

1616
# Note: when adding method to builder classes, please do not forget to update the
@@ -32,6 +32,7 @@
3232
ErrorBarCurveItem,
3333
HistogramItem,
3434
Marker,
35+
QuiverItem,
3536
XRangeSelection,
3637
YRangeSelection,
3738
)
@@ -1023,3 +1024,70 @@ def marker(
10231024
marker.set_movable(False)
10241025
marker.set_resizable(False)
10251026
return marker
1027+
1028+
def quiver(
1029+
self,
1030+
x: numpy.ndarray,
1031+
y: numpy.ndarray,
1032+
u: numpy.ndarray,
1033+
v: numpy.ndarray,
1034+
title: str = "",
1035+
color: str | None = None,
1036+
arrow_scale: float = 30.0,
1037+
arrow_head_size: float = 6.0,
1038+
headwidth: float = 0.7,
1039+
xaxis: str = "bottom",
1040+
yaxis: str = "left",
1041+
) -> QuiverItem:
1042+
"""Make a quiver (vector field) `plot item`
1043+
1044+
Displays arrows at grid positions (x, y) with direction and magnitude
1045+
defined by (u, v) components, similar to Matplotlib's ``quiver``.
1046+
1047+
Args:
1048+
x: 1D or 2D array of arrow X positions
1049+
y: 1D or 2D array of arrow Y positions
1050+
u: 1D or 2D array of arrow X components
1051+
v: 1D or 2D array of arrow Y components
1052+
title: plot item title. Default is ''
1053+
color: arrow color name. Default is None (black)
1054+
arrow_scale: scale factor for arrow length in pixels.
1055+
Default is 30.0. Larger values produce longer arrows.
1056+
arrow_head_size: size of arrow heads in pixels.
1057+
Default is 6.0
1058+
headwidth: arrow head width as multiple of head size.
1059+
Default is 0.7
1060+
xaxis: x axis name. Default is 'bottom'
1061+
yaxis: y axis name. Default is 'left'
1062+
1063+
Returns:
1064+
:py:class:`.QuiverItem` object
1065+
1066+
Example::
1067+
1068+
import numpy as np
1069+
x = np.linspace(-2, 2, 10)
1070+
y = np.linspace(-2, 2, 10)
1071+
X, Y = np.meshgrid(x, y)
1072+
U, V = -Y, X # Rotational field
1073+
quiver(X, Y, U, V, title="Rotation", color="blue")
1074+
"""
1075+
if color is None:
1076+
color = "black"
1077+
item = QuiverItem(
1078+
x,
1079+
y,
1080+
u,
1081+
v,
1082+
color=color,
1083+
arrow_scale=arrow_scale,
1084+
arrow_head_size=arrow_head_size,
1085+
headwidth=headwidth,
1086+
)
1087+
if title:
1088+
item.setTitle(title)
1089+
else:
1090+
item.setTitle(_("Quiver"))
1091+
item.setXAxis(BasePlot.AXIS_NAMES[xaxis])
1092+
item.setYAxis(BasePlot.AXIS_NAMES[yaxis])
1093+
return item

plotpy/data/icons/items/quiver.png

148 Bytes
Loading

plotpy/io.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ def register_serializable_items(modname, classnames):
594594
"plotpy.items",
595595
[
596596
"CurveItem",
597+
"QuiverItem",
597598
"PolygonMapItem",
598599
"ErrorBarCurveItem",
599600
"RawImageItem",

plotpy/items/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
SelectedLegendBoxItem,
5656
)
5757
from .polygonmap import PolygonMapItem
58+
from .quiver import QuiverItem
5859
from .shape import (
5960
AbstractShape,
6061
Axes,

0 commit comments

Comments
 (0)