diff options
author | Jakob Odersky <jodersky@gmail.com> | 2012-10-06 19:04:51 +0200 |
---|---|---|
committer | Jakob Odersky <jodersky@gmail.com> | 2012-10-06 19:04:51 +0200 |
commit | f47512f3b84fce4c561256c65e224d0b65405e2b (patch) | |
tree | d2d0e339ded2f8b92fd1288e157ec2a35e3b560d | |
parent | bd16da96d89c391c07573b38d150b7c9df2b74be (diff) | |
download | scalam-f47512f3b84fce4c561256c65e224d0b65405e2b.tar.gz scalam-f47512f3b84fce4c561256c65e224d0b65405e2b.tar.bz2 scalam-f47512f3b84fce4c561256c65e224d0b65405e2b.zip |
add initial files
-rw-r--r-- | build.sbt | 15 | ||||
-rw-r--r-- | project/plugins.sbt | 3 | ||||
-rw-r--r-- | src/main/scala/scalam/DataSet.scala | 24 | ||||
-rw-r--r-- | src/main/scala/scalam/charting/MatlabChart.scala | 79 | ||||
-rw-r--r-- | src/main/scala/scalam/charting/colorSchemes.scala | 50 | ||||
-rw-r--r-- | src/main/scala/scalam/charting/package.scala | 17 | ||||
-rw-r--r-- | src/main/scala/scalam/m/ast/tree.scala | 40 | ||||
-rw-r--r-- | src/main/scala/scalam/plotting/Plot.scala | 88 | ||||
-rw-r--r-- | src/main/scala/scalam/plotting/colorSchemes.scala | 62 |
9 files changed, 378 insertions, 0 deletions
diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..181b49c --- /dev/null +++ b/build.sbt @@ -0,0 +1,15 @@ +name := "scalam" + +version := "1.0" + +scalaVersion := "2.9.2" + +libraryDependencies += "com.github.scala-incubator.io" %% "scala-io-core" % "0.4.1-seq" + +libraryDependencies += "com.github.scala-incubator.io" %% "scala-io-file" % "0.4.1-seq" + +libraryDependencies += "org.scalanlp" %% "breeze-math" % "0.1" + +//libraryDependencies += "org.scala-lang" % "scala-swing" % "2.9.2" + + diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 0000000..cbf2566 --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1,3 @@ +resolvers += Classpaths.typesafeResolver + +addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.0.0") diff --git a/src/main/scala/scalam/DataSet.scala b/src/main/scala/scalam/DataSet.scala new file mode 100644 index 0000000..baff6a6 --- /dev/null +++ b/src/main/scala/scalam/DataSet.scala @@ -0,0 +1,24 @@ +package scalam + +import scalax.file.Path +import breeze.linalg.DenseVector + +class DataSet(val points: Seq[(Double, Double)], val name: String) { + + def save(path: Path) = { + path.createFile(createParents = true, failIfExists = false) + for (processor <- path.outputProcessor; out = processor.asOutput) + for ((x, y) <- points) out.write(x + " " + y + "\n") + } + + lazy val (xs, ys) = points.unzip match { + case (x, y) => (DenseVector(x: _*), DenseVector(y: _*)) + } + +} + +object DataSet { + + def apply(x: DenseVector[Double], y: DenseVector[Double], name: String = "") = new DataSet(x.data zip y.data, name) + +}
\ No newline at end of file diff --git a/src/main/scala/scalam/charting/MatlabChart.scala b/src/main/scala/scalam/charting/MatlabChart.scala new file mode 100644 index 0000000..4c8032a --- /dev/null +++ b/src/main/scala/scalam/charting/MatlabChart.scala @@ -0,0 +1,79 @@ +package scalam.charting + +import scalam._ +import scalax.file.Path +import scala.sys.process._ + +class MatlabChart( + val dataSets: Seq[DataSet], + title: String, + xAxis: String, + yAxis: String, + grid: Boolean = true, + fontSize: Int = 10, + legendFontSize: Int = 10, + colorScheme: ColorScheme = Uniform(), + name: String = "chart" + MatlabChart.next.toString +){ + + val directory = Path(name) + val dataDirectory = Path("data") + val mFile = Path("chart.m") + + private case class MatlabDataSet(underlying: DataSet, path: Path, variableName: String) + + private lazy val matlabDataSets: Seq[MatlabDataSet] = dataSets.zipWithIndex map { + case (dataSet, index) => + MatlabDataSet(dataSet, dataDirectory / (index.toString), "data" + index) + } + + lazy val mScriptLines: Seq[String] = + (for (m <- matlabDataSets) yield m.variableName + " = load('" + m.path.path + "');") ++ + Seq("legendText=cell(1," + matlabDataSets.length + ");", "fh=figure;", "hold('on');") ++ + (colorScheme match { + case m: MatlabColorScheme => Seq(m.initial) + case _ => Seq() + }) ++ + (for ((m, i) <- matlabDataSets.zipWithIndex) yield Seq( + "plot(" + m.variableName + "(:,1)" + ", " + m.variableName + "(:,2), 'color', " + colorScheme.color(m.underlying) + ");", + "legendText{" + (i+1) + "} = '" + m.underlying.name + "';" + )).flatten ++ + Seq("lg=legend(legendText{:});", + "set(gca, 'fontsize'," + fontSize + ");", + "set(lg, 'fontsize'," + legendFontSize + ");", + "grid('" + (if (grid) "on" else "off") + "');", + "title('" + title + "');", + "xlabel('" + xAxis + "');", + "ylabel('" + yAxis + "');", + "waitfor(fh);") + + + def save() = { + for (m <- matlabDataSets) m.underlying.save(directory / m.path) + val mFromHere = (directory / mFile) + mFromHere.createFile(createParents = true, failIfExists = false) + for (processor <- mFromHere.outputProcessor; out = processor.asOutput) + for (line <- mScriptLines) out.write(line + "\n") + } + + def run() = { + Process( + "matlab -nodesktop -nosplash -r " + mFile.name.takeWhile(_ != '.'), + directory.fileOption, + "" -> "" + ) #> (directory / "log.txt").fileOption.get run + } + +} + +object MatlabChart { + private var counter = -1; + private def next = { counter += 1; counter } + + val test = 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""")) + + val testChart = new MatlabChart(test, "title", "x [\\sigma \\epsilon]", "\\vec{y} [\\frac{1}{2}]", colorScheme = new HSV(test)) + +}
\ No newline at end of file diff --git a/src/main/scala/scalam/charting/colorSchemes.scala b/src/main/scala/scalam/charting/colorSchemes.scala new file mode 100644 index 0000000..62c1d39 --- /dev/null +++ b/src/main/scala/scalam/charting/colorSchemes.scala @@ -0,0 +1,50 @@ +package scalam.charting + +import scalam.DataSet + +trait ColorScheme { + def color(dataSet: DataSet): String +} + +trait ColorSchemeFactory[C <: ColorScheme] { + def create(dataSets: Seq[DataSet]): C +} + +trait MatlabColorScheme extends ColorScheme { + private final val ColorVariableName = "cc" + + protected val dataSets: Seq[DataSet] + protected val function: String + private val indices: Map[DataSet, Int] = dataSets.zipWithIndex.toMap + + def initial = { + ColorVariableName + " = " + function + "(" + dataSets.length + ");" + } + + def color(dataSet: DataSet) = ColorVariableName + "(" + (indices(dataSet) + 1) + ",:)" +} + +case class Uniform(rgb: (Double, Double, Double) = (0, 0, 0)) extends ColorScheme { + private val (r, g, b) = rgb + def color(dataSet: DataSet) = "[" + r + "," + g + "," + b + "]" +} + +class HSV(protected val dataSets: Seq[DataSet]) extends MatlabColorScheme {val function = "hsv"} +object HSV extends ColorSchemeFactory[HSV] {def create(dataSets: Seq[DataSet]) = new HSV(dataSets)} +class JET(protected val dataSets: Seq[DataSet]) extends MatlabColorScheme {val function = "hsv"} +object JET extends ColorSchemeFactory[JET] {def create(dataSets: Seq[DataSet]) = new JET(dataSets)} + +trait Special extends ColorScheme { + val specialDataSet: DataSet + val rgb: (Double, Double, Double) + + private val (r, g, b) = rgb + + abstract override def color(dataSet: DataSet): String = + if (dataSet == specialDataSet) "[" + r + "," + g + "," + b + "]" + else super.color(dataSet) +} + +//abstract class Special(val specialDataSet: DataSet, val rgb: (Double, Double, Double)) extends SpecialImpl + + diff --git a/src/main/scala/scalam/charting/package.scala b/src/main/scala/scalam/charting/package.scala new file mode 100644 index 0000000..4e474c3 --- /dev/null +++ b/src/main/scala/scalam/charting/package.scala @@ -0,0 +1,17 @@ +package scalam + +import scalam.charting.MatlabChart +import scalam.charting.HSV +import breeze.linalg.DenseVector + +package object charting { + + //test + def plot(dataSets: Seq[(DenseVector[Double], DenseVector[Double])]) = { + val ds: Seq[DataSet] = dataSets.map{case (xs, ys) => DataSet(xs, ys)} + val c = new MatlabChart(ds, "title", "x", "y", colorScheme = new HSV(ds)) + c.save() + c.run() + } + +}
\ No newline at end of file diff --git a/src/main/scala/scalam/m/ast/tree.scala b/src/main/scala/scalam/m/ast/tree.scala new file mode 100644 index 0000000..cad1859 --- /dev/null +++ b/src/main/scala/scalam/m/ast/tree.scala @@ -0,0 +1,40 @@ +package scalam.m.ast + +trait Mable { def m: String } + +//top level m constructs +case class Identifier(name: String) extends Mable { def m: String = name} +trait Expression extends Mable +trait Statement extends Mable + +//expressions +case class IntLiteral(x: Int) extends Expression { def m = x.toString } +case class DoubleLiteral(x: Double) extends Expression { def m = x.toString } +case class StringLiteral(x: String) extends Expression { def m = "'" + x.toString + "'" } +case object SliceLiteral extends Expression { def m = ":" } +case class ArrayLiteral(elements: Expression*) extends Expression { + def m = elements.mkString("[", ",", "]") +} + +case class Variable(id: Identifier) extends Expression { def m = id.m } +case class IndexMatrix(id: Identifier, indices: Expression*) extends Expression { + def m = id.m + indices.map(_.m).mkString("(", ",", ")") +} +case class IndexStructure(id: Identifier, indices: Expression*) extends Expression { + def m = id.m + indices.map(_.m).mkString("{", ",", "}") +} +case class Call(function: Identifier, params: Expression*) extends Expression { + def m = function.m + params.map(_.m).mkString("(", ",", ")") +} + +//statements +case class Assign(variable: Identifier, value: Expression) extends Statement { + def m = variable.m + " = " + value.m + ";" +} +case class AssignMatrixIndex(variable: Identifier, indices: Seq[Expression], value: Expression) extends Statement { + def m = variable.m + indices.map(_.m).mkString("(", ",", ")") + " = " + value.m + ";" +} + +case class Evaluate(expression: Expression) extends Statement { + def m = expression.m + ";" +}
\ No newline at end of file diff --git a/src/main/scala/scalam/plotting/Plot.scala b/src/main/scala/scalam/plotting/Plot.scala new file mode 100644 index 0000000..b9a0492 --- /dev/null +++ b/src/main/scala/scalam/plotting/Plot.scala @@ -0,0 +1,88 @@ +package scalam.plotting + +import scala.sys.process._ +import scalam.DataSet +import scalam.m.ast._ +import scalax.file.Path + +class Plot( + val dataSets: Seq[DataSet], + title: String, + xLabel: String, + yLabel: String, + grid: Boolean = true, + legend: Boolean = true, + fontSize: Int = 10, + colorScheme: ColorScheme = Uniform(Black), + name: String = "plot" + Plot.next) { + + val directory = Path(name) + + private case class RichDataSet(underlying: DataSet, localPath: Path) + private val richDataSets = dataSets.zipWithIndex.map { + case (d, i) => RichDataSet(d, Path("data") / i.toString) + } + + val statements: List[Statement] = { + def data = for ((d, i) <- richDataSets.zipWithIndex.toList) yield { + val id = Identifier("data" + i) + val load = Identifier("load") + Assign(id, Call(load, StringLiteral(d.localPath.path))) + } + + val figureId = Identifier("fh") + def figure = { + val on = StringLiteral("on") + val off = StringLiteral("off") + + val newFigure = Assign(figureId, Call(Identifier("figure"))) + val holdOn = Evaluate(Call(Identifier("hold"), on)) + val grid = Evaluate(Call(Identifier("grid"), if (this.grid) on else off)) + val title = Evaluate(Call(Identifier("title"), StringLiteral(this.title))) + val xlabel = Evaluate(Call(Identifier("xlabel"), StringLiteral(this.xLabel))) + val ylabel = Evaluate(Call(Identifier("ylabel"), StringLiteral(this.yLabel))) + val fontSize = Evaluate(Call(Identifier("set"), Call(Identifier("gca")), StringLiteral("fontsize"), IntLiteral(this.fontSize))) + List(newFigure, holdOn, grid, title, xlabel, ylabel, fontSize) + } + + def plot = for (assignment <- data) yield { + val plot = Identifier("plot") + Evaluate( + Call( + plot, + IndexMatrix(assignment.variable, SliceLiteral, IntLiteral(1)), + IndexMatrix(assignment.variable, SliceLiteral, IntLiteral(2)))) + } + + def legend = if (this.legend) + Evaluate(Call(Identifier("legend"), (for (d <- dataSets) yield StringLiteral(d.name)): _*)) :: Nil + else Nil + + def wait = List(Evaluate(Call(Identifier("waitfor"), Variable(figureId)))) + + data ::: figure ::: plot ::: legend ::: wait + } + + def save() = { + for (d <- richDataSets) d.underlying.save(directory / d.localPath) + + val plotFile = (directory / "results.m") + plotFile.createFile(createParents = true, failIfExists = false) + for (processor <- plotFile.outputProcessor; out = processor.asOutput) + for (s <- statements) out.write(s.m + "\n") + } + + def run() = { + Process( + "matlab -nodesktop -nosplash -r " + "results.m".takeWhile(_ != '.'), + directory.fileOption, + "" -> "" + ) #> (directory / "log.txt").fileOption.get run + } + +} + +object Plot { + private[this] var counter = -1 + private def next = { counter += 1; counter } +}
\ No newline at end of file diff --git a/src/main/scala/scalam/plotting/colorSchemes.scala b/src/main/scala/scalam/plotting/colorSchemes.scala new file mode 100644 index 0000000..270e775 --- /dev/null +++ b/src/main/scala/scalam/plotting/colorSchemes.scala @@ -0,0 +1,62 @@ +package scalam.plotting + +import scalam.DataSet +import scalam.m.ast._ + +trait Color { + def mColor: Expression +} +class RGB(r: Double, g: Double, b: Double) extends Color { + def mColor = ArrayLiteral(DoubleLiteral(r), DoubleLiteral(g), DoubleLiteral(b)) +} +case object Green extends RGB(0, 1, 0) +case object Red extends RGB(1, 0, 0) +case object Blue extends RGB(0, 0, 1) +case object Magenta extends RGB(1, 0, 1) +case object Cyan extends RGB(0, 1, 1) +case object Yellow extends RGB(1, 1, 0) +case object Black extends RGB(0, 0, 0) + +trait ColorScheme { self => + def color(dataSet: DataSet): Color + + def except(special: Map[DataSet, Color]) = new ColorScheme { + private val exceptions: Map[DataSet, Color] = special + def color(dataSet: DataSet) = { + exceptions.getOrElse(dataSet, self.color(dataSet)) + } + } +} + +trait ColorSchemeFactory[C <: ColorScheme] { self => + + def apply(dataSets: Seq[DataSet]): C + + def except(special: Map[DataSet, Color]) = new ColorSchemeFactory[ColorScheme] { + def apply(dataSets: Seq[DataSet]) = self.apply(dataSets) except special + } +} + +trait MColorScheme extends ColorScheme{ + protected val function: Identifier + protected val dataSets: Seq[DataSet] + private val indices: Map[DataSet, Int] = dataSets.zipWithIndex.toMap + + private val ColorVariable = Identifier("cc") + + def initial = Assign(ColorVariable, Call(function, IntLiteral(dataSets.length))) + + def color(dataSet: DataSet) = new Color{ + def mColor = IndexMatrix(ColorVariable, IntLiteral(indices(dataSet) + 1), SliceLiteral) + } +} + +class HSV(protected val dataSets: Seq[DataSet]) extends MColorScheme {val function = Identifier("hsv")} +object HSV extends ColorSchemeFactory[HSV] {def apply(dataSets: Seq[DataSet]) = new HSV(dataSets)} + +class JET(protected val dataSets: Seq[DataSet]) extends MColorScheme {val function = Identifier("jet")} +object JET extends ColorSchemeFactory[JET] {def apply(dataSets: Seq[DataSet]) = new JET(dataSets)} + +case class Uniform(color: Color) extends ColorScheme { + def color(dataSet: DataSet) = color +}
\ No newline at end of file |