8000 Fix log limits. For minor speed improvements. · matplotlib/matplotlib@426eabc · GitHub
[go: up one dir, main page]

Skip to content

Commit 426eabc

Browse files
committed
Fix log limits. For minor speed improvements.
svn path=/branches/transforms/; revision=3895
1 parent b0a1654 commit 426eabc

File tree

6 files changed

+144
-41
lines changed

6 files changed

+144
-41
lines changed

lib/matplotlib/axes.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,17 +1095,8 @@ def add_line(self, line):
10951095
line._remove_method = lambda h: self.lines.remove(h)
10961096

10971097
def _update_line_limits(self, line):
1098-
xdata = line.get_xdata(orig=False)
1099-
ydata = line.get_ydata(orig=False)
1100-
1101-
if line.get_transform() != self.transData:
1102-
xys = self._get_verts_in_data_coords(
1103-
line.get_transform(), zip(xdata, ydata))
1104-
xdata = npy.array([x for x,y in xys])
1105-
ydata = npy.array([y for x,y in xys])
1106-
1107-
self.update_datalim_numerix( xdata, ydata )
1108-
1098+
xydata = line.get_xydata()
1099+
self.update_datalim( xydata )
11091100

11101101
def add_patch(self, p):
11111102
"""
@@ -1151,7 +1142,6 @@ def update_datalim(self, xys):
11511142
xys = npy.asarray(xys)
11521143
self.update_datalim_numerix(xys[:, 0], xys[:, 1])
11531144

1154-
11551145
def update_datalim_numerix(self, x, y):
11561146
'Update the data lim bbox with seq of xy tups'
11571147
# if no data is set currently, the bbox will ignore it's

lib/matplotlib/axis.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,9 @@ def get_view_interval(self):
334334
'return the Interval instance for this axis view limits'
335335
return self.axes.viewLim.intervalx
336336

337+
def get_minpos(self):
338+
return self.axes.dataLim.minposx
339+
337340
def get_data_interval(self):
338341
'return the Interval instance for this axis data limits'
339342
return self.axes.dataLim.intervalx
@@ -458,6 +461,9 @@ def get_view_interval(self):
458461
'return the Interval instance for this axis view limits'
459462
return self.axes.viewLim.intervaly
460463

464+
def get_minpos(self):
465+
return self.axes.dataLim.minposy
466+
461467
def get_data_interval(self):
462468
'return the Interval instance for this axis data limits'
463469
return self.axes.dataLim.intervaly
@@ -518,7 +524,13 @@ def get_transform(self):
518524
def get_scale(self):
519525
return self._scale.name
520526

521-
def set_scale(self, value, base=10, subs=None):
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
522534
# MGDTODO: Move these settings (ticker etc.) into the scale class itself
523535
value = value.lower()
524536
assert value.lower() in ('log', 'linear')
@@ -534,7 +546,7 @@ def set_scale(self, value, base=10, subs=None):
534546
self.set_minor_locator(LogLocator(base,subs))
535547
# MGDTODO: Pass base along
536548
self._scale = LogScale()
537-
miny, maxy = getattr(self.axes.viewLim, 'interval' + self.axis)
549+
miny, maxy = getattr(self.axes.viewLim, 'interval' + self.axis_name)
538550
if min(miny, maxy)<=0:
539551
self.axes.autoscale_view()
540552

@@ -980,7 +992,7 @@ def zoom(self, direction):
980992

981993
class XAxis(Axis):
982994
__name__ = 'xaxis'
983-
axis = 'x'
995+
axis_name = 'x'
984996

985997
def contains(self,mouseevent):
986998
"""Test whether the mouse event occured in the x axis.
@@ -1156,14 +1168,17 @@ def get_view_interval(self):
11561168
'return the Interval instance for this axis view limits'
11571169
return self.axes.viewLim.intervalx
11581170

1171+
def get_minpos(self):
1172+
return self.axes.dataLim.minposx
1173+
11591174
def get_data_interval(self):
11601175
'return the Interval instance for this axis data limits'
11611176
return self.axes.dataLim.intervalx
11621177

11631178

11641179
class YAxis(Axis):
11651180
__name__ = 'yaxis'
1166-
axis = 'y'
1181+
axis_name = 'y'
11671182

11681183
def contains(self,mouseevent):
11691184
"""Test whether the mouse event occurred in the y axis.
@@ -1357,6 +1372,9 @@ def get_view_interval(self):
13571372
'return the Interval instance for this axis view limits'
13581373
return self.axes.viewLim.intervaly
13591374

1375+
def get_minpos(self):
1376+
return self.axes.dataLim.minposy
1377+
13601378
def get_data_interval(self):
13611379
'return the Interval instance for this axis data limits'
13621380
return self.axes.dataLim.intervaly

lib/matplotlib/lines.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,9 @@ def get_ydata(self, orig=True):
564564
return self._yorig
565565
return self._y
566566

567+
def get_xydata(self):
568+
return self._xy
569+
567570
def set_antialiased(self, b):
568571
"""
569572
True if line should be drawin with antialiased rendering

lib/matplotlib/scale.py

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,66 @@ def get_transform(self):
1313
return IdentityTransform()
1414

1515
class LogScale(ScaleBase):
16+
class Log10Transform(Transform):
17+
input_dims = 1
18+
output_dims = 1
19+
def __init__(self):
20+
Transform.__init__(self)
21+
22+
def is_separable(self):
23+
return True
24+
25+
def transform(self, a):
26+
return ma.log10(ma.masked_where(a <= 0.0, a * 10.0))
27+
28+
def inverted(self):
29+
return LogScale.InvertedLog10Transform()
30+
31+
class InvertedLog10Transform(Transform):
32+
input_dims = 1
33+
output_dims = 1
34+
def __init__(self):
35+
Transform.__init__(self)
36+
37+
def is_separable(self):
38+
return True
39+
40+
def transform(self, a):
41+
return ma.power(10.0, a) / 10.0
42+
43+
def inverted(self):
44+
return LogScale.Log10Transform()
45+
46+
class Log2Transform(Transform):
47+
input_dims = 1
48+
output_dims = 1
49+
def __init__(self):
50+
Transform.__init__(self)
51+
52+
def is_separable(self):
53+
return True
54+
55+
def transform(self, a):
56+
return ma.log2(ma.masked_where(a <= 0.0, a * 2.0))
57+
58+
def inverted(self):
59+
return LogScale.InvertedLog2Transform()
60+
61+
class InvertedLog2Transform(Transform):
62+
input_dims = 1
63+
output_dims = 1
64+
def __init__(self):
65+
Transform.__init__(self)
66+
67+
def is_separable(self):
68+
return True
69+
70+
def transform(self, a):
71+
return ma.power(2.0, a) / 2.0
72+
73+
def inverted(self):
74+
return LogScale.Log2Transform()
75+
1676
class LogTransform(Transform):
1777
input_dims = 1
1878
output_dims = 1
@@ -26,12 +86,12 @@ def is_separable(self):
2686
def transform(self, a):
2787
if len(a) > 10:
2888
print "Log Transforming..."
29-
return ma.log10(ma.masked_where(a <= 0.0, a * 10.0))
89+
return ma.log(ma.masked_where(a <= 0.0, a * self._base)) / npy.log(self._base)
3090

3191
def inverted(self):
3292
return LogScale.InvertedLogTransform(self._base)
3393

34-
class InvertedLogTransform(Transform):
94+
class InvertedLog2Transform(Transform):
3595
input_dims = 1
3696
output_dims = 1
3797
def __init__(self, base):
@@ -42,14 +102,21 @@ def is_separable(self):
42102
return True
43103

44104
def transform(self, a):
45-
return ma.power(10.0, a) / 10.0
105+
return ma.power(self._base, a) / self._base
46106

47107
def inverted(self):
48108
return LogScale.LogTransform(self._base)
49-
109+
110+
50111
def __init__(self, base=10):
51-
self._transform = self.LogTransform(base)
52-
112+
if base == 10.0:
113+
self._transform = self.Log10Transform()
114+
elif base == 2.0:
115+
self._transform = self.Log2Transform()
116+
# MGDTODO: Natural log etc.
117+
else:
118+
self._transform = self.LogTransform(base)
119+
53120
def get_transform(self):
54121
return self._transform
55122

lib/matplotlib/ticker.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -919,21 +919,21 @@ def __call__(self):
919919

920920
def autoscale(self):
921921
'Try to choose the view limits intelligently'
922-
vmin, vmax = self.axis.get_view_interval()
922+
vmin, vmax = self.axis.get_data_interval()
923923
if vmax<vmin:
924924
vmin, vmax = vmax, vmin
925925

926-
# minpos = self.dataInterval.minpos()
926+
minpos = self.axis.get_minpos()
927+
928+
if minpos<=0:
929+
raise RuntimeError('No positive data to plot')
927930

928-
# if minpos<=0:
929-
# raise RuntimeError('No positive data to plot')
931+
if vmin <= minpos:
932+
vmin = minpos
930933

931-
# MGDTODO: Find a good way to track minpos
932-
if vmin <= 0.0:
933-
vmin = 0.1
934-
935934
if not is_decade(vmin,self._base): vmin = decade_down(vmin,self._base)
936935
if not is_decade(vmax,self._base): vmax = decade_up(vmax,self._base)
936+
937937
if vmin==vmax:
938938
vmin = decade_down(vmin,self._base)
939939
vmax = decade_up(vmax,self._base)

lib/matplotlib/transforms.py

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ class Bbox(BboxBase):
224224
def __init__(self, points):
225225
BboxBase.__init__(self)
226226
self._points = npy.asarray(points, npy.float_)
227+
self._minpos = npy.array([0.0000001, 0.0000001])
227228
self._invalid = False
228229

229230
#@staticmethod
@@ -252,15 +253,22 @@ def _do_invalidation(self, affine_only):
252253
return result
253254

254255
def update_from_data(self, x, y, ignore=True):
255-
if ignore:
256-
self._points = npy.array(
257-
[[x.min(), y.min()], [x.max(), y.max()]],
258-
npy.float_)
259-
else:
256+
if ignore:
257+
self._points = npy.array(
258+
[[x.min(), y.min()], [x.max(), y.max()]],
259+
npy.float_)
260+
self._minpos = npy.array(
261+
[npy.where(x > 0.0, x, npy.inf).min(), npy.where(y > 0.0, y, npy.inf).min()],
262+
npy.float_)
263+
else:
260264
self._points = npy.array(
261265
[[min(x.min(), self.xmin), min(y.min(), self.ymin)],
262266
[max(x.max(), self.xmax), max(y.max(), self.ymax)]],
263267
npy.float_)
268+
minpos = npy.array(
269+
[npy.where(x > 0.0, x, npy.inf).min(), npy.where(y > 0.0, y, npy.inf).min()],
270+
npy.float_)
271+
self._minpos = npy.minimum(minpos, self._minpos)
264272
self.invalidate()
265273

266274
def _set_xmin(self, val):
@@ -309,6 +317,18 @@ def _set_bounds(self, bounds):
309317
self.invalidate()
310318
bounds = property(BboxBase._get_bounds, _set_bounds)
311319

320+
def _get_minpos(self):
321+
return self._minpos
322+
minpos = property(_get_minpos)
323+
324+
def _get_minposx(self):
325+
return self._minpos[0]
326+
minposx = property(_get_minposx)
327+
328+
def _get_minposy(self):
329+
return self._minpos[1]
330+
minposy = property(_get_minposy)
331+
312332
def get_points(self):
313333
self._invalid = False
314334
return self._points
@@ -541,7 +561,7 @@ def transform(self, values):
541561
# print "".join(traceback.format_stack())
542562
# print points
543563
mtx = self.get_matrix()
544-
points = npy.asarray(values, npy.float_)
564+
# points = npy.asarray(values, npy.float_)
545565
return points * mtx[0,0] + mtx[0,1]
546566

547567
transform_affine = transform
@@ -695,10 +715,15 @@ def transform(self, points):
695715
# print "".join(traceback.format_stack())
696716
# print points
697717
mtx = self.get_matrix()
698-
points = npy.asarray(points, npy.float_)
699-
points = points.transpose()
700-
points = npy.dot(mtx[0:2, 0:2], points)
701-
points = points + mtx[0:2, 2:]
718+
if ma.isarray(points):
719+
points = points.transpose()
720+
points = ma.dot(mtx[0:2, 0:2], points)
721+
points = points + mtx[0:2, 2:]
722+
else:
723+
points = npy.asarray(points, npy.float_)
724+
points = points.transpose()
725+
points = npy.dot(mtx[0:2, 0:2], points)
726+
points = points + mtx[0:2, 2:]
702727
return points.transpose()
703728

704729
transform_affine = transform
@@ -869,7 +894,7 @@ def transform(self, points):
869894
y_points = y.transform(points[:, 1])
870895
y_points = y_points.reshape((len(y_points), 1))
871896

872-
return npy.concatenate((x_points, y_points), 1)
897+
return ma.concatenate((x_points, y_points), 1)
873898
transform_non_affine = transform
874899

875900
def transform_affine(self, points):

0 commit comments

Comments
 (0)
0