从 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 mag1time2 vs mag2time3 vs mag3,都在同一个情节上,但我得到的是 time.. vs @ 987654332@,例如。代码:

df['ExpTime1.3'].plot()

当我想要的是 'ExpTime1.3''LimMag1.3' 时,我得到 'ExpTime1.3'(y 轴)相对于 M0M6(x 轴)绘制,带有 x 标签 M0 - @ 987654340@.

    如何获得 'ExpTime..''LimMag..' 的图,所有 3 组数据都在同一个图上?

    如何在 x 轴上为 'LimMag..' 值(也在 x 轴上)获取 M0 - M6 标签?

自从尝试了 askewchan 的解决方案(由于未知原因没有返回任何图)以来,我发现如果我更改数据帧索引(df.index ) 到 x 轴 (LimMag1.3) 的值。但是,这似乎意味着我必须通过手动输入所需 x 轴的所有值使其成为数据索引来将每个所需的 x 轴转换为数据帧索引。我有大量数据,这种方法太慢了,我一次只能绘制一组数据,当我需要在一张图上为每个数据集绘制所有 3 个系列时。有没有办法解决这个问题?或者有人可以提供一个理由和解决方案,为什么我用 askewchan 提供的解决方案没有任何情节?\

针对nordev,我再次尝试了第一个版本,但没有产生任何情节,甚至没有一个空图。每次我输入 ax.plotcommands 之一时,我都会得到以下类型的输出: [<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.3vs 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 鉴于您的 DataFrame df 格式正确,那么 @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 文件中绘制直方图

Gatsby - 从 csv 文件中的参考字段制作流体图像宽度 ImageSharp

python:数据可视化 - 动态

如何从 matplotlib 中的图像数组制作视频?

如何将csv数据加载到matplotlib?

从 Python 的 pandas 中的数据帧制作 matplotlib 散点图