Python 使pyplot比gnuplot更快

Python 使pyplot比gnuplot更快,python,gnuplot,matplotlib,Python,Gnuplot,Matplotlib,我最近决定尝试matplotlib.pyplot,多年来一直使用gnuplot绘制科学数据。我一开始只是简单地读取一个数据文件并绘制两列,就像gnuplot用绘制'datafile'u1:2所做的那样。 我的舒适度要求如下: 跳过以#开头的行,并跳过空行 允许在实际数字之间和之前使用任意数量的空格 允许任意数量的列 快点 现在,下面的代码是我解决这个问题的方法。然而,与gnuplot相比,它确实没有那么快。这有点奇怪,因为我读到py(plot/thon)比gnuplot的一大优势是它的速度

我最近决定尝试matplotlib.pyplot,多年来一直使用gnuplot绘制科学数据。我一开始只是简单地读取一个数据文件并绘制两列,就像gnuplot用
绘制'datafile'u1:2
所做的那样。 我的舒适度要求如下:

  • 跳过以
    #
    开头的行,并跳过空行
  • 允许在实际数字之间和之前使用任意数量的空格
  • 允许任意数量的列
  • 快点
现在,下面的代码是我解决这个问题的方法。然而,与gnuplot相比,它确实没有那么快。这有点奇怪,因为我读到py(plot/thon)比gnuplot的一大优势是它的速度

import numpy as np
import matplotlib.pyplot as plt
import sys

datafile = sys.argv[1]
data = []
for line in open(datafile,'r'):
    if line and line[0] != '#':
        cols = filter(lambda x: x!='',line.split(' '))
        for index,col in enumerate(cols):
            if len(data) <= index:
                data.append([])
            data[index].append(float(col))

plt.plot(data[0],data[1])
plt.show()
将numpy导入为np
将matplotlib.pyplot作为plt导入
导入系统
数据文件=sys.argv[1]
数据=[]
对于打开的行(数据文件,'r'):
如果行和行[0]!=“#”:
cols=过滤器(λx:x!='',行分割('')
对于索引,枚举中的列(cols):
如果len(data)你真的需要找出瓶颈是什么

以下是一些微观优化:

import numpy as np
import matplotlib.pyplot as plt
import sys

datafile = sys.argv[1]
data = []
# use with to auto-close the file
for line in open(datafile,'r'):
    # line will never be False because it will always have at least a newline
    # maybe you mean line.rstrip()?
    # you can also try line.startswith('#') instead of line[0] != '#'
    if line and line[0] != '#':
        # not sure of the point of this
        # just line.split() will allow any number of spaces
        # if you do need it, use a list comprehension
        # cols = [col for col in line.split(' ') if col]
        # filter on a user-defined function is slow
        cols = filter(lambda x: x!='',line.split(' '))

        for index,col in enumerate(cols):
            # just made data a collections.defaultdict
            # initialized as data = defaultdict(list)
            # and you can skip this 'if' statement entirely
            if len(data) <= index:
                data.append([])
            data[index].append(float(col))

plt.plot(data[0],data[1])
plt.show()
这将为您提供一个
列表
元组
s,而不是
列表
s的
int
键控的
dict
,但在其他方面看起来相同。它可以作为一行代码来完成,但我将其拆分以使其更易于阅读。

您确实需要找出瓶颈所在

以下是一些微观优化:

import numpy as np
import matplotlib.pyplot as plt
import sys

datafile = sys.argv[1]
data = []
# use with to auto-close the file
for line in open(datafile,'r'):
    # line will never be False because it will always have at least a newline
    # maybe you mean line.rstrip()?
    # you can also try line.startswith('#') instead of line[0] != '#'
    if line and line[0] != '#':
        # not sure of the point of this
        # just line.split() will allow any number of spaces
        # if you do need it, use a list comprehension
        # cols = [col for col in line.split(' ') if col]
        # filter on a user-defined function is slow
        cols = filter(lambda x: x!='',line.split(' '))

        for index,col in enumerate(cols):
            # just made data a collections.defaultdict
            # initialized as data = defaultdict(list)
            # and you can skip this 'if' statement entirely
            if len(data) <= index:
                data.append([])
            data[index].append(float(col))

plt.plot(data[0],data[1])
plt.show()

这将为您提供一个
列表
元组
s,而不是
列表
s的
int
键控的
dict
,但在其他方面看起来相同。它可以作为一个单行程序来完成,但我将其拆分以使其更易于阅读。

既然已经安装了matplotlib,那么还必须安装numpy。满足您的所有要求,并且应该比自己在Python循环中解析文件快得多:

import numpy as np
import matplotlib.pyplot as plt

import textwrap
fname='/tmp/tmp.dat'
with open(fname,'w') as f:
    f.write(textwrap.dedent('''\
        id col1 col2 col3
        2010 1 2 3 4
        # Foo

        2011 5 6 7 8
        # Bar        
        # Baz
        2012 8 7 6 5
        '''))

data = np.genfromtxt(fname, 
                     comments='#',    # skip comment lines
                     dtype = None,    # guess dtype of each column
                     names=True)      # use first line as column names
print(data)
plt.plot(data['id'],data['col2'])
plt.show()

由于已安装matplotlib,因此还必须安装numpy。满足您的所有要求,并且应该比自己在Python循环中解析文件快得多:

import numpy as np
import matplotlib.pyplot as plt

import textwrap
fname='/tmp/tmp.dat'
with open(fname,'w') as f:
    f.write(textwrap.dedent('''\
        id col1 col2 col3
        2010 1 2 3 4
        # Foo

        2011 5 6 7 8
        # Bar        
        # Baz
        2012 8 7 6 5
        '''))

data = np.genfromtxt(fname, 
                     comments='#',    # skip comment lines
                     dtype = None,    # guess dtype of each column
                     names=True)      # use first line as column names
print(data)
plt.plot(data['id'],data['col2'])
plt.show()

删除
names=True
参数以获得普通numpy数组,或使用
names=('col1'、'col2'、…)
提供头。有关更多详细信息,请参阅上面链接的文档。谢谢您的帮助。快速提示:当没有列名时,数据[0]将是第一行,而不是第一列。为了解决这个问题,我使用了:
data=np.genfromtxt(…).T
,它转换返回的数据数组。然而,使用此解决方案仍然比gnuplot慢得多。@janoliver:gnuplot是用C编写的专用工具,而pyplot是基于python的。matplotlib/numpy/Python比gnuplot更通用,但我不认为它比gnuplot在gnuplot所做的领域更快。当然,gnuplot在做它应该做的事情时非常有效。但我认为numpy也得到了很好的优化。我还认为大多数“著名”的软件包都与函数的编译版本接口,因此loadtxt或genfromtxt会自己调用一些C程序将文件读入内存。@janoliver:我生成了一些形状(10000,4)的测试数据,并试图比较genfromtxt+plt.plot和gnuplot的plot的速度。他们都能显示散点图,没有明显的延迟。您确定Python程序没有执行其他操作以导致1/4s延迟吗?请删除
names=True
参数以获得普通numpy数组,或者使用
names=('col1'、'col2'、…)
提供头。有关更多详细信息,请参阅上面链接的文档。谢谢您的帮助。快速提示:当没有列名时,数据[0]将是第一行,而不是第一列。为了解决这个问题,我使用了:
data=np.genfromtxt(…).T
,它转换返回的数据数组。然而,使用此解决方案仍然比gnuplot慢得多。@janoliver:gnuplot是用C编写的专用工具,而pyplot是基于python的。matplotlib/numpy/Python比gnuplot更通用,但我不认为它比gnuplot在gnuplot所做的领域更快。当然,gnuplot在做它应该做的事情时非常有效。但我认为numpy也得到了很好的优化。我还认为大多数“著名”的软件包都与函数的编译版本接口,因此loadtxt或genfromtxt会自己调用一些C程序将文件读入内存。@janoliver:我生成了一些形状(10000,4)的测试数据,并试图比较genfromtxt+plt.plot和gnuplot的plot的速度。他们都能显示散点图,没有明显的延迟。你确定你的Python程序没有做其他事情导致1/4秒的延迟吗?也谢谢你对Python的总体建议。@janoliver很乐意帮忙。谢谢你对另一个答案的评论,我不知道:)。也谢谢你对python的总体建议。@janoliver很乐意帮忙。谢谢你对另一个答案的评论,我不知道:)。有趣的是,你读到pyplot速度更快,我有相反的印象(除非你指的是开发速度)。有趣的是,你读到pyplot速度更快,我有相反的印象(除非你指的是开发速度)。例如。