Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从python调用gnuplot_Python_Gnuplot - Fatal编程技术网

从python调用gnuplot

从python调用gnuplot,python,gnuplot,Python,Gnuplot,我有一个python脚本,经过一些计算,它将生成两个格式化为gnuplot输入的数据文件 如何从python“调用”gnuplot 我想将以下python字符串作为输入发送到gnuplot: "plot '%s' with lines, '%s' with points;" % (eout,nout) 其中'eout'和'nout'是两个文件名 附言: 我宁愿不使用额外的python模块(例如gnuplotpy),而只使用标准API 谢谢此模块允许您调用其他程序: import subproc

我有一个python脚本,经过一些计算,它将生成两个格式化为gnuplot输入的数据文件

如何从python“调用”gnuplot

我想将以下python字符串作为输入发送到gnuplot:

"plot '%s' with lines, '%s' with points;" % (eout,nout)
其中'eout'和'nout'是两个文件名

附言: 我宁愿不使用额外的python模块(例如gnuplotpy),而只使用标准API

谢谢

此模块允许您调用其他程序:

import subprocess
plot = subprocess.Popen(['gnuplot'], stdin=subprocess.PIPE)
plot.communicate("plot '%s' with lines, '%s' with points;" % (eout,nout))

一种简单的方法可能是只编写包含gnuplot命令的第三个文件,然后告诉Python使用该文件执行gnuplot。说你写

"plot '%s' with lines, '%s' with points;" % (eout,nout)
到一个名为tmp.gp的文件。然后你可以用

from os import system, remove
system('gnuplot -persist tmp.gp')
remove('tmp.gp')

子流程在Doug Hellemann的文章中解释得非常清楚

这很有效:

import subprocess
proc = subprocess.Popen(['gnuplot','-p'], 
                        shell=True,
                        stdin=subprocess.PIPE,
                        )
proc.stdin.write('set xrange [0:10]; set yrange [-2:2]\n')
proc.stdin.write('plot sin(x)\n')
proc.stdin.write('quit\n') #close the gnuplot window
也可以使用“通信”,但除非使用gnuplot pause命令,否则绘图窗口将立即关闭

proc.communicate("""
set xrange [0:10]; set yrange [-2:2]
plot sin(x)
pause 4
""")

我试图做一些类似的事情,但另外,我想从python中输入数据,并将图形文件作为变量输出(因此数据和图形都不是实际文件)。这就是我想到的:

#! /usr/bin/env python

import subprocess
from sys import stdout, stderr
from os import linesep as nl

def gnuplot_ExecuteCommands(commands, data):
    args = ["gnuplot", "-e", (";".join([str(c) for c in commands]))]
    program = subprocess.Popen(\
        args, \
        stdin=subprocess.PIPE, \
        stdout=subprocess.PIPE, \
        stderr=subprocess.PIPE, \
        )
    for line in data:
        program.stdin.write(str(line)+nl)
    return program

def gnuplot_GifTest():
    commands = [\
        "set datafile separator ','",\
        "set terminal gif",\
        "set output",\
        "plot '-' using 1:2 with linespoints, '' using 1:2 with linespoints",\
        ]
    data = [\
        "1,1",\
        "2,2",\
        "3,5",\
        "4,2",\
        "5,1",\
        "e",\
        "1,5",\
        "2,4",\
        "3,1",\
        "4,4",\
        "5,5",\
        "e",\
        ]
    return (commands, data)

if __name__=="__main__":
    (commands, data) = gnuplot_GifTest()
    plotProg = gnuplot_ExecuteCommands(commands, data)
    (out, err) = (plotProg.stdout, plotProg.stderr)
    stdout.write(out.read())
该脚本将图形转储到stdout,作为main中的最后一步。等效的命令行(图形通过管道传输到'out.gif')将是:

gnuplot -e "set datafile separator ','; set terminal gif; set output; plot '-' using 1:2 with linespoints, '' using 1:2 with linespoints" > out.gif
1,1
2,2
3,5
4,2
5,1
e
1,5
2,4
3,1
4,4
5,5
e

下面是一个类,该类提供wgnuplot.exe的接口:

from ctypes import *
import time
import sys
import os

#
# some win32 constants
#
WM_CHAR     = 0X0102
WM_CLOSE    = 16
SW_HIDE     = 0
STARTF_USESHOWWINDOW = 1

WORD    = c_ushort
DWORD   = c_ulong
LPBYTE  = POINTER(c_ubyte)
LPTSTR  = POINTER(c_char) 
HANDLE  = c_void_p

class STARTUPINFO(Structure):
    _fields_ = [("cb",DWORD),
        ("lpReserved",LPTSTR), 
        ("lpDesktop", LPTSTR),
        ("lpTitle", LPTSTR),
        ("dwX", DWORD),
        ("dwY", DWORD),
        ("dwXSize", DWORD),
        ("dwYSize", DWORD),
        ("dwXCountChars", DWORD),
        ("dwYCountChars", DWORD),
        ("dwFillAttribute", DWORD),
        ("dwFlags", DWORD),
        ("wShowWindow", WORD),
        ("cbReserved2", WORD),
        ("lpReserved2", LPBYTE),
        ("hStdInput", HANDLE),
        ("hStdOutput", HANDLE),
        ("hStdError", HANDLE),]

class PROCESS_INFORMATION(Structure):
    _fields_ = [("hProcess", HANDLE),
        ("hThread", HANDLE),
        ("dwProcessId", DWORD),
        ("dwThreadId", DWORD),]

#
# Gnuplot
#
class Gnuplot:
    #
    # __init__
    #
    def __init__(self, path_to_exe):
        # open gnuplot
        self.launch(path_to_exe)
        # wait till it's ready
        if(windll.user32.WaitForInputIdle(self.hProcess, 1000)):
            print "Error: Gnuplot timeout!"
            sys.exit(1)
        # get window handles
        self.hwndParent = windll.user32.FindWindowA(None, 'gnuplot')
        self.hwndText = windll.user32.FindWindowExA(self.hwndParent, None, 'wgnuplot_text', None)



    #
    # __del__
    #
    def __del__(self):
        windll.kernel32.CloseHandle(self.hProcess);
        windll.kernel32.CloseHandle(self.hThread);
        windll.user32.PostMessageA(self.hwndParent, WM_CLOSE, 0, 0)


    #
    # launch
    #
    def launch(self, path_to_exe):
        startupinfo = STARTUPINFO()
        process_information = PROCESS_INFORMATION()

        startupinfo.dwFlags = STARTF_USESHOWWINDOW
        startupinfo.wShowWindow = SW_HIDE

        if windll.kernel32.CreateProcessA(path_to_exe, None, None, None, False, 0, None, None, byref(startupinfo), byref(process_information)):
            self.hProcess = process_information.hProcess
            self.hThread = process_information.hThread
        else:
            print "Error: Create Process - Error code: ", windll.kernel32.GetLastError()
            sys.exit(1)



    #
    # execute
    #
    def execute(self, script, file_path):
        # make sure file doesn't exist
        try: os.unlink(file_path)
        except: pass

        # send script to gnuplot window
        for c in script: windll.user32.PostMessageA(self.hwndText, WM_CHAR, ord(c), 1L)

        # wait till gnuplot generates the chart
        while( not (os.path.exists(file_path) and (os.path.getsize(file_path) > 0))): time.sleep(0.01)

我有点晚了,但因为我花了一些时间才把它做好,也许值得记下来。这些程序在Windows上使用Python 3.3.2

请注意,到处都使用字节,而不是字符串(例如b“plot x”,而不仅仅是“plot x”),但如果出现问题,只需执行以下操作:

"plot x".encode("ascii")
第一种解决方案:使用“通讯”发送所有内容,完成后关闭。不要忘记暂停,否则窗户马上就关上了。但是,如果使用gnuplot将图像存储在文件中,这并不是问题

from subprocess import *
path = "C:\\app\\gnuplot\\bin\\gnuplot"
p = Popen([path], stdin=PIPE, stdout=PIPE)
p.communicate(b"splot x*y\npause 4\n")
第二种解决方案:使用stdin.write(…)一个接一个地发送命令。但是,不要忘记同花顺!(这是我一开始没有弄对的)并在工作完成时使用terminate关闭连接和gnuplot

from subprocess import *
path = "C:\\app\\gnuplot\\bin\\gnuplot"
p = Popen([path], stdin=PIPE, stdout=PIPE)

p.stdin.write(b"splot x*y\n")
p.stdin.flush()
...
p.stdin.write(b"plot x,x*x\n")
p.stdin.flush()
...
p.terminate()

我接受了本的建议,当时我正在用芹菜做的工作计算图表,结果发现在读stdout时,图表会被锁住。我使用StringIO重新设计了它,创建了发送给stdin和subprocess.communicate的文件,以便通过stdout立即获得结果,无需读取


from subprocess import Popen, PIPE
from StringIO import StringIO                                            
from os import linesep as nl

def gnuplot(commands, data):                                                    
    """ drive gnuplot, expects lists, returns stdout as string """              

    dfile = StringIO()                                                          
    for line in data:                                                           
        dfile.write(str(line) + nl)                                             

    args = ["gnuplot", "-e", (";".join([str(c) for c in commands]))]            
    p = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE)                       

    dfile.seek(0)                                                               
    return p.communicate(dfile.read())[0]   

def gnuplot_GifTest():
    commands = [\
        "set datafile separator ','",\
        "set terminal gif",\
        "set output",\
        "plot '-' using 1:2 with linespoints, '' using 1:2 with linespoints",\
        ]
    data = [\
        "1,1",\
        "2,2",\
        "3,5",\
        "4,2",\
        "5,1",\
        "e",\
        "1,5",\
        "2,4",\
        "3,1",\
        "4,4",\
        "5,5",\
        "e",\
        ]
    return (commands, data)

if __name__=="__main__":
    (commands, data) = gnuplot_GifTest()
    print gnuplot(commands, data)

下面是另一个例子,它扩展了前面的一些答案。此解决方案需要Gnuplot 5.1,因为它使用数据块。有关数据块的更多信息,请在gnuplot中执行帮助数据块。 以前的一些方法的问题是
plot'-'
会立即消耗plot命令后面的数据。不可能在后续打印命令中重复使用相同的数据。数据块可以用来缓解这个问题。使用数据块,我们可以模拟多个数据文件。例如,您可能希望使用两个数据文件中的数据绘制图形,例如,
使用1:2与线条点绘制“myData.dat”,使用1:3与线条点绘制“myData2.dat”,使用1:2与线条点绘制“myData2.dat”
。我们可以直接将这些数据提供给gnuplot,而不需要创建实际的数据文件

import sys, subprocess
from os import linesep as nl
from subprocess import Popen, PIPE


def gnuplot(commands, data):                                                    
  """ drive gnuplot, expects lists, returns stdout as string """  
  script= nl.join(data)+nl.join(commands)+nl
  print script
  args = ["gnuplot", "-p"]
  p = Popen(args, shell=False, stdin=PIPE)                       
  return p.communicate(script)[0]  

def buildGraph():
  commands = [\
      "set datafile separator ','",\
      "plot '$data1' using 1:2 with linespoints, '' using 1:3 with linespoints, '$data2' using 1:2 with linespoints",\
      ]
  data = [\
      "$data1 << EOD",\
      "1,30,12",\
      "2,40,15",\
      "3,35,20",\
      "4,60,21",\
      "5,50,30",\
      "EOD",\
      "$data2 << EOD",\
      "1,20",\
      "2,40",\
      "3,40",\
      "4,50",\
      "5,60",\
      "EOD",\
      ]

  return (commands, data)  


def main(args):
  (commands, data) = buildGraph()
  print gnuplot(commands, data)


if __name__ == "__main__":
   main(sys.argv[1:])
导入系统,子流程 从操作系统导入linesep作为nl 从子流程导入Popen、PIPE def gnuplot(命令、数据): “”“驱动器gnuplot,需要列表,以字符串形式返回标准输出”“” 脚本=nl.join(数据)+nl.join(命令)+nl 打印脚本 args=[“gnuplot”,“-p”] p=Popen(args,shell=False,stdin=PIPE) 返回p.communicate(脚本)[0] def buildGraph(): 命令=[\ “设置数据文件分隔符','”\ “使用1:2和线条点绘制“$data1”,使用1:3和线条点绘制“$data2”,使用1:2和线条点绘制“$data2”\ ] 数据=[\
“$data1您想使用API调用gnuplot(它是C语言的,所以您必须编写一些像gnuplot py中那样的粘合代码)或者只在shell中执行“gnuplot”?只需在shell中执行gnuplot。在阅读了您的示例之后,我编写了一个类似的函数,不幸的是,没有结果。(POpen=POpen,我相信是一个拼写错误,但这不是问题)是的,POpen是一个输入错误。除此之外,也许你需要指定gnuplot的完整路径,或者添加你在另一条评论中提到的“-persist”开关。你也可以检查
plot.returncode
是否有错误。对于收到
TypeError的人来说:需要一个类似字节的对象,而不是“str”
错误:谢谢,这项破解终于奏效了。有一点值得一提:系统('gnuplot-persist tmp.gp')为了在脚本完成后持久化窗口,请使用
shell=False
和gnuplot
--persist
,如果您只是想显示窗口,而不是让Python关闭它…数据中的值必须在不使用comas的情况下写入。列之间用空格分隔,如gnuplot帮助中所述。在python3中,您还必须编码()字符串脚本:
return p.communicate(script.encode('utf-8'))[0]
@terencehill这不是真的:您可以使用任何分隔符,只要指定命令
set datafile separator','
,请参见上面的示例。很抱歉,我更改了该命令,并错过了指向分隔符的行。