5

I'm trying to call gunplot from swift to produce some plots in .png. However, the program below does not work --- the resulting 1.png file is empty. If I leave the "set term aqua" though, it does call the aqua window with the plot in it. However when I try to set output to file (png or pdf) the result is always an empty file.

The gnuplot commands are ok --- I can correctly run them manually.

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)!)

I'm new both to swift and pipes, so please tell me if there is something wrong or unrecommended with the code.

Yrogirg
  • 2,301
  • 3
  • 22
  • 33
  • 1
    I don't know `swift` but if I were you I can try: 1. to add a newline after the filename `"set output \"1.png\"\n"` (you miss __\n__). 2: to close the file in gnuplot adding something like `"set output \n "` before `"q\n"`. Let me know if it works. – Hastur Mar 17 '15 at 15:54
  • @Hastur no, neither helped. – Yrogirg Mar 17 '15 at 17:47
  • I hoped... Just that you fixed let we put even a + :-) `"set output \"1.png\"\n" +` (we miss +). Again let me know... – Hastur Mar 17 '15 at 17:51
  • @Hastur omg!! that's it! `\n` and `+` were missing, not it works. I think you can make an answer. – Yrogirg Mar 17 '15 at 19:58

2 Answers2

4

Often is easy to miss a simple sign when we concatenate strings.
In this case you can fix adding \n and + to the line with set output:

 "set output \"1.png\"\n" +

The idea is to create a string as if we were writing in the gnuplot shell, so with each\n we are simulating a new line and with each + we concatenate two or more strings...
this is even the idea that underlie the gnuplot scripting...

Often with gnuplot is cosy to write an external script and to load it with

  load "myscript.gnuplot"

or running it with

 gnuplot -persist myscript.gnuplot

In this way you will have always the possibility to redo your plot or analysis in a blink of an eye, and your result will be always reproducible.

Hastur
  • 2,470
  • 27
  • 36
0

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)")
}

Current Swift """ syntax allows for a multi-line string literial. This avoid then need for string concatenation.

Note: The commandString needs to terminate with a newline. An ending extra blank line is needed if \n is not used at the end.

quit\n
"""
quit

"""
marc-medley
  • 8,931
  • 5
  • 60
  • 66