Matplotlib绘图顺序错误

20

基本上我有两个数组,一个包含x轴的值,第二个包含y轴的值。问题是,当我执行操作时

plt.semilogy(out_samp,error_mc)

我遇到了这个问题

enter image description here

这个图看起来没有任何意义。原因是plot函数按照x数组中出现的顺序绘制所有点,而不关心它们是否按升序排序。我该如何对这两个数组进行排序,以便按递增值对x数组排序并以相同的方式对y轴排序,以便点相同但是图被连接在一起,这样就不会出现这种混乱情况了?


输入数据是Python列表还是numpy向量? - Łukasz Rogalski
它们是列表。抱歉,我应该早点说。 - user6334462
你可以使用散点图(在图表上具有未关联的点)作为第一步,而不是绘制一条线。 - belka
6个回答

24

16

在绘图之前按x轴的值进行排序。这是一个MWE。

import itertools

x = [3, 5, 6, 1, 2]
y = [6, 7, 8, 9, 10]

lists = sorted(itertools.izip(*[x, y]))
new_x, new_y = list(itertools.izip(*lists))

# import operator
# new_x = map(operator.itemgetter(0), lists)        # [1, 2, 3, 5, 6]
# new_y = map(operator.itemgetter(1), lists)        # [9, 10, 6, 7, 8]

# Plot
import matplotlib.pylab as plt
plt.plot(new_x, new_y)
plt.show()

对于小型数据,zip(如其他回答者所提到的)已经足够了。

new_x, new_y = zip(*sorted(zip(x, y)))

结果为,

这里输入图片描述


我遇到了一个“ValueError: too many values to unpack”的错误。正在尝试弄清它的含义。向量只包含50个值。(错误出现在sorted(...)行)。 - user6334462
@akinn,我刚刚更新了我的答案,包括一个例子。 - SparkAndShine
1
好的,现在它可以工作了,谢谢。不过,我在想,这样做是否更有效率?我的意思是使用itertools和operator。其他人提供的解决方案似乎也能工作。 - user6334462
@akinn,zip需要立即获取所有项。而izip只会推进底层迭代器。 - SparkAndShine
@akinn,请参考迭代工具 - 为高效循环创建迭代器的函数获取详细描述。 - SparkAndShine
MWE很好,但是@Hidde提供了一个更“现代”和更简单的Python 3.5答案。 - Tobbey

6

一种排序列表的替代方法是使用NumPy数组并使用np.sort()进行排序。使用数组的优点是在计算像y=f(x)这样的函数时可以进行矢量化操作。以下是绘制正态分布的示例:

不使用排序数据

mu, sigma = 0, 0.1
x = np.random.normal(mu, sigma, 200)
f = 1/(sigma * np.sqrt(2 * np.pi)) *np.exp( - (x - mu)**2 / (2 * sigma**2) )
plt.plot(x,f, '-bo', ms = 2)

输出 1

enter image description here

使用 np.sort() 函数,可以在计算正态分布时直接使用排序后的数组 x

mu, sigma = 0, 0.1
x = np.sort(np.random.normal(mu, sigma, 200)) 
# or use x = np.random.normal(mu, sigma, 200).sort()
f = 1/(sigma * np.sqrt(2 * np.pi)) *np.exp( - (x - mu)**2 / (2 * sigma**2) )
plt.plot(x,f, '-bo', ms = 2)

如果您已经有未排序的x和y数据,您可以使用numpy.argsort进行后排序。

mu, sigma = 0, 0.1
x = np.random.normal(mu, sigma, 200)
f = 1/(sigma * np.sqrt(2 * np.pi)) *np.exp( - (x - mu)**2 / (2 * sigma**2) )
plt.plot(np.sort(x), f[np.argsort(x)], '-bo', ms = 2)

注意上面的代码两次使用了 sort():首先使用 np.sort(x),然后使用 f[np.argsort(x)]。可以将总的 sort() 调用次数减少到一次:
# once you have your x and f...
indices = np.argsort(x)
plt.plot(x[indices], f[indices], '-bo', ms = 2)

在这两种情况下,输出结果如下: Output 2 enter image description here

你可以通过仅使用 sort(x) 一次来进一步提高性能。 - Thomas Kühn
1
@ThomasKühn:我在我的答案中添加了它作为一个替代方案。 - Sheldore
我编辑了答案,使其更清晰。如果您不同意,可以撤销更改。 - ImportanceOfBeingErnest
1
@Sheldore 我认为你仍然使用了两次排序:首先,当你执行 np.sort(x),其次是当你执行 f[np.argsort(x)]。我会改为这样做:indices = np.argsort(x),然后通过以下方式绘图:plt.plot(x[indices], f[indices]) - pfabri

1

只需要做这个

list=zip(*sorted(zip(*(x,y))))
plt.plot(*list)

sorted函数将根据第一个参数即x值进行排序。


但是,在Python 3中,从我所看到的情况来看,它返回的是一个元组。我已经为你的答案点赞了。然而,你的列表变量实际上是一个元组。(顺便说一句,使用“list”作为变量是一个相当糟糕的主意,因为“list”是一个内置数据结构,“list()”在技术上初始化一个列表。) - Prasad Raghavendra

0
你可以将数组转换为numpy数组,然后在第一个数组上使用argsort函数,接着使用argsort数组对两个数组进行排序。

我绘制了一个散点图,但很难解释。本质上,我的x向量是迭代次数,y是误差。 - user6334462

0

我认为你需要对一个数组进行排序,另一个数组也应该根据第一个数组进行排序。我从其他一些stackoverflow问题中得到了这个解决方案。很可能这应该是你的解决方案。

out_samp,error_mc=zip(*sorted(zip(out_samp,error_mc)))

现在绘制这两个值,您会得到一个正确的图形。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接