使用Pyplot在一个图中绘制两个数据集,跳过y轴的一部分

2 投票
3 回答
4263 浏览
提问于 2025-04-16 20:14

我正在用pylab.plot()把不同的数据集画到同一张图上,这个方法很好用。但是有一个数据集的值在0%到25%之间,另一个数据集的值在75%到100%之间。我想在y轴上跳过30%到70%这部分,以节省一些空间。你们有什么建议可以用pyplot来实现这个吗?

编辑:

为了更清楚,我添加了下面的图。我想在y轴上跳过30%到60%,这样红线和绿线就能靠得更近一些。

graphic

3 个回答

0

matplotlib的文档里其实有一个示例,教你怎么做这个。

基本的思路是把图表分成两个子图,在每个图上画同样的图,然后调整每个图的坐标轴,只显示特定的部分,最后让它看起来更美观。

那么,我们来试试这个方法。假设这是你的起始代码:

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

你可以把第二个函数的x值减去40,这样x值的范围就会变得连续。这会让你的x值范围从0%到70%。然后你可以这样设置x轴的刻度和标签:

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轴的标签):

上面脚本的输出

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

这段代码会生成下面这个图形。在这里输入图片描述

撰写回答