aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jodersky@gmail.com>2012-10-06 19:04:51 +0200
committerJakob Odersky <jodersky@gmail.com>2012-10-06 19:04:51 +0200
commitf47512f3b84fce4c561256c65e224d0b65405e2b (patch)
treed2d0e339ded2f8b92fd1288e157ec2a35e3b560d
parentbd16da96d89c391c07573b38d150b7c9df2b74be (diff)
downloadscalam-f47512f3b84fce4c561256c65e224d0b65405e2b.tar.gz
scalam-f47512f3b84fce4c561256c65e224d0b65405e2b.tar.bz2
scalam-f47512f3b84fce4c561256c65e224d0b65405e2b.zip
add initial files
-rw-r--r--build.sbt15
-rw-r--r--project/plugins.sbt3
-rw-r--r--src/main/scala/scalam/DataSet.scala24
-rw-r--r--src/main/scala/scalam/charting/MatlabChart.scala79
-rw-r--r--src/main/scala/scalam/charting/colorSchemes.scala50
-rw-r--r--src/main/scala/scalam/charting/package.scala17
-rw-r--r--src/main/scala/scalam/m/ast/tree.scala40
-rw-r--r--src/main/scala/scalam/plotting/Plot.scala88
-rw-r--r--src/main/scala/scalam/plotting/colorSchemes.scala62
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