質問
いくつかの計算の後、gnuplot 入力としてフォーマットされた 2 つのデータ ファイルを生成する Python スクリプトがあります。
Python から gnuplot を「呼び出す」にはどうすればよいですか?
次の Python 文字列を入力として gnuplot に送信したいと考えています。
"plot '%s' with lines, '%s' with points;" % (eout,nout)
どこ 'アウト' そして 'ナウト' は 2 つのファイル名です。
追伸:私 好む 追加の Python モジュール (例:gnuplot-py)、標準 API のみ。
ありがとう
解決
単純なアプローチは、ちょうどあなたのgnuplotコマンドを含む第3のファイルを作成し、そのファイルにはgnuplotを実行するためのPythonを伝えるためにあるかもしれません。あなたが書いたと言う。
"plot '%s' with lines, '%s' with points;" % (eout,nout)
tmp.gp.というファイルにそして、あなたが使用することができます。
from os import system, remove
system('gnuplot tmp.gp')
remove('tmp.gp')
他のヒント
subprocess
のモジュールあなたが他のプログラムを呼び出すことができます:
import subprocess
plot = subprocess.Popen(['gnuplot'], stdin=subprocess.PIPE)
plot.communicate("plot '%s' with lines, '%s' with points;" % (eout,nout))
サブプロセスは、ダグHellemannの上で非常に明確に説明されています 今週ののPythonモジュールの
これはうまく動作します:
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の一時停止コマンドが使用されていない限り、プロットウィンドウがすぐに閉じができます。
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にグラフをダンプ。同等のコマンドライン(グラフであるパイプに「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
私はセロリジョブからチャートを計算したとして、ベンの提案を行って、標準出力からの読み取り時にはロックアップしまうことがわかりました。私はありませんが必要な読み取り、標準出力経由ですぐに結果を得るためにstdinとsubprocess.communicate宛てのファイルを作成するためにStringIOを使用してそのようにそれを再設計します。
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)
ここで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「プロットのx」ではなく、単に「プロットの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を(...)を使用して、次々に指示します。しかし、のフラッシュを忘れないでください! (これは私が右の最初に取得していないものです)と使用の終了のジョブが実行されたときに、接続とは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()
これは、以前の回答の一部を拡張した別の例です。この解決策 Gnuplot 5.1 が必要です データブロックを使用しているためです。データブロックの詳細については、次を実行してください。 help datablocks
gnuplot で。これまでのアプローチのいくつかの問題点は、 plot '-'
プロットコマンドの直後にあるデータを即座に消費します。後続のプロット コマンドで同じデータを再利用することはできません。データブロックを使用すると、この問題を軽減できます。データブロックを使用すると、複数のデータファイルを模倣できます。たとえば、2 つのデータ ファイルのデータを使用してグラフをプロットしたい場合があります。 plot "myData.dat" using 1:2 with linespoints, '' using 1:3 with linespoints, "myData2.dat" using 1:2 with linespoints
. 。実際のデータ ファイルを作成することなく、このデータを 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:])
この方法は、 plot '-'
同じプロット コマンドを含めて、同じデータを複数回再利用することが容易になるためです。 https://stackoverflow.com/a/33064402/895245このアプローチでは、データが次の場所に供給される必要があることに注意してください。 gnuplot プロットコマンドの前に!
また、私は @ppetraki のように IOString を使用しませんでした。なぜなら、これは単純なリスト結合器よりも遅いからです。 https://waymoot.org/home/python_string/