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
|
package scalam.plotting
import scala.sys.process._
import scalam.m.ast._
import scalax.file.Path
import scala.collection.mutable.Map
import scala.collection.mutable.ListBuffer
import scalam.io.Saveable
import scala.language.implicitConversions
class Plot(
val dataSets: Seq[DataSet],
title: String,
xAxis: Axis,
yAxis: Axis,
grid: Boolean = true,
legend: Boolean = true,
fontSize: Int = 10,
styles: Seq[Style[StyleElement]] = Seq()) {
def preamble = {
val df = new java.text.SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss")
val now = (new java.util.Date(System.currentTimeMillis()))
Seq(
DoubleComment("Generated by scalam, v1.0-SNAPSHOT"),
DoubleComment(df.format(now)))
}
class RichDataSet(val id: Identifier, val localPath: Path, val underlying: DataSet)
val richDataSets = {
val knownIds = Map[Identifier, Int]()
def toRich(dataSet: DataSet) = {
val firstId = Identifier(dataSet.name)
val finalId = knownIds.get(firstId) match {
case None => { //firstId is not already used
knownIds += (firstId -> 1)
firstId
}
case Some(prev) => { // firstId is already in use
knownIds(firstId) = prev + 1
Identifier(firstId.name + "_" + prev)
}
}
new RichDataSet(finalId, Path("data") / finalId.name, dataSet)
}
dataSets.map(toRich(_))
}
def resolveStyles: (Seq[Root], Seq[DataSet => StyleElement]) = {
val setupAndStyles = styles.map(_.apply(dataSets))
val setup = setupAndStyles.map(_._1).flatten
val styleMaps = setupAndStyles.map(_._2)
(setup, styleMaps)
}
def roots: Seq[Root] = {
import Plot._
val richDataSets = this.richDataSets
val (setup, styleMappings) = resolveStyles
val loads = richDataSets.map(r =>
m.load(r.id, r.localPath) withComment SimpleComment(r.underlying.label))
val plots = richDataSets.map { r =>
val styleElements = styleMappings.map(_.apply(r.underlying))
m.plot(r.id, styleElements)
}
val roots = new ListBuffer[Root]
roots ++= preamble
roots ++= loads
roots ++= setup
roots += m.newFigure
roots += m.hold(true)
roots += m.grid(this.grid)
roots += m.fontSize(this.fontSize)
roots += m.title(this.title)
roots ++= m.xAxis(this.xAxis)
roots ++= m.yAxis(this.yAxis)
roots ++= plots
roots += m.legend(dataSets)
roots.toList
}
}
object Plot {
val PlotFileName = "results.m"
private[this] var counter = -1
private def next = { counter += 1; counter }
implicit def plotIsSaveable(plot: Plot) = new Saveable {
def save(path: scalax.file.Path) = {
val plotFile = (path / PlotFileName)
plotFile.createFile(createParents = true, failIfExists = false)
for (processor <- plotFile.outputProcessor; out = processor.asOutput)
for (r <- plot.roots) out.write(r.line + "\n")
for (d <- plot.richDataSets) d.underlying.save(path / d.localPath)
}
}
private object m {
import scalam.m.ast._
val On = StringLiteral("on")
val Off = StringLiteral("off")
def newFigure = Function(Identifier("figure"))
def hold(b: Boolean) = Function(Identifier("hold"), if (b) On else Off)
def grid(show: Boolean) = Function(Identifier("grid"), if (show) On else Off)
def title(s: String) = Function(Identifier("title"), StringLiteral(s))
def xAxis(x: Axis) = Seq(
Function(Identifier("xlabel"), StringLiteral(x.label)),
Function(Identifier("set"), Variable(Identifier("gca")), StringLiteral("xscale"), x.scale.expression))
def yAxis(x: Axis) = Seq(
Function(Identifier("ylabel"), StringLiteral(x.label)),
Function(Identifier("set"), Variable(Identifier("gca")), StringLiteral("yscale"), x.scale.expression))
def fontSize(size: Int) = Function(Identifier("set"), Variable(Identifier("gca")), StringLiteral("fontsize"), IntLiteral(size))
def load(id: Identifier, path: Path) = Assign(id, Function(Identifier("load"), StringLiteral(path.path)))
def plot(dataSet: Identifier, styleElements: Seq[StyleElement]) = {
val plot = Identifier("plot")
val params = Seq(
IndexMatrix(dataSet, SliceLiteral, IntLiteral(1)),
IndexMatrix(dataSet, SliceLiteral, IntLiteral(2))) ++
styleElements.flatMap(e => Seq(e.name, e.expression))
Function(plot, params: _*)
}
def legend(dataSets: Seq[DataSet]) =
Function(Identifier("legend"), dataSets.map(d => StringLiteral(d.label)): _*)
}
}
|