Visualization¶
Plotting helpers for covariance ellipse fields. matplotlib is an optional
dependency: pip install 'psyphy[viz]'.
See the plotting guide for worked examples.
ellipses
¶
ellipses¶
Matplotlib drawing for fields of 2-D covariance ellipses.
matplotlib is an optional dependency (pip install psyphy[viz]) and is
imported inside the functions here, so importing psyphy never pulls it in.
The geometry these functions draw lives in :mod:psyphy.viz.geometry and needs
no plotting backend at all.
Functions:
| Name | Description |
|---|---|
plot_ellipses |
Draw one or more fields of 2-D covariance ellipses. |
plot_ellipses
¶
plot_ellipses(centers: ndarray, covs: Any, *, ax: Any = None, scale: float | str = 1.0, colors: Any = None, labels: Any = None, linestyles: Any = None, linewidths: Any = None, alpha: Any = None, show_centers: bool = False, skip_non_pd: bool = True, return_scale: bool = False, n_points: int = 100) -> Any
Draw one or more fields of 2-D covariance ellipses.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
centers
|
(array_like, shape(n_points, 2))
|
Ellipse centers, shared by every field. |
required |
covs
|
array_like or list
|
The covariances to draw, in any of three spellings:
|
required |
ax
|
Axes
|
Axes to draw into. A new figure and axes are created when omitted. Nothing is ever saved or shown; the caller owns the figure. |
None
|
scale
|
float or 'auto'
|
Multiplies every semi-axis. |
1.0
|
colors
|
color or array or list
|
A matplotlib color applied to a whole field, or an |
None
|
labels
|
str or list of str
|
Legend entries, one per field. A legend is drawn only if any is given. |
None
|
linestyles
|
optional
|
Per-field line styling, broadcast the same way as |
None
|
linewidths
|
optional
|
Per-field line styling, broadcast the same way as |
None
|
alpha
|
optional
|
Per-field line styling, broadcast the same way as |
None
|
show_centers
|
bool
|
Also scatter the center points. |
False
|
skip_non_pd
|
bool
|
Skip non-positive-definite covariances (and warn, naming the count) rather than raising. |
True
|
return_scale
|
bool
|
Also return the scale factor actually used -- worth doing with
|
False
|
n_points
|
int
|
Vertices per ellipse. |
100
|
Returns:
| Type | Description |
|---|---|
matplotlib.axes.Axes, or (Axes, float) when ``return_scale=True``
|
|
Examples:
One field, true size::
1 | |
Two fields overlaid, sized to the grid, reporting the factor::
1 2 3 4 5 6 7 8 9 | |
Posterior draws as an uncertainty band::
1 | |
Source code in src/psyphy/viz/ellipses.py
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | |
geometry
¶
geometry¶
Covariance-to-ellipse geometry, with no plotting dependency.
These helpers turn stacks of 2x2 covariance matrices into polyline vertices that any plotting backend can draw, and compute a magnification that makes a field of ellipses legible on its own grid. They import only numpy and scipy, both core psyphy dependencies, so they can be used (and tested) without matplotlib installed.
See :mod:psyphy.viz.ellipses for the matplotlib drawing layer.
Functions:
| Name | Description |
|---|---|
auto_scale |
Scale factor that fits a field of ellipses to its own grid. |
ellipse_segments |
Convert a field of covariances into closed polylines. |
auto_scale
¶
Scale factor that fits a field of ellipses to its own grid.
Sizes the median ellipse so its typical radius is fraction of the
median nearest-neighbour spacing between centers. This adapts to the grid
rather than assuming one: the same call gives a readable figure on a coarse
7x7 grid and on a dense 103x103 one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
centers
|
(array_like, shape(n_points, 2))
|
Ellipse centers. At least two are required, since the spacing is a nearest-neighbour distance. |
required |
covs
|
(array_like, shape(n_points, 2, 2))
|
Covariance matrix per center. |
required |
fraction
|
float
|
Target ratio of typical ellipse radius to typical center spacing. |
0.35
|
Returns:
| Type | Description |
|---|---|
float
|
Multiplier to pass as |
Notes
This is not always a magnification. On a dense grid the factor can be well below 1, shrinking ellipses so neighbours do not overlap. On the Hong et al. (2025) data it is ~1.24 for the 49-point threshold grid and ~0.22 for the 10 609-point noise grid.
Because it rescales, a figure drawn with it cannot be read for absolute
size. When comparing several fields, compute the factor once and apply
it to all of them, or relative sizes become meaningless;
:func:psyphy.viz.plot_ellipses enforces this.
Uses a KD-tree rather than a full pairwise distance matrix, which would be O(n^2) in time and memory -- negligible at n=49, about 1.8 GB at n=10 609.
Source code in src/psyphy/viz/geometry.py
ellipse_segments
¶
ellipse_segments(centers: ndarray, covs: ndarray, *, scale: float = 1.0, n_points: int = 100) -> tuple[list[ndarray], ndarray]
Convert a field of covariances into closed polylines.
Each covariance is drawn as its 1-standard-deviation ellipse,
{c + scale * L u : |u| = 1} where L is the Cholesky factor of the
covariance. The ellipse's semi-axes are therefore scale * sqrt(lambda_i)
for eigenvalues lambda_i.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
centers
|
(array_like, shape(n_points, 2))
|
Ellipse centers, typically the reference stimuli. |
required |
covs
|
(array_like, shape(n_points, 2, 2))
|
Covariance matrix per center. |
required |
scale
|
float
|
Multiplies every semi-axis. |
1.0
|
n_points
|
int
|
Vertices per ellipse. |
100
|
Returns:
| Name | Type | Description |
|---|---|---|
segments |
list of np.ndarray
|
One |
valid |
np.ndarray of bool, shape (n_points,)
|
Which covariances were positive-definite and therefore drawn. |
Notes
Non-positive-definite covariances are skipped rather than raising, because
a single bad matrix should not discard an otherwise usable field. Callers
should surface valid.sum() < len(valid) to the user rather than ignore
it -- a silently thinned field is hard to notice by eye.
Examples: