Plotting Example with EvilPlot

In [ ]:
interp.repositories() ++= Seq(
  coursierapi.MavenRepository.of("https://dl.bintray.com/cibotech/public")
)
In [ ]:
import $ivy.`com.cibo::evilplot-repl:0.6.3`

def showPlot(plot: com.cibo.evilplot.geometry.Drawable) =
  Image.fromRenderedImage(plot.asBufferedImage, format=Image.PNG)

Our first plot

EvilPlot is all about building larger graphical capabilities out of smaller ones. What this means for you is that making simple plots is easy, and we don't have to spend a lot of time going over all the features just to get started. So let's make our first plot, a simple scatter plot with sequential x-values and random y-values. Then we'll open that plot up in a new window and take a look at it.

In [ ]:
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 =>
  Point(i.toDouble, scala.util.Random.nextDouble())
}

showPlot(ScatterPlot(data).render())

There's a version of this example which renders to an HTML canvas using ScalaJS here

To break it down:

  • EvilPlot uses an implicit theming system, which lets you control the appearance of plots wholesale. In this case, we're just using the built-in one, so we import it.
  • ScatterPlot returns a Plot object, which is a description of how data should be plotted (plot these points as little circles on the screen), with what components (like axes, a background etc.). In this case, we've used no components. All we get is points on the screen!
  • render() on Plot returns a Drawable object. Think of a Drawable as a fully specified description of a scene. render itself does not perform any side-effects, it simply constructs a scene given a plot and a size.
  • Finally, displayPlot is an additional utility the opens the plot in a new window. You might not use this inside an application, but it's useful for exploring in the REPL!

This plot is not very interesting, of course. We should probably add some axes, so we know the range of the data, and some labels, so our audience knows what we're talking about. That's easy as well:

In [ ]:
import com.cibo.evilplot.plot._
import com.cibo.evilplot.plot.aesthetics.DefaultTheme._
import com.cibo.evilplot.numeric.Point

val data = Seq.tabulate(100) { i =>
  Point(i.toDouble, scala.util.Random.nextDouble())
}

val plot = ScatterPlot(data)
  .xAxis()
  .yAxis()
  .frame()
  .xLabel("x")
  .yLabel("y")
  .render()

showPlot(plot)

Adding these things is simply a matter of calling an additional method on your plot that specifies exactly what type of component you want to add.