绘制一个(x,y)坐标列表

180
我有一组配对的列表(a, b),我想用Python的matplotlib库将其绘制成实际的x-y坐标。目前,它会生成两个图表,其中列表的索引作为x坐标,第一个图表的y值是配对中的a,第二个图表的y值是配对中的b。
为了澄清,我的数据看起来像这样:li = [(a,b), (c,d), ... , (t, u)],我想要一个一行代码的简洁调用plt.plot()。
如果我不需要一行代码的话,我可以很容易地这样做:
xs = [x[0] for x in li]
ys = [x[1] for x in li]
plt.plot(xs, ys)

如何让matplotlib将这些对作为x-y坐标进行绘制?

样本数据

# sample data
li = list(zip(range(1, 14), range(14, 27)))

li → [(1, 14), (2, 15), (3, 16), (4, 17), (5, 18), (6, 19), (7, 20), (8, 21), (9, 22), (10, 23), (11, 24), (12, 25), (13, 26)]

错误的情节

plt.plot(li)
plt.title('Incorrect Plot:\nEach index of the tuple plotted as separate lines')

enter image description here

期望的情节

这个产生了正确的情节,但是使用了太多行代码来解包li。我需要用一行代码解包和绘制,而不是多个列表推导。

xs = [x[0] for x in li]
ys = [x[1] for x in li]
plt.plot(xs, ys)
plt.title('Correct Plot:\nBut uses to many lines to unpack li')

enter image description here


本质上,这是一个关于如何解包元组列表的问题,可以通过将一对列表/元组解包为两个列表/元组来解决。然而,该答案并未展示如何将zip对象解包到绘图API中。 - Trenton McKinney
4个回答

266

考虑到问题中给定的li

li = list(zip(range(1, 14), range(14, 27)))

要将数据从pairs解包成lists,请使用zip

x, y = zip(*li)

x → (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)
y → (14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)

这个一行代码使用拆包运算符 (*),将元组列表解压给zip函数,然后再把zip对象解压给图形 API。

plt.scatter(*zip(*li))

输入图像描述

plt.plot(*zip(*li))

输入图像描述在此


68
如果你有一个numpy数组,你可以这样做:
import numpy as np
from matplotlib import pyplot as plt

data = np.array([
    [1, 2],
    [2, 3],
    [3, 6],
])
x, y = data.T
plt.scatter(x,y)
plt.show()

3
无法使用np.array的形式data=np.array([[x1,y1],[x2,y2],etc.])并且使用plt.plot(data)。我将始终需要提供两个数组而不是数组的数组? - Max Coplan
2
@MaxCoplan,没错,但你可以使用plt.plot(*data.T),它与上面的代码相同,但跳过了中间步骤。 - Zweedeend

12

如果您想绘制一条连接列表中所有点的单条线

plt.plot(li[:])

plt.show()

这将把列表中的所有成对元素连接成一条线,以列表的起始点和终止点作为笛卡尔平面上的点。 我希望这正是您想要的。


5
他不想编写一行代码,他想用“一句代码”来实现绘图。他寻找的答案(在3年前已经找到)是使用 scatter() 函数。 - Dartmouth
2
@Gathide:是的,它应该被踩,因为它根本不起作用,也不符合描述。plt.plot(li) 就像 plt.plot(li[:]) 一样。它只是简单地绘制了两条线,使用成对的 (y1, y2) 而不是 (x1, y1) - Eric Duminil
1
@Dartmouth的评论只有一半是正确的。OP想要用一行代码生成一个图形线条。OP说:“如果我不需要一行代码,我可以轻松地做到”,然后是产生单行的代码。这个答案并没有解决问题。它会产生与OP已经拥有的不想要的双线图相同的结果。 - Trenton McKinney

-1
Matplotlib的plotscatter或任何绘图方法都将x轴值作为第一个参数,y轴值作为第二个参数,并通过索引在坐标平面上匹配;因此,作为x轴值传递的第一个元素和作为y轴值传递的第一个元素对应于第一个点的x-y坐标,依此类推。
当您拥有坐标列表或numpy数组时,例如:
li = [(1, 14), (2, 15), (3, 16), (4, 17), (5, 18), (6, 19)]
# or 
arr = np.array([[1, 14], [2, 15], [3, 16], [4, 17], [5, 18], [6, 19]])

当您使用zip(*li)arr.T转置它们时,您将创建x轴和y轴值。然后,当您将它们传递给plot()scatter()调用时,您将它们作为位置参数(*args)传递。
import matplotlib.pyplot as plt
plt.scatter(*zip(*li));
# or
plt.scatter(*arr.T);

与任何Python函数调用一样,您可以通过位置或关键字传递更多参数。例如,如果您想要更改散点图中点的大小,可以通过传递s=来实现:

plt.scatter(*arr.T, s=100);

此外,您也可以使用plot函数绘制散点图(地图上的x-y坐标)。您只需要传递一个圆形(o)或点(.)标记(它是第三个位置参数)即可。
plt.plot(*zip(*li), 'o');
# or
plt.plot(*arr.T, '.');

您还可以设置绘图的颜色和标记。例如,plt.plot(*arr.T, 'ko') 绘制带有黑色圆圈的散点图。


这似乎是一个解释为什么被接受的答案的答案。从技术上讲,我会将其标记为对另一个答案的评论。在这个问题和其他问题中已经详细解释了拆包。 - Trenton McKinney
@TrentonMcKinney 这并不是为了解释拆包,而是为了说明为什么点(作为数学符号)应该分成x轴值和y轴值来在平面上绘制它们。这非常基础,但从这个问题的浏览量来看,这是初学者经常遇到的问题。 - cottontail
这不是问题所在。OP已经知道如何做到这一点。唯一的问题是如何将元组列表解包成一个一行代码。 - Trenton McKinney
1
@TrentonMcKinney,说得好,但考虑到这个问题已经有9年了,我认为OP的潜在问题并不重要。鉴于这是“在Python中绘制x-y坐标平面上的数据点”的谷歌搜索结果中排名最高的帖子,我敢打赌,_确实有_人来到这篇文章,他们不知道有plt.plotplt.scatter,更不用说需要分别传递x和y轴值,特别是如果他们来自一个按点一次绘制的语言背景。 - cottontail
Stack Overflow的目的是回答OP提出的问题,而不是用回答来解释为什么认为其他人会来问这个问题。 - Trenton McKinney
如果您认为在Python中绘制x-y坐标平面上的数据点并且需要分别传递x和y轴值很重要,那么请创建一个新问题来解决这些问题。不要挪用他人的问题来达到您的目的。您说“我认为OP的潜在问题并不重要”,这与答案相反。 - Trenton McKinney

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