【问题标题】:Square root scale using matplotlib/python使用 matplotlib/python 的平方根刻度
【发布时间】:2017-07-05 19:15:52
【问题描述】:

我想用 Python 制作一个平方根比例的图:

但是,我不知道如何制作它。 Matplotlib 允许制作对数刻度,但在这种情况下,我需要像幂函数刻度这样的东西。

【问题讨论】:

标签: python matplotlib graph scale


【解决方案1】:

您可以创建自己的 ScaleBase 类来执行此操作。为了您的目的,我已经修改了 here 中的示例(它制作了平方比例,而不是平方根比例)。另请参阅文档here

请注意,要正确执行此操作,您可能还应该创建自己的自定义刻度定位器;不过,我还没有在这里这样做;我只是使用ax.set_yticks() 手动设置主要和次要刻度。

import matplotlib.scale as mscale
import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms
import matplotlib.ticker as ticker
import numpy as np

class SquareRootScale(mscale.ScaleBase):
    """
    ScaleBase class for generating square root scale.
    """
 
    name = 'squareroot'
 
    def __init__(self, axis, **kwargs):
        # note in older versions of matplotlib (<3.1), this worked fine.
        # mscale.ScaleBase.__init__(self)

        # In newer versions (>=3.1), you also need to pass in `axis` as an arg
        mscale.ScaleBase.__init__(self, axis)
 
    def set_default_locators_and_formatters(self, axis):
        axis.set_major_locator(ticker.AutoLocator())
        axis.set_major_formatter(ticker.ScalarFormatter())
        axis.set_minor_locator(ticker.NullLocator())
        axis.set_minor_formatter(ticker.NullFormatter())
 
    def limit_range_for_scale(self, vmin, vmax, minpos):
        return  max(0., vmin), vmax
 
    class SquareRootTransform(mtransforms.Transform):
        input_dims = 1
        output_dims = 1
        is_separable = True
 
        def transform_non_affine(self, a): 
            return np.array(a)**0.5
 
        def inverted(self):
            return SquareRootScale.InvertedSquareRootTransform()
 
    class InvertedSquareRootTransform(mtransforms.Transform):
        input_dims = 1
        output_dims = 1
        is_separable = True
 
        def transform(self, a):
            return np.array(a)**2
 
        def inverted(self):
            return SquareRootScale.SquareRootTransform()
 
    def get_transform(self):
        return self.SquareRootTransform()
 
mscale.register_scale(SquareRootScale)

fig, ax = plt.subplots(1)

ax.plot(np.arange(0, 9)**2, label='$y=x^2$')
ax.legend()

ax.set_yscale('squareroot')
ax.set_yticks(np.arange(0,9,2)**2)
ax.set_yticks(np.arange(0,8.5,0.5)**2, minor=True)

plt.show()

【讨论】:

    【解决方案2】:

    这是旧的,但我做了一个快速修复,因为我不想费心创建自定义刻度定位器。如果您要使用自定义比例制作很多地块,那可能是要走的路。只需按照您想要的比例绘制函数,然后如果您只需要一两个绘图,设置刻度和更改标签会更快。

    Nx = 100
    x = np.linspace(0,50,Nx)
    y = np.sqrt(x)
    
    fig, ax = plt.subplots(1, 1)
    
    plt.plot(np.sqrt(x), y)
    ax.set_xticks([np.sqrt(x[i]) for i in range(0, Nx, Nx // 10)])
    ax.set_xticklabels([str(round(x[i],0))[:-2] for i in range(0, Nx, Nx // 10)])
    plt.xlabel('x')
    plt.ylabel(r'y = $\sqrt{x}$')
    plt.grid()
    plt.show()
    

    产生情节

    【讨论】:

      【解决方案3】:

      我喜欢 lolopop 的评论和 tom 的回答,更快速和肮脏的解决方案是使用set_yticks and set_yticklabels,如下所示:

      x = np.arange(2, 15, 2)
      y = x * x
      
      fig = plt.figure()
      ax1 = fig.add_subplot(121)
      ax2 = fig.add_subplot(122)
      
      ax1.plot(x,y)
      
      ax2.plot(x, np.sqrt(y))
      ax2.set_yticks([2,4,6,8,10,12,14])
      ax2.set_yticklabels(['4','16','36','64','100','144','196'])
      

      【讨论】:

      • 据我了解“滴答机制”它只会强制使用错误的标签。绘图轴看起来像平方根刻度,但数据显示不会转换,因此绘图会完全误导。
      • @michal_2am 同意。将刻度标签与数据分离是一种不好的做法
      • 这就是我称之为“又快又脏”的原因。
      【解决方案4】:

      Matplotlib 现在提供了 powlaw 规范。因此将功率设置为 0.5 应该可以解决问题!

      参考Matplotlib Powerlaw norm

      还有他们的例子:

      """
      Demonstration of using norm to map colormaps onto data in non-linear ways.
      """
      
      import numpy as np
      import matplotlib.pyplot as plt
      import matplotlib.colors as colors
      from matplotlib.mlab import bivariate_normal
      
      N = 100
      X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)]
      
      '''
      PowerNorm: Here a power-law trend in X partially obscures a rectified
      sine wave in Y. We can remove gamma to 0.5 should do the trick using  PowerNorm.
      '''
      X, Y = np.mgrid[0:3:complex(0, N), 0:2:complex(0, N)]
      Z1 = (1 + np.sin(Y * 10.)) * X**(2.)
      
      fig, ax = plt.subplots(2, 1)
      
      pcm = ax[0].pcolormesh(X, Y, Z1, norm=colors.PowerNorm(gamma=1./2.),
                             cmap='PuBu_r')
      fig.colorbar(pcm, ax=ax[0], extend='max')
      
      pcm = ax[1].pcolormesh(X, Y, Z1, cmap='PuBu_r')
      fig.colorbar(pcm, ax=ax[1], extend='max')
      fig.show()
      

      【讨论】:

      • 这不能回答问题。问题是关于将轴比例更改为平方根比例。这个答案显示了如何将颜色图范数更改为平方根范数;虽然很有趣,但对原始问题没有帮助
      【解决方案5】:

      这是绘制的简单方法

      import numpy as np
      from matplotlib import pyplot as plt
      
      plt.rcParams["figure.dpi"] = 140
      
      fig, ax = plt.subplots()
      ax.spines["left"].set_position("zero")
      ax.spines["bottom"].set_position("zero")
      ax.spines["right"].set_color("none")
      ax.spines["top"].set_color("none")
      ax.xaxis.set_ticks_position("bottom")
      ax.yaxis.set_ticks_position("left")
      
      origin = [0, 0]
      
      # 45
      plt.plot(
          np.linspace(0, 1, 1000),
          np.sqrt(np.linspace(0, 1, 1000)),
          color="k",
      )
      
      ax.set_aspect("equal")
      plt.xlim(-0.25, 1)
      plt.ylim(0, 1)
      plt.yticks(ticks=np.linspace(0, 1, 6))
      plt.show()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-04-29
        • 2018-11-22
        • 1970-01-01
        • 2015-09-07
        • 2012-03-12
        • 1970-01-01
        • 2020-10-21
        相关资源
        最近更新 更多