Skip to content

Instantly share code, notes, and snippets.

@usametov
Created December 10, 2020 20:18
Show Gist options
  • Save usametov/6fbf519e25affcfcf4610dcb03b1a77c to your computer and use it in GitHub Desktop.
Save usametov/6fbf519e25affcfcf4610dcb03b1a77c to your computer and use it in GitHub Desktop.
Tutorial showcasing the usage of the ClojisR library to visualize data in Clojure

Data Visualization in Clojure using ggplot2 from R

We'll be using the ClojisR library to visualize data in Clojure. This library is a Clojure-R interop and it allows us to call R functions on R objects in Clojure.

Usage requirements

Before starting ensure that you have the following installed on your computer:

  • JDK 1.8 or later
  • Clojure 1.9.0 or later
  • R
  • The Rserve R package (install.packages("Rserve",,"http://rforge.net")) Tested with Rserve version 1.8.6. Earlier versions are known to have a bug.
  • ClojisR library: Clojars Project
  • Tidyverse: A collection of open source R packages. It contains the ggplot2 package, which we'll be using during this tutorial.

Setup

First, we require the necessary namespaces.

(require
   '[clojisr.v1.r :as r :refer
     [r eval-r->java r->java java->r
      java->clj java->naive-clj
      clj->java r->clj clj->r ->code r+
      colon]]
   '[clojisr.v1.require :refer
     [require-r]]
   '[clojisr.v1.robject :as robject]
   '[clojisr.v1.session :as session]
   '[clojisr.v1.rserve :as rserve]
   '[tech.ml.dataset :as dataset]
   '[clojisr.v1.applications.plotting :refer
     [plot->svg plot->file
      plot->buffered-image]])

Then we make sure that we're using the Rserve backend (in case we were using Renjin instead earlier), and that there are no R sessions currently running. This is typically not needed if you just started working. Here, we do it just in case.

(rserve/set-as-default!)
(r/discard-all-sessions)

Finally, we use require-r to bring functions and data from R packages to Clojure.

(require-r '[ggplot2 :as gg])

Note:

The following tutorial contains translated code samples from the 'Data Visualization' chapter of R for Data Science book.

Basic Example

ggplot2 comes with a selection of built-in datasets which we'll be using to illustrate various visualisations.
Let's start with the mpg data frame which shows the fuel economy data from 1999 to 2008 for 38 popular models of cars. You can see a small portion of the dataset by typing gg/mpg in the REPL.

# A tibble: 234 x 11
   manufacturer model    displ  year   cyl trans   drv     cty   hwy fl    class
   <chr>        <chr>    <dbl> <int> <int> <chr>   <chr> <int> <int> <chr> <chr>
 1 audi         a4         1.8  1999     4 auto(l… f        18    29 p     comp…
 2 audi         a4         1.8  1999     4 manual… f        21    29 p     comp…
 3 audi         a4         2    2008     4 manual… f        20    31 p     comp…
 4 audi         a4         2    2008     4 auto(a… f        21    30 p     comp…
 5 audi         a4         2.8  1999     6 auto(l… f        16    26 p     comp…
 6 audi         a4         2.8  1999     6 manual… f        18    26 p     comp…
 7 audi         a4         3.1  2008     6 auto(a… f        18    27 p     comp…
 8 audi         a4 quat…   1.8  1999     4 manual… 4        18    26 p     comp…
 9 audi         a4 quat…   1.8  1999     4 auto(l… 4        16    25 p     comp…
10 audi         a4 quat…   2    2008     4 manual… 4        20    28 p     comp…
# … with 224 more rows

Let's go ahead and plot our first visualization. Assuming you have a results folder in you Clojure project folder, the following code will create a scatterplot with displ on the x-axis and hwy on the y-axis and store it as an image inside the results folder.

(plot->file "results/basic_scatterplot.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'displ
                     		      :y 'hwy))
            (gg/geom_point)))

Scatterplot of displ vs hwy

Graphing template

Let’s turn this code into a reusable template for making graphs with ggplot2 in Clojure. To make a graph, replace the bracketed sections in the code below with a file name, a dataset, a collection of mappings, or a geom function.

(plot->file "<DESTINATION_FILE>" 
	(r+ (gg/ggplot <DATA> (gg/aes <MAPPINGS>))
            (<GEOM_FUNCTION>)))

The rest of this tutorial will show you how to complete and extend this template to make different types of graphs.

Aesthetic mappings

(plot->file "results/color_aes_scatterplot.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'displ
	                       	      :y 'hwy
				      :color 'class))
            (gg/geom_point)))

Scatterplot of displ vs hwy with color aesthetic mapped to class variable

(plot->file "results/alpha_aes_scatterplot.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'displ
                       		      :y 'hwy
			              :alpha 'class))
            (gg/geom_point)))

Scatterplot of displ vs hwy with alpha aesthetic mapped to class variable

(plot->file "results/blue_scatterplot.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'displ
	                     	      :y 'hwy))
            (gg/geom_point :color "blue")))

Scatterplot of displ vs hwy with color aesthetic manually set to blue

Facets

(plot->file "results/facet_scatterplot.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'displ
		                      :y 'hwy))
            (gg/geom_point)
	    (gg/facet_wrap '(tilde . class) :nrow 2)))

Scatterplot of displ vs hwy with facets displaying the class

Geometric Objects

(plot->file "results/point_geom.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'displ
                     		      :y 'hwy))
            (gg/geom_point)))

Point geom of displ vs hwy

(plot->file "results/smooth_geom.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'displ
                     		      :y 'hwy))
            (gg/geom_smooth)))

Smooth geom of displ vs hwy

(plot->file "results/linetype_aes_smooth_geom.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'displ
	                       	      :y 'hwy
				      :linetype 'drv))
            (gg/geom_smooth)))

Smooth geom of displ vs hwy with linetype aesthetic mapped to drv variable

(plot->file "results/group_aes_smooth_geom.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'displ
	                     	      :y 'hwy
				      :group 'drv))
            (gg/geom_smooth)))

Smooth geom of displ vs hwy with group aesthetic mapped to drv variable

(plot->file "results/color_aes_smooth_geom.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'displ
	                     	      :y 'hwy
				      :color 'drv))
            (gg/geom_smooth)))

Smooth geom of displ vs hwy with color aesthetic mapped to drv variable

(plot->file "results/mult_geom_basic.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'displ
                       		      :y 'hwy))
	    (gg/geom_point)
            (gg/geom_smooth)))

Plot displaying multiple geoms (scatterplot and line geom)

(plot->file "results/mult_geom_with_aes.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'displ
                       		      :y 'hwy))
	    (gg/geom_point (gg/aes :color 'class))
            (gg/geom_smooth)))

Plot displaying multiple geoms (scatterplot and line geom) with aesthetic mapping in scatterplot

Statistical transformations

(plot->file "results/basic_bar_geom.jpg" 
	(r+ (gg/ggplot gg/diamonds (gg/aes :x 'cut))
	    (gg/geom_bar)))

Smooth geom of displ vs hwy with color aesthetic mapped to drv variable

(plot->file "results/stat_transform_bar_geom.jpg" 
	(r+ (gg/ggplot gg/diamonds (gg/aes :x 'cut :y 'depth))
	    (gg/stat_summary :fun.ymin "min" :fun.ymax "max" :fun.y "median")))

Smooth geom of displ vs hwy with color aesthetic mapped to drv variable

Position adjustments

(plot->file "results/color_aes_bar_geom.jpg" 
	(r+ (gg/ggplot gg/diamonds (gg/aes :x 'cut :color 'cut))
	    (gg/geom_bar)))

Smooth geom of displ vs hwy with color aesthetic mapped to drv variable

(plot->file "results/fill_aes_bar_geom.jpg" 
	(r+ (gg/ggplot gg/diamonds (gg/aes :x 'cut :fill 'cut))
	    (gg/geom_bar)))

Smooth geom of displ vs hwy with color aesthetic mapped to drv variable

(plot->file "results/fill_aes_for_clarity_bar_geom.jpg" 
	(r+ (gg/ggplot gg/diamonds (gg/aes :x 'cut :fill 'clarity))
	    (gg/geom_bar)))

Smooth geom of displ vs hwy with color aesthetic mapped to drv variable

(plot->file "results/identity_pos_clarity_bar_geom.jpg" 
	(r+ (gg/ggplot gg/diamonds (gg/aes :x 'cut :fill 'clarity))
	    (gg/geom_bar :alpha 1/5 :position "identity")))

Smooth geom of displ vs hwy with color aesthetic mapped to drv variable

(plot->file "results/identity_pos_no_fill_bar_geom.jpg" 
	(r+ (gg/ggplot gg/diamonds (gg/aes :x 'cut :color 'clarity))
	    (gg/geom_bar :fill "NA" :position "identity")))

Smooth geom of displ vs hwy with color aesthetic mapped to drv variable

(plot->file "results/fill_pos_bar_geom.jpg" 
	(r+ (gg/ggplot gg/diamonds (gg/aes :x 'cut :fill 'clarity))
	    (gg/geom_bar :position "fill")))

Smooth geom of displ vs hwy with color aesthetic mapped to drv variable

(plot->file "results/dodge_pos_bar_geom.jpg" 
	(r+ (gg/ggplot gg/diamonds (gg/aes :x 'cut :fill 'clarity))
	    (gg/geom_bar :position "dodge")))

Smooth geom of displ vs hwy with color aesthetic mapped to drv variable

(plot->file "results/jitter_pos_point_geom_1.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'displ :y 'hwy))
	    (gg/geom_point :position "jitter")))

OR

(plot->file "results/jitter_pos_point_geom_2.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'displ :y 'hwy))
	    (gg/geom_jitter)))

Smooth geom of displ vs hwy with color aesthetic mapped to drv variable

Coordinate systems

(plot->file "results/box_plot_basic.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'class :y 'hwy))
	    (gg/geom_boxplot)))

Smooth geom of displ vs hwy with color aesthetic mapped to drv variable

(plot->file "results/box_plot_switch_axes.jpg" 
	(r+ (gg/ggplot gg/mpg (gg/aes :x 'class :y 'hwy))
	    (gg/geom_boxplot)
	    (gg/coord_flip)))

Smooth geom of displ vs hwy with color aesthetic mapped to drv variable

(plot->file "results/coord_flip.jpg" 
	(r+ (gg/ggplot gg/diamonds (gg/aes :x 'cut :fill 'cut))
	    (gg/geom_bar :show.legend "FALSE" :width 1)
	    (gg/theme :aspect.ratio 1)
	    (gg/labs :x "NULL" :y "NULL")
	    (gg/coord_flip)))

Smooth geom of displ vs hwy with color aesthetic mapped to drv variable

(plot->file "results/coord_polar.jpg" 
	(r+ (gg/ggplot gg/diamonds (gg/aes :x 'cut :fill 'cut))
	    (gg/geom_bar :show.legend "FALSE" :width 1)
	    (gg/theme :aspect.ratio 1)
	    (gg/labs :x "NULL" :y "NULL")
	    (gg/coord_polar)))

Smooth geom of displ vs hwy with color aesthetic mapped to drv variable

FINAL TEMPLATE

Acknowledgements

  1. Code samples translated from R for Data Science, by Hadley Wickham and Garrett Grolemund. Published by O'Reilly Media, Inc. Copyright © 2017 Garrett Grolemund, Hadley Wickham. Used with permission.
  2. A special thanks to all the contributors of the ClojisR library for building this amazing project.
  3. The following articles were used as references while writing this tutorial:
    -- ClojisR intro
    -- A tutorial about generating R code from Clojure
    -- Titanic tutorial #0
    -- DataVis in Clojure using R
    -- ggplot2 reference
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment