如何在x轴上在相同距离处放置不同的幅度值

时间:2017-07-25 14:21:13

标签: python matplotlib plot

我正在使用Python在同一个图上绘制几条直线。 我的值在x值上变化很大(在我的代码中用变量q调用),所以我想把它们放在x轴上相同的距离,以便在图的第一部分。

这是我的代码:

def c(m,x):
'''
Linear cost function, describing costs for each weight range
:param m: the slope, modelling rates
:param x: the abscissa, modelling quantity ordered
:return: the cost value for each quantity
'''
    return 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.show()

为简单起见,我的代码片段中包含所有数据:

enter image description here

正如您所看到的,这是经典的数量折扣研究。 所以,如果我只是简单地绘制这些值,我就无法区分第一条直线上发生的情况,因为前几个q值保留的空间很小,见下文:

enter image description here

现在我向您展示第一个q值的缩放图:

enter image description here

我想到的解决方案是在相同距离绘制所有q[]值:请参阅下一张图片。 enter image description here 所以我想要实现的只是让所有q []值在x轴上相同的距离,独立于它们的值。我怎么能这样做?

1 个答案:

答案 0 :(得分:1)

如评论中所述,当操纵刻度以显示不均匀的间距时,直线将不再是直线。

以下是在问题中实现所需比例的代码。

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()

enter image description here

除了可能不需要的线条中的扭结,但是这里使用的比例类型的必然结果,y轴上的值仍然是非常难以理解的。