首页 文章

Matplotlib:轴的负侧不同比例

提问于
浏览
1

Background


我试图在一个图上显示三个变量 . 我根据其他一些变量使用不同颜色的线连接了这三个点 . 这显示在这里


Problem


我想要做的是在负x轴上有不同的比例 . 这将有助于我提供正x_ticks,不同的轴标签以及图像左侧线条的清晰和整洁的表示


Question


  • 如何从0向负方向开始具有不同的正x轴?

  • 根据在该方向上绘制的数据具有xticks

  • 为此新轴提供单独的xlabel


Additional information


我已经检查了有关包含多个轴的其他问题,例如thisthis . 但是,这些问题并没有达到目的 .

Code Used

font_size = 20
plt.rcParams.update({'font.size': font_size})

fig = plt.figure()
ax = fig.add_subplot(111)
#read my_data from file or create it

for case in my_data:

    #Iterating over my_data

    if condition1 == True:
        local_linestyle = '-'
        local_color = 'r'
        local_line_alpha = 0.6
    elif condition2 == 1:
        local_linestyle = '-'
        local_color = 'b'
        local_line_alpha = 0.6
    else:
        local_linestyle = '--'
        local_color = 'g'
        local_line_alpha = 0.6

    datapoint = [case[0], case[1], case[2]]

    plt.plot(datapoint[0], 0, color=local_color)
    plt.plot(-datapoint[2], 0, color=local_color)
    plt.plot(0, datapoint[1], color=local_color)
    plt.plot([datapoint[0], 0], [0, datapoint[1]], linestyle=local_linestyle, color=local_color)
    plt.plot([-datapoint[2], 0], [0, datapoint[1]], linestyle=local_linestyle, color=local_color)
plt.show()
exit()

2 回答

  • 1

    您可以定义自定义比例,其中低于零的值与高于零的值不同 .

    import numpy as np
    from matplotlib import scale as mscale
    from matplotlib import transforms as mtransforms
    from matplotlib.ticker import FuncFormatter
    
    class AsymScale(mscale.ScaleBase):
        name = 'asym'
    
        def __init__(self, axis, **kwargs):
            mscale.ScaleBase.__init__(self)
            self.a = kwargs.get("a", 1)
    
        def get_transform(self):
            return self.AsymTrans(self.a)
    
        def set_default_locators_and_formatters(self, axis):
            # possibly, set a different locator and formatter here.
            fmt = lambda x,pos: "{}".format(np.abs(x))
            axis.set_major_formatter(FuncFormatter(fmt))
    
        class AsymTrans(mtransforms.Transform):
            input_dims = 1
            output_dims = 1
            is_separable = True
    
            def __init__(self, a):
                mtransforms.Transform.__init__(self)
                self.a = a
    
            def transform_non_affine(self, x):
                return (x >= 0)*x + (x < 0)*x*self.a
    
            def inverted(self):
                return AsymScale.InvertedAsymTrans(self.a)
    
        class InvertedAsymTrans(AsymTrans):
    
            def transform_non_affine(self, x):
                return (x >= 0)*x + (x < 0)*x/self.a
            def inverted(self):
                return AsymScale.AsymTrans(self.a)
    

    使用此方法,您将提供缩放参数 a ,可以缩放轴的负部分 .

    # Now that the Scale class has been defined, it must be registered so
    # that ``matplotlib`` can find it.
    mscale.register_scale(AsymScale)
    
    import matplotlib.pyplot as plt
    fig, ax = plt.subplots()
    
    ax.plot([-2, 0, 5], [0,1,0])
    ax.set_xscale("asym", a=2)
    
    ax.annotate("negative axis", xy=(.25,0), xytext=(0,-30), 
                xycoords = "axes fraction", textcoords="offset points", ha="center")
    ax.annotate("positive axis", xy=(.75,0), xytext=(0,-30), 
                xycoords = "axes fraction", textcoords="offset points", ha="center")
    plt.show()
    

    关于需要什么xticks和标签的问题不是很清楚,所以我现在就把它留了下来 .

  • 1

    这是如何得到你想要的 . 此解决方案使用两个twined axes 对象来获得原点左侧和右侧的不同缩放,然后隐藏所有证据:

    import matplotlib.pyplot as plt
    import matplotlib as mpl
    from numbers import Number
    
    tickkwargs = {m+k:False for k in ('bottom','top','left','right') for m in ('','label')}
    
    p = np.zeros((10, 3, 2))
    p[:,0,0] -= np.arange(10)*.1 + .5
    p[:,1,1] += np.repeat(np.arange(5), 2)*.1 + .3
    p[:,2,0] += np.arange(10)*.5 + 2
    
    fig = plt.figure(figsize=(8,6))
    host = fig.add_subplot(111)
    par = host.twiny()
    
    host.set_xlim(-6, 6)
    par.set_xlim(-1, 1)
    
    for ps in p:
        # mask the points with negative x values
        ppos = ps[ps[:,0] >= 0].T
        host.plot(*ppos)
    
        # mask the points with positive x values
        pneg = ps[ps[:,0] <= 0].T
        par.plot(*pneg)
    
    # hide all possible ticks/notation text that could be set by the second x axis
    par.tick_params(axis="both", **tickkwargs)
    par.xaxis.get_offset_text().set_visible(False)
    
    # fix the x tick labels so they're all positive
    host.set_xticklabels(np.abs(host.get_xticks()))
    
    fig.show()
    

    输出:

    这是我在上面的代码中使用的点集 p 在正常绘制时的样子:

    fig = plt.figure(figsize=(8,6))
    ax = fig.gca()
    for ps in p:
        ax.plot(*ps.T)
    fig.show()
    

    输出:

相关问题