aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jodersky@gmail.com>2012-10-18 12:47:14 +0200
committerJakob Odersky <jodersky@gmail.com>2012-10-18 12:47:14 +0200
commitccd005b60d87e800718fed605ef4ce2b226b942c (patch)
tree4c6dbc241c95e1bc4d8c5ac6edbb1dc7e6247b21
parenta4625a6010de7bd32f791200c688a5b5bb9f7b78 (diff)
downloadscalam-ccd005b60d87e800718fed605ef4ce2b226b942c.tar.gz
scalam-ccd005b60d87e800718fed605ef4ce2b226b942c.tar.bz2
scalam-ccd005b60d87e800718fed605ef4ce2b226b942c.zip
lots of changes:
*refactor styles to seperate packages *add io support *add interpreter support (removes need for seperate matlab instance for every figure)) *add plotting syntactic sugar
-rw-r--r--build.sbt7
-rw-r--r--project/plugins.sbt2
-rw-r--r--src/main/scala/scalam/io/package.scala23
-rw-r--r--src/main/scala/scalam/m/Interpreter.scala27
-rw-r--r--src/main/scala/scalam/m/MatlabInterpreter.scala9
-rw-r--r--src/main/scala/scalam/plotting/FontSize.scala6
-rw-r--r--src/main/scala/scalam/plotting/Plot.scala16
-rw-r--r--src/main/scala/scalam/plotting/Plotter.scala37
-rw-r--r--src/main/scala/scalam/plotting/package.scala7
-rw-r--r--src/main/scala/scalam/plotting/styles/color/colors.scala26
-rw-r--r--src/main/scala/scalam/plotting/styles/color/styles.scala20
-rw-r--r--src/main/scala/scalam/plotting/styles/colors.scala39
-rw-r--r--src/main/scala/scalam/plotting/styles/line/lines.scala (renamed from src/main/scala/scalam/plotting/styles/lines.scala)5
-rw-r--r--src/main/scala/scalam/plotting/styles/marker/markers.scala (renamed from src/main/scala/scalam/plotting/styles/markers.scala)19
-rw-r--r--src/main/scala/scalam/plotting/styles/marker/styles.scala17
-rw-r--r--src/main/scala/scalam/plotting/styles/styles.scala7
16 files changed, 191 insertions, 76 deletions
diff --git a/build.sbt b/build.sbt
index 407a5e3..b3f087e 100644
--- a/build.sbt
+++ b/build.sbt
@@ -1,6 +1,6 @@
name := "scalam"
-version := "1.0"
+version := "1.0-SNAPSHOT"
scalaVersion := "2.9.2"
@@ -10,11 +10,6 @@ libraryDependencies += "com.github.scala-incubator.io" %% "scala-io-file" % "0.4
libraryDependencies += "org.scalanlp" %% "breeze-math" % "0.1"
-//onejar
-seq(com.github.retronym.SbtOneJar.oneJarSettings: _*)
-
-libraryDependencies += "commons-lang" % "commons-lang" % "2.6"
-
//libraryDependencies += "org.scala-lang" % "scala-swing" % "2.9.2"
diff --git a/project/plugins.sbt b/project/plugins.sbt
index 0b524c3..cbf2566 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -1,5 +1,3 @@
resolvers += Classpaths.typesafeResolver
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.0.0")
-
-addSbtPlugin("com.github.retronym" % "sbt-onejar" % "0.8")
diff --git a/src/main/scala/scalam/io/package.scala b/src/main/scala/scalam/io/package.scala
new file mode 100644
index 0000000..a5217de
--- /dev/null
+++ b/src/main/scala/scalam/io/package.scala
@@ -0,0 +1,23 @@
+package scalam
+
+import scalax.file.Path
+import breeze.linalg._
+
+package object io {
+
+ def load(path: Path, separator: String = "\\s"): DenseMatrix[Double] = {
+ val lines = path.lines().dropWhile(_.isEmpty).toArray
+ val elements: Array[Array[String]] = lines map (_.split(separator))
+ require(elements.forall(_.length == elements(0).length), "Cannot load non-rectangular matrix. Check your data file.")
+
+ val rows: Array[Array[Double]] = elements.map(_.map(_.toDouble))
+ DenseMatrix(rows: _*)
+ }
+
+ def save(path: Path, m: DenseMatrix[Double]): Unit = {
+ path.createFile(createParents = true, failIfExists = false)
+ for (processor <- path.outputProcessor; out = processor.asOutput)
+ for (i <- 0 until m.rows) m(i, ::).valuesIterator.mkString(""," ","\n")
+ }
+
+} \ No newline at end of file
diff --git a/src/main/scala/scalam/m/Interpreter.scala b/src/main/scala/scalam/m/Interpreter.scala
new file mode 100644
index 0000000..6c23929
--- /dev/null
+++ b/src/main/scala/scalam/m/Interpreter.scala
@@ -0,0 +1,27 @@
+package scalam.m
+
+import scalax.file.Path
+import scala.sys.process._
+import scala.io._
+import java.io._
+import scala.concurrent._
+
+class Interpreter(command: String, pwd: Path) {
+
+ private val inputStream = new SyncVar[OutputStream];
+
+ val process = Process(command, pwd.fileOption, "" -> "").run(
+ new ProcessIO(
+ stdin => inputStream.put(stdin),
+ stdout => Source.fromInputStream(stdout).getLines.foreach(println),
+ stderr => Source.fromInputStream(stderr).getLines.foreach(println)));
+
+ def write(s: String): Unit = synchronized {
+ inputStream.get.write((s + "\n").getBytes)
+ inputStream.get.flush()
+ }
+
+ def close(): Unit = {
+ inputStream.get.close
+ }
+} \ No newline at end of file
diff --git a/src/main/scala/scalam/m/MatlabInterpreter.scala b/src/main/scala/scalam/m/MatlabInterpreter.scala
new file mode 100644
index 0000000..94cd148
--- /dev/null
+++ b/src/main/scala/scalam/m/MatlabInterpreter.scala
@@ -0,0 +1,9 @@
+package scalam.m
+
+import scalax.file.Path
+
+class MatlabInterpreter(pwd: Path = Path(".")) extends Interpreter("matlab -nosplash -nodesktop", pwd) {
+
+ def evaluate(statement: ast.Statement) = write(statement.m)
+
+} \ No newline at end of file
diff --git a/src/main/scala/scalam/plotting/FontSize.scala b/src/main/scala/scalam/plotting/FontSize.scala
new file mode 100644
index 0000000..edd2323
--- /dev/null
+++ b/src/main/scala/scalam/plotting/FontSize.scala
@@ -0,0 +1,6 @@
+package scalam.plotting
+
+
+/** Helper class used for implicit font size specification. A font size is nothing but an Int,
+ * but defining an implicit of type int could pollute a lot of code. */
+case class FontSize(fs: Int) \ No newline at end of file
diff --git a/src/main/scala/scalam/plotting/Plot.scala b/src/main/scala/scalam/plotting/Plot.scala
index 38a4da6..f354997 100644
--- a/src/main/scala/scalam/plotting/Plot.scala
+++ b/src/main/scala/scalam/plotting/Plot.scala
@@ -14,7 +14,7 @@ class Plot(
grid: Boolean = true,
legend: Boolean = true,
fontSize: Int = 10,
- styleSchemes: Seq[StyleScheme[Style]] = Seq(),
+ styles: Seq[Style[_]] = Seq(),
name: String = "plot" + Plot.next) {
val directory = Path(name)
@@ -28,7 +28,7 @@ class Plot(
lazy val statements: List[Statement] = {
def loadData(dataSet: RichDataSet) = Assign(dataSet.id, Function(Identifier("load"), StringLiteral(dataSet.localPath.path)))
- val (initial: Seq[Seq[Statement]], styleMaps: Seq[DataSet => Style]) = styleSchemes.map(_.apply(dataSets)).unzip
+ val (initial: Seq[Seq[Statement]], styleMaps: Iterable[DataSet => StyleElement]) = styles.map(_.apply(dataSets)).unzip
val figureId = Identifier("fh")
val on = StringLiteral("on")
@@ -52,7 +52,6 @@ class Plot(
}
def legend(dataSets: Seq[DataSet]) =
Evaluate(Function(Identifier("legend"), (for (d <- dataSets) yield StringLiteral(d.name)): _*)) :: Nil
- def wait(figureId: Identifier) = List(Evaluate(Function(Identifier("waitfor"), Variable(figureId))))
val commands = new scala.collection.mutable.ListBuffer[Statement]
commands ++= (for (d <- richDataSets) yield loadData(d))
@@ -66,7 +65,6 @@ class Plot(
commands += yLabel(this.yLabel)
commands ++= (for (d <- richDataSets) yield plot(d))
if (this.legend) commands ++= legend(dataSets)
- commands ++= wait(figureId)
commands.toList
}
@@ -74,10 +72,10 @@ class Plot(
val df = new java.text.SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss")
val now = (new java.util.Date(System.currentTimeMillis()))
- "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" +
- "% Generated by scalam, v1.0 %\n" +
- "% " + df.format(now) + " %\n" +
- "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
+
+ "%% Generated by scalam, v1.0\n" +
+ "%% " + df.format(now) + "\n"
+
}
def save() = {
@@ -109,7 +107,7 @@ object Plot {
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 = Random.nextString(10)
+ val name = "a"
new DataSet(data, name)
}
diff --git a/src/main/scala/scalam/plotting/Plotter.scala b/src/main/scala/scalam/plotting/Plotter.scala
new file mode 100644
index 0000000..9292490
--- /dev/null
+++ b/src/main/scala/scalam/plotting/Plotter.scala
@@ -0,0 +1,37 @@
+package scalam.plotting
+
+import scalam.DataSet
+import scalam.m._
+import scalam.m.ast._
+import scalam.plotting.styles._
+
+trait Plotter {
+ import Plotter._
+
+ val pwd: scalax.file.Path
+
+ lazy val interpreter = 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): Plot =
+ //new Plot(dataSets, title, x, y, grid, legend, styles = styles, fontSize = fontSize.fs)
+
+ 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) = {
+ val p = new Plot(dataSets, title, x, y, grid, legend, styles = styles, fontSize = fontSize.fs)
+ p.save()
+ val s = Evaluate(Function(Identifier("run"), StringLiteral((p.directory / p.localPlotFile).path)))
+ //val s = "run '" + (p.directory / p.localPlotFile).path + "'"
+ println(s.m)
+ interpreter.evaluate(s)
+ }
+
+ def exit() {
+ interpreter.write("exit")
+ interpreter.close()
+ }
+
+}
+
+object Plotter {
+ val defaultStyles = Seq(color.JET, Uniform(marker.Plus), Uniform(line.Solid))
+ val defaultFontSize = FontSize(16)
+} \ No newline at end of file
diff --git a/src/main/scala/scalam/plotting/package.scala b/src/main/scala/scalam/plotting/package.scala
new file mode 100644
index 0000000..3539470
--- /dev/null
+++ b/src/main/scala/scalam/plotting/package.scala
@@ -0,0 +1,7 @@
+package scalam
+
+import scalam.plotting.styles._
+
+package object plotting {
+
+} \ No newline at end of file
diff --git a/src/main/scala/scalam/plotting/styles/color/colors.scala b/src/main/scala/scalam/plotting/styles/color/colors.scala
new file mode 100644
index 0000000..73fa221
--- /dev/null
+++ b/src/main/scala/scalam/plotting/styles/color/colors.scala
@@ -0,0 +1,26 @@
+package scalam.plotting.styles.color
+
+import scalam.m.ast._
+import scalam.DataSet
+import scalam.plotting.styles.Style
+import scalam.plotting.styles.StyleElement
+
+trait Color extends StyleElement {
+ def name = StringLiteral("Color")
+}
+
+class RGB(r: Double, g: Double, b: Double) extends Color {
+ def expression = ArrayLiteral(DoubleLiteral(r), DoubleLiteral(g), DoubleLiteral(b))
+}
+
+class LiteralColor(value: String) extends Color {
+ def expression = StringLiteral(value)
+}
+
+case object Red extends LiteralColor("r")
+case object Green extends LiteralColor("g")
+case object Blue extends LiteralColor("b")
+case object Magenta extends LiteralColor("m")
+case object Cyan extends LiteralColor("c")
+case object Yellow extends LiteralColor("y")
+case object Black extends LiteralColor("k") \ No newline at end of file
diff --git a/src/main/scala/scalam/plotting/styles/color/styles.scala b/src/main/scala/scalam/plotting/styles/color/styles.scala
new file mode 100644
index 0000000..e50f507
--- /dev/null
+++ b/src/main/scala/scalam/plotting/styles/color/styles.scala
@@ -0,0 +1,20 @@
+package scalam.plotting.styles.color
+
+import scalam.m.ast._
+import scalam.DataSet
+import scalam.plotting.styles.Style
+import scalam.plotting.styles.StyleElement
+
+class MColorStyle(val function: Identifier) extends Style[Color] {
+ private val ColorVariable = Identifier("cc")
+
+ private def initial(dataSets: Seq[DataSet]) = Seq(Assign(ColorVariable, Function(function, IntLiteral(dataSets.length))))
+ private def map(dataSets: Iterable[DataSet]) = (for ((d, i) <- dataSets.zipWithIndex) yield d -> new Color {
+ def expression = IndexMatrix(ColorVariable, IntLiteral(i + 1), SliceLiteral)
+ }).toMap
+
+ override def apply(dataSets: Seq[DataSet]) = (initial(dataSets), map(dataSets))
+}
+
+object HSV extends MColorStyle(Identifier("hsv"))
+object JET extends MColorStyle(Identifier("jet")) \ No newline at end of file
diff --git a/src/main/scala/scalam/plotting/styles/colors.scala b/src/main/scala/scalam/plotting/styles/colors.scala
deleted file mode 100644
index d7463e5..0000000
--- a/src/main/scala/scalam/plotting/styles/colors.scala
+++ /dev/null
@@ -1,39 +0,0 @@
-package scalam.plotting.styles
-
-import scalam.m.ast._
-import scalam.DataSet
-
-trait Color extends Style {
- def name = StringLiteral("Color")
-}
-
-class RGB(r: Double, g: Double, b: Double) extends Color {
- def expression = ArrayLiteral(DoubleLiteral(r), DoubleLiteral(g), DoubleLiteral(b))
-}
-
-class LiteralColor(value: String) extends Color {
- def expression = StringLiteral(value)
-}
-
-case object Red extends LiteralColor("r")
-case object Green extends LiteralColor("g")
-case object Blue extends LiteralColor("b")
-case object Magenta extends LiteralColor("c")
-case object Cyan extends LiteralColor("m")
-case object Yellow extends LiteralColor("y")
-case object Black extends LiteralColor("k")
-
-
-class MColorScheme(val function: Identifier) extends StyleScheme[Color] {
- private val ColorVariable = Identifier("cc")
-
- private def initial(dataSets: Seq[DataSet]) = Seq(Assign(ColorVariable, Function(function, IntLiteral(dataSets.length))))
- private def map(dataSets: Seq[DataSet]) = (for ((d, i) <- dataSets.zipWithIndex) yield d -> new Color {
- def expression = IndexMatrix(ColorVariable, IntLiteral(i + 1), SliceLiteral)
- }).toMap
-
- override def apply(dataSets: Seq[DataSet]) = (initial(dataSets), map(dataSets))
-}
-
-object HSV extends MColorScheme(Identifier("hsv"))
-object JET extends MColorScheme(Identifier("jet")) \ No newline at end of file
diff --git a/src/main/scala/scalam/plotting/styles/lines.scala b/src/main/scala/scalam/plotting/styles/line/lines.scala
index c8c8bf3..63c6d23 100644
--- a/src/main/scala/scalam/plotting/styles/lines.scala
+++ b/src/main/scala/scalam/plotting/styles/line/lines.scala
@@ -1,8 +1,9 @@
-package scalam.plotting.styles
+package scalam.plotting.styles.line
import scalam.m.ast._
+import scalam.plotting.styles.StyleElement
-trait Line extends Style {
+trait Line extends StyleElement {
def name = StringLiteral("LineStyle")
}
diff --git a/src/main/scala/scalam/plotting/styles/markers.scala b/src/main/scala/scalam/plotting/styles/marker/markers.scala
index 6c83cdb..f821396 100644
--- a/src/main/scala/scalam/plotting/styles/markers.scala
+++ b/src/main/scala/scalam/plotting/styles/marker/markers.scala
@@ -1,9 +1,11 @@
-package scalam.plotting.styles
+package scalam.plotting.styles.marker
import scalam.DataSet
import scalam.m.ast._
+import scalam.plotting.styles.Style
+import scalam.plotting.styles.StyleElement
-trait Marker extends Style {
+trait Marker extends StyleElement {
def name = StringLiteral("Marker")
}
case object Plus extends Marker { def expression = StringLiteral("+") }
@@ -19,15 +21,4 @@ case object RightTriangle extends Marker { def expression = StringLiteral(">") }
case object LeftTriangle extends Marker { def expression = StringLiteral("<") }
case object Pentagram extends Marker { def expression = StringLiteral("p") }
case object Hexagram extends Marker { def expression = StringLiteral("h") }
-case object NoMarker extends Marker { def expression = StringLiteral("none") }
-
-object AllMarkerScheme extends StyleScheme[Marker] {
-
- val markers = List(Plus, Circle, Asterisk, Point, Cross, Square, Diamond, UpTriangle, DownTriangle, RightTriangle, LeftTriangle, Pentagram, Hexagram)
- private def map(dataSets: Seq[DataSet]): Map[DataSet, Marker] = dataSets.zipWithIndex.map{
- case (d, i) => d -> markers(i % (markers.length-1))
- }.toMap
-
- override def apply(dataSets: Seq[DataSet]) = (Seq.empty[Statement], map(dataSets))
-
-} \ No newline at end of file
+case object NoMarker extends Marker { def expression = StringLiteral("none") } \ No newline at end of file
diff --git a/src/main/scala/scalam/plotting/styles/marker/styles.scala b/src/main/scala/scalam/plotting/styles/marker/styles.scala
new file mode 100644
index 0000000..9663778
--- /dev/null
+++ b/src/main/scala/scalam/plotting/styles/marker/styles.scala
@@ -0,0 +1,17 @@
+package scalam.plotting.styles.marker
+
+import scalam.DataSet
+import scalam.m.ast._
+import scalam.plotting.styles.Style
+import scalam.plotting.styles.StyleElement
+
+object AllMarkerStyle extends Style[Marker] {
+
+ val markers = List(Plus, Circle, Asterisk, Point, Cross, Square, Diamond, UpTriangle, DownTriangle, RightTriangle, LeftTriangle, Pentagram, Hexagram)
+ private def map(dataSets: Iterable[DataSet]): Map[DataSet, Marker] = dataSets.zipWithIndex.map{
+ case (d, i) => d -> markers(i % (markers.length-1))
+ }.toMap
+
+ def apply(dataSets: Seq[DataSet]) = (Seq.empty[Statement], map(dataSets))
+
+} \ No newline at end of file
diff --git a/src/main/scala/scalam/plotting/styles/styles.scala b/src/main/scala/scalam/plotting/styles/styles.scala
index 7b05955..098fcf7 100644
--- a/src/main/scala/scalam/plotting/styles/styles.scala
+++ b/src/main/scala/scalam/plotting/styles/styles.scala
@@ -4,18 +4,17 @@ import scalam.DataSet
import scalam.m.ast._
-trait Style {
+trait StyleElement {
//command line option
def name: StringLiteral
//expression
def expression: Expression
}
-
-trait StyleScheme[+S <: Style] {
+trait Style[+S <: StyleElement] {
def apply(dataSets: Seq[DataSet]): Tuple2[Seq[Statement], DataSet => S]
}
-case class Uniform[S <: Style](element: S) extends StyleScheme[S] {
+case class Uniform[S <: StyleElement](element: S) extends Style[S] {
override def apply(dataSets: Seq[DataSet]) = (Seq.empty[Statement], (d: DataSet) => element)
} \ No newline at end of file