简体   繁体   中英

Two corresponding y-axis

I'm trying to make a plot with two corresponding y-axis. What I would like is to have the value in one unit on the left y-axis (eg meters) and the corresponding value in another units (eg inches) on the left y-axis. I managed to do this in this case with meters and inches.

However, things do not work so easily when the conversion is not as obvious as just multiplying by something. In my case I'm trying to plot flux and magnitude. The formula to go from flux to magnitude is: 23.9 - log(flux).

And what worked when I plotted meters and inches does not work anymore. Here is my code:

host = host_subplot(111)
host.set_xlim((0.1,5)) 
host.set_ylim((1.,50.))

par1 = host.twinx()
par1.set_ylim((23.899999999999999, 19.652574989159952)) # Converting the ylim from flux to mag

host.set_xlabel('Wavelength (Microns)')
host.set_ylabel('Flux density ($\mu$Jy)')
par1.set_ylabel("Magnitude ")

host.errorbar(x, flux, fmt='rx' , xerr=errx, yerr = errorFlux)
par1.errorbar(x, mag, fmt='bx', xerr=errx, yerr=errorMag)

If this worked the two plots should superimpose, but they do not (and again, I made this work when doing something similar from meters to inches). I suspect this as something to do with the log, but when setting the scale to log it is even worse.

Try this, taken from: http://matplotlib.org/examples/api/two_scales.html I put my version of the example below.

I just made-up some datasets of exponentially growing data. Of course the axes can be fiddled with more precisely, like creating your own scales, ranges, and ticks-marks; all you have to do is spend some time doing examples from online and reading the API documentation. Also I'd point you towards this resource http://nbviewer.ipython.org/github/jrjohansson/scientific-python-lectures/blob/master/Lecture-4-Matplotlib.ipynb for some good examples.

from numpy import *
import matplotlib.pyplot as plt


x_data = arange(0,100,.1)
y1_data = x_data**10
y2_data = x_data**4


fig, ax1 = plt.subplots(nrows=1, ncols=1)
ax1.set_yscale('linear')
ax1.plot(x_data,y1_data,'b-')
ax1.set_xlabel("Unitless X's")

ax1.set_ylabel('Linear Scale', color='b')
for tl in ax1.get_yticklabels():
    tl.set_color('b')

ax2 = ax1.twinx()
ax2.plot(x_data,y2_data,'r.')
ax2.set_ylabel("Log Scale", color='r')
ax2.set_yscale('log')
for tl in ax2.get_yticklabels():
    tl.set_color('r')
plt.show()

So I finally managed to do this by creating a new scale in matplotlib. It can be improved but here is my class definition, based on http://matplotlib.org/examples/api/custom_scale_example.html :

import numpy as np
import matplotlib.pyplot as plt

from matplotlib import scale as mscale
from matplotlib import transforms as mtransforms

class MagScale(mscale.ScaleBase):
    name = 'mag'

    def __init__(self, axis, **kwargs):
        mscale.ScaleBase.__init__(self)
        self.thresh = None #thresh

    def get_transform(self):
        return self.MagTransform(self.thresh)

    def set_default_locators_and_formatters(self, axis):
        pass

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

        def __init__(self, thresh):
            mtransforms.Transform.__init__(self)
            self.thresh = thresh

        def transform_non_affine(self, mag):
            return 10**((np.array(mag) -1)/(-2.5))

        def inverted(self):
            return MagScale.InvertedMagTransform(self.thresh)

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

        def __init__(self, thresh):
            mtransforms.Transform.__init__(self)
            self.thresh = thresh

        def transform_non_affine(self, flux):
            return -2.5 * np.log10(np.array(flux)) + 1.

        def inverted(self):
            return MagScale.MagTransform(self.thresh)



def flux_to_mag(flux):
    return  -2.5 * np.log10(flux) + 1


mscale.register_scale(MagScale)

And here is a working example :

x    = np.arange(20.)
flux = x * 2 + 1
mag  = flux_to_mag(flux)

MagTransform = MagScale.InvertedMagTransform(0)


fig = plt.figure()
ax_flux = fig.add_subplot(111)

ax_flux.plot(x, flux,'-')
ax_flux.set_ylim([1,40])
ax_flux.set_ylabel('flux')

ax_mag  = ax_flux.twinx()
ax_mag.set_ylim(MagTransform.transform_non_affine(ax_flux.get_ylim())) #There may be an easier to do this.
ax_mag.set_yscale('mag')

ax_mag.plot(x,mag,'+')
plt.show()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM