aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jodersky@gmail.com>2012-10-09 13:27:55 +0200
committerJakob Odersky <jodersky@gmail.com>2012-10-09 13:27:55 +0200
commit46c9121ac0856cbad855994941a4288e50da1cf1 (patch)
treede0afd2eea5a35849bcb762bd4662c9b78d3804e
parente5e135bf1c2c386037496e3f40adb10e0184e066 (diff)
downloadscalam-46c9121ac0856cbad855994941a4288e50da1cf1.tar.gz
scalam-46c9121ac0856cbad855994941a4288e50da1cf1.tar.bz2
scalam-46c9121ac0856cbad855994941a4288e50da1cf1.zip
refactor style support
-rw-r--r--.gitignore5
-rw-r--r--src/main/scala/scalam/DataSet.scala2
-rw-r--r--src/main/scala/scalam/charting/MatlabChart.scala86
-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/plotting/Plot.scala44
-rw-r--r--src/main/scala/scalam/plotting/colorSchemes.scala89
-rw-r--r--src/main/scala/scalam/plotting/styles/colors.scala39
-rw-r--r--src/main/scala/scalam/plotting/styles/lines.scala12
-rw-r--r--src/main/scala/scalam/plotting/styles/markers.scala32
-rw-r--r--src/main/scala/scalam/plotting/styles/styles.scala21
11 files changed, 138 insertions, 259 deletions
diff --git a/.gitignore b/.gitignore
index f5b7d72..95fb969 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,4 +10,7 @@ project/boot/
project/plugins/project/
# Scala-IDE specific
-.scala_dependencies \ No newline at end of file
+.scala_dependencies
+.project
+.classpath
+.cache
diff --git a/src/main/scala/scalam/DataSet.scala b/src/main/scala/scalam/DataSet.scala
index baff6a6..99e27a3 100644
--- a/src/main/scala/scalam/DataSet.scala
+++ b/src/main/scala/scalam/DataSet.scala
@@ -3,7 +3,7 @@ package scalam
import scalax.file.Path
import breeze.linalg.DenseVector
-class DataSet(val points: Seq[(Double, Double)], val name: String) {
+case class DataSet(val points: Seq[(Double, Double)], val name: String) {
def save(path: Path) = {
path.createFile(createParents = true, failIfExists = false)
diff --git a/src/main/scala/scalam/charting/MatlabChart.scala b/src/main/scala/scalam/charting/MatlabChart.scala
deleted file mode 100644
index 9ab3c69..0000000
--- a/src/main/scala/scalam/charting/MatlabChart.scala
+++ /dev/null
@@ -1,86 +0,0 @@
-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 }
-
- 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)
- new DataSet(data, name)
- }
-
- 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""")) ++ (0 to 10).map(_ => randomDataSet(10))
-
- 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
deleted file mode 100644
index 62c1d39..0000000
--- a/src/main/scala/scalam/charting/colorSchemes.scala
+++ /dev/null
@@ -1,50 +0,0 @@
-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
deleted file mode 100644
index 4e474c3..0000000
--- a/src/main/scala/scalam/charting/package.scala
+++ /dev/null
@@ -1,17 +0,0 @@
-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/plotting/Plot.scala b/src/main/scala/scalam/plotting/Plot.scala
index 1a92f79..2696f77 100644
--- a/src/main/scala/scalam/plotting/Plot.scala
+++ b/src/main/scala/scalam/plotting/Plot.scala
@@ -4,6 +4,7 @@ import scala.sys.process._
import scalam.DataSet
import scalam.m.ast._
import scalax.file.Path
+import scalam.plotting.styles._
class Plot(
val dataSets: Seq[DataSet],
@@ -13,7 +14,7 @@ class Plot(
grid: Boolean = true,
legend: Boolean = true,
fontSize: Int = 10,
- colorScheme: ColorScheme = JET,
+ styleSchemes: Seq[StyleScheme[Style]] = Seq(),
name: String = "plot" + Plot.next) {
val directory = Path(name)
@@ -24,14 +25,11 @@ class Plot(
case (d, i) => RichDataSet(d, Path("data") / i.toString, Identifier("data" + (i + 1)))
}
- private val colors = colorScheme(dataSets)
-
lazy val statements: List[Statement] = {
def loadData(dataSet: RichDataSet) = Assign(dataSet.id, Function(Identifier("load"), StringLiteral(dataSet.localPath.path)))
- def initialColor(ds: Seq[DataSet]) = colorScheme match {
- case predefined: MColorScheme => predefined.initial(ds) :: Nil
- case _ => Nil
- }
+
+ val (initial: Seq[Seq[Statement]], styleMaps: Seq[DataSet => Style]) = styleSchemes.map(_.apply(dataSets)).unzip
+
val figureId = Identifier("fh")
val on = StringLiteral("on")
val off = StringLiteral("off")
@@ -42,21 +40,23 @@ class Plot(
def xLabel(s: String) = Evaluate(Function(Identifier("xlabel"), StringLiteral(s)))
def yLabel(s: String) = Evaluate(Function(Identifier("ylabel"), StringLiteral(s)))
def fontSize(size: Int) = Evaluate(Function(Identifier("set"), Variable(Identifier("gca")), StringLiteral("fontsize"), IntLiteral(size)))
- def plot(dataSet: RichDataSet) =
- Evaluate(
- Function(
- Identifier("plot"),
+ 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)),
- StringLiteral("color"),
- colors(dataSet.underlying).expression))
+ IndexMatrix(dataSet.id, SliceLiteral, IntLiteral(2))) ++
+ styleParams
+
+ Evaluate(Function(plot, params: _*))
+ }
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))
- commands ++= initialColor(richDataSets.map(_.underlying))
+ commands ++= initial.flatten
commands += newFigure(figureId)
commands += hold(true)
commands += grid(this.grid)
@@ -104,4 +104,18 @@ class Plot(
object Plot {
private[this] var counter = -1
private def next = { counter += 1; counter }
+
+
+ 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)
+ 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")
} \ No newline at end of file
diff --git a/src/main/scala/scalam/plotting/colorSchemes.scala b/src/main/scala/scalam/plotting/colorSchemes.scala
deleted file mode 100644
index 0664575..0000000
--- a/src/main/scala/scalam/plotting/colorSchemes.scala
+++ /dev/null
@@ -1,89 +0,0 @@
-package scalam.plotting
-
-import scalam.DataSet
-import scalam.m.ast._
-
-trait Color {
- def expression: Expression
-}
-class RGB(r: Double, g: Double, b: Double) extends Color {
- def expression = ArrayLiteral(DoubleLiteral(r), DoubleLiteral(g), DoubleLiteral(b))
-}
-
-case object Red extends RGB(1, 0, 0)
-case object Green extends RGB(0, 1, 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 apply(dataSets: Seq[DataSet]): Map[DataSet, Color]
-}
-
-class MColorScheme(val function: Identifier) extends ColorScheme {
- private val ColorVariable = Identifier("cc")
-
- def initial(dataSets: Seq[DataSet]) = Assign(ColorVariable, Function(function, IntLiteral(dataSets.length)))
-
- def apply(dataSets: Seq[DataSet]) = (for ((d, i) <- dataSets.zipWithIndex) yield d -> new Color {
- def expression = IndexMatrix(ColorVariable, IntLiteral(i + 1), SliceLiteral)
- }).toMap
-
-}
-
-case class Uniform(color: Color) extends ColorScheme {
- def apply(dataSets: Seq[DataSet]) = dataSets.map(_ -> color).toMap
-}
-object HSV extends MColorScheme(Identifier("hsv"))
-object JET extends MColorScheme(Identifier("jet"))
-
-
-/*
-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 expression = 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
diff --git a/src/main/scala/scalam/plotting/styles/colors.scala b/src/main/scala/scalam/plotting/styles/colors.scala
new file mode 100644
index 0000000..d7463e5
--- /dev/null
+++ b/src/main/scala/scalam/plotting/styles/colors.scala
@@ -0,0 +1,39 @@
+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/lines.scala
new file mode 100644
index 0000000..187d4a9
--- /dev/null
+++ b/src/main/scala/scalam/plotting/styles/lines.scala
@@ -0,0 +1,12 @@
+package scalam.plotting.styles
+
+import scalam.m.ast._
+
+trait Line extends Style {
+ def name = StringLiteral("LineStyle")
+}
+
+case object Solid extends Line {def expression = StringLiteral("-")}
+case object Dashed extends Line {def expression = StringLiteral("--")}
+case object Dotted extends Line {def expression = StringLiteral(":")}
+case object DashDot extends Line {def expression = StringLiteral("-.")} \ No newline at end of file
diff --git a/src/main/scala/scalam/plotting/styles/markers.scala b/src/main/scala/scalam/plotting/styles/markers.scala
new file mode 100644
index 0000000..aad7685
--- /dev/null
+++ b/src/main/scala/scalam/plotting/styles/markers.scala
@@ -0,0 +1,32 @@
+package scalam.plotting.styles
+
+import scalam.DataSet
+import scalam.m.ast._
+
+trait Marker extends Style {
+ def name = StringLiteral("Marker")
+}
+case object Plus extends Marker { def expression = StringLiteral("+") }
+case object Circle extends Marker { def expression = StringLiteral("o") }
+case object Asterisk extends Marker { def expression = StringLiteral("*") }
+case object Point extends Marker { def expression = StringLiteral(".") }
+case object Cross extends Marker { def expression = StringLiteral("x") }
+case object Square extends Marker { def expression = StringLiteral("s") }
+case object Diamond extends Marker { def expression = StringLiteral("d") }
+case object UpTriangle extends Marker { def expression = StringLiteral("^") }
+case object DownTriangle extends Marker { def expression = StringLiteral("v") }
+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") }
+
+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 % dataSets.length)
+ }.toMap
+
+ override 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
new file mode 100644
index 0000000..7b05955
--- /dev/null
+++ b/src/main/scala/scalam/plotting/styles/styles.scala
@@ -0,0 +1,21 @@
+package scalam.plotting.styles
+
+import scalam.DataSet
+import scalam.m.ast._
+
+
+trait Style {
+ //command line option
+ def name: StringLiteral
+ //expression
+ def expression: Expression
+}
+
+
+trait StyleScheme[+S <: Style] {
+ def apply(dataSets: Seq[DataSet]): Tuple2[Seq[Statement], DataSet => S]
+}
+
+case class Uniform[S <: Style](element: S) extends StyleScheme[S] {
+ override def apply(dataSets: Seq[DataSet]) = (Seq.empty[Statement], (d: DataSet) => element)
+} \ No newline at end of file