在 Swift 中调用 Gnuplot
Calling Gnuplot in Swift
我正在尝试从 swift 调用 gunplot 以在 .png
中生成一些情节。但是,下面的程序不起作用 --- 结果 1.png
文件是空的。但是,如果我离开 "set term aqua",它会调用带有情节的 aqua window。但是,当我尝试将输出设置为文件(png 或 pdf)时,结果始终是一个空文件。
gnuplot 命令没问题 --- 我可以正确地手动 运行 它们。
import Foundation
let task = NSTask()
task.launchPath = "/opt/local/bin/gnuplot"
task.currentDirectoryPath = "~"
let pipeIn = NSPipe()
task.standardInput = pipeIn
task.launch()
let plotCommand: NSString =
"set term png\n" +
"set output \"1.png\"\n"
"plot sin(x)\n" +
"q\n"
pipeIn.fileHandleForWriting.writeData(plotCommand.dataUsingEncoding(NSUTF8StringEncoding)!)
我是 swift 和管道的新手,所以如果代码有问题或不推荐,请告诉我。
当我们连接字符串时,通常很容易错过一个简单的符号。
在这种情况下,您可以修复将 \n
和 +
添加到带有 set output
:
的行
"set output \"1.png\"\n" +
我们的想法是创建一个字符串,就像我们在 gnuplot
shell 中写入一样,所以对于每个 \n
我们模拟一个新行并且每个 +
我们连接两个或多个字符串...
这甚至是 gnuplot 脚本...
的基础思想
通常使用 gnuplot
编写外部脚本并使用
加载它很舒服
load "myscript.gnuplot"
或运行它与
gnuplot -persist myscript.gnuplot
通过这种方式,您将始终可以在眨眼之间重做您的绘图或分析,并且您的结果将始终可重现。
Swift 5.4
let commandString: String =
"""
set terminal png
set output 'FIND_ME_01.png'
plot sin(x)
quit\n
"""
func plot() {
let argv: [String] = ["--persist"] // do not close interactive plot
let task = Process()
task.arguments = argv
// "/opt/homebrew/bin/gnuplot" // Big Sur, Apple Silicon
task.launchPath = "/usr/local/bin/gnuplot" // Big Sur, Intel
// where to find the output
let homeDir = FileManager.default.homeDirectoryForCurrentUser
task.currentDirectoryURL = homeDir.appendingPathComponent("Desktop")
let pipeIn = Pipe()
task.standardInput = pipeIn
let pipeOut = Pipe()
task.standardOutput = pipeOut
let pipeErr = Pipe()
task.standardError = pipeErr
do {
try task.run()
let commandData = commandString.data(using: .utf8)!
pipeIn.fileHandleForWriting.write(commandData)
let dataOut = pipeOut.fileHandleForReading.readDataToEndOfFile()
if let output = String(data: dataOut, encoding: .utf8) {
print("STANDARD OUTPUT\n" + output)
}
let dataErr = pipeErr.fileHandleForReading.readDataToEndOfFile()
if let outputErr = String(data: dataErr, encoding: .utf8) {
print("STANDARD ERROR \n" + outputErr)
}
} catch {
print("FAILED: \(error)")
}
task.waitUntilExit()
print("STATUS: \(task.terminationStatus)")
}
当前 Swift """
语法允许多行字符串文字。这样就避免了字符串连接的需要。
注意:commandString
需要以换行结束。如果末尾没有使用\n
,则需要一个结束额外的空行。
quit\n
"""
quit
"""
我正在尝试从 swift 调用 gunplot 以在 .png
中生成一些情节。但是,下面的程序不起作用 --- 结果 1.png
文件是空的。但是,如果我离开 "set term aqua",它会调用带有情节的 aqua window。但是,当我尝试将输出设置为文件(png 或 pdf)时,结果始终是一个空文件。
gnuplot 命令没问题 --- 我可以正确地手动 运行 它们。
import Foundation
let task = NSTask()
task.launchPath = "/opt/local/bin/gnuplot"
task.currentDirectoryPath = "~"
let pipeIn = NSPipe()
task.standardInput = pipeIn
task.launch()
let plotCommand: NSString =
"set term png\n" +
"set output \"1.png\"\n"
"plot sin(x)\n" +
"q\n"
pipeIn.fileHandleForWriting.writeData(plotCommand.dataUsingEncoding(NSUTF8StringEncoding)!)
我是 swift 和管道的新手,所以如果代码有问题或不推荐,请告诉我。
当我们连接字符串时,通常很容易错过一个简单的符号。
在这种情况下,您可以修复将 \n
和 +
添加到带有 set output
:
"set output \"1.png\"\n" +
我们的想法是创建一个字符串,就像我们在 gnuplot
shell 中写入一样,所以对于每个 \n
我们模拟一个新行并且每个 +
我们连接两个或多个字符串...
这甚至是 gnuplot 脚本...
通常使用 gnuplot
编写外部脚本并使用
load "myscript.gnuplot"
或运行它与
gnuplot -persist myscript.gnuplot
通过这种方式,您将始终可以在眨眼之间重做您的绘图或分析,并且您的结果将始终可重现。
Swift 5.4
let commandString: String =
"""
set terminal png
set output 'FIND_ME_01.png'
plot sin(x)
quit\n
"""
func plot() {
let argv: [String] = ["--persist"] // do not close interactive plot
let task = Process()
task.arguments = argv
// "/opt/homebrew/bin/gnuplot" // Big Sur, Apple Silicon
task.launchPath = "/usr/local/bin/gnuplot" // Big Sur, Intel
// where to find the output
let homeDir = FileManager.default.homeDirectoryForCurrentUser
task.currentDirectoryURL = homeDir.appendingPathComponent("Desktop")
let pipeIn = Pipe()
task.standardInput = pipeIn
let pipeOut = Pipe()
task.standardOutput = pipeOut
let pipeErr = Pipe()
task.standardError = pipeErr
do {
try task.run()
let commandData = commandString.data(using: .utf8)!
pipeIn.fileHandleForWriting.write(commandData)
let dataOut = pipeOut.fileHandleForReading.readDataToEndOfFile()
if let output = String(data: dataOut, encoding: .utf8) {
print("STANDARD OUTPUT\n" + output)
}
let dataErr = pipeErr.fileHandleForReading.readDataToEndOfFile()
if let outputErr = String(data: dataErr, encoding: .utf8) {
print("STANDARD ERROR \n" + outputErr)
}
} catch {
print("FAILED: \(error)")
}
task.waitUntilExit()
print("STATUS: \(task.terminationStatus)")
}
当前 Swift """
语法允许多行字符串文字。这样就避免了字符串连接的需要。
注意:commandString
需要以换行结束。如果末尾没有使用\n
,则需要一个结束额外的空行。
quit\n
"""
quit
"""