Revision: 8074
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=8074&view=rev
Author:   heeres
Date:     2010-01-04 22:58:43 +0000 (Mon, 04 Jan 2010)

Log Message:
-----------
Add EngFormatter + example (Jason Heeris, Matthias Michler)

Modified Paths:
--------------
    trunk/matplotlib/lib/matplotlib/ticker.py

Added Paths:
-----------
    trunk/matplotlib/examples/api/engineering_formatter.py

Added: trunk/matplotlib/examples/api/engineering_formatter.py
===================================================================
--- trunk/matplotlib/examples/api/engineering_formatter.py                      
        (rev 0)
+++ trunk/matplotlib/examples/api/engineering_formatter.py      2010-01-04 
22:58:43 UTC (rev 8074)
@@ -0,0 +1,19 @@
+'''
+Demo to show use of the engineering Formatter.
+'''
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+from matplotlib.ticker import EngFormatter
+
+ax = plt.subplot(111)
+ax.set_xscale('log')
+formatter = EngFormatter(unit='Hz', places=1)
+ax.xaxis.set_major_formatter(formatter)
+
+xs = np.logspace(1, 9, 100)
+ys = (0.8 + 0.4 * np.random.uniform(size=100)) * np.log10(xs)**2
+ax.plot(xs, ys)
+
+plt.show()

Modified: trunk/matplotlib/lib/matplotlib/ticker.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/ticker.py   2010-01-04 17:22:32 UTC (rev 
8073)
+++ trunk/matplotlib/lib/matplotlib/ticker.py   2010-01-04 22:58:43 UTC (rev 
8074)
@@ -118,6 +118,7 @@
 
 
 from __future__ import division
+import decimal
 import math
 import numpy as np
 from matplotlib import rcParams
@@ -507,23 +508,23 @@
         is ``False``
         """
         self._base = base+0.0
-        self.labelOnlyBase=labelOnlyBase
+        self.labelOnlyBase = labelOnlyBase
         self.decadeOnly = True
 
-    def base(self,base):
+    def base(self, base):
         'change the *base* for labeling - warning: should always match the 
base used for :class:`LogLocator`'
-        self._base=base
+        self._base = base
 
-    def label_minor(self,labelOnlyBase):
+    def label_minor(self, labelOnlyBase):
         'switch on/off minor ticks labeling'
-        self.labelOnlyBase=labelOnlyBase
+        self.labelOnlyBase = labelOnlyBase
 
 
     def __call__(self, x, pos=None):
         'Return the format for tick val *x* at position *pos*'
         vmin, vmax = self.axis.get_view_interval()
         d = abs(vmax - vmin)
-        b=self._base
+        b = self._base
         if x == 0.0:
             return '0'
         sign = np.sign(x)
@@ -533,13 +534,13 @@
         if not isDecade and self.labelOnlyBase: s = ''
         elif x>10000: s= '%1.0e'%x
         elif x<1: s =  '%1.0e'%x
-        else        : s =  self.pprint_val(x,d)
+        else        : s =  self.pprint_val(x, d)
         if sign == -1:
             s =  '-%s' % s
 
         return self.fix_minus(s)
 
-    def format_data(self,value):
+    def format_data(self, value):
         self.labelOnlyBase = False
         value = cbook.strip_math(self.__call__(value))
         self.labelOnlyBase = True
@@ -554,14 +555,14 @@
         return abs(x-n)<1e-10
 
     def nearest_long(self, x):
-        if x==0: return 0L
-        elif x>0: return long(x+0.5)
+        if x == 0: return 0L
+        elif x > 0: return long(x+0.5)
         else: return long(x-0.5)
 
     def pprint_val(self, x, d):
         #if the number is not too big and it's an int, format it as an
         #int
-        if abs(x)<1e4 and x==int(x): return '%d' % x
+        if abs(x) < 1e4 and x == int(x): return '%d' % x
 
         if d < 1e-2: fmt = '%1.3e'
         elif d < 1e-1: fmt = '%1.3f'
@@ -572,7 +573,7 @@
         s =  fmt % x
         #print d, x, fmt, s
         tup = s.split('e')
-        if len(tup)==2:
+        if len(tup) == 2:
             mantissa = tup[0].rstrip('0').rstrip('.')
             sign = tup[1][0].replace('+', '')
             exponent = tup[1][1:].lstrip('0')
@@ -645,11 +646,97 @@
             if usetex:
                 s = r'$%s%d^{%d}$'% (sign_string, b, self.nearest_long(fx))
             else:
-                s = r'$\mathdefault{%s%d^{%d}}$'% (sign_string, b, 
self.nearest_long(fx))
+                s = r'$\mathdefault{%s%d^{%d}}$'% (sign_string, b,
+                                                   self.nearest_long(fx))
 
         return s
 
+class EngFormatter(Formatter):
+    """
+    Formats axis values using engineering prefixes to represent powers of 1000,
+    plus a specified unit, eg. 10 MHz instead of 1e7.
+    """
 
+    # The SI engineering prefixes
+    ENG_PREFIXES = {
+        -24: "y",
+        -21: "z",
+        -18: "a",
+        -15: "f",
+        -12: "p",
+         -9: "n",
+         -6: u"\u03bc", # Greek letter mu
+         -3: "m",
+          0: "",
+          3: "k",
+          6: "M",
+          9: "G",
+         12: "T",
+         15: "P",
+         18: "E",
+         21: "Z",
+         24: "Y"
+      }
+
+    def __init__(self, unit="", places=None):
+        self.unit = unit
+        self.places = places
+
+    def __call__(self, x, pos=None):
+        s = "%s%s" % (self.format_eng(x), self.unit)
+        return self.fix_minus(s)
+
+    def format_eng(self, num):
+        """ Formats a number in engineering notation, appending a letter
+        representing the power of 1000 of the original number. Some examples:
+
+        >>> format_eng(0)       for self.places = 0
+        '0'
+
+        >>> format_eng(1000000) for self.places = 1
+        '1.0 M'
+
+        >>> format_eng("-1e-6") for self.places = 2
+        u'-1.00 \u03bc'
+
+        @param num: the value to represent
+        @type num: either a numeric value or a string that can be converted to
+                   a numeric value (as per decimal.Decimal constructor)
+
+        @return: engineering formatted string
+        """
+
+        dnum = decimal.Decimal(str(num))
+
+        sign = 1
+
+        if dnum < 0:
+            sign = -1
+            dnum = -dnum
+
+        if dnum != 0:
+            pow10 = decimal.Decimal(int(math.floor(dnum.log10()/3)*3))
+        else:
+            pow10 = decimal.Decimal(0)
+
+        pow10 = pow10.min(max(self.ENG_PREFIXES.keys()))
+        pow10 = pow10.max(min(self.ENG_PREFIXES.keys()))
+
+        prefix = self.ENG_PREFIXES[int(pow10)]
+
+        mant = sign*dnum/(10**pow10)
+
+        if self.places is None:
+            format_str = u"%g %s"
+        elif self.places == 0:
+            format_str = u"%i %s"
+        elif self.places > 0:
+            format_str = (u"%%.%if %%s" % self.places)
+
+        formatted = format_str % (mant, prefix)
+
+        return formatted.strip()
+
 class Locator(TickHelper):
     """
     Determine the tick locations;


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

------------------------------------------------------------------------------
This SF.Net email is sponsored by the Verizon Developer Community
Take advantage of Verizon's best-in-class app development support
A streamlined, 14 day to market process makes app distribution fast and easy
Join now and get one step closer to millions of Verizon customers
http://p.sf.net/sfu/verizon-dev2dev 
_______________________________________________
Matplotlib-checkins mailing list
Matplotlib-checkins@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to