diff options
author | Jakob Odersky <jodersky@gmail.com> | 2012-10-09 13:27:55 +0200 |
---|---|---|
committer | Jakob Odersky <jodersky@gmail.com> | 2012-10-09 13:27:55 +0200 |
commit | 46c9121ac0856cbad855994941a4288e50da1cf1 (patch) | |
tree | de0afd2eea5a35849bcb762bd4662c9b78d3804e | |
parent | e5e135bf1c2c386037496e3f40adb10e0184e066 (diff) | |
download | scalam-46c9121ac0856cbad855994941a4288e50da1cf1.tar.gz scalam-46c9121ac0856cbad855994941a4288e50da1cf1.tar.bz2 scalam-46c9121ac0856cbad855994941a4288e50da1cf1.zip |
refactor style support
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | src/main/scala/scalam/DataSet.scala | 2 | ||||
-rw-r--r-- | src/main/scala/scalam/charting/MatlabChart.scala | 86 | ||||
-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/plotting/Plot.scala | 44 | ||||
-rw-r--r-- | src/main/scala/scalam/plotting/colorSchemes.scala | 89 | ||||
-rw-r--r-- | src/main/scala/scalam/plotting/styles/colors.scala | 39 | ||||
-rw-r--r-- | src/main/scala/scalam/plotting/styles/lines.scala | 12 | ||||
-rw-r--r-- | src/main/scala/scalam/plotting/styles/markers.scala | 32 | ||||
-rw-r--r-- | src/main/scala/scalam/plotting/styles/styles.scala | 21 |
11 files changed, 138 insertions, 259 deletions
@@ -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 |