Browse files

added some support for taking log of line plots with neg data

svn path=/trunk/matplotlib/; revision=925
  • Loading branch information...
1 parent 0a88696 commit 0cca80c010641848880fb99a5af71ee90e0e43ca @jdh2358 jdh2358 committed Feb 4, 2005
Showing with 133 additions and 10 deletions.
  1. +3 −1 CHANGELOG
  2. +5 −1 boilerplate.py
  3. +2 −2 examples/date_demo2.py
  4. +34 −0 lib/matplotlib/axes.py
  5. +50 −1 lib/matplotlib/collections.py
  6. +39 −5 lib/matplotlib/lines.py
View
4 CHANGELOG
@@ -1,6 +1,8 @@
New entries should be added at the top
-
+2005-02-05 Added some support for handling log switching for lines
+ that have nonpos data - JDH
+
2005-02-04 Added Nadia's contour patch - contour now has matlab
compatible syntax; this also fixed an unequal sized contour
array bug- JDH
View
6 boilerplate.py
@@ -1,5 +1,9 @@
# wrap the plot commands defined in axes. The code generated by this
-# file is pasted into pylab.py
+# file is pasted into pylab.py. We did try to do this the smart way,
+# with callable functions and new.function, but could never get the
+# docstrings right for python2.2. See
+# http://groups-beta.google.com/group/comp.lang.python/messages/1b14640f3a4ad3dc,b3d7453af21e5f82,17739e70ac6f710c,9d5291fce29cbbb1,c5b578e4ffc6af28,056ff270daa2f414?thread_id=dcd63ec13096a0f6&mode=thread
+
_fmtplot = """\
View
4 examples/date_demo2.py
@@ -16,7 +16,7 @@
mondays = WeekdayLocator(MONDAY) # every monday
months = MonthLocator(range(1,13), bymonthday=1) # every month
-monthsFmt = DateFormatter('%b %d')
+monthsFmt = DateFormatter("%b '%y")
quotes = quotes_historical_yahoo('INTC', date1, date2)
@@ -26,7 +26,7 @@
dates = [q[0] for q in quotes]
opens = [q[1] for q in quotes]
-
+
ax = subplot(111)
plot_date(dates, opens, '-')
ax.xaxis.set_major_locator(months)
View
34 lib/matplotlib/axes.py
@@ -3045,6 +3045,24 @@ def set_xscale(self, value, basex = 10, subsx=None):
if subsx is None: subsx = range(2, basex)
assert(value.lower() in ('log', 'linear', ))
if value == 'log':
+ minx, maxx = self.get_xlim()
+ if minx<=0 or maxx<=0:
+ # find the min pos value in the data
+ xs = []
+ for line in self.lines:
+ xs.extend(line.get_xdata())
+ for patch in self.patches:
+ xs.extend([x for x,y in patch.get_verts()])
+ for collection in self.collections:
+ xs.extend([x for x,y in collection.get_verts()])
+ posx = [x for x in xs if x>0]
+ minx = min(posx)
+ maxx = max(posx)
+ # warning, probably breaks inverted axis
+ self.set_xlim((0.1*minx, maxx))
+
+
+
self.xaxis.set_major_locator(LogLocator(basex))
self.xaxis.set_major_formatter(LogFormatterMathtext(basex))
self.xaxis.set_minor_locator(LogLocator(basex,subsx))
@@ -3125,6 +3143,22 @@ def set_yscale(self, value, basey=10, subsy=None):
assert(value.lower() in ('log', 'linear', ))
if value == 'log':
+ miny, maxy = self.get_ylim()
+ if miny<=0 or maxy<=0:
+ # find the min pos value in the data
+ ys = []
+ for line in self.lines:
+ ys.extend(line.get_ydata())
+ for patch in self.patches:
+ ys.extend([y for x,y in patch.get_verts()])
+ for collection in self.collections:
+ ys.extend([y for x,y in collection.get_verts()])
+ posy = [y for y in ys if y>0]
+ miny = min(posy)
+ maxy = max(posy)
+ # warning, probably breaks inverted axis
+ self.set_ylim((0.1*miny, maxy))
+
self.yaxis.set_major_locator(LogLocator(basey))
self.yaxis.set_major_formatter(LogFormatterMathtext(basey))
self.yaxis.set_minor_locator(LogLocator(basey,subsy))
View
51 lib/matplotlib/collections.py
@@ -35,6 +35,11 @@ class Collection(Artist):
def __init__(self):
Artist.__init__(self)
+
+ def get_verts(self):
+ 'return seq of (x,y) in collection'
+ raise NotImplementedError('Derived must override')
+
def _get_color(self, c, N=1):
if looks_like_color(c):
return [colorConverter.to_rgba(c)]*N
@@ -98,6 +103,7 @@ def __init__(self,
self._offsets = offsets
self._transOffset = transOffset
+
def set_linewidth(self, lw):
"""
Set the linewidth(s) for the collection. lw can be a scalar or a
@@ -186,6 +192,23 @@ def draw(self, renderer):
self._transform.thaw()
self._transOffset.thaw()
renderer.close_group('polycollection')
+
+
+
+ def get_verts(self):
+ 'return seq of (x,y) in collection'
+ if self._offsets is None:
+ offsets = [(0,0)]
+ else:
+ offsets = self._offsets
+ N = max(len(offsets), len(self._verts))
+ vertsall = []
+ for i in range(N):
+ ox, oy = offsets[i%N]
+ verts = self._verts[i%N]
+ vertsall.extend([(x+ox, y+oy) for x,y in verts])
+ return vertsall
+
class RegularPolyCollection(PatchCollection):
def __init__(self,
@@ -213,7 +236,7 @@ def __init__(self,
theta = (2*math.pi/numsides)*arange(numsides) + rotation
- self._verts = zip( r*sin(theta), r*cos(theta) )
+ self._verts = zip( r*cos(theta), r*sin(theta) )
@@ -239,6 +262,17 @@ def draw(self, renderer):
self._transOffset.thaw()
renderer.close_group('regpolycollection')
+
+
+ def get_verts(self):
+ 'return seq of (x,y) in collection'
+ if self._offsets is None:
+ offsets = [(0,0)]
+ else:
+ offsets = self._offsets
+ return [ (x+ox, y+oy) for x,y in self._verts for ox,oy in offsets]
+
+
class LineCollection(Collection):
"""
All parameters must be sequences. The property of the ith line
@@ -364,3 +398,18 @@ def get_linewidths(self):
def get_colors(self):
return self._colors
+
+
+ def get_verts(self):
+ 'return seq of (x,y) in collection'
+ if self._offsets is None:
+ offsets = [(0,0)]
+ else:
+ offsets = self._offsets
+ N = max(len(offsets), len(self._verts))
+ vertsall = []
+ for i in range(N):
+ ox, oy = offsets[i%N]
+ verts = self._segments[i%N]
+ vertsall.extend([(x+ox, y+oy) for x,y in verts])
+ return vertsall
View
44 lib/matplotlib/lines.py
@@ -9,14 +9,15 @@
import sys
from numerix import Float, alltrue, arange, array, logical_and,\
- nonzero, searchsorted, take, asarray, ones, where, less, ravel
+ nonzero, searchsorted, take, asarray, ones, where, less, ravel, \
+ greater, logical_and
from matplotlib import verbose
from artist import Artist
from cbook import iterable, is_string_like
from collections import RegularPolyCollection, PolyCollection
from colors import colorConverter
from patches import bbox_artist
-from transforms import lbwh_to_bbox
+from transforms import lbwh_to_bbox, LOG10
from matplotlib import rcParams
TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN = range(4)
@@ -140,6 +141,7 @@ def __init__(self, xdata, ydata,
self._lineFunc = self._lineStyles.get(linestyle, self._draw_nothing)
self._markerFunc = self._markers.get(marker, self._draw_nothing)
+ self._logcache = None
def get_window_extent(self, renderer):
x, y = self._get_numeric_clipped_data_in_range()
@@ -193,6 +195,8 @@ def set_data(self, *args):
raise RuntimeError('xdata and ydata must be the same length')
if self._useDataClipping: self._xsorted = self._is_sorted(self._x)
+
+ self._logcache = None
def set_data_clipping(self, b):
"""
@@ -210,12 +214,37 @@ def _is_sorted(self, x):
def _get_numeric_clipped_data_in_range(self):
# if the x or y clip is set, only plot the points in the
- # clipping region
+ # clipping region. If log scale is set, only pos data will be
+ # returned
try: self._xc, self._yc
except AttributeError: x, y = self._x, self._y
else: x, y = self._xc, self._yc
-
+ try: logx = self._transform.get_funcx().get_type()==LOG10
+ except RuntimeError: logx = False # non-separable
+
+ try: logy = self._transform.get_funcy().get_type()==LOG10
+ except RuntimeError: logy = False # non-separable
+
+ if not logx and not logy: return x, y
+
+ if self._logcache is not None:
+ return self._logcache
+
+ Nx = len(x)
+ Ny = len(y)
+
+ if logx: indx = greater(x, 0)
+ else: indx = ones(len(x))
+
+ if logy: indy = greater(y, 0)
+ else: indy = ones(len(y))
+
+ ind = nonzero(logical_and(indx, indy))
+ x = take(x, ind)
+ y = take(y, ind)
+
+ self._logcache = x, y
return x, y
def draw(self, renderer):
@@ -267,8 +296,11 @@ def get_ydata(self): return self._y
def _set_clip(self):
+
if not self._useDataClipping: return
+ #self._logcache = None
+
try: self._xmin, self._xmax
except AttributeError: indx = arange(len(self._x))
else:
@@ -402,7 +434,7 @@ def set_xdata(self, x):
except AttributeError: pass
self.set_data(x, self._y)
-
+
def set_ydata(self, y):
"""
Set the data array for y
@@ -427,6 +459,8 @@ def set_xclip(self, *args):
self._xmin, self._xmax = xmin, xmax
self._set_clip()
+
+
def set_yclip(self, *args):
"""
Set the y clipping range for data clipping to ymin, ymax

0 comments on commit 0cca80c

Please sign in to comment.