【问题标题】:Pyplot, plot 2 dataset into one figure, skip part of the y-axisPyplot,将 2 个数据集绘制成一个图,跳过部分 y 轴
【发布时间】:2011-06-24 21:12:38
【问题描述】:

我正在使用 pylab.plot() 将不同的数据集绘制成一张图,效果很好。但是一个数据集的值在 0% 到 25% 之间,而另一个数据集的值在 75% 到 100% 之间。我想在 y 轴上跳过 30% 到 70% 以节省一些空间。您对 pyplot 有什么建议吗?

编辑:

为了清楚起见,我添加了以下图形。我想在 y 轴上跳过 30% 到 60%,以便红线和绿线靠得更近。

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    解决方案基于 Space_C0wb0ys 帖子。

    fig = pylab.figure()
    ax = fig.add_subplot(111)
    ax.plot( range(1,10), camean - 25, 'ro-' )
    ax.plot( range(1,10), oemean , 'go-' )
    ax.plot( range(1,10), hlmean , 'bo-' ) 
    ax.set_yticks(range(5, 60, 5))
    ax.set_yticklabels(["5","10","15","20","25","30","...","65","70","75"]) 
    ax.legend(('ClassificationAccuracy','One-Error','HammingLoss'),loc='upper right')
    pylab.show()
    

    此代码创建以下图形。

    【讨论】:

    • 我的解决方案显然不正确。由于您自己找到了正确的解决方案,因此您也可以接受。这很好。
    【解决方案2】:

    您可以从第二个函数的 x 值中减去 40,以使 x 值的范围连续。这将为您提供从 0% 到 70% 的范围。然后你可以设置 x 轴的 tic 和 labes 如下:

    x_ticks = range(71, 0, 10)
    a.set_xticks(x_ticks)
    a.set_xticklabels([str(x) for x in [0, 10, 20, 30, 70, 80, 90, 100]])
    

    a 是当前坐标区。所以基本上,你在 0% 到 70% 的范围内绘制你的函数,但是用一个间隙标记轴。

    为了说明——下面的脚本:

    from numpy import arange
    import matplotlib.pyplot as plt
    
    x1 = arange(0, 26) # first function
    y1 = x1**2
    
    x2 = arange(75, 100) # second function
    y2 = x2*4 + 10
    
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(x1, y1)
    ax.plot(x2 - 40, y2) # shift second function 40 to left
    ax.set_xticks(range(0, 61, 5)) # set custom x-ticks
    # set labels for x-ticks - labels have the gap we want
    ax.set_xticklabels([str(x) for x in range(0, 26, 5) + range(70, 101, 5)])
    plt.show()
    

    生成以下图(注意 x 标签):

    【讨论】:

      【解决方案3】:

      matplotlib 文档实际上有 an example 说明如何做到这一点。

      基本思想是将绘图分成两个子图,在每个图上放置相同的图,然后更改每个图的轴以仅显示特定部分,然后使其看起来更好。

      所以,让我们应用它。想象一下这是你的起始代码:

      import matplotlib.pyplot as plt
      import random, math
      
      # Generates data
      i = range(10)
      x = [math.floor(random.random() * 5) + 67 for i in range(10)]
      y = [math.floor(random.random() * 5) + 22 for i in range(10)]
      z = [math.floor(random.random() * 5) + 13 for i in range(10)]
      
      # Original plot
      fig, ax = plt.subplots()
      ax.plot(i, x, 'ro-')
      ax.plot(i, y, 'go-')
      ax.plot(i, z, 'bo-')
      
      plt.show()
      

      然后我们设法让x 与其他部分分开显示。

      首先,我们想将同一张图绘制两次,一个在另一个之上。为此,绘图功能需要是通用的。现在它应该看起来像这样:

      # Plotting function
      def plot(ax):
          ax.plot(i, x, 'ro-')
          ax.plot(i, y, 'go-')
          ax.plot(i, z, 'bo-')
      
      # Draw the graph on two subplots
      fig, (ax1, ax2) = plt.subplots(2, 1)
      plot(ax1)
      plot(ax2)
      

      现在这似乎更糟了,但我们可以更改每个轴的范围以专注于我们想要的。现在我只是选择简单的范围,我知道这些范围可以捕获所有数据,但稍后我会专注于使坐标轴相等。

      # Changes graph axes
      ax1.set_ylim(65, 75) # Top graph
      ax2.set_ylim(5, 30) # Bottom graph
      

      这越来越接近我们正在寻找的东西。现在我们需要让它看起来更好一点:

      # Hides the spines between the axes
      ax1.spines.bottom.set_visible(False)
      ax2.spines.top.set_visible(False)
      ax1.xaxis.tick_top()
      ax1.tick_params(labeltop=False)  # Don't put tick labels at the top
      ax2.xaxis.tick_bottom()
      
      # Adds slanted lines to axes
      d = .5  # proportion of vertical to horizontal extent of the slanted line
      kwargs = dict(
          marker=[(-1, -d), (1, d)],
          markersize=12,
          linestyle='none',
          color='k',
          mec='k',
          mew=1,
          clip_on=False
      )
      ax1.plot([0, 1], [0, 0], transform=ax1.transAxes, **kwargs)
      ax2.plot([0, 1], [1, 1], transform=ax2.transAxes, **kwargs)
      

      最后,让我们修复轴。在这里,您需要做一些数学运算并在布局上做出更多决定。例如,也许我们想让顶部的图更小,因为底部的图有两条线。为此,我们需要更改子图的高度比,如下所示:

      # Draw the graph on two subplots
      # Bottom graph is twice the size of the top one
      fig, (ax1, ax2) = plt.subplots(2, 1, gridspec_kw={'height_ratios': [1, 2]})
      

      最后,让坐标轴匹配是个好主意。在这种情况下,由于底部图像的大小是顶部图像的两倍,因此我们需要更改其中一个的轴以反映这一点。这次我选择修改最上面的那个。底部的图表涵盖了 25 的范围,这意味着顶部的图表应该涵盖了 12.5 的范围。

      # Changes graph axes
      ax1.set_ylim(60.5, 73) # Top graph
      ax2.set_ylim(5, 30) # Bottom graph
      

      这对我来说已经足够好了。如果您不希望刻度与虚线重叠,您可以更多地使用轴或刻度标签。

      最终代码:

      import matplotlib.pyplot as plt
      import random, math
      
      # Generates data
      i = range(10)
      x = [math.floor(random.random() * 5) + 67 for i in range(10)]
      y = [math.floor(random.random() * 5) + 22 for i in range(10)]
      z = [math.floor(random.random() * 5) + 13 for i in range(10)]
      
      # Plotting function
      def plot(ax):
          ax.plot(i, x, 'ro-')
          ax.plot(i, y, 'go-')
          ax.plot(i, z, 'bo-')
      
      # Draw the graph on two subplots
      # Bottom graph is twice the size of the top one
      fig, (ax1, ax2) = plt.subplots(2, 1, gridspec_kw={'height_ratios': [1, 2]})
      plot(ax1)
      plot(ax2)
      
      # Changes graph axes
      ax1.set_ylim(60.5, 73) # Top graph
      ax2.set_ylim(5, 30) # Bottom graph
      
      # Hides the spines between the axes
      ax1.spines.bottom.set_visible(False)
      ax2.spines.top.set_visible(False)
      ax1.xaxis.tick_top()
      ax1.tick_params(labeltop=False)  # Don't put tick labels at the top
      ax2.xaxis.tick_bottom()
      
      # Adds slanted lines to axes
      d = .5  # proportion of vertical to horizontal extent of the slanted line
      kwargs = dict(
          marker=[(-1, -d), (1, d)],
          markersize=12,
          linestyle='none',
          color='k',
          mec='k',
          mew=1,
          clip_on=False
      )
      ax1.plot([0, 1], [0, 0], transform=ax1.transAxes, **kwargs)
      ax2.plot([0, 1], [1, 1], transform=ax2.transAxes, **kwargs)
      
      plt.show()
      

      【讨论】:

        猜你喜欢
        • 2021-10-09
        • 1970-01-01
        • 2016-10-27
        • 1970-01-01
        • 2019-01-17
        • 1970-01-01
        • 2021-12-05
        • 1970-01-01
        • 2018-03-29
        相关资源
        最近更新 更多