How to put different in magnitude values at same distance on x-axis

后端 未结 1 856
栀梦
栀梦 2020-12-02 02:48

I\'m using Python to plot several straight lines on the same plot. I have a great variability in values magnitude over x values (called with variable q in my c

相关标签:
1条回答
  • 2020-12-02 03:49

    As said in the comments, when manipulating scale to show uneven spacings, straight lines would not be as straight lines any more.

    Below is a code that implements a scale like desired in the question.

    import numpy as np
    from numpy import ma
    from matplotlib import scale as mscale
    from matplotlib import transforms as mtransforms
    from matplotlib.ticker import FixedLocator
    
    
    class SegmentedScale(mscale.ScaleBase):
        name = 'segmented'
    
        def __init__(self, axis, **kwargs):
            mscale.ScaleBase.__init__(self)
            self.points = kwargs.get('points',[0,1])
            self.lb = self.points[0]
            self.ub = self.points[-1]
    
        def get_transform(self):
            return self.SegTrans(self.lb, self.ub, self.points)
    
        def set_default_locators_and_formatters(self, axis):
            axis.set_major_locator(FixedLocator(self.points))
    
        def limit_range_for_scale(self, vmin, vmax, minpos):
            return max(vmin, self.lb), min(vmax, self.ub)
    
        class SegTrans(mtransforms.Transform):
            input_dims = 1
            output_dims = 1
            is_separable = True
    
            def __init__(self, lb, ub, points):
                mtransforms.Transform.__init__(self)
                self.lb = lb
                self.ub = ub
                self.points = points
    
            def transform_non_affine(self, a):
                masked = a # ma.masked_where((a < self.lb) | (a > self.ub), a)
                return np.interp(masked, self.points, np.arange(len(self.points)))
    
            def inverted(self):
                return SegmentedScale.InvertedSegTrans(self.lb, self.ub, self.points)
    
        class InvertedSegTrans(SegTrans):
    
            def transform_non_affine(self, a):
                return np.interp(a, np.arange(len(self.points)), self.points)
            def inverted(self):
                return SegmentedScale.SegTrans(self.lb, self.ub, self.points)
    
    # Now that the Scale class has been defined, it must be registered so
    # that ``matplotlib`` can find it.
    mscale.register_scale(SegmentedScale)
    
    
    if __name__ == '__main__':
    
        u=  u"""0, 137.13, 0.082
            0.1, 112.46, 0.175
            0.2, 98.23, 0.368
            0.5, 72.38, 0.838
            1, 60.69, 8.932
            10, 54.21, 17.602
            20, 47.71, 48.355
            50, 46.14, 89.358
            100, 41.23, 241.147
            250, 39.77, 0"""
    
        import io
        import matplotlib.pyplot as plt
    
        q,r,breakpoints = np.loadtxt(io.StringIO(u), delimiter=", ", unpack=True)
    
        c = lambda m,x : m*x
    
        for i in range(0,9):
            w = np.arange(0., q[9], 0.01)
            plt.plot(w,c(r[i],w),'b--',linewidth=0.3)
            plt.plot( [q[i],breakpoints[i]] , [c(r[i], q[i]), c(r[i], breakpoints[i])], 'r')
            plt.plot(q[i + 1], c(r[i], breakpoints[i]), 'r.')
    
        plt.gca().set_xscale('segmented', points = q)
        plt.show()
    

    Apart from the kinks in the lines, which might not be desired, but are a necessary consequence from the kind of scale used here, the values on the y axis are still quite unreadable.

    0 讨论(0)
提交回复
热议问题