Skip to content

Instantly share code, notes, and snippets.

@damuellen
Created September 3, 2020 13:30
Show Gist options
  • Save damuellen/bbf4344845ccbf6a54d13527e9349913 to your computer and use it in GitHub Desktop.
Save damuellen/bbf4344845ccbf6a54d13527e9349913 to your computer and use it in GitHub Desktop.
PerformanceDataPlot
import Foundation
public class PerformanceDataPlot {
let xy1s: [[(x: TimeInterval, y: Double)]]
let xy2s: [[(x: TimeInterval, y: Double)]]
public var y1Titles: [String]
public var y2Titles: [String]
public var y1Label: String = ""
public var y2Label: String = ""
public init(xy1s: [[(TimeInterval, Double)]], xy2s: [[(TimeInterval, Double)]] = [])
{
self.xy1s = xy1s
self.xy2s = xy2s
self.y1Titles = Array(repeating: "", count: xy1s.count)
self.y2Titles = Array(repeating: "", count: xy2s.count)
}
func plot(code: String) throws
{
let inputPipe = Pipe()
let inputFile = inputPipe.fileHandleForWriting
let gnuplot = Process()
gnuplot.executableURL = .init(fileURLWithPath: "/usr/bin/gnuplot")
gnuplot.arguments = ["-p", "-e", code]
gnuplot.standardInput = inputPipe
try gnuplot.run()
inputFile.write(plotData.data(using: .utf8)!)
}
public func plot(toFile: String? = nil) {
var code: String = ""
if let file = toFile {
code = """
set terminal pdf size 18,10 enhanced color font 'Helvetica,16' lw 1;
set output \"\(file).pdf \";
set title '\(file)';
unset key;
"""
}
code += setCommands + plotCommands
try! plot(code: code)
}
var plotData: String {
let xy1 = xy1s.map { $0.map { $0.x.description + ", " + $0.y.description }
.joined(separator: "\n") }.joined(separator: "\ne\n") + "\ne\n"
let xy2 = xy2s.map { $0.map { $0.x.description + ", " + $0.y.description }
.joined(separator: "\n") }.joined(separator: "\ne\n") + "\ne\n"
return xy1 + xy2
}
var setCommands: String {
let setCommands = [
"grid",
"ylabel '\(y1Label)'",
"y2label '\(y2Label)'",
"xlabel 'Time'",
"style textbox opaque margins 1.0, 1.0 fc bgnd border lt -1 linewidth 1.0",
"xdata time",
"timefmt '%s'",
#"format x '%d %b'"#,
#"xrange ["\(xy1s.first!.first!.0)":"\(xy1s.first!.last!.0)"]"#,
"xtics 60. * 60. * 24. ",
"xtics rotate",
"autoscale",
"autoscale y2",
"style data lines",
"ytics nomirror 10",
"y2tics;"
]
return setCommands.map { "set " + $0 }.joined(separator: ";")
}
var plotCommands: String {
let plotCommands = ["plot '-' using 1:2 title '\(y1Titles.first!)' axes x1y1 with lines linewidth 2"]
+ xy1s.indices.dropFirst().map { i in "'' using 1:2 title '\(y1Titles[i])' axes x1y1 with lines linewidth 2" }
+ xy2s.indices.map { i in "'' using 1:2 title '\(y2Titles[i])' axes x1y2 with lines linewidth 2" }
return plotCommands.joined(separator: ",")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment