SourceForge logo
SourceForge logo
Menu

matplotlib-checkins — Commit notification. DO NOT POST to this list, just subscribe to it.

You can subscribe to this list here.

2007 Jan
Feb
Mar
Apr
May
Jun
Jul
(115)
Aug
(120)
Sep
(137)
Oct
(170)
Nov
(461)
Dec
(263)
2008 Jan
(120)
Feb
(74)
Mar
(35)
Apr
(74)
May
(245)
Jun
(356)
Jul
(240)
Aug
(115)
Sep
(78)
Oct
(225)
Nov
(98)
Dec
(271)
2009 Jan
(132)
Feb
(84)
Mar
(74)
Apr
(56)
May
(90)
Jun
(79)
Jul
(83)
Aug
(296)
Sep
(214)
Oct
(76)
Nov
(82)
Dec
(66)
2010 Jan
(46)
Feb
(58)
Mar
(51)
Apr
(77)
May
(58)
Jun
(126)
Jul
(128)
Aug
(64)
Sep
(50)
Oct
(44)
Nov
(48)
Dec
(54)
2011 Jan
(68)
Feb
(52)
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec
(1)
2018 Jan
Feb
Mar
Apr
May
(1)
Jun
Jul
Aug
Sep
Oct
Nov
Dec
S M T W T F S


1
(3)
2
3
4
(1)
5
6
(1)
7
(2)
8
(22)
9
(8)
10
(24)
11
(3)
12
(4)
13
14
(3)
15
(3)
16
(1)
17
(2)
18
(6)
19
20
21
(3)
22
(2)
23
(8)
24
(1)
25
26
(6)
27
(1)
28
(3)
29
(4)
30
31
(9)


Showing 2 results of 2

From: <md...@us...> - 2008年01月07日 21:18:02
Revision: 4804
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4804&view=rev
Author: mdboom
Date: 2008年01月07日 13:18:00 -0800 (2008年1月07日)
Log Message:
-----------
Merged revisions 4801-4803 via svnmerge from 
http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib
........
 r4802 | cmoad | 2008年01月06日 13:28:17 -0500 (2008年1月06日) | 1 line
 
 minor rev bump
........
Modified Paths:
--------------
 branches/transforms/API_CHANGES
 branches/transforms/CHANGELOG
 branches/transforms/setupext.py
Property Changed:
----------------
 branches/transforms/
Property changes on: branches/transforms
___________________________________________________________________
Name: svnmerge-integrated
 - /trunk/matplotlib:1-4800
 + /trunk/matplotlib:1-4803
Modified: branches/transforms/API_CHANGES
===================================================================
--- branches/transforms/API_CHANGES	2008年01月07日 21:15:58 UTC (rev 4803)
+++ branches/transforms/API_CHANGES	2008年01月07日 21:18:00 UTC (rev 4804)
@@ -169,6 +169,8 @@
 
 END OF TRANSFORMS REFACTORING
 
+0.91.2 Released
+
 For csv2rec, checkrows=0 is the new default indicating all rows
 will be checked for type inference
 
@@ -181,6 +183,7 @@
 
 Removed, dead/experimental ExampleInfo, Namespace and Importer
 code from matplotlib/__init__.py
+
 0.91.1 Released
 
 0.91.0 Released
Modified: branches/transforms/CHANGELOG
===================================================================
--- branches/transforms/CHANGELOG	2008年01月07日 21:15:58 UTC (rev 4803)
+++ branches/transforms/CHANGELOG	2008年01月07日 21:18:00 UTC (rev 4804)
@@ -1,3 +1,6 @@
+===============================================================
+2008年01月06日 Released 0.91.2 at revision 4802
+
 2007年12月26日 Reduce too-late use of matplotlib.use() to a warning
 instead of an exception, for backwards compatibility - EF
 
Modified: branches/transforms/setupext.py
===================================================================
--- branches/transforms/setupext.py	2008年01月07日 21:15:58 UTC (rev 4803)
+++ branches/transforms/setupext.py	2008年01月07日 21:18:00 UTC (rev 4804)
@@ -903,9 +903,9 @@
 # First test for a MacOSX/darwin framework install
 from os.path import join, exists
 framework_dirs = [
+ join(os.getenv('HOME'), '/Library/Frameworks'),
+ '/Library/Frameworks',
 '/System/Library/Frameworks/',
- '/Library/Frameworks',
- join(os.getenv('HOME'), '/Library/Frameworks')
 ]
 
 # Find the directory that contains the Tcl.framework and Tk.framework
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2008年01月07日 21:16:07
Revision: 4803
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4803&view=rev
Author: mdboom
Date: 2008年01月07日 13:15:58 -0800 (2008年1月07日)
Log Message:
-----------
Provide heavily-documented examples for adding new scales and
projections.
Fix various bugs related to non-rectangular clipping.
Remove MercatorLatitude scale from core and put it in an example.
Modified Paths:
--------------
 branches/transforms/doc/devel/add_new_projection.rst
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/patches.py
 branches/transforms/lib/matplotlib/projections/__init__.py
 branches/transforms/lib/matplotlib/projections/geo.py
 branches/transforms/lib/matplotlib/projections/polar.py
 branches/transforms/lib/matplotlib/scale.py
Added Paths:
-----------
 branches/transforms/examples/custom_projection_example.py
 branches/transforms/examples/custom_scale_example.py
Modified: branches/transforms/doc/devel/add_new_projection.rst
===================================================================
--- branches/transforms/doc/devel/add_new_projection.rst	2008年01月06日 18:28:17 UTC (rev 4802)
+++ branches/transforms/doc/devel/add_new_projection.rst	2008年01月07日 21:15:58 UTC (rev 4803)
@@ -4,190 +4,99 @@
 
 .. ::author Michael Droettboom
 
-Matplotlib supports the addition of new transformations that transform
-the data before it is displayed. In ``matplotlib`` nomenclature,
-separable transformations, working on a single dimension, are called
-"scales", and non-separable transformations, that take handle data in
-two or more dimensions at a time, are called "projections".
+Matplotlib supports the addition of custom procedures that transform
+the data before it is displayed.
 
+There is an important distinction between two kinds of
+transformations. Separable transformations, working on a single
+dimension, are called "scales", and non-separable transformations,
+that handle data in two or more dimensions at a time, are called
+"projections".
+
 From the user's perspective, the scale of a plot can be set with
-``set_xscale`` and ``set_yscale``. Choosing the projection
-currently has no *standardized* method. [MGDTODO]
+``set_xscale()`` and ``set_yscale()``. Projections can be chosen using
+the ``projection`` keyword argument to the ``plot()`` or ``subplot()``
+functions::
 
+ plot(x, y, projection="custom")
+
 This document is intended for developers and advanced users who need
-to add more scales and projections to matplotlib.
+to create new scales and projections for matplotlib. The necessary
+code for scales and projections can be included anywhere: directly
+within a plot script, in third-party code, or in the matplotlib source
+tree itself.
 
 
 Creating a new scale
 ====================
 
-Adding a new scale consists of defining a subclass of ``ScaleBase``,
-that brings together the following elements:
+Adding a new scale consists of defining a subclass of ``ScaleBase``
+(in the ``matplotlib.scale`` module), that includes the following
+elements:
 
- - A transformation from data space into plot space.
+ - A transformation from data coordinates into display coordinates.
 
- - An inverse of that transformation. For example, this is used to
- convert mouse positions back into data space.
+ - An inverse of that transformation. This is used, for example, to
+ convert mouse positions from screen space back into data space.
 
- - A function to limit the range of the axis to acceptable values. A
- log scale, for instance, would prevent the range from including
- values less than or equal to zero.
+ - A function to limit the range of the axis to acceptable values
+ (``limit_range_for_scale()``). A log scale, for instance, would
+ prevent the range from including values less than or equal to
+ zero.
 
 - Locators (major and minor) that determine where to place ticks in
 the plot, and optionally, how to adjust the limits of the plot to
- some "good" values.
+ some "good" values. Unlike ``limit_range_for_scale()``, which is
+ always enforced, the range setting here is only used when
+ automatically setting the range of the plot.
 
 - Formatters (major and minor) that specify how the tick labels
 should be drawn.
 
-There are a number of ``Scale`` classes in ``scale.py`` that may be
-used as starting points for new scales. As an example, this document
-presents adding a new scale ``MercatorLatitudeScale`` which can be
-used to plot latitudes in a Mercator_ projection. For simplicity,
-this scale assumes that it has a fixed center at the equator. The
-code presented here is a simplification of actual code in
-``matplotlib``, with complications added only for the sake of
-optimization removed.
+Once the class is defined, it must be registered with ``matplotlib``
+so that the user can select it.
 
-First define a new subclass of ``ScaleBase``::
+A full-fledged and heavily annotated example is in
+``examples/custom_scale_example.py``. There are also some ``Scale``
+classes in ``scale.py`` that may be used as starting points.
 
- class MercatorLatitudeScale(ScaleBase):
- """
- Scales data in range -pi/2 to pi/2 (-90 to 90 degrees) using
- the system used to scale latitudes in a Mercator projection.
 
- The scale function:
- ln(tan(y) + sec(y))
+Creating a new projection
+=========================
 
- The inverse scale function:
- atan(sinh(y))
+Adding a new projection consists of defining a subclass of ``Axes``
+(in the ``matplotlib.axes`` module), that includes the following
+elements:
 
- Since the Mercator scale tends to infinity at +/- 90 degrees,
- there is user-defined threshold, above and below which nothing
- will be plotted. This defaults to +/- 85 degrees.
+ - A transformation from data coordinates into display coordinates.
 
- source:
- http://en.wikipedia.org/wiki/Mercator_projection
- """
- name = 'mercator_latitude'
+ - An inverse of that transformation. This is used, for example, to
+ convert mouse positions from screen space back into data space.
 
-This class must have a member ``name`` that defines the string used to
-select the scale. For example,
-``gca().set_yscale("mercator_latitude")`` would be used to select the
-Mercator latitude scale.
+ - Transformations for the gridlines, ticks and ticklabels. Custom
+ projections will often need to place these elements in special
+ locations, and ``matplotlib`` has a facility to help with doing so.
 
-Next define two nested classes: one for the data transformation and
-one for its inverse. Both of these classes must be subclasses of
-``Transform`` (defined in ``transforms.py``).::
+ - Setting up default values (overriding ``cla()``), since the
+ defaults for a rectilinear axes may not be appropriate.
 
- class MercatorLatitudeTransform(Transform):
- input_dims = 1
- output_dims = 1
+ - Defining the shape of the axes, for example, an elliptical axes,
+ that will be used to draw the background of the plot and for
+ clipping any data elements.
 
-There are two class-members that must be defined. ``input_dims`` and
-``output_dims`` specify number of input dimensions and output
-dimensions to the transformation. These are used by the
-transformation framework to do some error checking and prevent
-incompatible transformations from being connected together. When
-defining transforms for a scale, which are by definition separable and
-only have one dimension, these members should always be 1.
+ - Defining custom locators and formatters for the projection. For
+ example, in a geographic projection, it may be more convenient to
+ display the grid in degrees, even if the data is in radians.
 
-``MercatorLatitudeTransform`` has a simple constructor that takes and
-stores the *threshold* for the Mercator projection (to limit its range
-to prevent plotting to infinity).::
+ - Set up interactive panning and zooming. This is left as an
+ "advanced" feature left to the reader, but there is an example of
+ this for polar plots in ``polar.py``.
 
- def __init__(self, thresh):
- Transform.__init__(self)
- self.thresh = thresh
+ - Any additional methods for additional convenience or features.
 
-The ``transform`` method is where the real work happens: It takes an N
-x 1 ``numpy`` array and returns a transformed copy. Since the range
-of the Mercator scale is limited by the user-specified threshold, the
-input array must be masked to contain only valid values.
-``matplotlib`` will handle masked arrays and remove the out-of-range
-data from the plot. Importantly, the transformation should return an
-array that is the same shape as the input array, since these values
-need to remain synchronized with values in the other dimension.::
+Once the class is defined, it must be registered with ``matplotlib``
+so that the user can select it.
 
- def transform(self, a):
- masked = ma.masked_where((a < -self.thresh) | (a > self.thresh), a)
- return ma.log(ma.abs(ma.tan(masked) + 1.0 / ma.cos(masked)))
-
-Lastly for the transformation class, define a method to get the
-inverse transformation::
-
- def inverted(self):
- return MercatorLatitudeScale.InvertedMercatorLatitudeTransform(self.thresh)
-
-The inverse transformation class follows the same pattern, but
-obviously the mathematical operation performed is different::
-
- class InvertedMercatorLatitudeTransform(Transform):
- input_dims = 1
- output_dims = 1
-
- def __init__(self, thresh):
- Transform.__init__(self)
- self.thresh = thresh
-
- def transform(self, a):
- return npy.arctan(npy.sinh(a))
-
- def inverted(self):
- return MercatorLatitudeScale.MercatorLatitudeTransform(self.thresh)
-
-Now we're back to methods for the ``MercatorLatitudeScale`` class.
-Any keyword arguments passed to ``set_xscale`` and ``set_yscale`` will
-be passed along to the scale's constructor. In the case of
-``MercatorLatitudeScale``, the ``thresh`` keyword argument specifies
-the degree at which to crop the plot data. The constructor also
-creates a local instance of the ``Transform`` class defined above,
-which is made available through its ``get_transform`` method::
-
- def __init__(self, axis, **kwargs):
- thresh = kwargs.pop("thresh", (85 / 180.0) * npy.pi)
- if thresh >= npy.pi / 2.0:
- raise ValueError("thresh must be less than pi/2")
- self.thresh = thresh
- self._transform = self.MercatorLatitudeTransform(thresh)
-
- def get_transform(self):
- return self._transform
-
-The ``limit_range_for_scale`` method must be provided to limit the
-bounds of the axis to the domain of the function. In the case of
-Mercator, the bounds should be limited to the threshold that was
-passed in. Unlike the autoscaling provided by the tick locators, this
-range limiting will always be adhered to, whether the axis range is set
-manually, determined automatically or changed through panning and
-zooming::
-
- def limit_range_for_scale(self, vmin, vmax, minpos):
- return max(vmin, -self.thresh), min(vmax, self.thresh)
-
-Lastly, the ``set_default_locators_and_formatters`` method sets up the
-locators and formatters to use with the scale. It may be that the new
-scale requires new locators and formatters. Doing so is outside the
-scope of this document, but there are many examples in ``ticker.py``.
-The Mercator example uses a fixed locator from -90 to 90 degrees and a
-custom formatter class to put convert the radians to degrees and put a
-degree symbol after the value::
-
- def set_default_locators_and_formatters(self, axis):
- class DegreeFormatter(Formatter):
- def __call__(self, x, pos=None):
- # \u00b0 : degree symbol
- return u"%d\u00b0" % ((x / npy.pi) * 180.0)
-
- deg2rad = npy.pi / 180.0
- axis.set_major_locator(FixedLocator(
- npy.arange(-90, 90, 10) * deg2rad))
- axis.set_major_formatter(DegreeFormatter())
- axis.set_minor_formatter(DegreeFormatter())
-
-Now that the Scale class has been defined, it must be registered so
-that ``matplotlib`` can find it::
-
- register_scale(MercatorLatitudeScale)
-
-.. _Mercator: http://en.wikipedia.org/wiki/Mercator_projection
\ No newline at end of file
+A full-fledged and heavily annotated example is in
+``examples/custom_projection_example.py``. The polar plot
+functionality in ``polar.py`` may also be interest.
Added: branches/transforms/examples/custom_projection_example.py
===================================================================
--- branches/transforms/examples/custom_projection_example.py	 (rev 0)
+++ branches/transforms/examples/custom_projection_example.py	2008年01月07日 21:15:58 UTC (rev 4803)
@@ -0,0 +1,473 @@
+from matplotlib.axes import Axes
+from matplotlib import cbook
+from matplotlib.patches import Circle
+from matplotlib.path import Path
+from matplotlib.ticker import Formatter, Locator, NullLocator, FixedLocator, NullFormatter
+from matplotlib.transforms import Affine2D, Affine2DBase, Bbox, \
+ BboxTransformTo, IdentityTransform, Transform, TransformWrapper
+from matplotlib.projections import register_projection
+
+# This example projection class is rather long, but it is designed to
+# illustrate many features, not all of which will be used every time.
+# It is also common to factor out a lot of these methods into common
+# code used by a number of projections with similar characteristics
+# (see geo.py).
+
+class HammerAxes(Axes):
+ """
+ A custom class for the Aitoff-Hammer projection, an equal-area map
+ projection.
+
+ http://en.wikipedia.org/wiki/Hammer_projection
+ """
+ # The projection must specify a name. This will be used be the
+ # user to select the projection, i.e. ``subplot(111,
+ # projection='hammer')``.
+ name = 'hammer'
+
+ # The number of interpolation steps when converting from straight
+ # lines to curves. (See ``transform_path``).
+ RESOLUTION = 75
+
+ def __init__(self, *args, **kwargs):
+ Axes.__init__(self, *args, **kwargs)
+ self.set_aspect(0.5, adjustable='box', anchor='C')
+ self.cla()
+
+ def cla(self):
+ """
+ Override to set up some reasonable defaults.
+ """
+ # Don't forget to call the base class
+ Axes.cla(self)
+
+ # Set up a default grid spacing
+ self.set_longitude_grid(30)
+ self.set_latitude_grid(15)
+ self.set_longitude_grid_ends(75)
+
+ # Turn off minor ticking altogether
+ self.xaxis.set_minor_locator(NullLocator())
+ self.yaxis.set_minor_locator(NullLocator())
+
+ # Do not display ticks -- we only want gridlines and text
+ self.xaxis.set_ticks_position('none')
+ self.yaxis.set_ticks_position('none')
+
+ # The limits on this projection are fixed -- they are not to
+ # be changed by the user. This makes the math in the
+ # transformation itself easier, and since this is a toy
+ # example, the easier, the better.
+ Axes.set_xlim(self, -npy.pi, npy.pi)
+ Axes.set_ylim(self, -npy.pi / 2.0, npy.pi / 2.0)
+
+ def cla(self):
+ """
+ Initialize the Axes object to reasonable defaults.
+ """
+ Axes.cla(self)
+
+ self.set_longitude_grid(30)
+ self.set_latitude_grid(15)
+ self.set_longitude_grid_ends(75)
+ self.xaxis.set_minor_locator(NullLocator())
+ self.yaxis.set_minor_locator(NullLocator())
+ self.xaxis.set_ticks_position('none')
+ self.yaxis.set_ticks_position('none')
+
+ # self.grid(rcParams['axes.grid'])
+
+ Axes.set_xlim(self, -npy.pi, npy.pi)
+ Axes.set_ylim(self, -npy.pi / 2.0, npy.pi / 2.0)
+
+ def _set_lim_and_transforms(self):
+ """
+ This is called once when the plot is created to set up all the
+ transforms for the data, text and grids.
+ """
+ # There are three important coordinate spaces going on here:
+ #
+ # 1. Data space: The space of the data itself
+ #
+ # 2. Axes space: The unit rectangle (0, 0) to (1, 1)
+ # covering the entire plot area.
+ #
+ # 3. Display space: The coordinates of the resulting image,
+ # often in pixels or dpi/inch.
+
+ # This function makes heavy use of the Transform classes in
+ # ``lib/matplotlib/transforms.py.`` For more information, see
+ # the inline documentation there.
+
+ # The goal of the first two transformations is to get from the
+ # data space (in this case longitude and latitude) to axes
+ # space. It is separated into a non-affine and affine part so
+ # that the non-affine part does not have to be recomputed when
+ # a simple affine change to the figure has been made (such as
+ # resizing the window or changing the dpi).
+
+ # 1) The core transformation from data space into
+ # rectilinear space defined in the HammerTransform class.
+ self.transProjection = self.HammerTransform(self.RESOLUTION)
+
+ # 2) The above has an output range that is not in the unit
+ # rectangle, so scale and translate it so it fits correctly
+ # within the axes. The peculiar calculations of xscale and
+ # yscale are specific to a Aitoff-Hammer projection, so don't
+ # worry about them too much.
+ xscale = 2.0 * npy.sqrt(2.0) * npy.sin(0.5 * npy.pi)
+ yscale = npy.sqrt(2.0) * npy.sin(0.5 * npy.pi)
+ self.transAffine = Affine2D() \
+ .scale(0.5 / xscale, 0.5 / yscale) \
+ .translate(0.5, 0.5)
+
+ # 3) This is the transformation from axes space to display
+ # space.
+ self.transAxes = BboxTransformTo(self.bbox)
+
+ # Now put these 3 transforms together -- from data all the way
+ # to display coordinates. Using the '+' operator, these
+ # transforms will be applied "in order". The transforms are
+ # automatically simplified, if possible, by the underlying
+ # transformation framework.
+ self.transData = \
+ self.transProjection + \
+ self.transAffine + \
+ self.transAxes
+
+ # The main data transformation is set up. Now deal with
+ # gridlines and tick labels.
+
+ # Longitude gridlines and ticklabels. The input to these
+ # transforms are in display space in x and axes space in y.
+ # Therefore, the input values will be in range (-xmin, 0),
+ # (xmax, 1). The goal of these transforms is to go from that
+ # space to display space. The tick labels will be offset 4
+ # pixels from the equator.
+ self._xaxis_pretransform = \
+ Affine2D() \
+ .scale(1.0, npy.pi) \
+ .translate(0.0, -npy.pi)
+ self._xaxis_transform = \
+ self._xaxis_pretransform + \
+ self.transData
+ self._xaxis_text1_transform = \
+ Affine2D().scale(1.0, 0.0) + \
+ self.transData + \
+ Affine2D().translate(0.0, 4.0)
+ self._xaxis_text2_transform = \
+ Affine2D().scale(1.0, 0.0) + \
+ self.transData + \
+ Affine2D().translate(0.0, -4.0)
+
+ # Now set up the transforms for the latitude ticks. The input to
+ # these transforms are in axes space in x and display space in
+ # y. Therefore, the input values will be in range (0, -ymin),
+ # (1, ymax). The goal of these transforms is to go from that
+ # space to display space. The tick labels will be offset 4
+ # pixels from the edge of the axes ellipse.
+ yaxis_stretch = Affine2D().scale(npy.pi * 2.0, 1.0).translate(-npy.pi, 0.0)
+ yaxis_space = Affine2D().scale(1.0, 1.1)
+ self._yaxis_transform = \
+ yaxis_stretch + \
+ self.transData
+ yaxis_text_base = \
+ yaxis_stretch + \
+ self.transProjection + \
+ (yaxis_space + \
+ self.transAffine + \
+ self.transAxes)
+ self._yaxis_text1_transform = \
+ yaxis_text_base + \
+ Affine2D().translate(-8.0, 0.0)
+ self._yaxis_text2_transform = \
+ yaxis_text_base + \
+ Affine2D().translate(8.0, 0.0)
+
+ def get_xaxis_transform(self):
+ """
+ Override this method to provide a transformation for the
+ x-axis grid and ticks.
+ """
+ return self._xaxis_transform
+
+ def get_xaxis_text1_transform(self, pixelPad):
+ """
+ Override this method to provide a transformation for the
+ x-axis tick labels.
+
+ Returns a tuple of the form (transform, valign, halign)
+ """
+ return self._xaxis_text1_transform, 'bottom', 'center'
+
+ def get_xaxis_text2_transform(self, pixelPad):
+ """
+ Override this method to provide a transformation for the
+ secondary x-axis tick labels.
+
+ Returns a tuple of the form (transform, valign, halign)
+ """
+ return self._xaxis_text2_transform, 'top', 'center'
+
+ def get_yaxis_transform(self):
+ """
+ Override this method to provide a transformation for the
+ y-axis grid and ticks.
+ """
+ return self._yaxis_transform
+
+ def get_yaxis_text1_transform(self, pixelPad):
+ """
+ Override this method to provide a transformation for the
+ y-axis tick labels.
+
+ Returns a tuple of the form (transform, valign, halign)
+ """
+ return self._yaxis_text1_transform, 'center', 'right'
+
+ def get_yaxis_text2_transform(self, pixelPad):
+ """
+ Override this method to provide a transformation for the
+ secondary y-axis tick labels.
+
+ Returns a tuple of the form (transform, valign, halign)
+ """
+ return self._yaxis_text2_transform, 'center', 'left'
+
+ def get_axes_patch(self):
+ """
+ Override this method to define the shape that is used for the
+ background of the plot. It should be a subclass of Patch.
+
+ In this case, it is a Circle (that may be warped by the axes
+ transform into an ellipse). Any data and gridlines will be
+ clipped to this shape.
+ """
+ return Circle((0.5, 0.5), 0.5)
+
+ # Prevent the user from applying scales to one or both of the
+ # axes. In this particular case, scaling the axes wouldn't make
+ # sense, so we don't allow it.
+ def set_xscale(self, *args, **kwargs):
+ if args[0] != 'linear':
+ raise NotImplementedError
+ Axes.set_xscale(self, *args, **kwargs)
+
+ def set_yscale(self, *args, **kwargs):
+ if args[0] != 'linear':
+ raise NotImplementedError
+ Axes.set_yscale(self, *args, **kwargs)
+
+ # Prevent the user from changing the axes limits. In our case, we
+ # want to display the whole sphere all the time, so we override
+ # set_xlim and set_ylim to ignore any input. This also applies to
+ # interactive panning and zooming in the GUI interfaces.
+ def set_xlim(self, *args, **kwargs):
+ Axes.set_xlim(self, -npy.pi, npy.pi)
+ Axes.set_ylim(self, -npy.pi / 2.0, npy.pi / 2.0)
+ set_ylim = set_xlim
+
+ def format_coord(self, long, lat):
+ """
+ Override this method to change how the values are displayed in
+ the status bar.
+
+ In this case, we want them to be displayed in degrees N/S/E/W.
+ """
+ long = long * (180.0 / npy.pi)
+ lat = lat * (180.0 / npy.pi)
+ if lat >= 0.0:
+ ns = 'N'
+ else:
+ ns = 'S'
+ if long >= 0.0:
+ ew = 'E'
+ else:
+ ew = 'W'
+ # \u00b0 : degree symbol
+ return u'%f\u00b0%s, %f\u00b0%s' % (abs(lat), ns, abs(long), ew)
+
+ class DegreeFormatter(Formatter):
+ """
+ This is a custom formatter that converts the native unit of
+ radians into (truncated) degrees and adds a degree symbol.
+ """
+ def __init__(self, round_to=1.0):
+ self._round_to = round_to
+
+ def __call__(self, x, pos=None):
+ degrees = (x / npy.pi) * 180.0
+ degrees = round(degrees / self._round_to) * self._round_to
+ # \u00b0 : degree symbol
+ return u"%d\u00b0" % degrees
+
+ def set_longitude_grid(self, degrees):
+ """
+ Set the number of degrees between each longitude grid.
+
+ This is an example method that is specific to this projection
+ class -- it provides a more convenient interface to set the
+ ticking than set_xticks would.
+ """
+ # Set up a FixedLocator at each of the points, evenly spaced
+ # by degrees.
+ number = (360.0 / degrees) + 1
+ self.xaxis.set_major_locator(
+ FixedLocator(
+ npy.linspace(-npy.pi, npy.pi, number, True)[1:-1]))
+ # Set the formatter to display the tick labels in degrees,
+ # rather than radians.
+ self.xaxis.set_major_formatter(self.DegreeFormatter(degrees))
+
+ def set_latitude_grid(self, degrees):
+ """
+ Set the number of degrees between each longitude grid.
+
+ This is an example method that is specific to this projection
+ class -- it provides a more convenient interface than
+ set_yticks would.
+ """
+ # Set up a FixedLocator at each of the points, evenly spaced
+ # by degrees.
+ number = (180.0 / degrees) + 1
+ self.yaxis.set_major_locator(
+ FixedLocator(
+ npy.linspace(-npy.pi / 2.0, npy.pi / 2.0, number, True)[1:-1]))
+ # Set the formatter to display the tick labels in degrees,
+ # rather than radians.
+ self.yaxis.set_major_formatter(self.DegreeFormatter(degrees))
+
+ def set_longitude_grid_ends(self, degrees):
+ """
+ Set the latitude(s) at which to stop drawing the longitude grids.
+
+ Often, in geographic projections, you wouldn't want to draw
+ longitude gridlines near the poles. This allows the user to
+ specify the degree at which to stop drawing longitude grids.
+
+ This is an example method that is specific to this projection
+ class -- it provides an interface to something that has no
+ analogy in the base Axes class.
+ """
+ longitude_cap = degrees * (npy.pi / 180.0)
+ # Change the xaxis gridlines transform so that it draws from
+ # -degrees to degrees, rather than -pi to pi.
+ self._xaxis_pretransform \
+ .clear() \
+ .scale(1.0, longitude_cap * 2.0) \
+ .translate(0.0, -longitude_cap)
+
+ def get_data_ratio(self):
+ """
+ Return the aspect ratio of the data itself.
+
+ This method should be overridden by any Axes that have a
+ fixed data ratio.
+ """
+ return 1.0
+
+ # Interactive panning and zooming is not supported with this projection,
+ # so we override all of the following methods to disable it.
+ def can_zoom(self):
+ """
+ Return True if this axes support the zoom box
+ """
+ return False
+ def start_pan(self, x, y, button):
+ pass
+ def end_pan(self):
+ pass
+ def drag_pan(self, button, key, x, y):
+ pass
+
+ # Now, the transforms themselves.
+
+ class HammerTransform(Transform):
+ """
+ The base Hammer transform.
+ """
+ input_dims = 2
+ output_dims = 2
+ is_separable = False
+
+ def __init__(self, resolution):
+ """
+ Create a new Hammer transform. Resolution is the number of steps
+ to interpolate between each input line segment to approximate its
+ path in curved Hammer space.
+ """
+ Transform.__init__(self)
+ self._resolution = resolution
+
+ def transform(self, ll):
+ """
+ Override the transform method to implement the custom transform.
+
+ The input and output are Nx2 numpy arrays.
+ """
+ longitude = ll[:, 0:1]
+ latitude = ll[:, 1:2]
+
+ # Pre-compute some values
+ half_long = longitude / 2.0
+ cos_latitude = npy.cos(latitude)
+ sqrt2 = npy.sqrt(2.0)
+
+ alpha = 1.0 + cos_latitude * npy.cos(half_long)
+ x = (2.0 * sqrt2) * (cos_latitude * npy.sin(half_long)) / alpha
+ y = (sqrt2 * npy.sin(latitude)) / alpha
+ return npy.concatenate((x, y), 1)
+
+ # This is where things get interesting. With this projection,
+ # straight lines in data space become curves in display space.
+ # This is done by interpolating new values between the input
+ # values of the data. Since ``transform`` must not return a
+ # differently-sized array, any transform that requires
+ # changing the length of the data array must happen within
+ # ``transform_path``.
+ def transform_path(self, path):
+ vertices = path.vertices
+ ipath = path.interpolated(self._resolution)
+ return Path(self.transform(ipath.vertices), ipath.codes)
+
+ def inverted(self):
+ return HammerAxes.InvertedHammerTransform(self._resolution)
+ inverted.__doc__ = Transform.inverted.__doc__
+
+ class InvertedHammerTransform(Transform):
+ input_dims = 2
+ output_dims = 2
+ is_separable = False
+
+ def __init__(self, resolution):
+ Transform.__init__(self)
+ self._resolution = resolution
+
+ def transform(self, xy):
+ x = xy[:, 0:1]
+ y = xy[:, 1:2]
+
+ quarter_x = 0.25 * x
+ half_y = 0.5 * y
+ z = npy.sqrt(1.0 - quarter_x*quarter_x - half_y*half_y)
+ longitude = 2 * npy.arctan((z*x) / (2.0 * (2.0*z*z - 1.0)))
+ latitude = npy.arcsin(y*z)
+ return npy.concatenate((longitude, latitude), 1)
+ transform.__doc__ = Transform.transform.__doc__
+
+ def inverted(self):
+ # The inverse of the inverse is the original transform... ;)
+ return HammerAxes.HammerTransform(self._resolution)
+ inverted.__doc__ = Transform.inverted.__doc__
+
+# Now register the projection with matplotlib so the user can select
+# it.
+register_projection(HammerAxes)
+
+# Now make a simple example using the custom projection.
+from pylab import *
+
+subplot(111, projection="hammer")
+grid(True)
+
+show()
Added: branches/transforms/examples/custom_scale_example.py
===================================================================
--- branches/transforms/examples/custom_scale_example.py	 (rev 0)
+++ branches/transforms/examples/custom_scale_example.py	2008年01月07日 21:15:58 UTC (rev 4803)
@@ -0,0 +1,165 @@
+from matplotlib import scale as mscale
+from matplotlib import transforms as mtransforms
+
+class MercatorLatitudeScale(mscale.ScaleBase):
+ """
+ Scales data in range -pi/2 to pi/2 (-90 to 90 degrees) using
+ the system used to scale latitudes in a Mercator projection.
+
+ The scale function:
+ ln(tan(y) + sec(y))
+
+ The inverse scale function:
+ atan(sinh(y))
+
+ Since the Mercator scale tends to infinity at +/- 90 degrees,
+ there is user-defined threshold, above and below which nothing
+ will be plotted. This defaults to +/- 85 degrees.
+
+ source:
+ http://en.wikipedia.org/wiki/Mercator_projection
+ """
+
+ # The scale class must have a member ``name`` that defines the
+ # string used to select the scale. For example,
+ # ``gca().set_yscale("mercator")`` would be used to select this
+ # scale.
+ name = 'mercator'
+
+
+ def __init__(self, axis, **kwargs):
+ """
+ Any keyword arguments passed to ``set_xscale`` and
+ ``set_yscale`` will be passed along to the scale's
+ constructor.
+
+ thresh: The degree above which to crop the data.
+ """
+ mscale.ScaleBase.__init__(self)
+ thresh = kwargs.pop("thresh", (85 / 180.0) * npy.pi)
+ if thresh >= npy.pi / 2.0:
+ raise ValueError("thresh must be less than pi/2")
+ self.thresh = thresh
+
+ def get_transform(self):
+ """
+ Override this method to return a new instance that does the
+ actual transformation of the data.
+
+ The MercatorLatitudeTransform class is defined below as a
+ nested class of this one.
+ """
+ return self.MercatorLatitudeTransform(self.thresh)
+
+ def set_default_locators_and_formatters(self, axis):
+ """
+ Override to set up the locators and formatters to use with the
+ scale. This is only required if the scale requires custom
+ locators and formatters. Writing custom locators and
+ formatters is rather outside the scope of this example, but
+ there are many helpful examples in ``ticker.py``.
+
+ In our case, the Mercator example uses a fixed locator from
+ -90 to 90 degrees and a custom formatter class to put convert
+ the radians to degrees and put a degree symbol after the
+ value::
+ """
+ class DegreeFormatter(Formatter):
+ def __call__(self, x, pos=None):
+ # \u00b0 : degree symbol
+ return u"%d\u00b0" % ((x / npy.pi) * 180.0)
+
+ deg2rad = npy.pi / 180.0
+ axis.set_major_locator(FixedLocator(
+ npy.arange(-90, 90, 10) * deg2rad))
+ axis.set_major_formatter(DegreeFormatter())
+ axis.set_minor_formatter(DegreeFormatter())
+
+ def limit_range_for_scale(self, vmin, vmax, minpos):
+ """
+ Override to limit the bounds of the axis to the domain of the
+ transform. In the case of Mercator, the bounds should be
+ limited to the threshold that was passed in. Unlike the
+ autoscaling provided by the tick locators, this range limiting
+ will always be adhered to, whether the axis range is set
+ manually, determined automatically or changed through panning
+ and zooming.
+ """
+ return max(vmin, -self.thresh), min(vmax, self.thresh)
+
+ class MercatorLatitudeTransform(mtransforms.Transform):
+ # There are two value members that must be defined.
+ # ``input_dims`` and ``output_dims`` specify number of input
+ # dimensions and output dimensions to the transformation.
+ # These are used by the transformation framework to do some
+ # error checking and prevent incompatible transformations from
+ # being connected together. When defining transforms for a
+ # scale, which are, by definition, separable and have only one
+ # dimension, these members should always be set to 1.
+ input_dims = 1
+ output_dims = 1
+ is_separable = True
+
+ def __init__(self, thresh):
+ mtransforms.Transform.__init__(self)
+ self.thresh = thresh
+
+ def transform(self, a):
+ """
+ This transform takes an Nx1 ``numpy`` array and returns a
+ transformed copy. Since the range of the Mercator scale
+ is limited by the user-specified threshold, the input
+ array must be masked to contain only valid values.
+ ``matplotlib`` will handle masked arrays and remove the
+ out-of-range data from the plot. Importantly, the
+ ``transform`` method *must* return an array that is the
+ same shape as the input array, since these values need to
+ remain synchronized with values in the other dimension.
+ """
+ masked = ma.masked_where((a < -self.thresh) | (a > self.thresh), a)
+ if masked.mask.any():
+ return ma.log(npy.abs(ma.tan(masked) + 1.0 / ma.cos(masked)))
+ else:
+ return npy.log(npy.abs(npy.tan(a) + 1.0 / npy.cos(a)))
+
+ def inverted(self):
+ """
+ Override this method so matplotlib knows how to get the
+ inverse transform for this transform.
+ """
+ return MercatorLatitudeScale.InvertedMercatorLatitudeTransform(self.thresh)
+
+ class InvertedMercatorLatitudeTransform(mtransforms.Transform):
+ input_dims = 1
+ output_dims = 1
+ is_separable = True
+
+ def __init__(self, thresh):
+ mtransforms.Transform.__init__(self)
+ self.thresh = thresh
+
+ def transform(self, a):
+ return npy.arctan(npy.sinh(a))
+
+ def inverted(self):
+ return MercatorLatitudeScale.MercatorLatitudeTransform(self.thresh)
+
+# Now that the Scale class has been defined, it must be registered so
+# that ``matplotlib`` can find it.
+mscale.register_scale(MercatorLatitudeScale)
+
+from pylab import *
+import numpy as npy
+
+t = arange(-180.0, 180.0, 0.1)
+s = t / 360.0 * npy.pi
+
+plot(t, s, '-', lw=2)
+gca().set_yscale('mercator')
+
+xlabel('Longitude')
+ylabel('Latitude')
+title('Mercator: Projection of the Oppressor')
+grid(True)
+
+show()
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2008年01月06日 18:28:17 UTC (rev 4802)
+++ branches/transforms/lib/matplotlib/axes.py	2008年01月07日 21:15:58 UTC (rev 4803)
@@ -550,6 +550,10 @@
 
 self.bbox = mtransforms.TransformedBbox(self._position, fig.transFigure)
 #these will be updated later as data is added
+	self.dataLim = mtransforms.Bbox.unit()
+ self.viewLim = mtransforms.Bbox.unit()
+ self.transScale = mtransforms.TransformWrapper(mtransforms.IdentityTransform())
+
 self._set_lim_and_transforms()
 
 def _set_lim_and_transforms(self):
@@ -558,8 +562,6 @@
 transScale, transData, transLimits and transAxes
 transformations.
 """
-	self.dataLim = mtransforms.Bbox.unit()
- self.viewLim = mtransforms.Bbox.unit()
 self.transAxes = mtransforms.BboxTransformTo(self.bbox)
 
 # Transforms the x and y axis separately by a scale factor
Modified: branches/transforms/lib/matplotlib/patches.py
===================================================================
--- branches/transforms/lib/matplotlib/patches.py	2008年01月06日 18:28:17 UTC (rev 4802)
+++ branches/transforms/lib/matplotlib/patches.py	2008年01月07日 21:15:58 UTC (rev 4803)
@@ -371,6 +371,7 @@
 self._width = width
 self._height = height
 self._rect_transform = transforms.IdentityTransform()
+ self._update_patch_transform()
 __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
 
 def get_path(self):
@@ -862,6 +863,7 @@
 self.angle = angle
 self._path = Path.unit_circle()
 self._patch_transform = transforms.IdentityTransform()
+ self._recompute_transform()
 
 def _recompute_transform(self):
 center = (self.convert_xunits(self.center[0]),
Modified: branches/transforms/lib/matplotlib/projections/__init__.py
===================================================================
--- branches/transforms/lib/matplotlib/projections/__init__.py	2008年01月06日 18:28:17 UTC (rev 4802)
+++ branches/transforms/lib/matplotlib/projections/__init__.py	2008年01月07日 21:15:58 UTC (rev 4803)
@@ -26,7 +26,11 @@
 AitoffAxes,
 HammerAxes,
 LambertAxes)
+)
 
+def register_projection(cls):
+ projection_registry.register(cls)
+
 def get_projection_class(projection):
 if projection is None:
 projection = 'rectilinear'
Modified: branches/transforms/lib/matplotlib/projections/geo.py
===================================================================
--- branches/transforms/lib/matplotlib/projections/geo.py	2008年01月06日 18:28:17 UTC (rev 4802)
+++ branches/transforms/lib/matplotlib/projections/geo.py	2008年01月07日 21:15:58 UTC (rev 4803)
@@ -51,19 +51,13 @@
 Axes.set_ylim(self, -npy.pi / 2.0, npy.pi / 2.0)
 
 def _set_lim_and_transforms(self):
-	self.dataLim = Bbox.unit()
- self.viewLim = Bbox.unit()
- self.transAxes = BboxTransformTo(self.bbox)
-
- # Transforms the x and y axis separately by a scale factor
- # It is assumed that this part will have non-linear components
- self.transScale = TransformWrapper(IdentityTransform())
-
 # A (possibly non-linear) projection on the (already scaled) data
 self.transProjection = self._get_core_transform(self.RESOLUTION)
 
 self.transAffine = self._get_affine_transform()
 
+ self.transAxes = BboxTransformTo(self.bbox)
+
 # The complete data transformation stack -- from data all the
 # way to display coordinates
 self.transData = \
Modified: branches/transforms/lib/matplotlib/projections/polar.py
===================================================================
--- branches/transforms/lib/matplotlib/projections/polar.py	2008年01月06日 18:28:17 UTC (rev 4802)
+++ branches/transforms/lib/matplotlib/projections/polar.py	2008年01月07日 21:15:58 UTC (rev 4803)
@@ -186,8 +186,6 @@
 self.yaxis.set_ticks_position('none')
 
 def _set_lim_and_transforms(self):
-	self.dataLim = Bbox.unit()
- self.viewLim = Bbox.unit()
 self.transAxes = BboxTransformTo(self.bbox)
 
 # Transforms the x and y axis separately by a scale factor
Modified: branches/transforms/lib/matplotlib/scale.py
===================================================================
--- branches/transforms/lib/matplotlib/scale.py	2008年01月06日 18:28:17 UTC (rev 4802)
+++ branches/transforms/lib/matplotlib/scale.py	2008年01月07日 21:15:58 UTC (rev 4803)
@@ -307,94 +307,11 @@
 return self._transform
 
 
-class MercatorLatitudeScale(ScaleBase):
- """
- Scales data in range -pi/2 to pi/2 (-90 to 90 degrees) using
- the system used to scale latitudes in a Mercator projection.
 
- The scale function:
- ln(tan(y) + sec(y))
-
- The inverse scale function:
- atan(sinh(y))
-
- Since the Mercator scale tends to infinity at +/- 90 degrees,
- there is user-defined threshold, above and below which nothing
- will be plotted. This defaults to +/- 85 degrees.
-
- source:
- http://en.wikipedia.org/wiki/Mercator_projection
- """
- name = 'mercator_latitude'
-
- class MercatorLatitudeTransform(Transform):
- input_dims = 1
- output_dims = 1
- is_separable = True
-
- def __init__(self, thresh):
- Transform.__init__(self)
- self.thresh = thresh
-
- def transform(self, a):
- masked = ma.masked_where((a < -self.thresh) | (a > self.thresh), a)
- if masked.mask.any():
- return ma.log(npy.abs(ma.tan(masked) + 1.0 / ma.cos(masked)))
- else:
- return npy.log(npy.abs(npy.tan(a) + 1.0 / npy.cos(a)))
-
- def inverted(self):
- return MercatorLatitudeScale.InvertedMercatorLatitudeTransform(self.thresh)
-
- class InvertedMercatorLatitudeTransform(Transform):
- input_dims = 1
- output_dims = 1
- is_separable = True
-
- def __init__(self, thresh):
- Transform.__init__(self)
- self.thresh = thresh
-
- def transform(self, a):
- return npy.arctan(npy.sinh(a))
-
- def inverted(self):
- return MercatorLatitudeScale.MercatorLatitudeTransform(self.thresh)
-
- def __init__(self, axis, **kwargs):
- """
- thresh: The degree above which to crop the data.
- """
- thresh = kwargs.pop("thresh", (85 / 180.0) * npy.pi)
- if thresh >= npy.pi / 2.0:
- raise ValueError("thresh must be less than pi/2")
- self.thresh = thresh
- self._transform = self.MercatorLatitudeTransform(thresh)
-
- def set_default_locators_and_formatters(self, axis):
- class DegreeFormatter(Formatter):
- def __call__(self, x, pos=None):
- # \u00b0 : degree symbol
- return u"%d\u00b0" % ((x / npy.pi) * 180.0)
-
- deg2rad = npy.pi / 180.0
- axis.set_major_locator(FixedLocator(
- npy.arange(-90, 90, 10) * deg2rad))
- axis.set_major_formatter(DegreeFormatter())
- axis.set_minor_formatter(DegreeFormatter())
-
- def get_transform(self):
- return self._transform
-
- def limit_range_for_scale(self, vmin, vmax, minpos):
- return max(vmin, -self.thresh), min(vmax, self.thresh)
-
-
 _scale_mapping = {
 'linear' : LinearScale,
 'log' : LogScale,
- 'symlog' : SymmetricalLogScale,
- 'mercator_latitude' : MercatorLatitudeScale
+ 'symlog' : SymmetricalLogScale
 }
 def scale_factory(scale, axis, **kwargs):
 scale = scale.lower()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.

Showing 2 results of 2

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.
Thanks for helping keep SourceForge clean.
X





Briefly describe the problem (required):
Upload screenshot of ad (required):
Select a file, or drag & drop file here.
Screenshot instructions:

Click URL instructions:
Right-click on the ad, choose "Copy Link", then paste here →
(This may not be possible with some types of ads)

More information about our ad policies

Ad destination/click URL:

AltStyle によって変換されたページ (->オリジナル) /