Ответ 1
Не элегантный, увы, но вы можете изменить полярное преобразование координат, чтобы делать то, что вы хотите. Я получил код отсюда: https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/projections/polar.py.
Я изменил имена на LogPolarTransform и InvertedLogPolarTransform, а затем изменил формулы, чтобы использовать шкалу журнала. В принципе, я изменил эти строки:
x[:] = np.where(mask, np.nan, r * np.cos(t))
y[:] = np.where(mask, np.nan, r * np.sin(t))
к ним:
x[:] = np.where(mask, np.nan, np.log(r) * np.cos(t))
y[:] = np.where(mask, np.nan, np.log(r) * np.sin(t))
и эта строка:
r = np.sqrt(x*x + y*y)
:
r = np.exp(np.sqrt(x*x + y*y))
Если вы скопируете и вставьте следующий код выше того, что у вас уже есть, и измените tr = PolarAxes.PolarTransform()
на tr = LogPolarTransform()
, вы должны получить радиальную ось с масштабированием по шкале. Вот результат (я изменил plot_real_min
на 5.0, так что все будет лучше):
from matplotlib.transforms import Transform
class LogPolarTransform(PolarAxes.PolarTransform):
input_dims = 2
output_dims = 2
is_separable = False
def __init__(self, axis=None, use_rmin=True):
Transform.__init__(self)
self._axis = axis
self._use_rmin = use_rmin
def transform_non_affine(self, tr):
xy = np.empty(tr.shape, np.float_)
if self._axis is not None:
if self._use_rmin:
rmin = self._axis.viewLim.ymin
else:
rmin = 0
theta_offset = self._axis.get_theta_offset()
theta_direction = self._axis.get_theta_direction()
else:
rmin = 0
theta_offset = 0
theta_direction = 1
t = tr[:, 0:1]
r = tr[:, 1:2]
x = xy[:, 0:1]
y = xy[:, 1:2]
t *= theta_direction
t += theta_offset
r = r - rmin
mask = r < 0
x[:] = np.where(mask, np.nan, np.log(r) * np.cos(t))
y[:] = np.where(mask, np.nan, np.log(r) * np.sin(t))
return xy
def inverted(self):
return InvertedLogPolarTransform(self._axis, self._use_rmin)
inverted.__doc__ = Transform.inverted.__doc__
class InvertedLogPolarTransform(Transform):
"""
The inverse of the polar transform, mapping Cartesian
coordinate space *x* and *y* back to *theta* and *r*.
"""
input_dims = 2
output_dims = 2
is_separable = False
def __init__(self, axis=None, use_rmin=True):
Transform.__init__(self)
self._axis = axis
self._use_rmin = use_rmin
def transform_non_affine(self, xy):
if self._axis is not None:
if self._use_rmin:
rmin = self._axis.viewLim.ymin
else:
rmin = 0
theta_offset = self._axis.get_theta_offset()
theta_direction = self._axis.get_theta_direction()
else:
rmin = 0
theta_offset = 0
theta_direction = 1
x = xy[:, 0:1]
y = xy[:, 1:]
r = np.exp(np.sqrt(x*x + y*y))
with np.errstate(invalid='ignore'):
# At x=y=r=0 this will raise an
# invalid value warning when doing 0/0
# Divide by zero warnings are only raised when
# the numerator is different from 0. That
# should not happen here.
theta = np.arccos(x / r)
theta = np.where(y < 0, 2 * np.pi - theta, theta)
theta -= theta_offset
theta *= theta_direction
theta %= 2 * np.pi
r += rmin
return np.concatenate((theta, r), 1)
def inverted(self):
return PolarAxes.LogPolarTransform(self._axis, self._use_rmin)