Plot Catalog
EvilPlot examples both simple and built-in as well as complex and custom are here. If you have one you’d like to share, please contribute it!
Bar Chart
import com.cibo.evilplot.colors.RGB
import com.cibo.evilplot.geometry.{Align, Drawable, Extent, Rect, Text}
import com.cibo.evilplot.plot._
import com.cibo.evilplot.plot.aesthetics.DefaultTheme.{DefaultFonts, DefaultTheme}
import com.cibo.evilplot.plot.renderers.BarRenderer
implicit val theme: DefaultTheme = DefaultTheme().copy(
fonts = DefaultFonts()
.copy(tickLabelSize = 14, legendLabelSize = 14, fontFace = "'Lato', sans-serif")
)
val percentChange = Seq[Double](-10, 5, 12, 68, -22)
val labels = Seq("one", "two", "three", "four", "five")
val labeledByColor = new BarRenderer {
val positive = RGB(241, 121, 6)
val negative = RGB(226, 56, 140)
def render(plot: Plot, extent: Extent, category: Bar): Drawable = {
val rect = Rect(extent)
val value = category.values.head
val color = if (value >= 0) positive else negative
Align.center(rect filled color, Text(s"$value%", size = 20)
.filled(theme.colors.label)
).group
}
}
BarChart
.custom(percentChange.map(Bar.apply), spacing = Some(20),
barRenderer = Some(labeledByColor)
)
.standard(xLabels = labels)
.hline(0)
.render()
Clustered Bar Chart
import com.cibo.evilplot.plot._
val data = Seq[Seq[Double]](
Seq(1, 2, 3),
Seq(4, 5, 6),
Seq(3, 4, 1),
Seq(2, 3, 4)
)
BarChart
.clustered(
data,
labels = Seq("one", "two", "three")
)
.title("Clustered Bar Chart Demo")
.xAxis(Seq("a", "b", "c", "d"))
.yAxis()
.frame()
.bottomLegend()
.render()
Stacked Bar Chart
import com.cibo.evilplot.plot._
val data = Seq[Seq[Double]](
Seq(1, 2, 3),
Seq(4, 5, 6),
Seq(3, 4, 1),
Seq(2, 3, 4)
)
BarChart
.stacked(
data,
labels = Seq("one", "two", "three")
)
.title("Stacked Bar Chart Demo")
.xAxis(Seq("a", "b", "c", "d"))
.yAxis()
.frame()
.bottomLegend()
.render()
Clustered Stacked Bar Chart
import com.cibo.evilplot.plot._
val data = Seq[Seq[Seq[Double]]](
Seq(Seq(1, 2, 3), Seq(4, 5, 6)),
Seq(Seq(3, 4, 1), Seq(2, 3, 4))
)
BarChart
.clusteredStacked(
data,
labels = Seq("one", "two", "three")
).title("Clustered Stacked Bar Chart Demo")
.standard(Seq("Category 1", "Category 2"))
.xLabel("Category")
.yLabel("Level")
.rightLegend()
.render()
Function Plot
import com.cibo.evilplot.colors.HTMLNamedColors._
import com.cibo.evilplot.numeric.Bounds
import com.cibo.evilplot.plot._
Overlay(
FunctionPlot.series(x => x * x, "y = x^2",
HTMLNamedColors.dodgerBlue, xbounds = Some(Bounds(-1, 1))),
FunctionPlot.series(x => math.pow(x, 3), "y = x^3",
HTMLNamedColors.crimson, xbounds = Some(Bounds(-1, 1))),
FunctionPlot.series(x => math.pow(x, 4), "y = x^4",
HTMLNamedColors.green, xbounds = Some(Bounds(-1, 1)))
).title("A bunch of polynomials.")
.overlayLegend()
.standard()
.render()
Box Plot
import com.cibo.evilplot.plot._
import scala.util.Random
val data = Seq.fill(10)(Seq.fill(Random.nextInt(30))(Random.nextDouble()))
BoxPlot(data)
.standard(xLabels = (1 to 10).map(_.toString))
.render()
Scatter Plot
import com.cibo.evilplot.numeric._
import com.cibo.evilplot.plot._
import com.cibo.evilplot.plot.renderers.PointRenderer
val points = Seq.fill(150) {
Point(Random.nextDouble(), Random.nextDouble())
} :+ Point(0.0, 0.0)
val years = Seq.fill(150)(Random.nextDouble()) :+ 1.0
ScatterPlot(
points,
pointRenderer = Some(PointRenderer.depthColor(years, None, None))
)
.standard()
.xLabel("x")
.yLabel("y")
.trend(1, 0)
.rightLegend()
.render()
Scatter Plot with Marginal Histograms
import com.cibo.evilplot.colors.RGB
import com.cibo.evilplot.geometry.Extent
import com.cibo.evilplot.geometry.LineStyle.DashDot
import com.cibo.evilplot.numeric.Point
import com.cibo.evilplot.plot._
import com.cibo.evilplot.plot.renderers.PointRenderer
val allYears = (2007 to 2013).map(_.toDouble).toVector
val data = Seq.fill(150)(Point(Random.nextDouble(), Random.nextDouble()))
val years = Seq.fill(150)(allYears(Random.nextInt(allYears.length)))
val xhist = Histogram(data.map(_.x), bins = 50)
val yhist = Histogram(data.map(_.y), bins = 40)
ScatterPlot(
data = data,
pointRenderer = Some(PointRenderer.colorByCategory(years))
).topPlot(xhist)
.rightPlot(yhist)
.standard()
.title("Measured vs Actual")
.xLabel("measured")
.yLabel("actual")
.trend(1, 0, color = RGB(45, 45, 45), lineStyle = LineStyle.DashDot)
.overlayLegend(x = 0.95, y = 0.8)
.render(Extent(600, 400))
Pie Chart
import com.cibo.evilplot.plot._
val data = Seq("one" -> 1.5, "two" -> 3.5, "three" -> 2.0)
PieChart(data).rightLegend().render()
Pairs Plot
A pairs plot can be built by combining ScatterPlot
and Histogram
plots with Facet
.
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")
val data = for (i <- 1 to 4) yield {
(labels(i - 1), Seq.fill(10) { Random.nextDouble() * 10 })
}
val plots = for ((xlabel, xdata) <- data) yield {
for ((ylabel, ydata) <- data) yield {
val points = (xdata, ydata).zipped.map { (a, b) => Point(a, b) }
if (ylabel == xlabel) {
Histogram(xdata, bins = 4)
} else {
ScatterPlot(points)
}
}
}
Facets(plots)
.standard()
.title("Pairs Plot with Histograms")
.topLabels(data.map { _._1 })
.rightLabels(data.map { _._1 })
.render()
Density Plot
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
def gaussianKernel(u: Double): Double = {
1 / math.sqrt(2 * math.Pi) * math.exp(-0.5d * u * u)
}
def densityEstimate(data: Seq[Double], bandwidth: Double)(
x: Double
): Double = {
val totalProbDensity = data.map { x_i =>
gaussianKernel((x - x_i) / bandwidth)
}.sum
totalProbDensity / (data.length * bandwidth)
}
val data = Seq.fill(150)(Random.nextDouble() * 30)
val colors = Color.getGradientSeq(3)
val bandwidths = Seq(5d, 2d, 0.5d)
Overlay(
colors.zip(bandwidths).map { case (c, b) =>
FunctionPlot(
densityEstimate(data, b),
Some(Bounds(0, 30)),
Some(500),
Some(PathRenderer.default(color = Some(c)))
)
}:_*
)
.standard()
.xbounds(0, 30)
.render()
Overlapping Histograms
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
val plotAreaSize: Extent = Extent(1000, 600)
val data = Seq.fill(150)(Random.nextDouble() * 22)
val data2 = Seq.fill(150)((Random.nextDouble() * 28) + 12)
Overlay(
Histogram(data,
barRenderer = Some(BarRenderer.default(Some(red.copy(opacity = 0.5))))),
Histogram(data2,
barRenderer = Some(BarRenderer.default(Some(green.copy(opacity = 0.5)))))
)
.standard()
.render(plotAreaSize)
Contour Plot
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) {
Point(Random.nextDouble() * 20, Random.nextDouble() * 20
}
ContourPlot(data)
.standard()
.xbounds(0, 20)
.ybounds(0, 20)
.render()