From eef73a1bc8260b41e394288e4da57b8df66e9ff0 Mon Sep 17 00:00:00 2001 From: "Aaron J. Radke" Date: Mon, 1 Oct 2018 09:30:54 -0500 Subject: [PATCH 1/8] add default them to the Theme companion object --- .../main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala b/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala index 7060b143..8ea524db 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala @@ -44,3 +44,8 @@ final case class Theme( colors: Colors, elements: Elements ) + +object Theme{ + /**An automatic default theme at a low priority precedence*/ + implicit val defaultTheme:Theme = com.cibo.evilplot.plot.aesthetics.DefaultTheme.defaultTheme +} From 9b3027e34cb4afc664dafd745c3ef22aca25f638 Mon Sep 17 00:00:00 2001 From: "Aaron J. Radke" Date: Mon, 1 Oct 2018 11:31:21 -0500 Subject: [PATCH 2/8] remove all explicit default theme imports --- docs/src/main/tut/getting-started.md | 2 -- docs/src/main/tut/plot-catalog.md | 4 ---- docs/src/main/tut/plots.md | 1 - docs/src/main/tut/render-context.md | 1 - .../scala/com/cibo/evilplot/plot/aesthetics/Theme.scala | 5 ++++- .../test/scala/com/cibo/evilplot/colors/ColoringSpec.scala | 6 ++---- .../com/cibo/evilplot/geometry/AffineTransformSpec.scala | 2 -- .../scala/com/cibo/evilplot/geometry/DrawableSpec.scala | 2 -- .../test/scala/com/cibo/evilplot/plot/BarChartSpec.scala | 2 -- .../src/test/scala/com/cibo/evilplot/plot/BoxPlotSpec.scala | 2 -- .../test/scala/com/cibo/evilplot/plot/ContourPlotSpec.scala | 2 -- .../src/test/scala/com/cibo/evilplot/plot/FacetsSpec.scala | 2 -- .../src/test/scala/com/cibo/evilplot/plot/HeatmapSpec.scala | 2 -- .../test/scala/com/cibo/evilplot/plot/HistogramSpec.scala | 2 -- .../com/cibo/evilplot/plot/MixedBoundsOverlaySpec.scala | 2 -- .../src/test/scala/com/cibo/evilplot/plot/OverlaySpec.scala | 2 -- shared/src/test/scala/com/cibo/evilplot/plot/PlotSpec.scala | 2 -- .../test/scala/com/cibo/evilplot/plot/ScatterPlotSpec.scala | 2 -- .../src/test/scala/com/cibo/evilplot/plot/XyPlotSpec.scala | 2 -- .../scala/com/cibo/evilplot/plot/components/AxesSpec.scala | 2 -- .../cibo/evilplot/plot/components/ComponentGroupSpec.scala | 2 -- 21 files changed, 6 insertions(+), 43 deletions(-) diff --git a/docs/src/main/tut/getting-started.md b/docs/src/main/tut/getting-started.md index e04fb53d..9a74da50 100644 --- a/docs/src/main/tut/getting-started.md +++ b/docs/src/main/tut/getting-started.md @@ -43,7 +43,6 @@ and take a look at it. ```scala import com.cibo.evilplot._ import com.cibo.evilplot.plot._ -import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ import com.cibo.evilplot.numeric.Point val data = Seq.tabulate(100) { i => @@ -77,7 +76,6 @@ some labels, so our audience knows what we're talking about. That's easy as well
```scala import com.cibo.evilplot.plot._ -import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ import com.cibo.evilplot.numeric.Point val data = Seq.tabulate(100) { i => diff --git a/docs/src/main/tut/plot-catalog.md b/docs/src/main/tut/plot-catalog.md index dbad2885..53a1ca58 100644 --- a/docs/src/main/tut/plot-catalog.md +++ b/docs/src/main/tut/plot-catalog.md @@ -293,7 +293,6 @@ A pairs plot can be built by combining `ScatterPlot` and `Histogram` plots with ```scala import com.cibo.evilplot.numeric.Point import com.cibo.evilplot.plot._ -import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ import scala.util.Random val labels = Vector("a", "b", "c", "d") @@ -332,7 +331,6 @@ A `FunctionPlot` can be used to build density plots. import com.cibo.evilplot.colors.Color import com.cibo.evilplot.numeric.Bounds import com.cibo.evilplot.plot._ -import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ import com.cibo.evilplot.plot.renderers.PathRenderer import scala.util.Random @@ -379,7 +377,6 @@ Overlay( import com.cibo.evilplot.colors.HTMLNamedColors.{green, red} import com.cibo.evilplot.geometry.Extent import com.cibo.evilplot.plot._ -import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ import com.cibo.evilplot.plot.renderers.BarRenderer import scala.util.Random @@ -408,7 +405,6 @@ Overlay( ```scala import com.cibo.evilplot.numeric.Point import com.cibo.evilplot.plot._ -import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ import scala.util.Random val data = Seq.fill(100) { diff --git a/docs/src/main/tut/plots.md b/docs/src/main/tut/plots.md index 349a267f..d71a8661 100644 --- a/docs/src/main/tut/plots.md +++ b/docs/src/main/tut/plots.md @@ -37,7 +37,6 @@ A `PointRenderer` tells your plot how to draw the data. When we don't pass one i import com.cibo.evilplot.numeric.Point import com.cibo.evilplot.plot._ import com.cibo.evilplot.plot.renderers.PointRenderer -import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ import scala.util.Random val qualities = Seq("good", "bad") diff --git a/docs/src/main/tut/render-context.md b/docs/src/main/tut/render-context.md index 5454e441..63f5f10c 100644 --- a/docs/src/main/tut/render-context.md +++ b/docs/src/main/tut/render-context.md @@ -18,7 +18,6 @@ Started page using `CanvasRenderContext`. ```scala import com.cibo.evilplot.geometry.{CanvasRenderContext, Extent} import com.cibo.evilplot.plot._ -import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ import com.cibo.evilplot.numeric.Point import org.scalajs.dom diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala b/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala index 8ea524db..edf3bba0 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala @@ -47,5 +47,8 @@ final case class Theme( object Theme{ /**An automatic default theme at a low priority precedence*/ - implicit val defaultTheme:Theme = com.cibo.evilplot.plot.aesthetics.DefaultTheme.defaultTheme + implicit val defaultTheme:Theme = DefaultTheme.defaultTheme + + /**A simpler constructor for a classic Theme without requiring the entire Classic import */ + val classic:Theme = ClassicTheme.classicTheme } diff --git a/shared/src/test/scala/com/cibo/evilplot/colors/ColoringSpec.scala b/shared/src/test/scala/com/cibo/evilplot/colors/ColoringSpec.scala index ea08857f..15e149ea 100644 --- a/shared/src/test/scala/com/cibo/evilplot/colors/ColoringSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/colors/ColoringSpec.scala @@ -30,13 +30,11 @@ package com.cibo.evilplot.colors -import com.cibo.evilplot.plot.aesthetics.DefaultTheme.{DefaultElements, DefaultFonts} import com.cibo.evilplot.plot.aesthetics.{Colors, Elements, Fonts, Theme} import org.scalatest.{FunSpec, Matchers} class ColoringSpec extends FunSpec with Matchers { describe("multi color gradient construction") { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ it("should return a function when Colors has only one element") { val min: Double = 0 val max: Double = 100 @@ -77,8 +75,8 @@ class ColoringSpec extends FunSpec with Matchers { coloring(6.0) shouldBe HTMLNamedColors.blue } } - describe("coloring from the theme") { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme.{DefaultColors => AesColors} + describe("overriding the default color from the theme") { + import com.cibo.evilplot.plot.aesthetics.DefaultTheme.{DefaultElements,DefaultFonts,DefaultColors => AesColors} implicit val overriddenTheme: Theme = Theme( fonts = DefaultFonts, elements = DefaultElements, diff --git a/shared/src/test/scala/com/cibo/evilplot/geometry/AffineTransformSpec.scala b/shared/src/test/scala/com/cibo/evilplot/geometry/AffineTransformSpec.scala index cda1457c..4b8ea53b 100644 --- a/shared/src/test/scala/com/cibo/evilplot/geometry/AffineTransformSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/geometry/AffineTransformSpec.scala @@ -34,8 +34,6 @@ import org.scalatest.{FunSpec, Matchers} class AffineTransformSpec extends FunSpec with Matchers { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ - describe("The AffineTransform") { it("should translate a point") { AffineTransform.identity.translate(1.0, 0.0)(1.0, 1.0) should be((2.0, 1.0)) diff --git a/shared/src/test/scala/com/cibo/evilplot/geometry/DrawableSpec.scala b/shared/src/test/scala/com/cibo/evilplot/geometry/DrawableSpec.scala index c5e916e0..4541501a 100644 --- a/shared/src/test/scala/com/cibo/evilplot/geometry/DrawableSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/geometry/DrawableSpec.scala @@ -34,8 +34,6 @@ import org.scalatest.{FunSpec, Matchers} class DrawableSpec extends FunSpec with Matchers { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ - describe("EmptyDrawable") { it("has zero size") { EmptyDrawable().extent shouldBe Extent(0, 0) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/BarChartSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/BarChartSpec.scala index 1a61a7ca..06ffc9bd 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/BarChartSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/BarChartSpec.scala @@ -36,8 +36,6 @@ import org.scalatest.{FunSpec, Matchers} class BarChartSpec extends FunSpec with Matchers { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ - describe("BarChart") { it("should have the right bounds without buffer") { val plot = BarChart(Seq[Double](10, 20, 15)) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/BoxPlotSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/BoxPlotSpec.scala index ffcb3ed8..2aa58277 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/BoxPlotSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/BoxPlotSpec.scala @@ -36,8 +36,6 @@ import org.scalatest.{FunSpec, Matchers} class BoxPlotSpec extends FunSpec with Matchers { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ - describe("BoxPlot") { it("should have the right extents") { val plot = BoxPlot(Seq(Seq(1.0, 2.0))) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/ContourPlotSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/ContourPlotSpec.scala index 57d97f60..1759cb62 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/ContourPlotSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/ContourPlotSpec.scala @@ -36,8 +36,6 @@ import org.scalatest.{FunSpec, Matchers} class ContourPlotSpec extends FunSpec with Matchers { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ - describe("ContourPlot") { it("it has the right bounds") { val plot = ContourPlot(Seq(Point(1, 2), Point(3, 4)), boundBuffer = Some(0.0)) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/FacetsSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/FacetsSpec.scala index 7e05630b..deee8504 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/FacetsSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/FacetsSpec.scala @@ -38,8 +38,6 @@ import com.cibo.evilplot.plot.components.{FacetedPlotComponent, Position} class FacetsSpec extends FunSpec with Matchers { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ - describe("Facets") { it("is the correct size with one facet") { val inner = ScatterPlot(Seq(Point(1, 1), Point(2, 2))) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/HeatmapSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/HeatmapSpec.scala index b2ce77a1..c961d5c1 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/HeatmapSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/HeatmapSpec.scala @@ -36,8 +36,6 @@ import org.scalatest.{FunSpec, Matchers} class HeatmapSpec extends FunSpec with Matchers { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ - describe("Heatmap") { it("has the right bounds") { val plot = Heatmap(Seq(Seq(1), Seq(2))) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/HistogramSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/HistogramSpec.scala index 1c921480..cadf5555 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/HistogramSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/HistogramSpec.scala @@ -36,8 +36,6 @@ import org.scalatest.{FunSpec, Matchers} class HistogramSpec extends FunSpec with Matchers { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ - describe("Histogram") { val plot = Histogram(Seq(1.0, 1, 1, 2, 3, 4, 4, 5), boundBuffer = Some(0)) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/MixedBoundsOverlaySpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/MixedBoundsOverlaySpec.scala index 3c04a391..ace4bf75 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/MixedBoundsOverlaySpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/MixedBoundsOverlaySpec.scala @@ -38,8 +38,6 @@ import org.scalatest.{FunSpec, Matchers} class MixedBoundsOverlaySpec extends FunSpec with Matchers { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ - describe("MixedBoundsOverlay") { it("it has the bounds that are set for it") { diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/OverlaySpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/OverlaySpec.scala index 0866bc8f..c2d3da91 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/OverlaySpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/OverlaySpec.scala @@ -38,8 +38,6 @@ import org.scalatest.{FunSpec, Matchers} class OverlaySpec extends FunSpec with Matchers { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ - describe("Overlay") { it("it gets the bounds right for a single plot") { val inner = ScatterPlot(Seq(Point(1.0, 10.0), Point(2.0, 20.0))) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/PlotSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/PlotSpec.scala index 3f847a77..2a277b99 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/PlotSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/PlotSpec.scala @@ -39,8 +39,6 @@ import org.scalatest.{FunSpec, Matchers} class PlotSpec extends FunSpec with Matchers { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ - DOMInitializer.init() // Renderer to do nothing. diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/ScatterPlotSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/ScatterPlotSpec.scala index 52c7166a..6ee1866b 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/ScatterPlotSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/ScatterPlotSpec.scala @@ -35,8 +35,6 @@ import org.scalatest.{FunSpec, Matchers} class ScatterPlotSpec extends FunSpec with Matchers { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ - describe("ScatterPlot") { it("sets adheres to bound buffers") { val data = Seq(Point(-1, 10), Point(20, -5)) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/XyPlotSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/XyPlotSpec.scala index 1ca0d725..7a24b351 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/XyPlotSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/XyPlotSpec.scala @@ -36,8 +36,6 @@ import org.scalatest.{FunSpec, Matchers} class XyPlotSpec extends FunSpec with Matchers { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ - describe("XyPlot") { it("has the right bounds") { val plot = diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/components/AxesSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/components/AxesSpec.scala index 40e02e4a..6987a3a0 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/components/AxesSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/components/AxesSpec.scala @@ -36,8 +36,6 @@ import org.scalatest.{FunSpec, Matchers} class AxesSpec extends FunSpec with Matchers { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ - describe("discrete X") { it("should set the default bounds") { val plot = BarChart(Seq(3.0, 4)).xAxis() diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/components/ComponentGroupSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/components/ComponentGroupSpec.scala index 2c965ad9..6485f16b 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/components/ComponentGroupSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/components/ComponentGroupSpec.scala @@ -37,8 +37,6 @@ import org.scalatest.{FunSpec, Matchers} class ComponentGroupSpec extends FunSpec with Matchers { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ - abstract class MockComponent(val position: Position) extends FacetedPlotComponent abstract class LeftComponent extends MockComponent(Position.Left) abstract class TopComponent extends MockComponent(Position.Top) From c77fb3129a324fa126b20175617f73233f6d24fb Mon Sep 17 00:00:00 2001 From: "Aaron J. Radke" Date: Mon, 1 Oct 2018 11:31:26 -0500 Subject: [PATCH 3/8] update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8404cc39..61d4f3e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## [Changes since last release] +## [0.5.x] - 2018-??-?? +- added a low priority default Theme so this cumbersome import is only necessary when desired + ## [0.5.0] - 2018-09-21 ### Added - `ComponentGroup` for combining plot components From 331307f3b65480c2682fa7b69b5bdd6e5848bfa1 Mon Sep 17 00:00:00 2001 From: "Aaron J. Radke" Date: Mon, 1 Oct 2018 14:44:05 -0500 Subject: [PATCH 4/8] explicitly select all theme implicits to ensure propogation --- .../com/cibo/evilplot/plot/BarChart.scala | 20 +++++++------- .../com/cibo/evilplot/plot/BoxPlot.scala | 16 ++++++------ .../scala/com/cibo/evilplot/plot/Facets.scala | 2 +- .../com/cibo/evilplot/plot/FunctionPlot.scala | 14 +++++----- .../com/cibo/evilplot/plot/Heatmap.scala | 14 +++++----- .../com/cibo/evilplot/plot/Histogram.scala | 8 +++--- .../cibo/evilplot/plot/LegendContext.scala | 4 +-- .../com/cibo/evilplot/plot/LinePlot.scala | 18 ++++++------- .../evilplot/plot/MixedBoundsOverlay.scala | 2 +- .../com/cibo/evilplot/plot/Overlay.scala | 6 ++--- .../com/cibo/evilplot/plot/PieChart.scala | 4 +-- .../scala/com/cibo/evilplot/plot/Plot.scala | 10 +++---- .../com/cibo/evilplot/plot/ScatterPlot.scala | 12 ++++----- .../com/cibo/evilplot/plot/SurfacePlot.scala | 8 +++--- .../scala/com/cibo/evilplot/plot/XyPlot.scala | 8 +++--- .../plot/aesthetics/DefaultTheme.scala | 7 ++--- .../cibo/evilplot/plot/aesthetics/Theme.scala | 11 ++++++-- .../evilplot/plot/components/Background.scala | 4 +-- .../evilplot/plot/components/BorderPlot.scala | 10 +++---- .../components/FacetedPlotComponent.scala | 4 +-- .../cibo/evilplot/plot/components/Label.scala | 10 +++---- .../evilplot/plot/components/Legend.scala | 16 ++++++------ .../plot/components/PlotComponent.scala | 6 ++--- .../evilplot/plot/components/PlotLine.scala | 4 +-- .../evilplot/plot/renderers/BarRenderer.scala | 6 ++--- .../evilplot/plot/renderers/BoxRenderer.scala | 12 ++++----- .../plot/renderers/ComponentRenderer.scala | 26 +++++++++---------- .../plot/renderers/PlotRenderer.scala | 4 +-- .../plot/renderers/PointRenderer.scala | 20 +++++++------- .../plot/renderers/SurfaceRenderer.scala | 16 ++++++------ .../cibo/evilplot/colors/ColoringSpec.scala | 6 +++-- .../com/cibo/evilplot/plot/BarChartSpec.scala | 1 + .../com/cibo/evilplot/plot/BoxPlotSpec.scala | 2 ++ .../cibo/evilplot/plot/ContourPlotSpec.scala | 2 ++ .../com/cibo/evilplot/plot/FacetsSpec.scala | 2 ++ .../com/cibo/evilplot/plot/HeatmapSpec.scala | 2 ++ .../cibo/evilplot/plot/HistogramSpec.scala | 2 ++ .../plot/MixedBoundsOverlaySpec.scala | 2 ++ .../com/cibo/evilplot/plot/OverlaySpec.scala | 2 ++ .../com/cibo/evilplot/plot/PlotSpec.scala | 2 ++ .../cibo/evilplot/plot/ScatterPlotSpec.scala | 2 ++ .../com/cibo/evilplot/plot/XyPlotSpec.scala | 2 ++ .../evilplot/plot/components/AxesSpec.scala | 2 ++ .../plot/components/ComponentGroupSpec.scala | 4 ++- 44 files changed, 186 insertions(+), 149 deletions(-) diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/BarChart.scala b/shared/src/main/scala/com/cibo/evilplot/plot/BarChart.scala index 37b4e1fe..b7ef4f4f 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/BarChart.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/BarChart.scala @@ -33,7 +33,7 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.colors.{Color, DefaultColors} import com.cibo.evilplot.geometry.{Drawable, EmptyDrawable, Extent, Rect, Style, Text} import com.cibo.evilplot.numeric.Bounds -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme,DefaultTheme} import com.cibo.evilplot.plot.renderers.{BarRenderer, PlotRenderer} /** Data for a bar in a bar chart. @@ -61,13 +61,13 @@ final case class Bar( ) } -object Bar { +object Bar extends DefaultTheme{ def apply(value: Double)(implicit theme: Theme): Bar = Bar(Seq(value), 0, theme.colors.stream) def apply(value: Double, cluster: Int)(implicit theme: Theme): Bar = Bar(Seq(value), cluster = cluster, theme.colors.stream) } -object BarChart { +object BarChart extends DefaultTheme{ val defaultBoundBuffer: Double = 0.1 @@ -151,9 +151,9 @@ object BarChart { spacing: Option[Double] = None, boundBuffer: Option[Double] = None )(implicit theme: Theme): Plot = { - val barRenderer = BarRenderer.default(color) - val bars = values.map(Bar(_)) - custom(bars, Some(barRenderer), spacing, None, boundBuffer) + val barRenderer = BarRenderer.default(color)(theme) + val bars = values.map(Bar(_)(theme)) + custom(bars, Some(barRenderer), spacing, None, boundBuffer)(theme) } /** Create a bar chart where bars are divided into clusters. */ @@ -195,7 +195,7 @@ object BarChart { Some(barRenderer), spacing, Some(clusterSpacing.getOrElse(theme.elements.clusterSpacing)), - boundBuffer) + boundBuffer)(theme) } /** Create a stacked bar chart. @@ -220,7 +220,7 @@ object BarChart { val bars = values.map { stack => Bar(stack, colors = colorStream, labels = barLabels, cluster = 0) } - custom(bars, Some(barRenderer), spacing, None, boundBuffer) + custom(bars, Some(barRenderer), spacing, None, boundBuffer)(theme) } /** Create a clustered bar chart of stacked bars. @@ -261,7 +261,7 @@ object BarChart { Some(barRenderer), spacing, Some(clusterSpacing.getOrElse(theme.elements.clusterSpacing)), - boundBuffer) + boundBuffer)(theme) } /** Create a custom bar chart. @@ -292,7 +292,7 @@ object BarChart { ybounds, BarChartRenderer( bars, - barRenderer.getOrElse(BarRenderer.default()), + barRenderer.getOrElse(BarRenderer.default()(theme)), spacing.getOrElse(theme.elements.barSpacing), clusterSpacing ) diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/BoxPlot.scala b/shared/src/main/scala/com/cibo/evilplot/plot/BoxPlot.scala index e213d85e..62c12c08 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/BoxPlot.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/BoxPlot.scala @@ -32,7 +32,7 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.geometry._ import com.cibo.evilplot.numeric.{Bounds, BoxPlotSummaryStatistics} -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import com.cibo.evilplot.plot.renderers.BoxRenderer.BoxRendererContext import com.cibo.evilplot.plot.renderers.{BoxRenderer, PlotRenderer, PointRenderer} @@ -42,7 +42,7 @@ final case class BoxPlotRenderer( pointRenderer: PointRenderer, spacing: Double, clusterSpacing: Option[Double] -) extends PlotRenderer { +) extends PlotRenderer with DefaultTheme{ private val isClustered = clusterSpacing.isDefined private val clusterPadding = clusterSpacing.getOrElse(spacing) @@ -106,7 +106,7 @@ final case class BoxPlotRenderer( override def legendContext: LegendContext = boxRenderer.legendContext } -object BoxPlot { +object BoxPlot extends DefaultTheme{ /** Create box plots for a sequence of distributions. * @@ -141,7 +141,7 @@ object BoxPlot { boundBuffer, boxRenderer, pointRenderer - ) + )(theme) } @@ -185,7 +185,7 @@ object BoxPlot { boundBuffer, boxRenderer, pointRenderer - ) + )(theme) } private def makePlot( @@ -210,8 +210,8 @@ object BoxPlot { ybounds, BoxPlotRenderer( boxContexts, - boxRenderer.getOrElse(BoxRenderer.default()), - pointRenderer.getOrElse(PointRenderer.default()), + boxRenderer.getOrElse(BoxRenderer.default()(theme)), + pointRenderer.getOrElse(PointRenderer.default()(theme)), spacing.getOrElse(theme.elements.boxSpacing), clusterSpacing ) @@ -236,6 +236,6 @@ object BoxPlot { spacing: Option[Double] = None, boundBuffer: Option[Double] = None )(implicit theme: Theme): Plot = { - apply(data, quantiles, spacing, boundBuffer, Some(boxRenderer), Some(pointRenderer)) + apply(data, quantiles, spacing, boundBuffer, Some(boxRenderer), Some(pointRenderer))(theme) } } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/Facets.scala b/shared/src/main/scala/com/cibo/evilplot/plot/Facets.scala index 8fb0aec1..e3b08858 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/Facets.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/Facets.scala @@ -77,7 +77,7 @@ object Facets { row.zipWithIndex.map { case (subplot, xIndex) => val x = xIndex * innerExtent.width - subplot.render(innerExtent).translate(x = x, y = y) + subplot.render(innerExtent)(theme).translate(x = x, y = y) }.group }.group } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/FunctionPlot.scala b/shared/src/main/scala/com/cibo/evilplot/plot/FunctionPlot.scala index fb16f82e..d80eefda 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/FunctionPlot.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/FunctionPlot.scala @@ -33,11 +33,11 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.colors.Color import com.cibo.evilplot.geometry.Drawable import com.cibo.evilplot.numeric.Bounds -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import com.cibo.evilplot.plot.components.FunctionPlotLine import com.cibo.evilplot.plot.renderers.{PathRenderer, PointRenderer} -object FunctionPlot { +object FunctionPlot extends DefaultTheme{ val defaultBounds: Bounds = Bounds(0, 1) val defaultNumPoints: Int = 800 @@ -66,7 +66,7 @@ object FunctionPlot { pointRenderer.orElse(Some(PointRenderer.empty())), pathRenderer, xBoundBuffer, - yBoundBuffer) + yBoundBuffer)(theme) } /** Plot a function using a name for the legend. @@ -85,8 +85,8 @@ object FunctionPlot { xBoundBuffer: Option[Double] = None, yBoundBuffer: Option[Double] = None )(implicit theme: Theme): Plot = { - val renderer = Some(PathRenderer.named(name, color, strokeWidth)) - apply(function, xbounds, numPoints, renderer, None, xBoundBuffer, yBoundBuffer) + val renderer = Some(PathRenderer.named(name, color, strokeWidth)(theme)) + apply(function, xbounds, numPoints, renderer, None, xBoundBuffer, yBoundBuffer)(theme) } /** Plot a function using a name for the legend. @@ -104,7 +104,7 @@ object FunctionPlot { strokeWidth: Option[Double], xBoundBuffer: Option[Double], yBoundBuffer: Option[Double])(implicit theme: Theme): Plot = { - val renderer = Some(PathRenderer.default(strokeWidth, Some(color), label)) - apply(function, xbounds, numPoints, renderer, None, xBoundBuffer, yBoundBuffer) + val renderer = Some(PathRenderer.default(strokeWidth, Some(color), label)(theme)) + apply(function, xbounds, numPoints, renderer, None, xBoundBuffer, yBoundBuffer)(theme) } } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/Heatmap.scala b/shared/src/main/scala/com/cibo/evilplot/plot/Heatmap.scala index c79159c2..0b410697 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/Heatmap.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/Heatmap.scala @@ -33,10 +33,12 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.colors.{Color, Coloring, ScaledColorBar} import com.cibo.evilplot.geometry.{Drawable, Extent, Rect} import com.cibo.evilplot.numeric.Bounds -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import com.cibo.evilplot.plot.renderers.PlotRenderer -object Heatmap { +object Heatmap extends DefaultTheme{ + + implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default val defaultColorCount: Int = 10 @@ -80,7 +82,7 @@ object Heatmap { ybounds = ybounds, xfixed = true, yfixed = true, - renderer = HeatmapRenderer(data, colorBar) + renderer = HeatmapRenderer(data, colorBar)(theme) ) } @@ -99,7 +101,7 @@ object Heatmap { val minValue = flattenedData.reduceOption[Double](math.min).getOrElse(0.0) val maxValue = flattenedData.reduceOption[Double](math.max).getOrElse(0.0) val colorBar = ScaledColorBar(colorStream.take(colorCount), minValue, maxValue) - apply(data, colorBar) + apply(data, colorBar)(theme) } def apply(data: Seq[Seq[Double]], @@ -108,9 +110,9 @@ object Heatmap { val minValue = flattenedData.reduceOption[Double](math.min).getOrElse(0.0) val maxValue = flattenedData.reduceOption[Double](math.max).getOrElse(0.0) val useColoring = coloring.getOrElse(theme.colors.continuousColoring) - val colorFunc = useColoring(flattenedData) + val colorFunc = useColoring(flattenedData)(theme) val colorBar = ScaledColorBar(flattenedData.map(point => colorFunc.apply(point)), minValue, maxValue) - apply(data, colorBar) + apply(data, colorBar)(theme) } } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/Histogram.scala b/shared/src/main/scala/com/cibo/evilplot/plot/Histogram.scala index 2589181b..f2830d95 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/Histogram.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/Histogram.scala @@ -32,10 +32,10 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.geometry.{Drawable, EmptyDrawable, Extent} import com.cibo.evilplot.numeric.{Bounds, Point} -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import com.cibo.evilplot.plot.renderers.{BarRenderer, PlotRenderer} -object Histogram { +object Histogram extends DefaultTheme{ val defaultBinCount: Int = 20 @@ -128,7 +128,7 @@ object Histogram { val clippedY = math.min(point.y * yscale, plot.ybounds.max) val y = ytransformer(clippedY) val barWidth = math.max(xtransformer(point.x + binWidth) - x - spacing, 0) - val bar = Bar(clippedY) + val bar = Bar(clippedY)(theme) val barHeight = yintercept - y barRenderer.render(plot, Extent(barWidth, barHeight), bar).translate(x = x, y = y) }.group @@ -173,7 +173,7 @@ object Histogram { ybounds = Bounds(0, maxY * (1.0 + boundBuffer.getOrElse(theme.elements.boundBuffer))), renderer = HistogramRenderer( values, - barRenderer.getOrElse(BarRenderer.default()), + barRenderer.getOrElse(BarRenderer.default()(theme)), bins, spacing.getOrElse(theme.elements.barSpacing), boundBuffer.getOrElse(theme.elements.boundBuffer), diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/LegendContext.scala b/shared/src/main/scala/com/cibo/evilplot/plot/LegendContext.scala index a0217537..9e54c74b 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/LegendContext.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/LegendContext.scala @@ -32,7 +32,7 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.colors.ScaledColorBar import com.cibo.evilplot.geometry.{Drawable, Rect, Style, Text} -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} sealed trait LegendStyle @@ -68,7 +68,7 @@ case class LegendContext( } } -object LegendContext { +object LegendContext extends DefaultTheme{ def empty: LegendContext = LegendContext() def single( diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/LinePlot.scala b/shared/src/main/scala/com/cibo/evilplot/plot/LinePlot.scala index ae45ed8f..69b02049 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/LinePlot.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/LinePlot.scala @@ -33,10 +33,10 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.colors.Color import com.cibo.evilplot.geometry.Drawable import com.cibo.evilplot.numeric.Point -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import com.cibo.evilplot.plot.renderers.{PathRenderer, PointRenderer} -object LinePlot { +object LinePlot extends DefaultTheme{ /** Create a line plot from some data. Convenience method on top of XyPlot * @@ -56,10 +56,10 @@ object LinePlot { XyPlot( data, pointRenderer = Some(pointRenderer.getOrElse(PointRenderer.empty())), - pathRenderer = Some(pathRenderer.getOrElse(PathRenderer.default())), + pathRenderer = Some(pathRenderer.getOrElse(PathRenderer.default()(theme))), xboundBuffer.orElse(Some(0)), yboundBuffer - ) + )(theme) } /** Create a line plot from some data. Convenience method on top of XyPlot @@ -78,7 +78,7 @@ object LinePlot { xboundBuffer: Double, yboundBuffer: Double )(implicit theme: Theme): Plot = { - XyPlot(data, Some(pointRenderer), Some(pathRenderer), Some(xboundBuffer), Some(yboundBuffer)) + XyPlot(data, Some(pointRenderer), Some(pathRenderer), Some(xboundBuffer), Some(yboundBuffer))(theme) } /** Create a line plot with the specified name and color. @@ -98,14 +98,14 @@ object LinePlot { yboundBuffer: Option[Double] = None )(implicit theme: Theme): Plot = { val pointRenderer = PointRenderer.empty() - val pathRenderer = PathRenderer.named(name, color, strokeWidth) + val pathRenderer = PathRenderer.named(name, color, strokeWidth)(theme) XyPlot( data, Some(pointRenderer), Some(pathRenderer), xboundBuffer, yboundBuffer - ) + )(theme) } /** Create a line plot with the specified name and color. @@ -125,7 +125,7 @@ object LinePlot { yboundBuffer: Option[Double] )(implicit theme: Theme): Plot = { val pointRenderer = PointRenderer.empty() - val pathRenderer = PathRenderer.default(strokeWidth, Some(color), label) - XyPlot(data, Some(pointRenderer), Some(pathRenderer), xboundBuffer, yboundBuffer) + val pathRenderer = PathRenderer.default(strokeWidth, Some(color), label)(theme) + XyPlot(data, Some(pointRenderer), Some(pathRenderer), xboundBuffer, yboundBuffer)(theme) } } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/MixedBoundsOverlay.scala b/shared/src/main/scala/com/cibo/evilplot/plot/MixedBoundsOverlay.scala index 12d49828..c348b091 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/MixedBoundsOverlay.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/MixedBoundsOverlay.scala @@ -41,7 +41,7 @@ object MixedBoundsOverlay { override def legendContext: LegendContext = LegendContext.combine(subplots.map(_.renderer.legendContext)) def render(plot: Plot, plotExtent: Extent)(implicit theme: Theme): Drawable = - Plot.padPlots(Seq(subplots), plotExtent, 0, 0).head.map(_.render(plotExtent)).group + Plot.padPlots(Seq(subplots), plotExtent, 0, 0).head.map(_.render(plotExtent)(theme)).group } /** Overlay plots without updating bounds or transforms for individual plots. diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/Overlay.scala b/shared/src/main/scala/com/cibo/evilplot/plot/Overlay.scala index b3d2cb48..05b4bba7 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/Overlay.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/Overlay.scala @@ -32,10 +32,10 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.geometry.{Drawable, Extent} import com.cibo.evilplot.numeric.Bounds -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import com.cibo.evilplot.plot.renderers.PlotRenderer -object Overlay { +object Overlay extends DefaultTheme{ // Update subplots to have the specified bounds (if not already fixed). private def updateSubplotBounds( @@ -71,7 +71,7 @@ object Overlay { xbounds = plot.xbounds, ybounds = plot.ybounds ) - updatedPlots.map(_.render(plotExtent)).group + updatedPlots.map(_.render(plotExtent)(theme)).group } } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/PieChart.scala b/shared/src/main/scala/com/cibo/evilplot/plot/PieChart.scala index dd64ca0e..0c73c3a7 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/PieChart.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/PieChart.scala @@ -33,10 +33,10 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.colors.{Color, HTMLNamedColors} import com.cibo.evilplot.geometry.{Drawable, Extent, Rect, Text, Wedge} import com.cibo.evilplot.numeric.Bounds -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme,DefaultTheme} import com.cibo.evilplot.plot.renderers.PlotRenderer -object PieChart { +object PieChart extends DefaultTheme{ case class PieChartRenderer( data: Seq[(Drawable, Double)], diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/Plot.scala b/shared/src/main/scala/com/cibo/evilplot/plot/Plot.scala index 059c2931..935c674b 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/Plot.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/Plot.scala @@ -32,7 +32,7 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.geometry._ import com.cibo.evilplot.numeric.{Bounds, Point} -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import com.cibo.evilplot.plot.components.{FacetedPlotComponent, Position} import com.cibo.evilplot.plot.renderers.{ComponentRenderer, PlotRenderer} @@ -57,7 +57,7 @@ final case class Plot( xfixed: Boolean = false, yfixed: Boolean = false, components: Seq[FacetedPlotComponent] = Seq.empty -) { +) extends DefaultTheme{ private[plot] def inBounds(point: Point): Boolean = xbounds.isInBounds(point.x) && ybounds.isInBounds(point.y) @@ -135,11 +135,11 @@ final case class Plot( * @param extent the desired size of the resulting Drawable */ def render(extent: Extent = Plot.defaultExtent)(implicit theme: Theme): Drawable = { - val overlays = componentRenderer.renderFront(this, extent) - val backgrounds = componentRenderer.renderBack(this, extent) + val overlays = componentRenderer.renderFront(this, extent)(theme) + val backgrounds = componentRenderer.renderBack(this, extent)(theme) val pextent = plotExtent(extent) val renderedPlot = - renderer.render(this, pextent).resize(pextent).translate(x = plotOffset.x, y = plotOffset.y) + renderer.render(this, pextent)(theme).resize(pextent).translate(x = plotOffset.x, y = plotOffset.y) backgrounds behind renderedPlot behind overlays } } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/ScatterPlot.scala b/shared/src/main/scala/com/cibo/evilplot/plot/ScatterPlot.scala index 1bc3a804..84bf1cc7 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/ScatterPlot.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/ScatterPlot.scala @@ -33,10 +33,10 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.colors.Color import com.cibo.evilplot.geometry.{Drawable, Style, Text} import com.cibo.evilplot.numeric.Point -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import com.cibo.evilplot.plot.renderers.{PathRenderer, PointRenderer} -object ScatterPlot { +object ScatterPlot extends DefaultTheme{ /** Create a scatter plot from some data. * @param data The points to plot. @@ -49,7 +49,7 @@ object ScatterPlot { pointRenderer: Option[PointRenderer] = None, boundBuffer: Option[Double] = None )(implicit theme: Theme): Plot = { - XyPlot(data, pointRenderer, Some(PathRenderer.empty()), boundBuffer, boundBuffer) + XyPlot(data, pointRenderer, Some(PathRenderer.empty()), boundBuffer, boundBuffer)(theme) } /** Create a scatter plot with the specified name and color. @@ -74,7 +74,7 @@ object ScatterPlot { color, pointSize, boundBuffer - ) + )(theme) /** Create a scatter plot with the specified name and color. * @param data The points to plot. @@ -90,8 +90,8 @@ object ScatterPlot { pointSize: Option[Double], boundBuffer: Option[Double] )(implicit theme: Theme): Plot = { - val pointRenderer = PointRenderer.default(Some(color), pointSize, name) + val pointRenderer = PointRenderer.default(Some(color), pointSize, name)(theme) val pathRenderer = PathRenderer.empty() - XyPlot(data, Some(pointRenderer), Some(pathRenderer), boundBuffer, boundBuffer) + XyPlot(data, Some(pointRenderer), Some(pathRenderer), boundBuffer, boundBuffer)(theme) } } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/SurfacePlot.scala b/shared/src/main/scala/com/cibo/evilplot/plot/SurfacePlot.scala index 370e24ea..883caf87 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/SurfacePlot.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/SurfacePlot.scala @@ -32,11 +32,11 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.geometry.{Drawable, Extent} import com.cibo.evilplot.numeric._ -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme,DefaultTheme} import com.cibo.evilplot.plot.renderers.SurfaceRenderer.SurfaceRenderContext import com.cibo.evilplot.plot.renderers.{PlotRenderer, SurfaceRenderer} -object SurfacePlot { +object SurfacePlot extends DefaultTheme{ private[plot] case class SurfacePlotRenderer( data: Seq[Seq[Seq[Point3]]], surfaceRenderer: SurfaceRenderer @@ -72,7 +72,7 @@ object SurfacePlot { } } -object ContourPlot { +object ContourPlot extends DefaultTheme{ import SurfacePlot._ val defaultGridDimensions: (Int, Int) = (100, 100) @@ -120,7 +120,7 @@ object ContourPlot { } } - val sr = surfaceRenderer.getOrElse(SurfaceRenderer.densityColorContours()) + val sr = surfaceRenderer.getOrElse(SurfaceRenderer.densityColorContours()(theme)) Plot( xbounds, ybounds, diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/XyPlot.scala b/shared/src/main/scala/com/cibo/evilplot/plot/XyPlot.scala index 1bfd21ba..8591e356 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/XyPlot.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/XyPlot.scala @@ -32,10 +32,10 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.geometry._ import com.cibo.evilplot.numeric.{Bounds, Point} -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme,DefaultTheme} import com.cibo.evilplot.plot.renderers.{PathRenderer, PlotRenderer, PointRenderer} -object XyPlot { +object XyPlot extends DefaultTheme{ final case class XyPlotRenderer( data: Seq[Point], @@ -104,8 +104,8 @@ object XyPlot { ybounds, XyPlotRenderer( data, - pointRenderer.getOrElse(PointRenderer.default()), - pathRenderer.getOrElse(PathRenderer.default())) + pointRenderer.getOrElse(PointRenderer.default()(theme)), + pathRenderer.getOrElse(PathRenderer.default()(theme))) ) } } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/DefaultTheme.scala b/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/DefaultTheme.scala index 2ea23641..032f7837 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/DefaultTheme.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/DefaultTheme.scala @@ -34,7 +34,7 @@ import com.cibo.evilplot.colors._ import com.cibo.evilplot.colors.ContinuousColoring.gradient import com.cibo.evilplot.geometry.LineStyle -object DefaultTheme { +object DefaultTheme extends DefaultTheme{ private val darkGray: HSLA = HSLA(0, 0, 12, 1.0) private val lightGray: HSLA = HSLA(0, 0, 65, 0.8) private val darkBlue: HSLA = HSLA(211, 38, 48, 1.0) @@ -108,6 +108,7 @@ object DefaultTheme { elements = DefaultElements ) - implicit val defaultTheme: Theme = DefaultTheme - +} +trait DefaultTheme{ + implicit val defaultTheme: Theme = DefaultTheme.DefaultTheme } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala b/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala index edf3bba0..a7047c88 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala @@ -45,9 +45,16 @@ final case class Theme( elements: Elements ) -object Theme{ +object Theme { + + // trait Default{ + // implicit val defaultTheme: Theme = DefaultTheme.DefaultTheme + // } + /**An automatic default theme at a low priority precedence*/ - implicit val defaultTheme:Theme = DefaultTheme.defaultTheme + val default:Theme = DefaultTheme.defaultTheme + // /**An automatic default theme at a low priority precedence*/ + // implicit val default:Theme = Default.theme /**A simpler constructor for a classic Theme without requiring the entire Classic import */ val classic:Theme = ClassicTheme.classicTheme diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/components/Background.scala b/shared/src/main/scala/com/cibo/evilplot/plot/components/Background.scala index b8d0ea9d..b3534255 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/components/Background.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/components/Background.scala @@ -33,7 +33,7 @@ package com.cibo.evilplot.plot.components import com.cibo.evilplot.colors.Color import com.cibo.evilplot.geometry.{Drawable, Extent, Line, Rect, StrokeStyle} import com.cibo.evilplot.plot.Plot -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} final case class Background( f: (Plot, Extent) => Drawable @@ -43,7 +43,7 @@ final case class Background( def render(plot: Plot, extent: Extent)(implicit theme: Theme): Drawable = f(plot, extent) } -trait BackgroundImplicits { +trait BackgroundImplicits extends DefaultTheme{ protected val plot: Plot /** Set the background (this will replace any existing background). diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/components/BorderPlot.scala b/shared/src/main/scala/com/cibo/evilplot/plot/components/BorderPlot.scala index f47a1780..8cb52730 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/components/BorderPlot.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/components/BorderPlot.scala @@ -46,13 +46,13 @@ case class BorderPlot( border .xbounds(plot.xbounds) .copy(xtransform = plot.xtransform) - .render(extent.copy(height = borderSize)) + .render(extent.copy(height = borderSize))(theme) case Position.Bottom => val borderExent = extent.copy(height = borderSize) border .xbounds(plot.xbounds) .copy(xtransform = plot.xtransform) - .render(borderExent) + .render(borderExent)(theme) .rotated(180) .flipX case Position.Left => @@ -60,7 +60,7 @@ case class BorderPlot( border .xbounds(plot.ybounds) .copy(xtransform = plot.xtransform) - .render(borderExtent) + .render(borderExtent)(theme) .resize(borderExtent) .rotated(270) case Position.Right => @@ -68,12 +68,12 @@ case class BorderPlot( border .xbounds(plot.ybounds) .copy(xtransform = plot.xtransform) - .render(borderExtent) + .render(borderExtent)(theme) .resize(borderExtent) .rotated(90) .flipY case _ => - border.render(extent) + border.render(extent)(theme) } } } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/components/FacetedPlotComponent.scala b/shared/src/main/scala/com/cibo/evilplot/plot/components/FacetedPlotComponent.scala index 1a08fa4e..60640119 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/components/FacetedPlotComponent.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/components/FacetedPlotComponent.scala @@ -32,10 +32,10 @@ package com.cibo.evilplot.plot.components import com.cibo.evilplot.geometry.{Drawable, Extent} import com.cibo.evilplot.plot.Plot -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} /** A component that is aligned with the data of a plot. */ -trait FacetedPlotComponent { +trait FacetedPlotComponent extends DefaultTheme{ /** The position of this component. */ val position: Position diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/components/Label.scala b/shared/src/main/scala/com/cibo/evilplot/plot/components/Label.scala index b0f84347..1addf21a 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/components/Label.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/components/Label.scala @@ -32,7 +32,7 @@ package com.cibo.evilplot.plot.components import com.cibo.evilplot.colors.{Color, HTMLNamedColors} import com.cibo.evilplot.geometry.{Drawable, Extent, StrokeStyle, Style, Text} -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import com.cibo.evilplot.plot.Plot /** A plot label. @@ -44,7 +44,7 @@ case class Label( position: Position, f: Extent => Drawable, minExtent: Extent -) extends PlotComponent { +) extends PlotComponent with DefaultTheme{ override def size(plot: Plot): Extent = minExtent def render(plot: Plot, extent: Extent)(implicit theme: Theme): Drawable = position match { case Position.Top => f(extent).center(extent.width) @@ -59,7 +59,7 @@ object Label { def apply(position: Position, d: Drawable): Label = Label(position, _ => d, d.extent) } -trait LabelImplicits { +trait LabelImplicits extends DefaultTheme{ protected val plot: Plot def title(d: Drawable): Plot = plot :+ Label(Position.Top, d) @@ -138,12 +138,12 @@ trait LabelImplicits { label: String, size: Option[Double] = None, color: Option[Color] = None - )(implicit theme: Theme): Plot = bottomLabel(label, size, color) + )(implicit theme: Theme): Plot = bottomLabel(label, size, color)(theme) def yLabel(d: Drawable): Plot = leftLabel(d) def yLabel( label: String, size: Option[Double] = None, color: Option[Color] = None - )(implicit theme: Theme): Plot = leftLabel(label, size, color) + )(implicit theme: Theme): Plot = leftLabel(label, size, color)(theme) } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/components/Legend.scala b/shared/src/main/scala/com/cibo/evilplot/plot/components/Legend.scala index cdcda9a2..b35b79ce 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/components/Legend.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/components/Legend.scala @@ -31,7 +31,7 @@ package com.cibo.evilplot.plot.components import com.cibo.evilplot.geometry._ -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import com.cibo.evilplot.plot.renderers.LegendRenderer import com.cibo.evilplot.plot.{LegendContext, Plot} @@ -55,7 +55,7 @@ case class Legend( } } -trait LegendImplicits { +trait LegendImplicits extends DefaultTheme{ protected val plot: Plot private def setLegend( @@ -87,25 +87,25 @@ trait LegendImplicits { def rightLegend( renderer: LegendRenderer = LegendRenderer.vertical(), labels: Option[Seq[String]] = None - )(implicit theme: Theme): Plot = setLegend(Position.Right, renderer, 0, 0.5, labels) + )(implicit theme: Theme): Plot = setLegend(Position.Right, renderer, 0, 0.5, labels)(theme) /** Place a legend on the left side of the plot. */ def leftLegend( renderer: LegendRenderer = LegendRenderer.vertical(), labels: Option[Seq[String]] = None - )(implicit theme: Theme): Plot = setLegend(Position.Left, renderer, 0, 0.5, labels) + )(implicit theme: Theme): Plot = setLegend(Position.Left, renderer, 0, 0.5, labels)(theme) /** Place a legend on the top of the plot. */ def topLegend( renderer: LegendRenderer = LegendRenderer.horizontal(), labels: Option[Seq[String]] = None - )(implicit theme: Theme): Plot = setLegend(Position.Top, renderer, 0.5, 0, labels) + )(implicit theme: Theme): Plot = setLegend(Position.Top, renderer, 0.5, 0, labels)(theme) /** Place a legend on the bottom of the plot. */ def bottomLegend( renderer: LegendRenderer = LegendRenderer.horizontal(), labels: Option[Seq[String]] = None - )(implicit theme: Theme): Plot = setLegend(Position.Bottom, renderer, 0.5, 0, labels) + )(implicit theme: Theme): Plot = setLegend(Position.Bottom, renderer, 0.5, 0, labels)(theme) /** Overlay a legend on the plot. * @param x The relative X position (0 to 1). @@ -117,7 +117,7 @@ trait LegendImplicits { y: Double = 0.0, renderer: LegendRenderer = LegendRenderer.vertical(), labels: Option[Seq[String]] = None - )(implicit theme: Theme): Plot = setLegend(Position.Overlay, renderer, x, y, labels) + )(implicit theme: Theme): Plot = setLegend(Position.Overlay, renderer, x, y, labels)(theme) /** Get the legend as a drawable. */ def renderLegend( @@ -125,6 +125,6 @@ trait LegendImplicits { )(implicit theme: Theme): Option[Drawable] = if (plot.renderer.legendContext.nonEmpty) { val legend = Legend(Position.Right, plot.renderer.legendContext, renderer, 0, 0) - Some(legend.render(plot, legend.size(plot))) + Some(legend.render(plot, legend.size(plot))(theme)) } else None } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotComponent.scala b/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotComponent.scala index e197d5bd..8ba0c09f 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotComponent.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotComponent.scala @@ -32,10 +32,10 @@ package com.cibo.evilplot.plot.components import com.cibo.evilplot.geometry._ import com.cibo.evilplot.plot.Plot -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} /** A component that is aligned with the data of a plot (used when all facets are treated identically). */ -trait PlotComponent extends FacetedPlotComponent { +trait PlotComponent extends FacetedPlotComponent{ // Render the component (assumes all facets are handled the same way). def render(plot: Plot, extent: Extent)(implicit theme: Theme): Drawable @@ -44,5 +44,5 @@ trait PlotComponent extends FacetedPlotComponent { // This this calls the implementation that ignores facet information. final def render(plot: Plot, extent: Extent, row: Int, column: Int)( implicit theme: Theme): Drawable = - render(plot, extent) + render(plot, extent)(theme) } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotLine.scala b/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotLine.scala index 2a0fd439..b0da4932 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotLine.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotLine.scala @@ -34,7 +34,7 @@ import com.cibo.evilplot.colors.Color import com.cibo.evilplot.geometry.{Drawable, EmptyDrawable, Extent, Line, LineStyle, Path} import com.cibo.evilplot.numeric.{Bounds, Point} import com.cibo.evilplot.plot.Plot -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import scala.annotation.tailrec @@ -167,7 +167,7 @@ object FunctionPlotLine { } } -trait PlotLineImplicits { +trait PlotLineImplicits extends DefaultTheme{ protected val plot: Plot val defaultThickness: Double = 2.0 diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BarRenderer.scala b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BarRenderer.scala index 465908a1..d0f54677 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BarRenderer.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BarRenderer.scala @@ -32,7 +32,7 @@ package com.cibo.evilplot.plot.renderers import com.cibo.evilplot.colors.Color import com.cibo.evilplot.geometry._ -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import com.cibo.evilplot.plot.{Bar, LegendContext, Plot} trait BarRenderer extends PlotElementRenderer[Bar] { @@ -40,7 +40,7 @@ trait BarRenderer extends PlotElementRenderer[Bar] { def legendContext: Option[LegendContext] = None } -object BarRenderer { +object BarRenderer extends DefaultTheme{ /** Default bar renderer. */ def default( @@ -68,7 +68,7 @@ object BarRenderer { Rect(legSize, legSize).filled(color.getOrElse(theme.colors.bar)) }, label = n - ) + )(theme) } } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BoxRenderer.scala b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BoxRenderer.scala index 75b137d8..77233775 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BoxRenderer.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BoxRenderer.scala @@ -44,11 +44,11 @@ import com.cibo.evilplot.geometry.{ Translate } import com.cibo.evilplot.numeric.BoxPlotSummaryStatistics -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import com.cibo.evilplot.plot.renderers.BoxRenderer.BoxRendererContext import com.cibo.evilplot.plot.{LegendContext, Plot} -trait BoxRenderer extends PlotElementRenderer[BoxRendererContext] { br => +trait BoxRenderer extends PlotElementRenderer[BoxRendererContext] with DefaultTheme{ br => def render(plot: Plot, extent: Extent, summary: BoxRendererContext): Drawable def legendContext: LegendContext = LegendContext.empty @@ -76,7 +76,7 @@ trait BoxRenderer extends PlotElementRenderer[BoxRendererContext] { br => } } -object BoxRenderer { +object BoxRenderer extends DefaultTheme { final case class BoxRendererContext( summaryStatistics: BoxPlotSummaryStatistics, index: Int, @@ -173,16 +173,16 @@ object BoxRenderer { strokeWidth: Option[Double] = None )(implicit theme: Theme): BoxRenderer = new BoxRenderer { private val useColoring = fillColoring.getOrElse(CategoricalColoring.themed[A]) - private val colorFunc = useColoring(colorDimension) + private val colorFunc = useColoring(colorDimension)(theme) def render(plot: Plot, extent: Extent, context: BoxRendererContext): Drawable = { BoxRenderer - .default(fillColor = Some(colorFunc(colorDimension(context.index)))) + .default(fillColor = Some(colorFunc(colorDimension(context.index))))(theme) .render(plot, extent, context) } override def legendContext: LegendContext = { - useColoring.legendContext(colorDimension, legendGlyph = d => Rect(d)) + useColoring.legendContext(colorDimension, legendGlyph = d => Rect(d))(theme) } } } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/ComponentRenderer.scala b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/ComponentRenderer.scala index 1fc542b8..1513aa9b 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/ComponentRenderer.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/ComponentRenderer.scala @@ -33,7 +33,7 @@ package com.cibo.evilplot.plot.renderers import com.cibo.evilplot.geometry.{Drawable, EmptyDrawable, Extent} import com.cibo.evilplot.numeric.Point import com.cibo.evilplot.plot.Plot -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} /** Renderer for non-plot area components of a plot (labels, etc.). */ trait ComponentRenderer { @@ -48,7 +48,7 @@ trait ComponentRenderer { def plotOffset(plot: Plot): Point } -object ComponentRenderer { +object ComponentRenderer extends DefaultTheme{ case class Default() extends ComponentRenderer { @@ -58,7 +58,7 @@ object ComponentRenderer { val plotExtent = plot.plotExtent(extent) plot.topComponents.reverse.foldLeft(empty) { (d, c) => val componentExtent = plotExtent.copy(height = c.size(plot).height) - c.render(plot, componentExtent, 0, 0) + c.render(plot, componentExtent, 0, 0)(theme) .translate(x = plot.plotOffset.x, y = d.extent.height) behind d } } @@ -69,7 +69,7 @@ object ComponentRenderer { .foldLeft((extent.height, empty)) { case ((y, d), c) => val componentExtent = plotExtent.copy(height = c.size(plot).height) - val rendered = c.render(plot, plotExtent, 0, 0) + val rendered = c.render(plot, plotExtent, 0, 0)(theme) val newY = y - rendered.extent.height (newY, rendered.translate(x = plot.plotOffset.x, y = newY) behind d) } @@ -80,7 +80,7 @@ object ComponentRenderer { val plotExtent = plot.plotExtent(extent) plot.leftComponents.foldLeft(empty) { (d, c) => val componentExtent = plotExtent.copy(width = c.size(plot).width) - c.render(plot, componentExtent, 0, 0).translate(y = plot.plotOffset.y) beside d + c.render(plot, componentExtent, 0, 0)(theme).translate(y = plot.plotOffset.y) beside d } } @@ -90,7 +90,7 @@ object ComponentRenderer { .foldLeft((extent.width, empty)) { case ((x, d), c) => val componentExtent = plotExtent.copy(width = c.size(plot).width) - val rendered = c.render(plot, componentExtent, 0, 0) + val rendered = c.render(plot, componentExtent, 0, 0)(theme) val newX = x - rendered.extent.width (newX, rendered.translate(x = newX, y = plot.plotOffset.y) behind d) } @@ -100,22 +100,22 @@ object ComponentRenderer { private def renderOverlay(plot: Plot, extent: Extent)(implicit theme: Theme): Drawable = { val plotExtent = plot.plotExtent(extent) plot.overlayComponents.map { a => - a.render(plot, plotExtent, 0, 0).translate(x = plot.plotOffset.x, y = plot.plotOffset.y) + a.render(plot, plotExtent, 0, 0)(theme).translate(x = plot.plotOffset.x, y = plot.plotOffset.y) }.group } def renderFront(plot: Plot, extent: Extent)(implicit theme: Theme): Drawable = { - renderOverlay(plot, extent) - .behind(renderLeft(plot, extent)) - .behind(renderRight(plot, extent)) - .behind(renderBottom(plot, extent)) - .behind(renderTop(plot, extent)) + renderOverlay(plot, extent)(theme) + .behind(renderLeft(plot, extent)(theme)) + .behind(renderRight(plot, extent)(theme)) + .behind(renderBottom(plot, extent)(theme)) + .behind(renderTop(plot, extent)(theme)) } def renderBack(plot: Plot, extent: Extent)(implicit theme: Theme): Drawable = { val plotExtent = plot.plotExtent(extent) plot.backgroundComponents.map { a => - a.render(plot, plotExtent, 0, 0).translate(x = plot.plotOffset.x, y = plot.plotOffset.y) + a.render(plot, plotExtent, 0, 0)(theme).translate(x = plot.plotOffset.x, y = plot.plotOffset.y) }.group } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PlotRenderer.scala b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PlotRenderer.scala index 2e12ef03..8b3bc3d4 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PlotRenderer.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PlotRenderer.scala @@ -31,11 +31,11 @@ package com.cibo.evilplot.plot.renderers import com.cibo.evilplot.geometry.{Drawable, Extent} -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import com.cibo.evilplot.plot.{LegendContext, Plot} /** Renderer for the plot area. */ -trait PlotRenderer { +trait PlotRenderer extends DefaultTheme{ def legendContext: LegendContext = LegendContext.empty def render(plot: Plot, plotExtent: Extent)(implicit theme: Theme): Drawable } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PointRenderer.scala b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PointRenderer.scala index 956f32b5..661e642a 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PointRenderer.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PointRenderer.scala @@ -32,7 +32,7 @@ package com.cibo.evilplot.plot.renderers import com.cibo.evilplot.colors._ import com.cibo.evilplot.geometry.{Disc, Drawable, EmptyDrawable, Extent, Style, Text} -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import com.cibo.evilplot.plot.{LegendContext, LegendStyle, Plot} trait PointRenderer extends PlotElementRenderer[Int] { @@ -40,7 +40,7 @@ trait PointRenderer extends PlotElementRenderer[Int] { def render(plot: Plot, extent: Extent, index: Int): Drawable } -object PointRenderer { +object PointRenderer extends DefaultTheme{ val defaultColorCount: Int = 10 @@ -78,7 +78,7 @@ object PointRenderer { size: Option[Double] = None )(implicit theme: Theme): PointRenderer = new PointRenderer { private val useColoring = coloring.getOrElse(theme.colors.continuousColoring) - private val colorFunc = useColoring(depths) + private val colorFunc = useColoring(depths)(theme) private val radius = size.getOrElse(theme.elements.pointSize) def render(plot: Plot, extent: Extent, index: Int): Drawable = { @@ -86,7 +86,7 @@ object PointRenderer { } override def legendContext: LegendContext = - useColoring.legendContext(depths) + useColoring.legendContext(depths)(theme) } /** @@ -103,14 +103,14 @@ object PointRenderer { size: Option[Double] = None )(implicit theme: Theme): PointRenderer = new PointRenderer { private val useColoring = coloring.getOrElse(CategoricalColoring.themed[A]) - private val colorFunc = useColoring(colorDimension) + private val colorFunc = useColoring(colorDimension)(theme) private val radius = size.getOrElse(theme.elements.pointSize) def render(plot: Plot, extent: Extent, index: Int): Drawable = { Disc.centered(radius).filled(colorFunc(colorDimension(index))) } - override def legendContext: LegendContext = useColoring.legendContext(colorDimension) + override def legendContext: LegendContext = useColoring.legendContext(colorDimension)(theme) } /** @@ -138,7 +138,7 @@ object PointRenderer { theme.fonts.fontFace), theme.colors.legendLabel) } - oldDepthColor(depths, labels, bar, None) + oldDepthColor(depths, labels, bar, None)(theme) } /** Render points with colors based on depth. @@ -154,7 +154,7 @@ object PointRenderer { bar: ScaledColorBar, size: Option[Double] )(implicit theme: Theme): PointRenderer = { - oldDepthColor(depths, labels, bar, size) + oldDepthColor(depths, labels, bar, size)(theme) } /** Render points with colors based on depth. @@ -167,7 +167,7 @@ object PointRenderer { depths: Seq[Double], labels: Seq[Drawable], bar: ScaledColorBar - )(implicit theme: Theme): PointRenderer = oldDepthColor(depths, labels, bar, None) + )(implicit theme: Theme): PointRenderer = oldDepthColor(depths, labels, bar, None)(theme) /** Render points with colors based on depth. * @param depths The depths. @@ -186,7 +186,7 @@ object PointRenderer { theme.fonts.fontFace), theme.colors.legendLabel) } - oldDepthColor(depths, labels, bar, None) + oldDepthColor(depths, labels, bar, None)(theme) } // Old `depthColor` implementation, called to by all deprecated `depthColor` diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/SurfaceRenderer.scala b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/SurfaceRenderer.scala index 38922b48..e6a6776e 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/SurfaceRenderer.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/SurfaceRenderer.scala @@ -33,7 +33,7 @@ package com.cibo.evilplot.plot.renderers import com.cibo.evilplot.colors._ import com.cibo.evilplot.geometry.{Drawable, EmptyDrawable, Extent, LineStyle, Path} import com.cibo.evilplot.numeric.{Bounds, Point, Point3} -import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} import com.cibo.evilplot.plot.renderers.SurfaceRenderer.SurfaceRenderContext import com.cibo.evilplot.plot.{LegendContext, Plot} @@ -42,7 +42,7 @@ trait SurfaceRenderer extends PlotElementRenderer[SurfaceRenderContext] { def render(plot: Plot, extent: Extent, surface: SurfaceRenderContext): Drawable } -object SurfaceRenderer { +object SurfaceRenderer extends DefaultTheme{ /** The element renderer context for surface renderers. */ case class SurfaceRenderContext( @@ -91,9 +91,9 @@ object SurfaceRenderer { val surfaceRenderer = getBySafe(points)(_.headOption.flatMap(_.headOption.map(_.z))) .map { bs => val bar = ScaledColorBar(getColorSeq(points.length), bs.min, bs.max) - densityColorContours(bar)(points) + densityColorContours(bar)(points)(theme) } - .getOrElse(contours()) + .getOrElse(contours()(theme)) surfaceRenderer.render(plot, extent, surface) } } @@ -105,7 +105,7 @@ object SurfaceRenderer { surface.currentLevelPaths.headOption .map(pts => contours(Some(pts.headOption.fold(theme.colors.path)(_ => - bar.getColor(surface.currentLevel)))) + bar.getColor(surface.currentLevel))))(theme) .render(plot, extent, surface)) .getOrElse(EmptyDrawable()) } @@ -120,17 +120,17 @@ object SurfaceRenderer { coloring.getOrElse(theme.colors.continuousColoring) def render(plot: Plot, extent: Extent, surface: SurfaceRenderContext): Drawable = { - val color = useColoring(surface.levels).apply(surface.currentLevel) + val color = useColoring(surface.levels)(theme).apply(surface.currentLevel) surface.currentLevelPaths .map( pts => - contours(Some(color), strokeWidth, dashPattern) + contours(Some(color), strokeWidth, dashPattern)(theme) .render(plot, extent, surface)) .group } override def legendContext(levels: Seq[Double]): LegendContext = { - useColoring.legendContext(levels) + useColoring.legendContext(levels)(theme) } } } diff --git a/shared/src/test/scala/com/cibo/evilplot/colors/ColoringSpec.scala b/shared/src/test/scala/com/cibo/evilplot/colors/ColoringSpec.scala index 15e149ea..cd47f66c 100644 --- a/shared/src/test/scala/com/cibo/evilplot/colors/ColoringSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/colors/ColoringSpec.scala @@ -34,6 +34,8 @@ import com.cibo.evilplot.plot.aesthetics.{Colors, Elements, Fonts, Theme} import org.scalatest.{FunSpec, Matchers} class ColoringSpec extends FunSpec with Matchers { + implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default + describe("multi color gradient construction") { it("should return a function when Colors has only one element") { val min: Double = 0 @@ -77,7 +79,8 @@ class ColoringSpec extends FunSpec with Matchers { } describe("overriding the default color from the theme") { import com.cibo.evilplot.plot.aesthetics.DefaultTheme.{DefaultElements,DefaultFonts,DefaultColors => AesColors} - implicit val overriddenTheme: Theme = Theme( + // implicit val overriddenTheme: Theme = Theme( + implicit val theme: Theme = Theme( //shadowed implicit theme fonts = DefaultFonts, elements = DefaultElements, colors = AesColors.copy(stream = Seq(HTMLNamedColors.red)) @@ -88,7 +91,6 @@ class ColoringSpec extends FunSpec with Matchers { } } describe("making a coloring out of a custom mapping") { - import com.cibo.evilplot.plot.aesthetics.DefaultTheme._ it("should actually use the mapping") { val f = (s: String) => if (s == "hello") HTMLNamedColors.blue else HTMLNamedColors.red val coloring = CategoricalColoring.fromFunction(Seq("hello", "world"), f) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/BarChartSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/BarChartSpec.scala index 06ffc9bd..4725df57 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/BarChartSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/BarChartSpec.scala @@ -35,6 +35,7 @@ import com.cibo.evilplot.numeric.Bounds import org.scalatest.{FunSpec, Matchers} class BarChartSpec extends FunSpec with Matchers { + implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default describe("BarChart") { it("should have the right bounds without buffer") { diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/BoxPlotSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/BoxPlotSpec.scala index 2aa58277..a124d383 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/BoxPlotSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/BoxPlotSpec.scala @@ -36,6 +36,8 @@ import org.scalatest.{FunSpec, Matchers} class BoxPlotSpec extends FunSpec with Matchers { + implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default + describe("BoxPlot") { it("should have the right extents") { val plot = BoxPlot(Seq(Seq(1.0, 2.0))) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/ContourPlotSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/ContourPlotSpec.scala index 1759cb62..ce0b6c07 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/ContourPlotSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/ContourPlotSpec.scala @@ -36,6 +36,8 @@ import org.scalatest.{FunSpec, Matchers} class ContourPlotSpec extends FunSpec with Matchers { + implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default + describe("ContourPlot") { it("it has the right bounds") { val plot = ContourPlot(Seq(Point(1, 2), Point(3, 4)), boundBuffer = Some(0.0)) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/FacetsSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/FacetsSpec.scala index deee8504..d579a660 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/FacetsSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/FacetsSpec.scala @@ -38,6 +38,8 @@ import com.cibo.evilplot.plot.components.{FacetedPlotComponent, Position} class FacetsSpec extends FunSpec with Matchers { + implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default + describe("Facets") { it("is the correct size with one facet") { val inner = ScatterPlot(Seq(Point(1, 1), Point(2, 2))) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/HeatmapSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/HeatmapSpec.scala index c961d5c1..90131be3 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/HeatmapSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/HeatmapSpec.scala @@ -36,6 +36,8 @@ import org.scalatest.{FunSpec, Matchers} class HeatmapSpec extends FunSpec with Matchers { + implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default + describe("Heatmap") { it("has the right bounds") { val plot = Heatmap(Seq(Seq(1), Seq(2))) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/HistogramSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/HistogramSpec.scala index cadf5555..9ab457e4 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/HistogramSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/HistogramSpec.scala @@ -36,6 +36,8 @@ import org.scalatest.{FunSpec, Matchers} class HistogramSpec extends FunSpec with Matchers { + implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default + describe("Histogram") { val plot = Histogram(Seq(1.0, 1, 1, 2, 3, 4, 4, 5), boundBuffer = Some(0)) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/MixedBoundsOverlaySpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/MixedBoundsOverlaySpec.scala index ace4bf75..ab07b96b 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/MixedBoundsOverlaySpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/MixedBoundsOverlaySpec.scala @@ -38,6 +38,8 @@ import org.scalatest.{FunSpec, Matchers} class MixedBoundsOverlaySpec extends FunSpec with Matchers { + implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default + describe("MixedBoundsOverlay") { it("it has the bounds that are set for it") { diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/OverlaySpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/OverlaySpec.scala index c2d3da91..a253b095 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/OverlaySpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/OverlaySpec.scala @@ -38,6 +38,8 @@ import org.scalatest.{FunSpec, Matchers} class OverlaySpec extends FunSpec with Matchers { + implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default + describe("Overlay") { it("it gets the bounds right for a single plot") { val inner = ScatterPlot(Seq(Point(1.0, 10.0), Point(2.0, 20.0))) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/PlotSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/PlotSpec.scala index 2a277b99..4543ce1d 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/PlotSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/PlotSpec.scala @@ -39,6 +39,8 @@ import org.scalatest.{FunSpec, Matchers} class PlotSpec extends FunSpec with Matchers { + implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default + DOMInitializer.init() // Renderer to do nothing. diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/ScatterPlotSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/ScatterPlotSpec.scala index 6ee1866b..9257f8d3 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/ScatterPlotSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/ScatterPlotSpec.scala @@ -35,6 +35,8 @@ import org.scalatest.{FunSpec, Matchers} class ScatterPlotSpec extends FunSpec with Matchers { + implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default + describe("ScatterPlot") { it("sets adheres to bound buffers") { val data = Seq(Point(-1, 10), Point(20, -5)) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/XyPlotSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/XyPlotSpec.scala index 7a24b351..5279c3ec 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/XyPlotSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/XyPlotSpec.scala @@ -36,6 +36,8 @@ import org.scalatest.{FunSpec, Matchers} class XyPlotSpec extends FunSpec with Matchers { + implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default + describe("XyPlot") { it("has the right bounds") { val plot = diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/components/AxesSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/components/AxesSpec.scala index 6987a3a0..aaa46c2a 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/components/AxesSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/components/AxesSpec.scala @@ -36,6 +36,8 @@ import org.scalatest.{FunSpec, Matchers} class AxesSpec extends FunSpec with Matchers { + implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default + describe("discrete X") { it("should set the default bounds") { val plot = BarChart(Seq(3.0, 4)).xAxis() diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/components/ComponentGroupSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/components/ComponentGroupSpec.scala index 6485f16b..3695e25e 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/components/ComponentGroupSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/components/ComponentGroupSpec.scala @@ -35,7 +35,9 @@ import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.{Plot, XyPlot} import org.scalatest.{FunSpec, Matchers} -class ComponentGroupSpec extends FunSpec with Matchers { +class ComponentGroupSpec extends FunSpec with Matchers{ + + implicit val theme = Theme.default abstract class MockComponent(val position: Position) extends FacetedPlotComponent abstract class LeftComponent extends MockComponent(Position.Left) From 93fd359c586058f5f320936fb9a184697ab8eaee Mon Sep 17 00:00:00 2001 From: "Aaron J. Radke" Date: Mon, 1 Oct 2018 15:11:13 -0500 Subject: [PATCH 5/8] remove the explicit implicit themes in the tests --- shared/src/main/scala/com/cibo/evilplot/plot/Heatmap.scala | 2 -- .../com/cibo/evilplot/plot/aesthetics/DefaultTheme.scala | 6 ++++-- .../scala/com/cibo/evilplot/plot/aesthetics/Theme.scala | 6 +----- .../com/cibo/evilplot/plot/renderers/PathRenderer.scala | 4 ++-- .../test/scala/com/cibo/evilplot/colors/ColoringSpec.scala | 4 +--- .../test/scala/com/cibo/evilplot/plot/BarChartSpec.scala | 1 - .../src/test/scala/com/cibo/evilplot/plot/BoxPlotSpec.scala | 2 -- .../test/scala/com/cibo/evilplot/plot/ContourPlotSpec.scala | 2 -- .../src/test/scala/com/cibo/evilplot/plot/FacetsSpec.scala | 2 -- .../src/test/scala/com/cibo/evilplot/plot/HeatmapSpec.scala | 2 -- .../test/scala/com/cibo/evilplot/plot/HistogramSpec.scala | 2 -- .../com/cibo/evilplot/plot/MixedBoundsOverlaySpec.scala | 2 -- .../src/test/scala/com/cibo/evilplot/plot/OverlaySpec.scala | 2 -- shared/src/test/scala/com/cibo/evilplot/plot/PlotSpec.scala | 2 -- .../test/scala/com/cibo/evilplot/plot/ScatterPlotSpec.scala | 2 -- .../src/test/scala/com/cibo/evilplot/plot/XyPlotSpec.scala | 2 -- .../scala/com/cibo/evilplot/plot/components/AxesSpec.scala | 2 -- .../cibo/evilplot/plot/components/ComponentGroupSpec.scala | 2 -- 18 files changed, 8 insertions(+), 39 deletions(-) diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/Heatmap.scala b/shared/src/main/scala/com/cibo/evilplot/plot/Heatmap.scala index 0b410697..4399c689 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/Heatmap.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/Heatmap.scala @@ -38,8 +38,6 @@ import com.cibo.evilplot.plot.renderers.PlotRenderer object Heatmap extends DefaultTheme{ - implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default - val defaultColorCount: Int = 10 final case class HeatmapRenderer( diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/DefaultTheme.scala b/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/DefaultTheme.scala index 032f7837..072d13cc 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/DefaultTheme.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/DefaultTheme.scala @@ -34,7 +34,7 @@ import com.cibo.evilplot.colors._ import com.cibo.evilplot.colors.ContinuousColoring.gradient import com.cibo.evilplot.geometry.LineStyle -object DefaultTheme extends DefaultTheme{ +object DefaultTheme{ private val darkGray: HSLA = HSLA(0, 0, 12, 1.0) private val lightGray: HSLA = HSLA(0, 0, 65, 0.8) private val darkBlue: HSLA = HSLA(211, 38, 48, 1.0) @@ -108,7 +108,9 @@ object DefaultTheme extends DefaultTheme{ elements = DefaultElements ) + implicit val defaultTheme: Theme = this.DefaultTheme + } trait DefaultTheme{ - implicit val defaultTheme: Theme = DefaultTheme.DefaultTheme + implicit val defaultTheme: Theme = DefaultTheme.defaultTheme } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala b/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala index a7047c88..74a42cf6 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/Theme.scala @@ -47,12 +47,8 @@ final case class Theme( object Theme { - // trait Default{ - // implicit val defaultTheme: Theme = DefaultTheme.DefaultTheme - // } - /**An automatic default theme at a low priority precedence*/ - val default:Theme = DefaultTheme.defaultTheme + implicit val default:Theme = DefaultTheme.defaultTheme // /**An automatic default theme at a low priority precedence*/ // implicit val default:Theme = Default.theme diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PathRenderer.scala b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PathRenderer.scala index 9c14639a..2c02a761 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PathRenderer.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PathRenderer.scala @@ -90,7 +90,7 @@ object PathRenderer { Text(name, theme.fonts.legendLabelSize, theme.fonts.fontFace), theme.colors.legendLabel), lineStyle - ) + )(theme) /** Path renderer for closed paths. The first point is connected to the last point. * @param color the color of this path. @@ -175,4 +175,4 @@ class DefaultPathRenderer (strokeWidth: Double, ) .group } -} \ No newline at end of file +} diff --git a/shared/src/test/scala/com/cibo/evilplot/colors/ColoringSpec.scala b/shared/src/test/scala/com/cibo/evilplot/colors/ColoringSpec.scala index cd47f66c..071d02a7 100644 --- a/shared/src/test/scala/com/cibo/evilplot/colors/ColoringSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/colors/ColoringSpec.scala @@ -34,7 +34,6 @@ import com.cibo.evilplot.plot.aesthetics.{Colors, Elements, Fonts, Theme} import org.scalatest.{FunSpec, Matchers} class ColoringSpec extends FunSpec with Matchers { - implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default describe("multi color gradient construction") { it("should return a function when Colors has only one element") { @@ -79,8 +78,7 @@ class ColoringSpec extends FunSpec with Matchers { } describe("overriding the default color from the theme") { import com.cibo.evilplot.plot.aesthetics.DefaultTheme.{DefaultElements,DefaultFonts,DefaultColors => AesColors} - // implicit val overriddenTheme: Theme = Theme( - implicit val theme: Theme = Theme( //shadowed implicit theme + implicit val overriddenTheme: Theme = Theme( fonts = DefaultFonts, elements = DefaultElements, colors = AesColors.copy(stream = Seq(HTMLNamedColors.red)) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/BarChartSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/BarChartSpec.scala index 4725df57..06ffc9bd 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/BarChartSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/BarChartSpec.scala @@ -35,7 +35,6 @@ import com.cibo.evilplot.numeric.Bounds import org.scalatest.{FunSpec, Matchers} class BarChartSpec extends FunSpec with Matchers { - implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default describe("BarChart") { it("should have the right bounds without buffer") { diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/BoxPlotSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/BoxPlotSpec.scala index a124d383..2aa58277 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/BoxPlotSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/BoxPlotSpec.scala @@ -36,8 +36,6 @@ import org.scalatest.{FunSpec, Matchers} class BoxPlotSpec extends FunSpec with Matchers { - implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default - describe("BoxPlot") { it("should have the right extents") { val plot = BoxPlot(Seq(Seq(1.0, 2.0))) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/ContourPlotSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/ContourPlotSpec.scala index ce0b6c07..1759cb62 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/ContourPlotSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/ContourPlotSpec.scala @@ -36,8 +36,6 @@ import org.scalatest.{FunSpec, Matchers} class ContourPlotSpec extends FunSpec with Matchers { - implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default - describe("ContourPlot") { it("it has the right bounds") { val plot = ContourPlot(Seq(Point(1, 2), Point(3, 4)), boundBuffer = Some(0.0)) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/FacetsSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/FacetsSpec.scala index d579a660..deee8504 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/FacetsSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/FacetsSpec.scala @@ -38,8 +38,6 @@ import com.cibo.evilplot.plot.components.{FacetedPlotComponent, Position} class FacetsSpec extends FunSpec with Matchers { - implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default - describe("Facets") { it("is the correct size with one facet") { val inner = ScatterPlot(Seq(Point(1, 1), Point(2, 2))) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/HeatmapSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/HeatmapSpec.scala index 90131be3..c961d5c1 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/HeatmapSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/HeatmapSpec.scala @@ -36,8 +36,6 @@ import org.scalatest.{FunSpec, Matchers} class HeatmapSpec extends FunSpec with Matchers { - implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default - describe("Heatmap") { it("has the right bounds") { val plot = Heatmap(Seq(Seq(1), Seq(2))) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/HistogramSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/HistogramSpec.scala index 9ab457e4..cadf5555 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/HistogramSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/HistogramSpec.scala @@ -36,8 +36,6 @@ import org.scalatest.{FunSpec, Matchers} class HistogramSpec extends FunSpec with Matchers { - implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default - describe("Histogram") { val plot = Histogram(Seq(1.0, 1, 1, 2, 3, 4, 4, 5), boundBuffer = Some(0)) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/MixedBoundsOverlaySpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/MixedBoundsOverlaySpec.scala index ab07b96b..ace4bf75 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/MixedBoundsOverlaySpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/MixedBoundsOverlaySpec.scala @@ -38,8 +38,6 @@ import org.scalatest.{FunSpec, Matchers} class MixedBoundsOverlaySpec extends FunSpec with Matchers { - implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default - describe("MixedBoundsOverlay") { it("it has the bounds that are set for it") { diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/OverlaySpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/OverlaySpec.scala index a253b095..c2d3da91 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/OverlaySpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/OverlaySpec.scala @@ -38,8 +38,6 @@ import org.scalatest.{FunSpec, Matchers} class OverlaySpec extends FunSpec with Matchers { - implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default - describe("Overlay") { it("it gets the bounds right for a single plot") { val inner = ScatterPlot(Seq(Point(1.0, 10.0), Point(2.0, 20.0))) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/PlotSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/PlotSpec.scala index 4543ce1d..2a277b99 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/PlotSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/PlotSpec.scala @@ -39,8 +39,6 @@ import org.scalatest.{FunSpec, Matchers} class PlotSpec extends FunSpec with Matchers { - implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default - DOMInitializer.init() // Renderer to do nothing. diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/ScatterPlotSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/ScatterPlotSpec.scala index 9257f8d3..6ee1866b 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/ScatterPlotSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/ScatterPlotSpec.scala @@ -35,8 +35,6 @@ import org.scalatest.{FunSpec, Matchers} class ScatterPlotSpec extends FunSpec with Matchers { - implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default - describe("ScatterPlot") { it("sets adheres to bound buffers") { val data = Seq(Point(-1, 10), Point(20, -5)) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/XyPlotSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/XyPlotSpec.scala index 5279c3ec..7a24b351 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/XyPlotSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/XyPlotSpec.scala @@ -36,8 +36,6 @@ import org.scalatest.{FunSpec, Matchers} class XyPlotSpec extends FunSpec with Matchers { - implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default - describe("XyPlot") { it("has the right bounds") { val plot = diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/components/AxesSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/components/AxesSpec.scala index aaa46c2a..6987a3a0 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/components/AxesSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/components/AxesSpec.scala @@ -36,8 +36,6 @@ import org.scalatest.{FunSpec, Matchers} class AxesSpec extends FunSpec with Matchers { - implicit val theme = com.cibo.evilplot.plot.aesthetics.Theme.default - describe("discrete X") { it("should set the default bounds") { val plot = BarChart(Seq(3.0, 4)).xAxis() diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/components/ComponentGroupSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/components/ComponentGroupSpec.scala index 3695e25e..ce8f20bb 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/components/ComponentGroupSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/components/ComponentGroupSpec.scala @@ -37,8 +37,6 @@ import org.scalatest.{FunSpec, Matchers} class ComponentGroupSpec extends FunSpec with Matchers{ - implicit val theme = Theme.default - abstract class MockComponent(val position: Position) extends FacetedPlotComponent abstract class LeftComponent extends MockComponent(Position.Left) abstract class TopComponent extends MockComponent(Position.Top) From 879bb487be01a007ea32a7e73215441fce7407dd Mon Sep 17 00:00:00 2001 From: "Aaron J. Radke" Date: Mon, 1 Oct 2018 16:07:22 -0500 Subject: [PATCH 6/8] use the train name ExplicitImplicits to capture the development use --- .../com/cibo/evilplot/plot/BarChart.scala | 6 +-- .../com/cibo/evilplot/plot/BoxPlot.scala | 6 +-- .../evilplot/plot/ExplicitImplicits.scala | 37 ++++++++++++++ .../com/cibo/evilplot/plot/FunctionPlot.scala | 4 +- .../com/cibo/evilplot/plot/Heatmap.scala | 4 +- .../com/cibo/evilplot/plot/Histogram.scala | 4 +- .../cibo/evilplot/plot/LegendContext.scala | 4 +- .../com/cibo/evilplot/plot/LinePlot.scala | 4 +- .../com/cibo/evilplot/plot/Overlay.scala | 4 +- .../com/cibo/evilplot/plot/PieChart.scala | 4 +- .../scala/com/cibo/evilplot/plot/Plot.scala | 4 +- .../com/cibo/evilplot/plot/ScatterPlot.scala | 4 +- .../com/cibo/evilplot/plot/SurfacePlot.scala | 6 +-- .../scala/com/cibo/evilplot/plot/XyPlot.scala | 4 +- .../plot/aesthetics/DefaultTheme.scala | 4 -- .../evilplot/plot/components/Background.scala | 5 +- .../components/FacetedPlotComponent.scala | 5 +- .../cibo/evilplot/plot/components/Label.scala | 7 +-- .../evilplot/plot/components/Legend.scala | 5 +- .../plot/components/PlotComponent.scala | 2 +- .../evilplot/plot/components/PlotLine.scala | 5 +- .../evilplot/plot/renderers/BarRenderer.scala | 5 +- .../evilplot/plot/renderers/BoxRenderer.scala | 7 +-- .../plot/renderers/ComponentRenderer.scala | 5 +- .../plot/renderers/PathRenderer.scala | 7 +-- .../plot/renderers/PlotRenderer.scala | 5 +- .../plot/renderers/PointRenderer.scala | 5 +- .../plot/renderers/SurfaceRenderer.scala | 5 +- .../evilplot/plot/ExplicitImplicitsSpec.scala | 50 +++++++++++++++++++ 29 files changed, 156 insertions(+), 61 deletions(-) create mode 100644 shared/src/main/scala/com/cibo/evilplot/plot/ExplicitImplicits.scala create mode 100644 shared/src/test/scala/com/cibo/evilplot/plot/ExplicitImplicitsSpec.scala diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/BarChart.scala b/shared/src/main/scala/com/cibo/evilplot/plot/BarChart.scala index b7ef4f4f..378150cc 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/BarChart.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/BarChart.scala @@ -33,7 +33,7 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.colors.{Color, DefaultColors} import com.cibo.evilplot.geometry.{Drawable, EmptyDrawable, Extent, Rect, Style, Text} import com.cibo.evilplot.numeric.Bounds -import com.cibo.evilplot.plot.aesthetics.{Theme,DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.renderers.{BarRenderer, PlotRenderer} /** Data for a bar in a bar chart. @@ -61,13 +61,13 @@ final case class Bar( ) } -object Bar extends DefaultTheme{ +object Bar extends ExplicitImplicits{ def apply(value: Double)(implicit theme: Theme): Bar = Bar(Seq(value), 0, theme.colors.stream) def apply(value: Double, cluster: Int)(implicit theme: Theme): Bar = Bar(Seq(value), cluster = cluster, theme.colors.stream) } -object BarChart extends DefaultTheme{ +object BarChart extends ExplicitImplicits{ val defaultBoundBuffer: Double = 0.1 diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/BoxPlot.scala b/shared/src/main/scala/com/cibo/evilplot/plot/BoxPlot.scala index 62c12c08..d02131dc 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/BoxPlot.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/BoxPlot.scala @@ -32,7 +32,7 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.geometry._ import com.cibo.evilplot.numeric.{Bounds, BoxPlotSummaryStatistics} -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.renderers.BoxRenderer.BoxRendererContext import com.cibo.evilplot.plot.renderers.{BoxRenderer, PlotRenderer, PointRenderer} @@ -42,7 +42,7 @@ final case class BoxPlotRenderer( pointRenderer: PointRenderer, spacing: Double, clusterSpacing: Option[Double] -) extends PlotRenderer with DefaultTheme{ +) extends PlotRenderer with ExplicitImplicits{ private val isClustered = clusterSpacing.isDefined private val clusterPadding = clusterSpacing.getOrElse(spacing) @@ -106,7 +106,7 @@ final case class BoxPlotRenderer( override def legendContext: LegendContext = boxRenderer.legendContext } -object BoxPlot extends DefaultTheme{ +object BoxPlot extends ExplicitImplicits{ /** Create box plots for a sequence of distributions. * diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/ExplicitImplicits.scala b/shared/src/main/scala/com/cibo/evilplot/plot/ExplicitImplicits.scala new file mode 100644 index 00000000..97fc372b --- /dev/null +++ b/shared/src/main/scala/com/cibo/evilplot/plot/ExplicitImplicits.scala @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018, CiBO Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.cibo.evilplot.plot + +import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} + +trait ExplicitImplicits{ + implicit val defaultTheme: Theme = DefaultTheme.defaultTheme +} diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/FunctionPlot.scala b/shared/src/main/scala/com/cibo/evilplot/plot/FunctionPlot.scala index d80eefda..c26bc3eb 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/FunctionPlot.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/FunctionPlot.scala @@ -33,11 +33,11 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.colors.Color import com.cibo.evilplot.geometry.Drawable import com.cibo.evilplot.numeric.Bounds -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.components.FunctionPlotLine import com.cibo.evilplot.plot.renderers.{PathRenderer, PointRenderer} -object FunctionPlot extends DefaultTheme{ +object FunctionPlot extends ExplicitImplicits{ val defaultBounds: Bounds = Bounds(0, 1) val defaultNumPoints: Int = 800 diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/Heatmap.scala b/shared/src/main/scala/com/cibo/evilplot/plot/Heatmap.scala index 4399c689..de617e94 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/Heatmap.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/Heatmap.scala @@ -33,10 +33,10 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.colors.{Color, Coloring, ScaledColorBar} import com.cibo.evilplot.geometry.{Drawable, Extent, Rect} import com.cibo.evilplot.numeric.Bounds -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.renderers.PlotRenderer -object Heatmap extends DefaultTheme{ +object Heatmap extends ExplicitImplicits{ val defaultColorCount: Int = 10 diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/Histogram.scala b/shared/src/main/scala/com/cibo/evilplot/plot/Histogram.scala index f2830d95..6fa845ec 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/Histogram.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/Histogram.scala @@ -32,10 +32,10 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.geometry.{Drawable, EmptyDrawable, Extent} import com.cibo.evilplot.numeric.{Bounds, Point} -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.renderers.{BarRenderer, PlotRenderer} -object Histogram extends DefaultTheme{ +object Histogram extends ExplicitImplicits{ val defaultBinCount: Int = 20 diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/LegendContext.scala b/shared/src/main/scala/com/cibo/evilplot/plot/LegendContext.scala index 9e54c74b..c791baad 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/LegendContext.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/LegendContext.scala @@ -32,7 +32,7 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.colors.ScaledColorBar import com.cibo.evilplot.geometry.{Drawable, Rect, Style, Text} -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme sealed trait LegendStyle @@ -68,7 +68,7 @@ case class LegendContext( } } -object LegendContext extends DefaultTheme{ +object LegendContext extends ExplicitImplicits{ def empty: LegendContext = LegendContext() def single( diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/LinePlot.scala b/shared/src/main/scala/com/cibo/evilplot/plot/LinePlot.scala index 69b02049..f904e506 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/LinePlot.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/LinePlot.scala @@ -33,10 +33,10 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.colors.Color import com.cibo.evilplot.geometry.Drawable import com.cibo.evilplot.numeric.Point -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.renderers.{PathRenderer, PointRenderer} -object LinePlot extends DefaultTheme{ +object LinePlot extends ExplicitImplicits{ /** Create a line plot from some data. Convenience method on top of XyPlot * diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/Overlay.scala b/shared/src/main/scala/com/cibo/evilplot/plot/Overlay.scala index 05b4bba7..751e8a8d 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/Overlay.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/Overlay.scala @@ -32,10 +32,10 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.geometry.{Drawable, Extent} import com.cibo.evilplot.numeric.Bounds -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.renderers.PlotRenderer -object Overlay extends DefaultTheme{ +object Overlay extends ExplicitImplicits{ // Update subplots to have the specified bounds (if not already fixed). private def updateSubplotBounds( diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/PieChart.scala b/shared/src/main/scala/com/cibo/evilplot/plot/PieChart.scala index 0c73c3a7..354fa958 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/PieChart.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/PieChart.scala @@ -33,10 +33,10 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.colors.{Color, HTMLNamedColors} import com.cibo.evilplot.geometry.{Drawable, Extent, Rect, Text, Wedge} import com.cibo.evilplot.numeric.Bounds -import com.cibo.evilplot.plot.aesthetics.{Theme,DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.renderers.PlotRenderer -object PieChart extends DefaultTheme{ +object PieChart extends ExplicitImplicits{ case class PieChartRenderer( data: Seq[(Drawable, Double)], diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/Plot.scala b/shared/src/main/scala/com/cibo/evilplot/plot/Plot.scala index 935c674b..df821593 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/Plot.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/Plot.scala @@ -32,7 +32,7 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.geometry._ import com.cibo.evilplot.numeric.{Bounds, Point} -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.components.{FacetedPlotComponent, Position} import com.cibo.evilplot.plot.renderers.{ComponentRenderer, PlotRenderer} @@ -57,7 +57,7 @@ final case class Plot( xfixed: Boolean = false, yfixed: Boolean = false, components: Seq[FacetedPlotComponent] = Seq.empty -) extends DefaultTheme{ +) extends ExplicitImplicits{ private[plot] def inBounds(point: Point): Boolean = xbounds.isInBounds(point.x) && ybounds.isInBounds(point.y) diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/ScatterPlot.scala b/shared/src/main/scala/com/cibo/evilplot/plot/ScatterPlot.scala index 84bf1cc7..a5068857 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/ScatterPlot.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/ScatterPlot.scala @@ -33,10 +33,10 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.colors.Color import com.cibo.evilplot.geometry.{Drawable, Style, Text} import com.cibo.evilplot.numeric.Point -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.renderers.{PathRenderer, PointRenderer} -object ScatterPlot extends DefaultTheme{ +object ScatterPlot extends ExplicitImplicits{ /** Create a scatter plot from some data. * @param data The points to plot. diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/SurfacePlot.scala b/shared/src/main/scala/com/cibo/evilplot/plot/SurfacePlot.scala index 883caf87..028b7e94 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/SurfacePlot.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/SurfacePlot.scala @@ -32,11 +32,11 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.geometry.{Drawable, Extent} import com.cibo.evilplot.numeric._ -import com.cibo.evilplot.plot.aesthetics.{Theme,DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.renderers.SurfaceRenderer.SurfaceRenderContext import com.cibo.evilplot.plot.renderers.{PlotRenderer, SurfaceRenderer} -object SurfacePlot extends DefaultTheme{ +object SurfacePlot extends ExplicitImplicits{ private[plot] case class SurfacePlotRenderer( data: Seq[Seq[Seq[Point3]]], surfaceRenderer: SurfaceRenderer @@ -72,7 +72,7 @@ object SurfacePlot extends DefaultTheme{ } } -object ContourPlot extends DefaultTheme{ +object ContourPlot extends ExplicitImplicits{ import SurfacePlot._ val defaultGridDimensions: (Int, Int) = (100, 100) diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/XyPlot.scala b/shared/src/main/scala/com/cibo/evilplot/plot/XyPlot.scala index 8591e356..44640026 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/XyPlot.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/XyPlot.scala @@ -32,10 +32,10 @@ package com.cibo.evilplot.plot import com.cibo.evilplot.geometry._ import com.cibo.evilplot.numeric.{Bounds, Point} -import com.cibo.evilplot.plot.aesthetics.{Theme,DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.renderers.{PathRenderer, PlotRenderer, PointRenderer} -object XyPlot extends DefaultTheme{ +object XyPlot extends ExplicitImplicits{ final case class XyPlotRenderer( data: Seq[Point], diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/DefaultTheme.scala b/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/DefaultTheme.scala index 072d13cc..5b9efaa5 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/DefaultTheme.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/aesthetics/DefaultTheme.scala @@ -109,8 +109,4 @@ object DefaultTheme{ ) implicit val defaultTheme: Theme = this.DefaultTheme - -} -trait DefaultTheme{ - implicit val defaultTheme: Theme = DefaultTheme.defaultTheme } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/components/Background.scala b/shared/src/main/scala/com/cibo/evilplot/plot/components/Background.scala index b3534255..51d428d5 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/components/Background.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/components/Background.scala @@ -33,7 +33,8 @@ package com.cibo.evilplot.plot.components import com.cibo.evilplot.colors.Color import com.cibo.evilplot.geometry.{Drawable, Extent, Line, Rect, StrokeStyle} import com.cibo.evilplot.plot.Plot -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.ExplicitImplicits final case class Background( f: (Plot, Extent) => Drawable @@ -43,7 +44,7 @@ final case class Background( def render(plot: Plot, extent: Extent)(implicit theme: Theme): Drawable = f(plot, extent) } -trait BackgroundImplicits extends DefaultTheme{ +trait BackgroundImplicits extends ExplicitImplicits{ protected val plot: Plot /** Set the background (this will replace any existing background). diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/components/FacetedPlotComponent.scala b/shared/src/main/scala/com/cibo/evilplot/plot/components/FacetedPlotComponent.scala index 60640119..bc188940 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/components/FacetedPlotComponent.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/components/FacetedPlotComponent.scala @@ -32,10 +32,11 @@ package com.cibo.evilplot.plot.components import com.cibo.evilplot.geometry.{Drawable, Extent} import com.cibo.evilplot.plot.Plot -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.ExplicitImplicits /** A component that is aligned with the data of a plot. */ -trait FacetedPlotComponent extends DefaultTheme{ +trait FacetedPlotComponent extends ExplicitImplicits{ /** The position of this component. */ val position: Position diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/components/Label.scala b/shared/src/main/scala/com/cibo/evilplot/plot/components/Label.scala index 1addf21a..e0ebc2cb 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/components/Label.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/components/Label.scala @@ -32,8 +32,9 @@ package com.cibo.evilplot.plot.components import com.cibo.evilplot.colors.{Color, HTMLNamedColors} import com.cibo.evilplot.geometry.{Drawable, Extent, StrokeStyle, Style, Text} -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.Plot +import com.cibo.evilplot.plot.ExplicitImplicits /** A plot label. * @param position The position of this component. @@ -44,7 +45,7 @@ case class Label( position: Position, f: Extent => Drawable, minExtent: Extent -) extends PlotComponent with DefaultTheme{ +) extends PlotComponent with ExplicitImplicits{ override def size(plot: Plot): Extent = minExtent def render(plot: Plot, extent: Extent)(implicit theme: Theme): Drawable = position match { case Position.Top => f(extent).center(extent.width) @@ -59,7 +60,7 @@ object Label { def apply(position: Position, d: Drawable): Label = Label(position, _ => d, d.extent) } -trait LabelImplicits extends DefaultTheme{ +trait LabelImplicits extends ExplicitImplicits{ protected val plot: Plot def title(d: Drawable): Plot = plot :+ Label(Position.Top, d) diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/components/Legend.scala b/shared/src/main/scala/com/cibo/evilplot/plot/components/Legend.scala index b35b79ce..936440a6 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/components/Legend.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/components/Legend.scala @@ -31,9 +31,10 @@ package com.cibo.evilplot.plot.components import com.cibo.evilplot.geometry._ -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.renderers.LegendRenderer import com.cibo.evilplot.plot.{LegendContext, Plot} +import com.cibo.evilplot.plot.ExplicitImplicits case class Legend( position: Position, @@ -55,7 +56,7 @@ case class Legend( } } -trait LegendImplicits extends DefaultTheme{ +trait LegendImplicits extends ExplicitImplicits{ protected val plot: Plot private def setLegend( diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotComponent.scala b/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotComponent.scala index 8ba0c09f..5ae38992 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotComponent.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotComponent.scala @@ -32,7 +32,7 @@ package com.cibo.evilplot.plot.components import com.cibo.evilplot.geometry._ import com.cibo.evilplot.plot.Plot -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme /** A component that is aligned with the data of a plot (used when all facets are treated identically). */ trait PlotComponent extends FacetedPlotComponent{ diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotLine.scala b/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotLine.scala index b0da4932..ad4207d4 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotLine.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/components/PlotLine.scala @@ -34,7 +34,8 @@ import com.cibo.evilplot.colors.Color import com.cibo.evilplot.geometry.{Drawable, EmptyDrawable, Extent, Line, LineStyle, Path} import com.cibo.evilplot.numeric.{Bounds, Point} import com.cibo.evilplot.plot.Plot -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.ExplicitImplicits import scala.annotation.tailrec @@ -167,7 +168,7 @@ object FunctionPlotLine { } } -trait PlotLineImplicits extends DefaultTheme{ +trait PlotLineImplicits extends ExplicitImplicits{ protected val plot: Plot val defaultThickness: Double = 2.0 diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BarRenderer.scala b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BarRenderer.scala index d0f54677..aab03334 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BarRenderer.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BarRenderer.scala @@ -32,15 +32,16 @@ package com.cibo.evilplot.plot.renderers import com.cibo.evilplot.colors.Color import com.cibo.evilplot.geometry._ -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.{Bar, LegendContext, Plot} +import com.cibo.evilplot.plot.ExplicitImplicits trait BarRenderer extends PlotElementRenderer[Bar] { def render(plot: Plot, extent: Extent, category: Bar): Drawable def legendContext: Option[LegendContext] = None } -object BarRenderer extends DefaultTheme{ +object BarRenderer extends ExplicitImplicits{ /** Default bar renderer. */ def default( diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BoxRenderer.scala b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BoxRenderer.scala index 77233775..d3c915a9 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BoxRenderer.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/BoxRenderer.scala @@ -44,11 +44,12 @@ import com.cibo.evilplot.geometry.{ Translate } import com.cibo.evilplot.numeric.BoxPlotSummaryStatistics -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.renderers.BoxRenderer.BoxRendererContext import com.cibo.evilplot.plot.{LegendContext, Plot} +import com.cibo.evilplot.plot.ExplicitImplicits -trait BoxRenderer extends PlotElementRenderer[BoxRendererContext] with DefaultTheme{ br => +trait BoxRenderer extends PlotElementRenderer[BoxRendererContext] with ExplicitImplicits{ br => def render(plot: Plot, extent: Extent, summary: BoxRendererContext): Drawable def legendContext: LegendContext = LegendContext.empty @@ -76,7 +77,7 @@ trait BoxRenderer extends PlotElementRenderer[BoxRendererContext] with DefaultTh } } -object BoxRenderer extends DefaultTheme { +object BoxRenderer extends ExplicitImplicits { final case class BoxRendererContext( summaryStatistics: BoxPlotSummaryStatistics, index: Int, diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/ComponentRenderer.scala b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/ComponentRenderer.scala index 1513aa9b..9737cff3 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/ComponentRenderer.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/ComponentRenderer.scala @@ -33,7 +33,8 @@ package com.cibo.evilplot.plot.renderers import com.cibo.evilplot.geometry.{Drawable, EmptyDrawable, Extent} import com.cibo.evilplot.numeric.Point import com.cibo.evilplot.plot.Plot -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme +import com.cibo.evilplot.plot.ExplicitImplicits /** Renderer for non-plot area components of a plot (labels, etc.). */ trait ComponentRenderer { @@ -48,7 +49,7 @@ trait ComponentRenderer { def plotOffset(plot: Plot): Point } -object ComponentRenderer extends DefaultTheme{ +object ComponentRenderer extends ExplicitImplicits{ case class Default() extends ComponentRenderer { diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PathRenderer.scala b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PathRenderer.scala index 2c02a761..77af103b 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PathRenderer.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PathRenderer.scala @@ -46,13 +46,14 @@ import com.cibo.evilplot.geometry.{ import com.cibo.evilplot.numeric.Point import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.{LegendContext, Plot} +import com.cibo.evilplot.plot.ExplicitImplicits trait PathRenderer extends PlotElementRenderer[Seq[Point]] { def legendContext: LegendContext = LegendContext.empty def render(plot: Plot, extent: Extent, path: Seq[Point]): Drawable } -object PathRenderer { +object PathRenderer extends ExplicitImplicits{ private[renderers] val baseLegendStrokeLength: Double = 8.0 /** The default path renderer. @@ -96,7 +97,7 @@ object PathRenderer { * @param color the color of this path. */ @deprecated("Use the overload taking a strokeWidth, color, label and lineStyle", "2 April 2018") - def closed(color: Color)(implicit theme: Theme): PathRenderer = closed(color = Some(color)) + def closed(color: Color)(implicit theme: Theme): PathRenderer = closed(color = Some(color))(theme) /** Path renderer for closed paths. The first point is connected to the last point. * @param strokeWidth the stroke width @@ -111,7 +112,7 @@ object PathRenderer { )(implicit theme: Theme): PathRenderer = new PathRenderer { def render(plot: Plot, extent: Extent, path: Seq[Point]): Drawable = { path.headOption.fold(EmptyDrawable(): Drawable) { head => - default(strokeWidth, color, label, lineStyle).render(plot, extent, path :+ head) + default(strokeWidth, color, label, lineStyle)(theme).render(plot, extent, path :+ head) } } } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PlotRenderer.scala b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PlotRenderer.scala index 8b3bc3d4..6a2a076c 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PlotRenderer.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PlotRenderer.scala @@ -31,11 +31,12 @@ package com.cibo.evilplot.plot.renderers import com.cibo.evilplot.geometry.{Drawable, Extent} -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.{LegendContext, Plot} +import com.cibo.evilplot.plot.ExplicitImplicits /** Renderer for the plot area. */ -trait PlotRenderer extends DefaultTheme{ +trait PlotRenderer extends ExplicitImplicits{ def legendContext: LegendContext = LegendContext.empty def render(plot: Plot, plotExtent: Extent)(implicit theme: Theme): Drawable } diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PointRenderer.scala b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PointRenderer.scala index 661e642a..916b2aab 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PointRenderer.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/PointRenderer.scala @@ -32,15 +32,16 @@ package com.cibo.evilplot.plot.renderers import com.cibo.evilplot.colors._ import com.cibo.evilplot.geometry.{Disc, Drawable, EmptyDrawable, Extent, Style, Text} -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.{LegendContext, LegendStyle, Plot} +import com.cibo.evilplot.plot.ExplicitImplicits trait PointRenderer extends PlotElementRenderer[Int] { def legendContext: LegendContext = LegendContext() def render(plot: Plot, extent: Extent, index: Int): Drawable } -object PointRenderer extends DefaultTheme{ +object PointRenderer extends ExplicitImplicits{ val defaultColorCount: Int = 10 diff --git a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/SurfaceRenderer.scala b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/SurfaceRenderer.scala index e6a6776e..4433d6dd 100644 --- a/shared/src/main/scala/com/cibo/evilplot/plot/renderers/SurfaceRenderer.scala +++ b/shared/src/main/scala/com/cibo/evilplot/plot/renderers/SurfaceRenderer.scala @@ -33,16 +33,17 @@ package com.cibo.evilplot.plot.renderers import com.cibo.evilplot.colors._ import com.cibo.evilplot.geometry.{Drawable, EmptyDrawable, Extent, LineStyle, Path} import com.cibo.evilplot.numeric.{Bounds, Point, Point3} -import com.cibo.evilplot.plot.aesthetics.{Theme, DefaultTheme} +import com.cibo.evilplot.plot.aesthetics.Theme import com.cibo.evilplot.plot.renderers.SurfaceRenderer.SurfaceRenderContext import com.cibo.evilplot.plot.{LegendContext, Plot} +import com.cibo.evilplot.plot.ExplicitImplicits trait SurfaceRenderer extends PlotElementRenderer[SurfaceRenderContext] { def legendContext(levels: Seq[Double]): LegendContext = LegendContext.empty def render(plot: Plot, extent: Extent, surface: SurfaceRenderContext): Drawable } -object SurfaceRenderer extends DefaultTheme{ +object SurfaceRenderer extends ExplicitImplicits{ /** The element renderer context for surface renderers. */ case class SurfaceRenderContext( diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/ExplicitImplicitsSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/ExplicitImplicitsSpec.scala new file mode 100644 index 00000000..b785b9dc --- /dev/null +++ b/shared/src/test/scala/com/cibo/evilplot/plot/ExplicitImplicitsSpec.scala @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018, CiBO Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.cibo.evilplot.plot + +import org.scalatest.{FunSpec, Matchers} + +class ExplcitImplicitsSpec extends FunSpec with Matchers { + describe("ExplicitImplicit") { + it("allows default implicit themes"){ + val hist = Histogram(Seq(1, 2, 2)) + hist.render().extent shouldBe Plot.defaultExtent + } + it("still provides a mechansim to catch accidental default themes at compile time"){ + assertDoesNotCompile(""" + import com.cibo.evilplot.plot.aesthetics.Theme + object CustomHistogram extends ExplicitImplicits{ + def hist(xs:Seq[Double])(implicit theme:Theme) = Histogram(xs).render()(theme) + } + """) + } + } +} From c0e3cdb492fba8ab87d50ac0e8c80fdcc14379a4 Mon Sep 17 00:00:00 2001 From: "Aaron J. Radke" Date: Mon, 1 Oct 2018 16:53:01 -0500 Subject: [PATCH 7/8] make ExplicitImplicitsSpec require a type error for all missing implicits --- .../evilplot/plot/ExplicitImplicitsSpec.scala | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/shared/src/test/scala/com/cibo/evilplot/plot/ExplicitImplicitsSpec.scala b/shared/src/test/scala/com/cibo/evilplot/plot/ExplicitImplicitsSpec.scala index b785b9dc..e34de83d 100644 --- a/shared/src/test/scala/com/cibo/evilplot/plot/ExplicitImplicitsSpec.scala +++ b/shared/src/test/scala/com/cibo/evilplot/plot/ExplicitImplicitsSpec.scala @@ -38,11 +38,39 @@ class ExplcitImplicitsSpec extends FunSpec with Matchers { val hist = Histogram(Seq(1, 2, 2)) hist.render().extent shouldBe Plot.defaultExtent } - it("still provides a mechansim to catch accidental default themes at compile time"){ - assertDoesNotCompile(""" + + it("Provides a mechansim to *require* explicit themes at compile time"){ + import com.cibo.evilplot.plot.aesthetics.Theme + object CustomHistogram extends ExplicitImplicits{ + def hist(xs:Seq[Double])(implicit theme:Theme) = Histogram(xs)(theme).render()(theme) + } + CustomHistogram.hist( Seq(1,2,2) ).extent shouldBe Plot.defaultExtent + } + + it("still provides a mechansim to catch accidental default themes at compile time with a type Error"){ + + assertTypeError(""" + import com.cibo.evilplot.plot.aesthetics.Theme + object CustomHistogram extends ExplicitImplicits{ + def hist(xs:Seq[Double])(implicit theme:Theme) = Histogram(xs).render() // both implicit + } + """) + assertTypeError(""" + import com.cibo.evilplot.plot.aesthetics.Theme + object CustomHistogram extends ExplicitImplicits{ + def hist(xs:Seq[Double])(implicit theme:Theme) = Histogram(xs)(theme).render() // first explicit + } + """) + assertTypeError(""" + import com.cibo.evilplot.plot.aesthetics.Theme + object CustomHistogram extends ExplicitImplicits{ + def hist(xs:Seq[Double])(implicit theme:Theme) = Histogram(xs)().render()(theme) //second explicit + } + """) + assertCompiles(""" import com.cibo.evilplot.plot.aesthetics.Theme object CustomHistogram extends ExplicitImplicits{ - def hist(xs:Seq[Double])(implicit theme:Theme) = Histogram(xs).render()(theme) + def hist(xs:Seq[Double])(implicit theme:Theme) = Histogram(xs)(theme).render()(theme) //both explicit } """) } From 7d2bbdbafbbeb59c06b73f5ca4c09f8fe36ecc6f Mon Sep 17 00:00:00 2001 From: "Aaron J. Radke" Date: Mon, 1 Oct 2018 17:08:57 -0500 Subject: [PATCH 8/8] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61d4f3e1..e8069d0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ## [0.5.x] - 2018-??-?? - added a low priority default Theme so this cumbersome import is only necessary when desired +- added a ExplicitImplicit trait to help library authors catch unintentional implicit theme's ## [0.5.0] - 2018-09-21 ### Added