在 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

"""