-
Notifications
You must be signed in to change notification settings - Fork 19
/
core.go
142 lines (123 loc) · 3.26 KB
/
core.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package glot
import (
"fmt"
"io"
"os"
"os/exec"
"runtime"
)
var gGnuplotCmd string
var gGnuplotPrefix = "go-gnuplot-"
const defaultStyle = "points" // The default style for a curve
const plotCommand = "replot" // The default style for a curve
func min(a, b int) int {
if a < b {
return a
}
return b
}
// Function to intialize the package and check for GNU plot installation
// This raises an error if GNU plot is not installed
func init() {
var err error
gnuplotExecutableName := "gnuplot"
if runtime.GOOS == "windows" {
gnuplotExecutableName = "gnuplot.exe"
}
gGnuplotCmd, err = exec.LookPath(gnuplotExecutableName)
if err != nil {
fmt.Errorf("** could not find path to 'gnuplot':\n%v\n", err)
fmt.Errorf("** set custom path to 'gnuplot' ")
}
}
type gnuplotError struct {
err string
}
func (e *gnuplotError) Error() string {
return e.err
}
// plotterProcess is the type for handling gnu commands.
type plotterProcess struct {
handle *exec.Cmd
stdin io.WriteCloser
}
// newPlotterProc function makes the plotterProcess struct
func newPlotterProc(persist bool) (*plotterProcess, error) {
procArgs := []string{}
if persist {
procArgs = append(procArgs, "-persist")
}
cmd := exec.Command(gGnuplotCmd, procArgs...)
stdin, err := cmd.StdinPipe()
if err != nil {
return nil, err
}
return &plotterProcess{handle: cmd, stdin: stdin}, cmd.Start()
}
// Cmd sends a command to the gnuplot subprocess and returns an error
// if something bad happened in the gnuplot process.
// ex:
//
// fname := "foo.dat"
// err := p.Cmd("plot %s", fname)
// if err != nil {
// panic(err)
// }
func (plot *Plot) Cmd(format string, a ...interface{}) error {
cmd := fmt.Sprintf(format, a...) + "\n"
n, err := io.WriteString(plot.proc.stdin, cmd)
if plot.debug {
//buf := new(bytes.Buffer)
//io.Copy(buf, plot.proc.handle.Stdout)
fmt.Printf("cmd> %v", cmd)
fmt.Printf("res> %v\n", n)
}
return err
}
// CheckedCmd is a convenience wrapper around Cmd: it will error if the
// error returned by Cmd isn't nil.
// ex:
//
// fname := "foo.dat"
// p.CheckedCmd("plot %s", fname)
func (plot *Plot) CheckedCmd(format string, a ...interface{}) {
err := plot.Cmd(format, a...)
if err != nil {
_ = fmt.Errorf("** err: %v\n", err)
}
}
// A map between os files and file names
type tmpfilesDb map[string]*os.File
// Close makes sure all resources used by the gnuplot subprocess are reclaimed.
// This method is typically called when the Plotter instance is not needed
// anymore. That's usually done via a defer statement:
//
// p, err := gnuplot.NewPlotter(...)
// if err != nil { /* handle error */ }
// defer p.Close()
func (plot *Plot) Close() (err error) {
if plot.proc != nil && plot.proc.handle != nil {
plot.proc.stdin.Close()
err = plot.proc.handle.Wait()
}
plot.ResetPlot()
return err
}
func (plot *Plot) cleanplot() (err error) {
plot.tmpfiles = make(tmpfilesDb)
plot.nplots = 0
return err
}
// ResetPlot is used to reset the whole plot.
// This removes all the PointGroup's from the plot and makes it new.
// Usage
//
// plot.ResetPlot()
func (plot *Plot) ResetPlot() (err error) {
plot.cleanplot()
plot.PointGroup = make(map[string]*PointGroup) // Adding a mapping between a curve name and a curve
return err
}
func SetCustomPathToGNUPlot(path string) {
gGnuplotCmd = path
}