Skip to content

Commit b9813ec

Browse files
committed
Curved polar errorbars
- uses _interpolation_steps - prefers transform MarkerStyle in init over _transform property - adjusted what's new
1 parent ecab6de commit b9813ec

File tree

4 files changed

+41
-9
lines changed

4 files changed

+41
-9
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fixed errorbars in polar plots
2+
------------------------------
3+
Caps and error lines are now drawn with respect to polar coordinates,
4+
when plotting errorbars on polar plots.

lib/matplotlib/axes/_axes.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3522,10 +3522,11 @@ def _upcast_err(err):
35223522
eb_cap_style['color'] = ecolor
35233523

35243524
barcols = []
3525-
caplines = []
3525+
caplines = {'x': [], 'y': []}
35263526

35273527
# Vectorized fancy-indexer.
3528-
def apply_mask(arrays, mask): return [array[mask] for array in arrays]
3528+
def apply_mask(arrays, mask):
3529+
return [array[mask] for array in arrays]
35293530

35303531
# dep: dependent dataset, indep: independent dataset
35313532
for (dep_axis, dep, err, lolims, uplims, indep, lines_func,
@@ -3556,9 +3557,12 @@ def apply_mask(arrays, mask): return [array[mask] for array in arrays]
35563557
# return dep - elow * ~lolims, dep + ehigh * ~uplims
35573558
# except that broadcast_to would strip units.
35583559
low, high = dep + np.row_stack([-(1 - lolims), 1 - uplims]) * err
3559-
35603560
barcols.append(lines_func(
35613561
*apply_mask([indep, low, high], everymask), **eb_lines_style))
3562+
if self.name == "polar" and dep_axis == "x":
3563+
for b in barcols:
3564+
for p in b.get_paths():
3565+
p._interpolation_steps = 12
35623566
# Normal errorbars for points without upper/lower limits.
35633567
nolims = ~(lolims | uplims)
35643568
if nolims.any() and capsize > 0:
@@ -3571,7 +3575,7 @@ def apply_mask(arrays, mask): return [array[mask] for array in arrays]
35713575
line = mlines.Line2D(indep_masked, indep_masked,
35723576
marker=marker, **eb_cap_style)
35733577
line.set(**{f"{dep_axis}data": lh_masked})
3574-
caplines.append(line)
3578+
caplines[dep_axis].append(line)
35753579
for idx, (lims, hl) in enumerate([(lolims, high), (uplims, low)]):
35763580
if not lims.any():
35773581
continue
@@ -3585,15 +3589,29 @@ def apply_mask(arrays, mask): return [array[mask] for array in arrays]
35853589
line = mlines.Line2D(x_masked, y_masked,
35863590
marker=hlmarker, **eb_cap_style)
35873591
line.set(**{f"{dep_axis}data": hl_masked})
3588-
caplines.append(line)
3592+
caplines[dep_axis].append(line)
35893593
if capsize > 0:
3590-
caplines.append(mlines.Line2D(
3594+
caplines[dep_axis].append(mlines.Line2D(
35913595
x_masked, y_masked, marker=marker, **eb_cap_style))
3592-
3593-
for l in caplines:
3594-
self.add_line(l)
3596+
if self.name == 'polar':
3597+
for axis in caplines:
3598+
for l in caplines[axis]:
3599+
# Rotate caps to be perpendicular to the error bars
3600+
for theta, r in zip(l.get_xdata(), l.get_ydata()):
3601+
rotation = mtransforms.Affine2D().rotate(theta)
3602+
if axis == 'y':
3603+
rotation.rotate(-np.pi / 2)
3604+
ms = mmarkers.MarkerStyle(marker=marker,
3605+
transform=rotation)
3606+
self.add_line(mlines.Line2D([theta], [r], marker=ms,
3607+
**eb_cap_style))
3608+
else:
3609+
for axis in caplines:
3610+
for l in caplines[axis]:
3611+
self.add_line(l)
35953612

35963613
self._request_autoscale_view()
3614+
caplines = caplines['x'] + caplines['y']
35973615
errorbar_container = ErrorbarContainer(
35983616
(data_line, tuple(caplines), tuple(barcols)),
35993617
has_xerr=(xerr is not None), has_yerr=(yerr is not None),
52.7 KB
Loading

lib/matplotlib/tests/test_axes.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3600,6 +3600,16 @@ def test_errorbar():
36003600
ax.set_title("Simplest errorbars, 0.2 in x, 0.4 in y")
36013601

36023602

3603+
@image_comparison(['errorbar_polar_caps'], extensions=['png'])
3604+
def test_errorbar_polar_caps():
3605+
fig = plt.figure()
3606+
ax = plt.subplot(111, projection='polar')
3607+
theta = np.arange(0, 2*np.pi, np.pi / 4)
3608+
r = theta / np.pi / 2 + 0.5
3609+
ax.errorbar(theta, r, xerr=0.15, yerr=0.1, fmt="o")
3610+
ax.set_rlim(0, 2)
3611+
3612+
36033613
def test_errorbar_colorcycle():
36043614

36053615
f, ax = plt.subplots()

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy