Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit ed92da8

Browse filesBrowse files
committed
Allow setting an "origin" radius for polar plots.
This means that the minimum radius can be offset to not occur right at the middle of the plot.
1 parent 97e0d51 commit ed92da8
Copy full SHA for ed92da8

File tree

Expand file treeCollapse file tree

1 file changed

+82
-20
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+82
-20
lines changed

‎lib/matplotlib/projections/polar.py

Copy file name to clipboardExpand all lines: lib/matplotlib/projections/polar.py
+82-20Lines changed: 82 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@
1414
import matplotlib.axis as maxis
1515
from matplotlib import cbook
1616
from matplotlib import docstring
17-
from matplotlib.patches import Circle
17+
from matplotlib.patches import Wedge
1818
from matplotlib.path import Path
1919
from matplotlib.ticker import Formatter, Locator, FormatStrFormatter
2020
from matplotlib.transforms import Affine2D, Affine2DBase, Bbox, \
2121
BboxTransformTo, IdentityTransform, Transform, TransformWrapper, \
22-
ScaledTranslation, blended_transform_factory, BboxTransformToMaxOnly
22+
ScaledTranslation, blended_transform_factory, BboxTransformToMaxOnly, \
23+
TransformedBbox
2324
import matplotlib.spines as mspines
2425

2526

@@ -43,7 +44,7 @@ def transform_non_affine(self, tr):
4344
xy = np.empty(tr.shape, np.float_)
4445
if self._axis is not None:
4546
if self._use_rmin:
46-
rmin = self._axis.viewLim.ymin
47+
rmin = self._axis.get_rorigin()
4748
else:
4849
rmin = 0
4950
theta_offset = self._axis.get_theta_offset()
@@ -130,7 +131,7 @@ def __init__(self, axis=None, use_rmin=True):
130131
def transform_non_affine(self, xy):
131132
if self._axis is not None:
132133
if self._use_rmin:
133-
rmin = self._axis.viewLim.ymin
134+
rmin = self._axis.get_rorigin()
134135
else:
135136
rmin = 0
136137
theta_offset = self._axis.get_theta_offset()
@@ -216,6 +217,29 @@ def view_limits(self, vmin, vmax):
216217
return min(0, vmin), vmax
217218

218219

220+
class _RadialOffsetTransform(Transform):
221+
"""
222+
Adjust Bbox so that is spans from the Origin to the Maximum in data space
223+
coordinates, instead of Minimum to Maximum.
224+
"""
225+
input_dims = 2
226+
output_dims = 2
227+
is_separable = False
228+
229+
def __init__(self, axis):
230+
Transform.__init__(self)
231+
self._axis = axis
232+
233+
def transform_non_affine(self, tr):
234+
xy = tr.copy()
235+
rmin = self._axis._rorigin
236+
if rmin is not None:
237+
# This is expected to be applied to only the viewLim Bbox.
238+
xy[0, 1] = rmin
239+
return xy
240+
transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__
241+
242+
219243
class PolarAxes(Axes):
220244
"""
221245
A polar graph projection, where the input dimensions are *theta*, *r*.
@@ -238,6 +262,9 @@ def __init__(self, *args, **kwargs):
238262
self._default_theta_offset = kwargs.pop('theta_offset', 0)
239263
self._default_theta_direction = kwargs.pop('theta_direction', 1)
240264
self._default_rlabel_position = kwargs.pop('rlabel_position', 22.5)
265+
self._rorigin = None
266+
self._rotransform = _RadialOffsetTransform(self)
267+
self._rotransform._parents[id(self)] = self # Hack?
241268

242269
if self.resolution not in (None, 1):
243270
warnings.warn(
@@ -262,11 +289,13 @@ def cla(self):
262289

263290
self.grid(rcParams['polaraxes.grid'])
264291
self.xaxis.set_ticks_position('none')
292+
self.spines['inner'].set_visible(False)
265293
self.yaxis.set_ticks_position('none')
266294
self.yaxis.set_tick_params(label1On=True)
267295
# Why do we need to turn on yaxis tick labels, but
268296
# xaxis tick labels are already on?
269297

298+
self._rorigin = None
270299
self.set_theta_offset(self._default_theta_offset)
271300
self.set_theta_direction(self._default_theta_direction)
272301

@@ -296,7 +325,9 @@ def _set_lim_and_transforms(self):
296325

297326
# An affine transformation on the data, generally to limit the
298327
# range of the axes
299-
self.transProjectionAffine = self.PolarAffine(self.transScale, self.viewLim)
328+
self._offsetViewLim = TransformedBbox(self.viewLim, self._rotransform)
329+
self.transProjectionAffine = self.PolarAffine(self.transScale,
330+
self._offsetViewLim)
300331

301332
# The complete data transformation stack -- from data all the
302333
# way to display coordinates
@@ -375,24 +406,36 @@ def get_yaxis_text2_transform(self, pad):
375406
else:
376407
return self._yaxis_text_transform, 'bottom', 'right'
377408

378-
def _gen_axes_patch(self):
379-
return Circle((0.5, 0.5), 0.5)
380-
381-
def _gen_axes_spines(self):
382-
return {'polar':mspines.Spine.circular_spine(self,
383-
(0.5, 0.5), 0.5)}
409+
def _invalidate_internal(self, *args, **kwargs):
410+
rmin, rmax = self.viewLim.intervaly
411+
rorigin = self.get_rorigin()
412+
inner = self.spines.get('inner', None)
413+
414+
if rorigin < rmin:
415+
width = (rmax - rmin) / (rmax - rorigin) * 0.5
416+
self.patch.set_width(width)
417+
if inner:
418+
inner.set_visible(True)
419+
inner.set_patch_circle((0.5, 0.5), 0.5 - width)
420+
else:
421+
self.patch.set_width(0.5)
422+
if inner:
423+
inner.set_patch_circle((0.5, 0.5), 0.0)
424+
inner.set_visible(False)
384425

385-
def set_rmax(self, rmax):
386-
self.viewLim.y1 = rmax
426+
for line in self.lines:
427+
self._update_line_limits(line)
428+
for p in self.patches:
429+
self._update_patch_limits(p)
387430

388-
def get_rmax(self):
389-
return self.viewLim.ymax
390-
391-
def set_rmin(self, rmin):
392-
self.viewLim.y0 = rmin
431+
def _gen_axes_patch(self):
432+
return Wedge((0.5, 0.5), 0.5, 0.0, 360.0)
393433

394-
def get_rmin(self):
395-
return self.viewLim.ymin
434+
def _gen_axes_spines(self):
435+
return {'outer': mspines.Spine.circular_spine(self,
436+
(0.5, 0.5), 0.5),
437+
'inner': mspines.Spine.circular_spine(self,
438+
(0.5, 0.5), 0.0)}
396439

397440
def set_theta_offset(self, offset):
398441
"""
@@ -455,6 +498,25 @@ def get_theta_direction(self):
455498
"""
456499
return self._direction
457500

501+
def set_rmax(self, rmax):
502+
self.viewLim.y1 = rmax
503+
504+
def get_rmax(self):
505+
return self.viewLim.ymax
506+
507+
def set_rmin(self, rmin):
508+
self.viewLim.y0 = rmin
509+
510+
def get_rmin(self):
511+
return self.viewLim.ymin
512+
513+
def set_rorigin(self, rorigin):
514+
self._rorigin = rorigin
515+
self._rotransform.invalidate()
516+
517+
def get_rorigin(self):
518+
return self._rorigin or self.get_rmin()
519+
458520
def set_rlim(self, *args, **kwargs):
459521
if 'rmin' in kwargs:
460522
kwargs['ymin'] = kwargs.pop('rmin')

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.