1 """
2 Experimental replacements for log formatting and tick marks.
3 """
4
5
6 from __future__ import division
7 import sys, os, re, time, math, warnings
8 import numpy as npy
9 import matplotlib as mpl
10 from matplotlib import verbose, rcParams
11 from matplotlib import cbook
12 from matplotlib import transforms as mtrans
13 from matplotlib import ticker
14
15
17 """
18 Format values for log axis; using exponent = log_base(value)
19 """
20
22 'Return the format for tick val x at position pos'
23 self.verify_intervals()
24
25 b = self._base
26 fx = math.log(abs(x))/math.log(b)
27 isDecade = self.is_decade(fx)
28
29 usetex = rcParams['text.usetex']
30
31 if x < 0: b = -b
32
33 if not isDecade and self.labelOnlyBase:
34 s = ''
35 elif not isDecade:
36
37
38
39
40 s = '%g'%(x)
41 else:
42 exp = self.nearest_long(fx)
43 if exp == 0:
44 s = 1
45 elif exp == 1:
46 s = '%g'%(x)
47 elif usetex:
48 s = r'$%g^{%d}$'% (b, self.nearest_long(fx))
49 else:
50 s = r'$\mathdefault{%g^{%d}}$'% (b, self.nearest_long(fx))
51
52 return s
53
54
56 'floor x to the nearest lower decade'
57
58 lx = math.floor(math.log(x)/math.log(base))
59 return base**lx
60
62 'ceil x to the nearest higher decade'
63 lx = math.ceil(math.log(x)/math.log(base))
64 return base**lx
65
67 lx = math.log(x)/math.log(base)
68 return lx==int(lx)
69
71 """
72 Determine the tick locations for log axes
73 """
74
75 - def __init__(self, base=10.0, subs=[1.0], ntics=5):
76 """
77 place ticks on the location= base**i*subs[j]
78 """
79 self.base(base)
80 self.subs(subs)
81 self.numticks = 15
82
83
84 self._ntics = 5
85 self._trim = True
86 self._integer = False
87 self._steps = [1.,2.,5.]
88
89 - def base(self,base):
90 """
91 set the base of the log scaling (major tick every base**i, i interger)
92 """
93 self._base=base+0.0
94
95 - def subs(self,subs):
96 """
97 set the minor ticks the log scaling every base**i*subs[j]
98 """
99 if subs is None:
100 self._subs = None
101 else:
102 self._subs = npy.asarray(subs)+0.0
103
106
108 nbins = self._ntics
109 scale, offset = ticker.scale_range(vmin, vmax, nbins)
110 vmin -= offset
111 vmax -= offset
112 raw_step = (vmax-vmin)/nbins
113 scaled_raw_step = raw_step/scale
114
115 for step in [1,2,5,10]:
116 if step < scaled_raw_step:
117 continue
118 step *= scale
119 best_vmin = step*divmod(vmin, step)[0]
120 best_vmax = best_vmin + step*nbins
121 if (best_vmax >= vmax):
122 break
123 if self._trim:
124 extra_bins = int(divmod((best_vmax - vmax), step)[0])
125 nbins -= extra_bins
126 return (npy.arange(nbins+1) * step + best_vmin + offset)
127
128
130 'Return the locations of the ticks'
131 self.verify_intervals()
132 b=self._base
133
134 linvmin, linvmax = self.viewInterval.get_bounds()
135
136 vmin = math.log(linvmin)/math.log(b)
137 vmax = math.log(linvmax)/math.log(b)
138 if vmax<vmin:
139 vmin, vmax = vmax, vmin
140 if vmax-vmin <= 1.:
141 return self.linear_tics(linvmin, linvmax)
142
143
144 ticklocs = []
145
146 numdec = math.floor(vmax)-math.ceil(vmin)
147
148 if self._subs is None:
149 if numdec>10: subs = npy.array([1.0])
150 elif numdec>6: subs = npy.arange(2.0, b, 2.0)
151 else: subs = npy.arange(2.0, b)
152 else:
153 subs = self._subs
154
155 stride = 1
156 while numdec/stride+1 > self.numticks:
157 stride += 1
158
159 for decadeStart in b**npy.arange(math.floor(vmin),
160 math.ceil(vmax)+stride, stride):
161 ticklocs.extend( subs*decadeStart )
162
163 return npy.array(ticklocs)
164
166 'Try to choose the view limits intelligently'
167 self.verify_intervals()
168
169 vmin, vmax = self.dataInterval.get_bounds()
170 if vmax<vmin:
171 vmin, vmax = vmax, vmin
172
173 minpos = self.dataInterval.minpos()
174
175 if minpos<=0:
176 raise RuntimeError('No positive data to plot')
177 if vmin<=0:
178 vmin = minpos
179 if not is_decade(vmin,self._base): vmin = decade_down(vmin,self._base)
180 if not is_decade(vmax,self._base): vmax = decade_up(vmax,self._base)
181 if vmin==vmax:
182 vmin = decade_down(vmin,self._base)
183 vmax = decade_up(vmax,self._base)
184 return mtrans.nonsingular(vmin, vmax)
185