8000 Move ticking/formatting defaults to scale.py. Speed improvements in … · matplotlib/matplotlib@bde568c · GitHub
[go: up one dir, main page]

Skip to content

Commit bde568c

Browse files
committed
Move ticking/formatting defaults to scale.py. Speed improvements in transforms.py
svn path=/branches/transforms/; revision=3905
1 parent 7a34814 commit bde568c

File tree

9 files changed

+602
-417
lines changed

9 files changed

+602
-417
lines changed

lib/matplotlib/axes.py

Lines changed: 276 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from matplotlib import mlab
2424
from matplotlib import cm
2525
from matplotlib import patches as mpatches
26+
from matplotlib import path as mpath
2627
from matplotlib import pbox as mpbox
2728
from matplotlib import quiver as mquiver
2829
from matplotlib import scale as mscale
@@ -1461,7 +1462,7 @@ def set_axis_bgcolor(self, color):
14611462
self.axesPatch.set_facecolor(color)
14621463

14631464
### data limits, ticks, tick labels, and formatting
1464-
1465+
14651466
def get_xlim(self):
14661467
'Get the x axis range [xmin, xmax]'
14671468
return self.viewLim.intervalx
@@ -1503,11 +1504,6 @@ def set_xlim(self, xmin=None, xmax=None, emit=True, **kwargs):
15031504
if xmin is None: xmin = old_xmin
15041505
if xmax is None: xmax = old_xmax
15051506

1506-
# MGDTODO
1507-
# if (self.transData.get_funcx().get_type()==mtrans.LOG10
1508-
# and min(xmin, xmax)<=0):
1509-
# raise ValueError('Cannot set nonpositive limits with log transform')
1510-
15111507
xmin, xmax = mtransforms.nonsingular(xmin, xmax, increasing=False)
15121508

15131509
self.viewLim.intervalx = (xmin, xmax)
@@ -1516,7 +1512,7 @@ def set_xlim(self, xmin=None, xmax=None, emit=True, **kwargs):
15161512
# Call all of the other x-axes that are shared with this one
15171513
for other in self._shared_x_axes.get_siblings(self):
15181514
if other is not self:
1519-
other.set_xlim(self.viewLim.xmin, self.viewLim.xmax, emit=False)
1515+
other.set_xlim(self.viewLim.intervalx, emit=False)
15201516

15211517
return xmin, xmax
15221518

@@ -1634,7 +1630,7 @@ def get_yscale(self):
16341630
'return the yaxis scale string: log or linear'
16351631
return self.yaxis.get_scale()
16361632

1637-
def set_yscale(self, value, basey=10, subsy=None):
1633+
def set_yscale(self, value, **kwargs):
16381634
"""
16391635
SET_YSCALE(value, basey=10, subsy=None)
16401636
@@ -1652,7 +1648,7 @@ def set_yscale(self, value, basey=10, subsy=None):
16521648
16531649
ACCEPTS: ['log' | 'linear']
16541650
"""
1655-
self.yaxis.set_scale(value, basey, subsy)
1651+
self.yaxis.set_scale(value, **kwargs)
16561652
self._update_transScale()
16571653

16581654
def get_yticks(self):
@@ -1788,6 +1784,32 @@ def set_navigate_mode(self, b):
17881784
"""
17891785
self._navigate_mode = b
17901786

1787+
def drag_pan(self, button, x, y, startx, starty, start_lim, start_trans):
1788+
if button == 1:
1789+
inverse = start_trans.inverted()
1790+
dx = startx - x
1791+
dy = starty - y
1792+
result = self.bbox.frozen().translated(dx, dy).transformed(inverse)
1793+
elif button == 3:
1794+
try:
1795+
inverse = start_trans.inverted()
1796+
dx = (startx - x) / float(self.bbox.width)
1797+
dy = (starty - y) / float(self.bbox.height)
1798+
xmin, ymin, xmax, ymax = start_lim.lbrt
1799+
1800+
alpha = npy.power(10.0, (dx, dy))
1801+
start = inverse.transform_point((startx, starty))
1802+
lim_points = start_lim.get_points()
1803+
result = start + alpha * (lim_points - start)
1804+
result = mtransforms.Bbox(result)
1805+
except OverflowError:
1806+
warnings.warn('Overflow while panning')
1807+
return
1808+
1809+
# MGDTODO: Could we do this with a single set_lim?
1810+
self.set_xlim(*result.intervalx)
1811+
self.set_ylim(*result.intervaly)
1812+
17911813
def get_cursor_props(self):
17921814
"""return the cursor props as a linewidth, color tuple where
17931815
linewidth is a float and color is an RGBA tuple"""
@@ -5658,8 +5680,253 @@ def __init__(self, fig, *args, **kwargs):
56585680
self, fig,
56595681
[self.figLeft, self.figBottom, self.figW, self.figH], **kwargs)
56605682

5683+
######################################################################
5684+
# New Polar Axes
5685+
5686+
class PolarAxes(Axes):
5687+
class PolarTransform(mtransforms.Transform):
5688+
input_dims = 2
5689+
output_dims = 2
5690+
is_separable = False
5691+
5692+
def transform(self, tr):
5693+
xy = npy.zeros(tr.shape, npy.float_)
5694+
t = tr[:, 0:1]
5695+
r = tr[:, 1:2]
5696+
x = xy[:, 0:1]
5697+
y = xy[:, 1:2]
5698+
x += r * npy.cos(t)
5699+
y += r * npy.sin(t)
5700+
return xy
5701+
transform_non_affine = transform
5702+
5703+
def interpolate(self, a, steps):
5704+
steps = npy.floor(steps)
5705+
new_length = ((len(a) - 1) * steps) + 1
5706+
new_shape = list(a.shape)
5707+
new_shape[0] = new_length
5708+
result = npy.zeros(new_shape, a.dtype)
5709+
5710+
result[0] = a[0]
5711+
a0 = a[0:-1]
5712+
a1 = a[1: ]
5713+
delta = ((a1 - a0) / steps)
5714+
5715+
for i in range(1, int(steps)+1):
5716+
result[i::steps] = delta * i + a0
5717+
5718+
return result
5719+
5720+
# def transform_path(self, path):
5721+
# twopi = 2.0 * npy.pi
5722+
# halfpi = 0.5 * npy.pi
5723+
5724+
# vertices = path.vertices
5725+
# t0 = vertices[0:-1, 0]
5726+
# t1 = vertices[1: , 0]
5727+
# td = npy.where(t1 > t0, t1 - t0, twopi - (t0 - t1))
5728+
# maxtd = td.max()
5729+
# interpolate = npy.ceil(maxtd / halfpi)
5730+
# if interpolate > 1.0:
5731+
# vertices = self.interpolate(vertices, interpolate)
5732+
5733+
# vertices = self.transform(vertices)
5734+
5735+
# result = npy.zeros((len(vertices) * 3 - 2, 2), npy.float_)
5736+
# codes = mpath.Path.CURVE4 * npy.ones((len(vertices) * 3 - 2, ), mpath.Path.code_type)
5737+
# result[0] = vertices[0]
5738+
# codes[0] = mpath.Path.MOVETO
5739+
5740+
# kappa = 4.0 * ((npy.sqrt(2.0) - 1.0) / 3.0)
5741+
# kappa = 0.5
5742+
5743+
# p0 = vertices[0:-1]
5744+
# p1 = vertices[1: ]
5745+
5746+
# x0 = p0[:, 0:1]
5747+
# y0 = p0[:, 1: ]
5748+
# b0 = ((y0 - x0) - y0) / ((x0 + y0) - x0)
5749+
# a0 = y0 - b0*x0
5750+
5751+
# x1 = p1[:, 0:1]
5752+
# y1 = p1[:, 1: ]
5753+
# b1 = ((y1 - x1) - y1) / ((x1 + y1) - x1)
5754+
# a1 = y1 - b1*x1
5755+
5756+
# x = -(a0-a1) / (b0-b1)
5757+
# y = a0 + b0*x
5758+
5759+
# xk = (x - x0) * kappa + x0
5760+
# yk = (y - y0) * kappa + y0
5761+
5762+
# result[1::3, 0:1] = xk
5763+
# result[1::3, 1: ] = yk
5764+
5765+
# xk = (x - x1) * kappa + x1
5766+
# yk = (y - y1) * kappa + y1
5767+
5768+
# result[2::3, 0:1] = xk
5769+
# result[2::3, 1: ] = yk
5770+
5771+
# result[3::3] = p1
5772+
5773+
# print vertices[-2:]
5774+
# print result[-2:]
5775+
5776+
# return mpath.Path(result, codes)
5777+
5778+
# twopi = 2.0 * npy.pi
5779+
# halfpi = 0.5 * npy.pi
5780+
5781+
# vertices = path.vertices
5782+
# t0 = vertices[0:-1, 0]
5783+
# t1 = vertices[1: , 0]
5784+
# td = npy.where(t1 > t0, t1 - t0, twopi - (t0 - t1))
5785+
# maxtd = td.max()
5786+
# interpolate = npy.ceil(maxtd / halfpi)
5787+
5788+
# print "interpolate", interpolate
5789+
# if interpolate > 1.0:
5790+
# vertices = self.interpolate(vertices, interpolate)
5791+
5792+
# result = npy.zeros((len(vertices) * 3 - 2, 2), npy.float_)
5793+
# codes = mpath.Path.CURVE4 * npy.ones((len(vertices) * 3 - 2, ), mpath.Path.code_type)
5794+
# result[0] = vertices[0]
5795+
# codes[0] = mpath.Path.MOVETO
5796+
5797+
# kappa = 4.0 * ((npy.sqrt(2.0) - 1.0) / 3.0)
5798+
# tkappa = npy.arctan(kappa)
5799+
# hyp_kappa = npy.sqrt(kappa*kappa + 1.0)
5800+
5801+
# t0 = vertices[0:-1, 0]
5802+
# t1 = vertices[1: , 0]
5803+
# r0 = vertices[0:-1, 1]
5804+
# r1 = vertices[1: , 1]
5805+
5806+
# td = npy.where(t1 > t0, t1 - t0, twopi - (t0 - t1))
5807+
# td_scaled = td / (npy.pi * 0.5)
5808+
# rd = r1 - r0
5809+
# r0kappa = r0 * kappa * td_scaled
5810+
# r1kappa = r1 * kappa * td_scaled
5811+
# ravg_kappa = ((r1 + r0) / 2.0) * kappa * td_scaled
5812+
5813+
# result[1::3, 0] = t0 + (tkappa * td_scaled)
5814+
# result[1::3, 1] = r0*hyp_kappa
5815+
# # result[1::3, 1] = r0 / npy.cos(tkappa * td_scaled) # npy.sqrt(r0*r0 + ravg_kappa*ravg_kappa)
5816+
5817+
# result[2::3, 0] = t1 - (tkappa * td_scaled)
5818+
# result[2::3, 1] = r1*hyp_kappa
5819+
# # result[2::3, 1] = r1 / npy.cos(tkappa * td_scaled) # npy.sqrt(r1*r1 + ravg_kappa*ravg_kappa)
5820+
5821+
# result[3::3, 0] = t1
5822+
# result[3::3, 1] = r1
5823+
5824+
# print vertices[:6], result[:6], t0[:6], t1[:6], td[:6], td_scaled[:6], tkappa
5825+
# result = self.transform(result)
5826+
# return mpath.Path(result, codes)
5827+
# transform_path_non_affine = transform_path
5828+
5829+
def inverted(self):
5830+
return PolarAxes.InvertedPolarTransform()
5831+
5832+
class PolarAffine(mtransforms.Affine2DBase):
5833+
def __init__(self, limits):
5834+
mtransforms.Affine2DBase.__init__(self)
5835+
self._limits = limits
5836+
self.set_children(limits)
5837+
self._mtx = None
5838+
5839+
def get_matrix(self):
5840+
if self._invalid:
5841+
xmin, ymin, xmax, ymax = self._limits.lbrt
5842+
affine = mtransforms.Affine2D().rotate(xmin).scale(0.5 / ymax).translate(0.5, 0.5)
5843+
self._mtx = affine.get_matrix()
5844+
self._inverted = None
5845+
self._invalid = 0
5846+
return self._mtx
5847+
5848+
class InvertedPolarTransform(mtransforms.Transform):
5849+
input_dims = 2
5850+
output_dims = 2
5851+
is_separable = False
5852+
5853+
def transform(self, xy):
5854+
x = xy[:, 0:1]
5855+
y = xy[:, 1:]
5856+
r = npy.sqrt(x*x + y*y)
5857+
theta = npy.arccos(x / r)
5858+
theta = npy.where(y < 0, 2 * npy.pi - theta, theta)
5859+
return npy.concatenate((theta, r), 1)
5860+
5861+
def inverted(self):
5862+
return PolarAxes.PolarTransform()
5863+
5864+
def _set_lim_and_transforms(self):
5865+
"""
5866+
set the dataLim and viewLim BBox attributes and the
5867+
transData and transAxes Transformation attributes
5868+
"""
5869+
self.dataLim = mtransforms.Bbox.unit()
5870+
self.viewLim = mtransforms.Bbox.unit()
5871+
self.transAxes = mtransforms.BboxTransform(
5872+
mtransforms.Bbox.unit(), self.bbox)
56615873

5874+
# Transforms the x and y axis separately by a scale factor
5875+
# It is assumed that this part will have non-linear components
5876+
self.transScale = mtransforms.TransformWrapper(mtransforms.IdentityTransform())
5877+
5878+
# A (possibly non-linear) projection on the (already scaled) data
5879+
self.transProjection = self.PolarTransform()
56625880

5881+
# An affine transformation on the data, generally to limit the
5882+
# range of the axes
5883+
self.transProjectionAffine = self.PolarAffine(self.viewLim)
5884+
5885+
self.transData = self.transScale + self.transProjection + \
5886+
self.transProjectionAffine + self.transAxes
5887+
5888+
def drag_pan(self, button, x, y, startx, starty, start_lim, start_trans):
5889+
if button == 1:
5890+
inverse = start_trans.inverted()
5891+
startt, startr = inverse.transform_point((startx, starty))
5892+
t, r = inverse.transform_point((x, y))
5893+
5894+
scale = r / startr
5895+
self.set_ylim(start_lim.ymin, start_lim.ymax / scale)
5896+
5897+
dt0 = t - startt
5898+
dt1 = startt - t
5899+
if abs(dt1) < abs(dt0):
5900+
dt = abs(dt1) * sign(dt0) * -1.0
5901+
else:
5902+
dt = dt0 * -1.0
5903+
self.set_xlim(start_lim.xmin - dt, start_lim.xmin - dt + npy.pi*2.0)
5904+
5905+
def set_rmax(self, rmax):
5906+
self.viewLim.maxy = rmax
5907+
5908+
class PolarSubplot(SubplotBase, PolarAxes):
5909+
"""
5910+
Create a polar subplot with
5911+
5912+
PolarSubplot(numRows, numCols, plotNum)
5913+
5914+
where plotNum=1 is the first plot number and increasing plotNums
5915+
fill rows first. max(plotNum)==numRows*numCols
5916+
5917+
You can leave out the commas if numRows<=numCols<=plotNum<10, as
5918+
in
5919+
5920+
Subplot(211) # 2 rows, 1 column, first (upper) plot
5921+
"""
5922+
def __str__(self):
5923+
return "PolarSubplot(%gx%g)"%(self.figW,self.figH)
5924+
def __init__(self, fig, *args, **kwargs):
5925+
SubplotBase.__init__(self, fig, *args)
5926+
PolarAxes.__init__(
5927+
self, fig,
5928+
[self.figLeft, self.figBottom, self.figW, self.figH], **kwargs)
5929+
56635930
martist.kwdocd['Axes'] = martist.kwdocd['Subplot'] = martist.kwdoc(Axes)
56645931
"""
56655932
# this is some discarded code I was using to find the minimum positive

lib/matplotlib/axis.py

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from transforms import Affine2D, Bbox, blended_transform_factory, interval_contains, \
2121
interval_contains_open, IntervalTransform
2222
from patches import bbox_artist
23-
from scale import LinearScale, LogScale
23+
from scale import scale_factory
2424

2525
import matplotlib.units as units
2626
#import pdb
@@ -514,41 +514,19 @@ def __init__(self, axes, pickradius=15):
514514
self.majorTicks = []
515515
self.minorTicks = []
516516
self.pickradius = pickradius
517-
self._scale = LinearScale()
518517

519518
self.cla()
520-
519+
self.set_scale('linear')
520+
521521
def get_transform(self):
522522
return self._scale.get_transform()
523-
523+
524524
def get_scale(self):
525525
return self._scale.name
526526

527-
def set_scale(self, value, basex=10, subsx=None, basey=10, subsy=None):
528-
if self.axis_name == 'x':
529-
base = basex
530-
subs = subsx
531-
else:
532-
base = basey
533-
subs = subsy
534-
# MGDTODO: Move these settings (ticker etc.) into the scale class itself
535-
value = value.lower()
536-
assert value.lower() in ('log', 'linear')
537-
if value == 'linear':
538-
self.set_major_locator(AutoLocator())
539-
self.set_major_formatter(ScalarFormatter())
540-
self.set_minor_locator(NullLocator())
541-
self.set_minor_formatter(NullFormatter())
542-
self._scale = LinearScale()
543-
elif value == 'log':
544-
self.set_major_locator(LogLocator(base))
545-
self.set_major_formatter(LogFormatterMathtext(base))
546-
self.set_minor_locator(LogLocator(base,subs))
547-
# MGDTODO: Pass base along
548-
self._scale = LogScale()
549-
miny, maxy = getattr(self.axes.viewLim, 'interval' + self.axis_name)
550-
if min(miny, maxy)<=0:
551-
self.axes.autoscale_view()
527+
def set_scale(self, value, **kwargs):
528+
self._scale = scale_factory(value, self, **kwargs)
529+
self._scale.set_default_locators_and_formatters(self)
552530

553531
def get_children(self):
554532
children = [self.label]

0 commit comments

Comments
 (0)
0