Problems with creating a new matplotlib ScaleBase class

· plotting, Uncategorized
Authors

So I have managed to create a new scale type in matplotlib using the ScaleBase class which is very useful and rather powerful. The scale subjects an axis to a squared transform, meaning that like a log plot, the x-values are spread out along the axis on a scale that is annotated with the actual values but visually and spatially scales as the square of those values. This is particularly useful for Guinier plots which are usually plotted as the square of Q versus the natural log of intensity.

At first the problem was that it was throwing errors all over the place when I attempted to move the view of the plot. Guessing that this was due to attempting to move across the axis and therefore taking the square root of a negative number on the inverse scale transform I first tried to modify the inverse transform to make sure it was multiplying negative numbers by minus one before taking the square root. Fiddling with this a variety of ways didn’t seem to help.

The next approach was to figure out how to set the scale defaults so that it stops you going to negative values on a squared scale. This seems fine, and now when re-scaling using the rectangle magnifier it no longer tries to expand the x-axis beyond zero. But now when using the cross hairs to move the data around in the plot it throws a segmentation fault when you attempt to move across the zero point on the x-axis. I’m not sure whether this is a real bug I’ve uncovered or whether I’m just doing something stupid but nonetheless, here is the code.

#!/usr/bin/env python
class SquaredScale(mscale.ScaleBase):
    """ScaleBase class for generating x axis of Guinier plots.

    Uses the built in scalebase to generate a transformed axis type
    called SquaredScale which can be called using ax.set_xscale('q_squared').
    Currently uses the default ticker and scale setup which will need
    to be changed in the future.

    The class requires the import of pylab (AutoLocator, ScalarFormatter
    NullLocator and NullFormatter) matplotlib.transforms (imported as
    mtransforms, required for the mtransforms.Transform class) and
    matplotlib.scale (imported as mscale, required for the mscale.ScaleBase
    class for inheritance of the scale).
    """

name = 'q_squared'

    def __init__(self, axis, **kwargs):
        mscale.ScaleBase.__init__(self)

    def set_default_locators_and_formatters(self, axis):
        """
        Set the locators and formatters to reasonable defaults for
        scaling. Not really too sure what these do at the moment.
        """
        axis.set_major_locator(AutoLocator())
        axis.set_major_formatter(ScalarFormatter())
        axis.set_minor_locator(NullLocator())
        axis.set_minor_formatter(NullFormatter())

    def limit_range_for_scale(self, vmin, vmax, minpos):
        return  0, vmax

    class SquaredTransform(mtransforms.Transform):
        input_dims = 1
        output_dims = 1
        is_separable = True

        def transform(self, a): return a**2

        def inverted(self):
            return SquaredScale.InvertedSquaredTransform()

    class InvertedSquaredTransform(mtransforms.Transform):
        input_dims = 1
        output_dims = 1
        is_separable = True

        def transform(self, a):
            return sqrt(a)

        def inverted(self):
            return SquaredScale.SquaredTransform()

    def get_transform(self):
        """Set the actual transform for the axis coordinates.

        """
        return self.SquaredTransform()

mscale.register_scale(SquaredScale)

3 Comments

Comments RSS

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: