diff options
author | Jakob Odersky <jodersky@gmail.com> | 2012-11-01 11:46:54 +0100 |
---|---|---|
committer | Jakob Odersky <jodersky@gmail.com> | 2012-11-01 11:46:54 +0100 |
commit | cde13945605fb9f543cfb960728c5c7d48d6f3f5 (patch) | |
tree | 6bf8055115061ac54cd24083a178abbb63af914a | |
parent | 604c0af33343169f9d19e6e3f350c8f10a4d577f (diff) | |
parent | 9e226e73e6e145e6a45dc580d3bbba9cee6a3c9e (diff) | |
download | scalam-cde13945605fb9f543cfb960728c5c7d48d6f3f5.tar.gz scalam-cde13945605fb9f543cfb960728c5c7d48d6f3f5.tar.bz2 scalam-cde13945605fb9f543cfb960728c5c7d48d6f3f5.zip |
Merge branch 'new-plot'
-rw-r--r-- | src/main/scala/scalam/plotting/DataSet.scala | 2 | ||||
-rw-r--r-- | src/main/scala/scalam/plotting/Plot.scala | 148 | ||||
-rw-r--r-- | src/main/scala/scalam/plotting/Plotter.scala | 2 | ||||
-rw-r--r-- | src/main/scala/scalam/plotting/styles/styles.scala | 4 |
4 files changed, 97 insertions, 59 deletions
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) = { diff --git a/src/main/scala/scalam/plotting/Plot.scala b/src/main/scala/scalam/plotting/Plot.scala index 5494ace..3c96a22 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,66 +15,76 @@ class Plot( grid: Boolean = true, legend: Boolean = true, fontSize: Int = 10, - styles: Seq[Style[_]] = Seq(), + styles: Seq[Style[StyleElement]] = 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))) + 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("data") / 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(_)) } - 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 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) + } - Seq(DoubleComment("Generated by scalam, v1.0-new"), DoubleComment(df.format(now))) + 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 } def save() = { @@ -99,18 +111,44 @@ class Plot( 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 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)) 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] { |