从 matplotlib 中的 .CSV 文件制作多线图
Posted
技术标签:
【中文标题】从 matplotlib 中的 .CSV 文件制作多线图【英文标题】:Make a multiline plot from .CSV file in matplotlib 【发布时间】:2013-05-10 06:08:44 【问题描述】:几周以来,我一直在尝试从 .CSV 文件在同一个图上绘制 3 组 (x, y) 数据,但我一无所获。我的数据最初是一个 Excel 文件,我已将其转换为 .CSV 文件,并使用 pandas
按照以下代码将其读入 IPython:
from pandas import DataFrame, read_csv
import pandas as pd
# define data location
df = read_csv(Location)
df[['LimMag1.3', 'ExpTime1.3', 'LimMag2.0', 'ExpTime2.0', 'LimMag2.5','ExpTime2.5']][:7]
我的数据格式如下:
Type mag1 time1 mag2 time2 mag3 time3
M0 8.87 41.11 8.41 41.11 8.16 65.78;
...
M6 13.95 4392.03 14.41 10395.13 14.66 25988.32
我正在尝试绘制time1
vs mag1
、time2
vs mag2
和 time3
vs mag3
,都在同一个情节上,但我得到的是 time..
vs @ 987654332@,例如。代码:
df['ExpTime1.3'].plot()
当我想要的是 'ExpTime1.3'
与 'LimMag1.3'
时,我得到 'ExpTime1.3'
(y 轴)相对于 M0
到 M6
(x 轴)绘制,带有 x 标签 M0
- @ 987654340@.
如何获得 'ExpTime..'
与 'LimMag..'
的图,所有 3 组数据都在同一个图上?
如何在 x 轴上为 'LimMag..'
值(也在 x 轴上)获取 M0
- M6
标签?
自从尝试了 askewchan 的解决方案(由于未知原因没有返回任何图)以来,我发现如果我更改数据帧索引(df.index ) 到 x 轴 (LimMag1.3) 的值。但是,这似乎意味着我必须通过手动输入所需 x 轴的所有值使其成为数据索引来将每个所需的 x 轴转换为数据帧索引。我有大量数据,这种方法太慢了,我一次只能绘制一组数据,当我需要在一张图上为每个数据集绘制所有 3 个系列时。有没有办法解决这个问题?或者有人可以提供一个理由和解决方案,为什么我用 askewchan 提供的解决方案没有任何情节?\
针对nordev,我再次尝试了第一个版本,但没有产生任何情节,甚至没有一个空图。每次我输入 ax.plot
commands 之一时,我都会得到以下类型的输出:
[<matplotlib.lines.Line2D at 0xb5187b8>]
,但是当我输入命令plt.show()
什么都没有发生。
当我在 askewchan 的第二个解决方案的循环之后输入 plt.show()
时,我收到一条错误消息,说 AttributeError: 'function' object has no attribute 'show'
我对我的原始代码做了更多的摆弄,现在可以通过使索引与 x 轴相同 (LimMag1.3) 来获得带有代码 df['ExpTime1.3'][:7].plot()
的 ExpTime1.3
vs LimMag1.3
的图,但我无法在同一个图上获得其他两组数据。如果您有任何进一步的建议,我将不胜感激。我在 Windows 7(64 位)上通过 Anaconda 1.5.0(64 位)和 spyder 使用 ipython 0.11.0,python 版本是 2.7.4。
【问题讨论】:
只是一个想法;在这种情况下,将M0
- M6
作为 x 轴上的标签没有实际意义,因为每个 M..
-标签都有 三个不同的 LimMag..
-值,意思是每个标签都必须放置在轴上的三个不同位置。这最终看起来很混乱,而不是信息丰富。
plt
定义为什么?应该不是'function' object
你熟悉matplotlib和pyplot的使用吗?
您好 askewchan,回答您的问题,我对 matplotlib、pylab、python 完全不熟悉;事实上,我从来没有做过任何类型的编程,也没有使用过 Excel 以外的任何东西——因此很困难..
@user2324693 试试看这里开始绘图:matplotlib.org/users/pyplot_tutorial.html
您好 nordev,带有 log x 轴的解决方案可能是最好的,减去末端标签,因为它们不正确,即 M0 不是最低值的光谱类别。但是,当我尝试运行它时,我收到一条关于范围的错误消息,即“期望整数,但得到浮点数”。数据是小数,但我不知道如何解决这个问题,所以它会期望浮动,因为我不明白你的代码。
【参考方案1】:
您可以在同一个图中调用pyplot.plot(time, mag)
三个不同的时间。给他们贴标签是明智的。像这样的:
import matplotlib.pyplot as plt
...
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(df['LimMag1.3'], df['ExpTime1.3'], label="1.3")
ax.plot(df['LimMag2.0'], df['ExpTime2.0'], label="2.0")
ax.plot(df['LimMag2.5'], df['ExpTime2.5'], label="2.5")
plt.show()
如果你想循环它,这会起作用:
fig = plt.figure()
ax = fig.add_subplot(111)
for x,y in [['LimMag1.3', 'ExpTime1.3'],['LimMag2.0', 'ExpTime2.0'], ['LimMag2.5','ExpTime2.5']]:
ax.plot(df[x], df[y], label=y)
plt.show()
【讨论】:
您好,askewchan,非常感谢您的帮助,但似乎仍然存在问题。我已经运行了您提供的两个代码,即使没有返回错误,也没有显示任何图。是否缺少一行代码,即 ax.plot 命令和 plt.show() 命令之间是否应该有一些代码?我得到的明显印象是 ipython 正在等待其他一些输入,但我对那可能是什么一无所知.. @user2324693 鉴于您的 DataFramedf
格式正确,那么 @askewchan 的代码应该可以完美运行。至少我从他的代码(pandas 0.11.0 & matplotlib 1.2.1)创建图没有问题。
@user2324693 我不确定是什么原因造成的。由于 nordev 似乎能够让它工作,我不知道如何重现这个问题(我没有 pandas)。
谢谢@nordev,我已经习惯了在x轴上:P【参考方案2】:
如果我对您的理解正确,无论是从这个问题还是您的previous one on the same subject,以下应该是您可以根据需要自定义的基本解决方案。
几个子图:
请注意,此解决方案将输出与同一图上垂直的光谱类(M0、M1、...)一样多的子图。如果您希望将每个 Spectral 类的图保存在单独的图中,则需要对代码进行一些修改。
import pandas as pd
from pandas import DataFrame, read_csv
import numpy as np
import matplotlib.pyplot as plt
# Here you put your code to read the CSV-file into a DataFrame df
plt.figure(figsize=(7,5)) # Set the size of your figure, customize for more subplots
for i in range(len(df)):
xs = np.array(df[df.columns[0::2]])[i] # Use values from odd numbered columns as x-values
ys = np.array(df[df.columns[1::2]])[i] # Use values from even numbered columns as y-values
plt.subplot(len(df), 1, i+1)
plt.plot(xs, ys, marker='o') # Plot circle markers with a line connecting the points
for j in range(len(xs)):
plt.annotate(df.columns[0::2][j][-3:] + '"', # Annotate every plotted point with last three characters of the column-label
xy = (xs[j],ys[j]),
xytext = (0, 5),
textcoords = 'offset points',
va = 'bottom',
ha = 'center',
clip_on = True)
plt.title('Spectral class ' + df.index[i])
plt.xlabel('Limiting Magnitude')
plt.ylabel('Exposure Time')
plt.grid(alpha=0.4)
plt.tight_layout()
plt.show()
所有在同一个轴上,按行分组(M0、M1、...)
这是另一种解决方案,可以将所有不同的 Spectral 类绘制在相同的 Axes 中,并带有标识不同类的图例。 plt.yscale('log')
是可选的,但鉴于值如何跨越如此大的范围,建议使用。
import pandas as pd
from pandas import DataFrame, read_csv
import numpy as np
import matplotlib.pyplot as plt
# Here you put your code to read the CSV-file into a DataFrame df
for i in range(len(df)):
xs = np.array(df[df.columns[0::2]])[i] # Use values from odd numbered columns as x-values
ys = np.array(df[df.columns[1::2]])[i] # Use values from even numbered columns as y-values
plt.plot(xs, ys, marker='o', label=df.index[i])
for j in range(len(xs)):
plt.annotate(df.columns[0::2][j][-3:] + '"', # Annotate every plotted point with last three characters of the column-label
xy = (xs[j],ys[j]),
xytext = (0, 6),
textcoords = 'offset points',
va = 'bottom',
ha = 'center',
rotation = 90,
clip_on = True)
plt.title('Spectral classes')
plt.xlabel('Limiting Magnitude')
plt.ylabel('Exposure Time')
plt.grid(alpha=0.4)
plt.yscale('log')
plt.legend(loc='best', title='Spectral classes')
plt.show()
所有在同一个轴上,按列分组(1.3"、2.0"、2.5")
第三种解决方案如下所示,其中数据按系列(列 1.3"、2.0"、2.5")而不是按 Spectral 类(M0、M1、...)分组。这个例子非常相似 @askewchan 的解决方案。一个不同之处在于,这里的 y 轴是对数轴,使线条非常平行。
import pandas as pd
from pandas import DataFrame, read_csv
import numpy as np
import matplotlib.pyplot as plt
# Here you put your code to read the CSV-file into a DataFrame df
xs = np.array(df[df.columns[0::2]]) # Use values from odd numbered columns as x-values
ys = np.array(df[df.columns[1::2]]) # Use values from even numbered columns as y-values
for i in range(df.shape[1]/2):
plt.plot(xs[:,i], ys[:,i], marker='o', label=df.columns[0::2][i][-3:]+'"')
for j in range(len(xs[:,i])):
plt.annotate(df.index[j], # Annotate every plotted point with its Spectral class
xy = (xs[:,i][j],ys[:,i][j]),
xytext = (0, -6),
textcoords = 'offset points',
va = 'top',
ha = 'center',
clip_on = True)
plt.title('Spectral classes')
plt.xlabel('Limiting Magnitude')
plt.ylabel('Exposure Time')
plt.grid(alpha=0.4)
plt.yscale('log')
plt.legend(loc='best', title='Series')
plt.show()
【讨论】:
您好 nordev,我刚刚看到上面的内容,谢谢,我会试一试。我希望能够将它们全部放在一个情节上,因为我有 6 个类似的情节要做,所有情节都有 3 个单独的系列(1.3 英寸、2.0 英寸和 2.5 英寸)。如果这将是一个可怕的图表我必须独立完成每个光谱类别!我的第一次尝试是在 Excel 中,它有点像我想要的,但只是在 3D 图中,而且信息量非常大 - 因此切换到 matplotlib... 您好 nordev,非常感谢您的辛勤工作,非常感谢 :) 希望我能够完成这些工作并获得一些有用的图表 - 非常适合这里的初学者,直到两几周前,我以前从未做过任何类型的编程;谈论被扔到最深处!大声笑:) 您好 nordev,如上所述,这第三个选项是我想使用的选项,但没有 M 标签。省略“j”循环,我得到一个带有“i”循环的线性图。但是,当我运行“plt.title”时,我会丢失我的情节并留下一个空框。运行其余代码会导致错误消息:C:\Anaconda\lib\site-packages\matplotlib\axes.py:4601: UserWarning: No labelled objects found。在单个 plots.warnings.warn("未找到标记的对象。" 上使用 label='...' kwarg,以及一个格式良好的网格,其中没有数据,尽管在 'i' 循环运行后在线性图中有数据. 另一个问题:如何限制要绘制的行数?我只想从 M0 到 M6。 'i' 循环后显示的完整数据转到 M9。 重新评论在我的图表中没有数据,我认为问题可能与 (label=df.columns[0::2][i][-3 ]+'"') 代码,因为如果我省略它,我不会收到“未找到标记的对象”错误,但是一旦我输入标题和 x,y 标签或更改 y,我仍然没有数据要记录的轴。但是,我不知道问题可能是什么,也不知道如何解决。以上是关于从 matplotlib 中的 .CSV 文件制作多线图的主要内容,如果未能解决你的问题,请参考以下文章
使用 matplotlib 和 pandas 从 csv 文件中绘制直方图