From eaadb40c8968333b609a6a17bb089fce19950e95 Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Tue, 30 Oct 2012 21:54:22 +0100 Subject: remove save and run capability from plots --- src/main/scala/scalam/plotting/Plot.scala | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/main/scala/scalam/plotting/Plot.scala b/src/main/scala/scalam/plotting/Plot.scala index 5494ace..dede530 100644 --- a/src/main/scala/scalam/plotting/Plot.scala +++ b/src/main/scala/scalam/plotting/Plot.scala @@ -16,9 +16,6 @@ class Plot( styles: Seq[Style[_]] = Seq(), name: String = "plot" + Plot.next) { - val directory = Path(name) - val localPlotFile = Path("results.m") - private case class RichDataSet(underlying: DataSet, localPath: Path, id: Identifier) private val richDataSets = dataSets.zipWithIndex.map { case (d, i) => RichDataSet(d, Path("data") / i.toString, Identifier("data" + (i + 1))) @@ -75,24 +72,6 @@ class Plot( Seq(DoubleComment("Generated by scalam, v1.0-new"), DoubleComment(df.format(now))) } - def save() = { - for (d <- richDataSets) d.underlying.save(directory / d.localPath) - - val plotFile = (directory / localPlotFile) - plotFile.createFile(createParents = true, failIfExists = false) - for (processor <- plotFile.outputProcessor; out = processor.asOutput) { - for (p <- preamble) out.write(p.line + "\n") - for (r <- roots) out.write(r.line + "\n") - } - - } - - def run() = { - Process( - "matlab -nodesktop -nosplash -r " + localPlotFile.path.takeWhile(_ != '.'), - directory.fileOption, - "" -> "") #> (directory / "log.txt").fileOption.get run - } } -- cgit v1.2.3 From 38ea0931471326f11ea7d83fd9e30dadd6256fc4 Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Tue, 30 Oct 2012 23:30:35 +0100 Subject: less restrictive style element definition --- src/main/scala/scalam/plotting/styles/styles.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/scalam/plotting/styles/styles.scala b/src/main/scala/scalam/plotting/styles/styles.scala index 705b88b..e7d59fc 100644 --- a/src/main/scala/scalam/plotting/styles/styles.scala +++ b/src/main/scala/scalam/plotting/styles/styles.scala @@ -6,13 +6,13 @@ import scalam.m.ast._ trait StyleElement { //command line option - def name: StringLiteral + def name: Expression //expression def expression: Expression } trait Style[+S <: StyleElement] { - def apply(dataSets: Seq[DataSet]): Tuple2[Seq[Statement], DataSet => S] + def apply(dataSets: Seq[DataSet]): Tuple2[Seq[Root], DataSet => S] } case class Uniform[S <: StyleElement](element: S) extends Style[S] { -- cgit v1.2.3 From 3d5b08cf59375233b693803511ea7fc75a3da1cc Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Tue, 30 Oct 2012 23:31:46 +0100 Subject: re-implement Plot (hopefully in a cleaner way) --- src/main/scala/scalam/plotting/Plot.scala | 152 +++++++++++++++++++----------- 1 file changed, 95 insertions(+), 57 deletions(-) diff --git a/src/main/scala/scalam/plotting/Plot.scala b/src/main/scala/scalam/plotting/Plot.scala index dede530..1391143 100644 --- a/src/main/scala/scalam/plotting/Plot.scala +++ b/src/main/scala/scalam/plotting/Plot.scala @@ -4,6 +4,8 @@ import scala.sys.process._ import scalam.m.ast._ import scalax.file.Path import scalam.plotting.styles._ +import scala.collection.mutable.Map +import scala.collection.mutable.ListBuffer class Plot( val dataSets: Seq[DataSet], @@ -13,83 +15,119 @@ class Plot( grid: Boolean = true, legend: Boolean = true, fontSize: Int = 10, - styles: Seq[Style[_]] = Seq(), - name: String = "plot" + Plot.next) { + styles: Seq[Style[StyleElement]] = Seq(), + name: String = "") { - private case class RichDataSet(underlying: DataSet, localPath: Path, id: Identifier) - private val richDataSets = dataSets.zipWithIndex.map { - case (d, i) => RichDataSet(d, Path("data") / i.toString, Identifier("data" + (i + 1))) + 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))) } - lazy val roots: List[Root] = { - def loadData(dataSet: RichDataSet) = - Assign(dataSet.id, Function(Identifier("load"), StringLiteral(dataSet.localPath.path))) withComment SimpleComment(dataSet.id.m) - - val (initial: Seq[Seq[Statement]], styleMaps: Iterable[DataSet => StyleElement]) = styles.map(_.apply(dataSets)).unzip - - val figureId = Identifier("fh") - val on = StringLiteral("on") - val off = StringLiteral("off") - def newFigure(figureId: Identifier) = Assign(figureId, 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 xLabel(s: String) = Function(Identifier("xlabel"), StringLiteral(s)) - def yLabel(s: String) = Function(Identifier("ylabel"), StringLiteral(s)) - def fontSize(size: Int) = Function(Identifier("set"), Variable(Identifier("gca")), StringLiteral("fontsize"), IntLiteral(size)) - def plot(dataSet: RichDataSet) = { - val plot = Identifier("plot") - val styleParams = styleMaps.flatMap(styleMap => {val style = styleMap.apply(dataSet.underlying); Seq(style.name, style.expression)}) - val params = Seq( - IndexMatrix(dataSet.id, SliceLiteral, IntLiteral(1)), - IndexMatrix(dataSet.id, SliceLiteral, IntLiteral(2))) ++ - styleParams - - Function(plot, params: _*) + class RichDataSet(val id: Identifier, val localPath: Path, val underlying: DataSet) + + def 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(".") / finalId.name, dataSet) } - def legend(dataSets: Seq[DataSet]) = - Function(Identifier("legend"), (for (d <- dataSets) yield StringLiteral(d.label)): _*) :: Nil - - val commands = new scala.collection.mutable.ListBuffer[Root] - commands ++= (for (d <- richDataSets) yield loadData(d)) - commands ++= initial.flatten - commands += newFigure(figureId) - commands += hold(true) - commands += grid(this.grid) - commands += fontSize(this.fontSize) - commands += title(this.title) - commands += xLabel(this.xLabel) - commands += yLabel(this.yLabel) - commands ++= (for (d <- richDataSets) yield plot(d)) - if (this.legend) commands ++= legend(dataSets) - commands.toList + 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) } - private def preamble = { - val df = new java.text.SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss") - val now = (new java.util.Date(System.currentTimeMillis())) + def roots: Seq[Root] = { + import Plot._ + val richDataSets = this.richDataSets - Seq(DoubleComment("Generated by scalam, v1.0-new"), DoubleComment(df.format(now))) + 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 += m.newFigure + roots += m.hold(true) + roots += m.grid(this.grid) + roots += m.title(this.title) + roots += m.xLabel(this.xLabel) + roots += m.yLabel(this.yLabel) + roots += m.fontSize(this.fontSize) + roots ++= plots + roots += m.legend(dataSets) + + roots.toList } - } object Plot { private[this] var counter = -1 private def next = { counter += 1; counter } - - - private def randomDataSet(length: Int) = { + + private def randomDataSet(length: Int) = { import scala.util.Random val data = for (i <- 0 until length) yield (i * 1.0, Random.nextDouble() * 10) val name = "a" new DataSet(data, name) - } - + } + val ds = Seq( new DataSet(Seq((0.0, 1.0), (1.0, 1.0), (2.0, 1.0), (3.0, 0.0), (4.0, 1.0), (5.0, 1.0)), "temperature"), new DataSet(Seq((0.0, 0.0), (1.0, 1.0), (2.0, 4.0), (3.0, 9.0)), """\alpha""")) ++ (0 to 10).map(_ => randomDataSet(10)) - + val test = new Plot(ds, "title", "x", "y") + + 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 xLabel(s: String) = Function(Identifier("xlabel"), StringLiteral(s)) + def yLabel(s: String) = Function(Identifier("ylabel"), StringLiteral(s)) + 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)): _*) + } + } \ No newline at end of file -- cgit v1.2.3 From 41c3018b7822ea511b037e55ee80c12dcfcf3980 Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Tue, 30 Oct 2012 23:35:49 +0100 Subject: modify plotter to support new plot --- src/main/scala/scalam/plotting/Plotter.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/scalam/plotting/Plotter.scala b/src/main/scala/scalam/plotting/Plotter.scala index 341b976..6d240d9 100644 --- a/src/main/scala/scalam/plotting/Plotter.scala +++ b/src/main/scala/scalam/plotting/Plotter.scala @@ -13,7 +13,7 @@ trait Plotter { lazy val interpreter: MInterpreter = new MatlabInterpreter(pwd) - def plot(dataSets: Seq[DataSet], title: String, x: String, y: String, grid: Boolean = true, legend: Boolean = true)(implicit styles: Seq[Style[_]] = defaultStyles, fontSize: FontSize = defaultFontSize) = { + def plot(dataSets: Seq[DataSet], title: String, x: String, y: String, grid: Boolean = true, legend: Boolean = true)(implicit styles: Seq[Style[StyleElement]] = defaultStyles, fontSize: FontSize = defaultFontSize) = { val p = new Plot(dataSets, title, x, y, grid, legend, styles = styles, fontSize = fontSize.fontSize) p.save() val s = Function(Identifier("run"), StringLiteral((p.directory / p.localPlotFile).path)) -- cgit v1.2.3 From 05dfbfd30def7e8aaa93454514ac7b36b0f210f6 Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Tue, 30 Oct 2012 23:38:37 +0100 Subject: temporarily re-enable save() and run() in plots for testing purposes --- src/main/scala/scalam/plotting/Plot.scala | 41 +++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/main/scala/scalam/plotting/Plot.scala b/src/main/scala/scalam/plotting/Plot.scala index 1391143..3c96a22 100644 --- a/src/main/scala/scalam/plotting/Plot.scala +++ b/src/main/scala/scalam/plotting/Plot.scala @@ -16,7 +16,10 @@ class Plot( legend: Boolean = true, fontSize: Int = 10, styles: Seq[Style[StyleElement]] = Seq(), - name: String = "") { + name: String = "plot" + Plot.next) { + + val directory = Path(name) + val localPlotFile = Path("results.m") def preamble = { val df = new java.text.SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss") @@ -42,11 +45,11 @@ class Plot( Identifier(firstId.name + "_" + prev) } } - new RichDataSet(finalId, Path(".") / finalId.name, dataSet) + 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 @@ -59,16 +62,15 @@ class 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 plots = richDataSets.map { r => val styleElements = styleMappings.map(_.apply(r.underlying)) - m.plot(r.id, styleElements) + m.plot(r.id, styleElements) } - - + val roots = new ListBuffer[Root] roots ++= preamble roots ++= loads @@ -81,10 +83,29 @@ class Plot( roots += m.fontSize(this.fontSize) roots ++= plots roots += m.legend(dataSets) - + roots.toList } + def save() = { + for (d <- richDataSets) d.underlying.save(directory / d.localPath) + + val plotFile = (directory / localPlotFile) + plotFile.createFile(createParents = true, failIfExists = false) + for (processor <- plotFile.outputProcessor; out = processor.asOutput) { + for (p <- preamble) out.write(p.line + "\n") + for (r <- roots) out.write(r.line + "\n") + } + + } + + def run() = { + Process( + "matlab -nodesktop -nosplash -r " + localPlotFile.path.takeWhile(_ != '.'), + directory.fileOption, + "" -> "") #> (directory / "log.txt").fileOption.get run + } + } object Plot { -- cgit v1.2.3 From fd271b42fd5f1ee04738c97600cedcde12ce93d8 Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Tue, 30 Oct 2012 23:41:52 +0100 Subject: fix forgotten sys.error in Identifier.toValid --- src/main/scala/scalam/m/ast/Identifier.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/scalam/m/ast/Identifier.scala b/src/main/scala/scalam/m/ast/Identifier.scala index 87bfa43..124125f 100644 --- a/src/main/scala/scalam/m/ast/Identifier.scala +++ b/src/main/scala/scalam/m/ast/Identifier.scala @@ -7,7 +7,7 @@ case class Identifier(name: String) extends Mable{ def toValid = { val word = name.filter(c => c.isLetterOrDigit || c == '_') val id = word.headOption match { - case None => sys.error("") + case None => "x" case Some(c) => if (!c.isLetter) 'x' + word else word } Identifier(id) -- cgit v1.2.3 From 9e226e73e6e145e6a45dc580d3bbba9cee6a3c9e Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Tue, 30 Oct 2012 23:51:39 +0100 Subject: temporary fix: DataSets labels are validated --- src/main/scala/scalam/plotting/DataSet.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/scalam/plotting/DataSet.scala b/src/main/scala/scalam/plotting/DataSet.scala index 07813ef..768189c 100644 --- a/src/main/scala/scalam/plotting/DataSet.scala +++ b/src/main/scala/scalam/plotting/DataSet.scala @@ -4,7 +4,7 @@ import scalax.file.Path import breeze.linalg.{ Vector, DenseVector } case class DataSet(points: Seq[(Double, Double)], label: String) { - val name = label + val name = scalam.m.ast.Identifier(label).toValid.name lazy val (xs, ys) = points.unzip def save(path: Path) = { -- cgit v1.2.3