4  Comparing the data representations of ggplot plots

SciCloj logo
This is part of the Scicloj Clojure Data Tutorials.
(ns comparing
  (:require [clojisr.v1.r :as r :refer [r r$ r->clj]]
            [clojisr.v1.applications.plotting :as plotting]
            [scicloj.kindly.v4.kind :as kind]
            [clojure.walk :as walk]
            [tablecloth.api :as tc]
            [editscript.core :as editscript]
            [clojure.pprint :as pp]
            [clojure.string :as str]
            [representing]))

4.1 Exlploring a few plots

Let us explore and compare a few plots through their Clojure representations:

(defn h3 [title] (kind/hiccup [:h3 title]))
(defn h4 [title] (kind/hiccup [:h4 title]))
(defn ggplot-summary
  ([title r-code]
   (ggplot-summary r-code))
  ([title r-code prev-clj-to-compare]
   (let [plot (r r-code)
         clj (-> plot
                 representing/ggplot->clj
                 (dissoc :data))]
     {:title title
      :r-code r-code
      :image (plotting/plot->buffered-image plot)
      :clj clj
      :diff (when prev-clj-to-compare
              (-> prev-clj-to-compare
                  (editscript/diff clj)
                  pp/pprint
                  with-out-str
                  (str/replace #": " ":_ ")
                  read-string))})))
(defn view-summary [{:keys [title r-code image clj diff]}]
  (kind/fragment
   [(h3 title)
    (h4 "R code")
    (kind/md
     (format "\n```\n%s\n```\n"
             r-code))
    (h4 "plot")
    image
    (h4 "clj data")
    clj
    (when diff
      (kind/fragment
       [(h4 "clj diff with previous")
        diff]))]))
(->> [;;
      ["A scatterplot"
       "(ggplot(mpg, aes(cty, hwy))
         + geom_point())"]
      ;;
      ["A scatterplot with colours"
       "(ggplot(mpg, aes(cty, hwy, color=factor(cyl)))
         + geom_point())"]
      ;;
      ["A scatterplot with colours and smoothing"
       "(ggplot(mpg, aes(cty, hwy, color=factor(cyl)))
         + geom_point()
         + stat_smooth(method=\"lm\"))"]
      ;;
      ["A scatterplot with colours, smoothing, and facets"
       "(ggplot(mpg, aes(cty, hwy, color=factor(cyl)))
         + geom_point()
         + stat_smooth(method=\"lm\")
         + facet_wrap(~cyl))"]]
     (reductions (fn [prev-summary [title r-code]]
                   (ggplot-summary title
                                   r-code
                                   (:clj prev-summary)))
                 nil)
     rest
     (map view-summary)
     kind/fragment)

A scatterplot

R code

(ggplot(mpg, aes(cty, hwy))
         + geom_point())

plot

clj data

{:labels {:x ["cty"], :y ["hwy"]},
 :coordinates
 {:expand [true],
  :clip ["on"],
  :limits {:x nil, :y nil},
  :super :ggproto-method,
  :default [true]},
 :layout {:super :ggproto-method},
 :mapping {:x [~ cty], :y [~ hwy]},
 :facet {:shrink [true], :super :ggproto-method},
 :scales {:scales [], :super :ggproto-method},
 :theme [],
 :guides {:guides nil, :super :ggproto-method},
 :layers
 [{:aes_params [],
   :stat {:compute_layer :ggproto-method, :super :ggproto-method},
   :show.legend [nil],
   :mapping nil,
   :super :ggproto-method,
   :inherit.aes [true],
   :geom_params {:na.rm [false]},
   :geom
   {:non_missing_aes ["size" "shape" "colour"],
    :draw_key :ggproto-method,
    :default_aes
    {:shape [19.0],
     :colour ["black"],
     :size [1.5],
     :fill [nil],
     :alpha [nil],
     :stroke [0.5]},
    :super :ggproto-method,
    :required_aes ["x" "y"],
    :draw_panel :ggproto-method},
   :stat_params {:na.rm [false]},
   :constructor [geom_point],
   :position {:compute_layer :ggproto-method, :super :ggproto-method},
   :data []}]}
nil

A scatterplot with colours

R code

(ggplot(mpg, aes(cty, hwy, color=factor(cyl)))
         + geom_point())

plot

clj data

{:labels {:x ["cty"], :y ["hwy"], :colour ["factor(cyl)"]},
 :coordinates
 {:expand [true],
  :clip ["on"],
  :limits {:x nil, :y nil},
  :super :ggproto-method,
  :default [true]},
 :layout {:super :ggproto-method},
 :mapping {:x [~ cty], :y [~ hwy], :colour [~ [factor cyl]]},
 :facet {:shrink [true], :super :ggproto-method},
 :scales {:scales [], :super :ggproto-method},
 :theme [],
 :guides {:guides nil, :super :ggproto-method},
 :layers
 [{:aes_params [],
   :stat {:compute_layer :ggproto-method, :super :ggproto-method},
   :show.legend [nil],
   :mapping nil,
   :super :ggproto-method,
   :inherit.aes [true],
   :geom_params {:na.rm [false]},
   :geom
   {:non_missing_aes ["size" "shape" "colour"],
    :draw_key :ggproto-method,
    :default_aes
    {:shape [19.0],
     :colour ["black"],
     :size [1.5],
     :fill [nil],
     :alpha [nil],
     :stroke [0.5]},
    :super :ggproto-method,
    :required_aes ["x" "y"],
    :draw_panel :ggproto-method},
   :stat_params {:na.rm [false]},
   :constructor [geom_point],
   :position {:compute_layer :ggproto-method, :super :ggproto-method},
   :data []}]}

clj diff with previous

[[[:labels :colour] :+ ["factor(cyl)"]]
 [[:mapping :colour] :+ [~[factor cyl]]]]

A scatterplot with colours and smoothing

R code

(ggplot(mpg, aes(cty, hwy, color=factor(cyl)))
         + geom_point()
         + stat_smooth(method="lm"))

plot

clj data

{:labels {:x ["cty"], :y ["hwy"], :colour ["factor(cyl)"]},
 :coordinates
 {:expand [true],
  :clip ["on"],
  :limits {:x nil, :y nil},
  :super :ggproto-method,
  :default [true]},
 :layout {:super :ggproto-method},
 :mapping {:x [~ cty], :y [~ hwy], :colour [~ [factor cyl]]},
 :facet {:shrink [true], :super :ggproto-method},
 :scales {:scales [], :super :ggproto-method},
 :theme [],
 :guides {:guides nil, :super :ggproto-method},
 :layers
 [{:aes_params [],
   :stat {:compute_layer :ggproto-method, :super :ggproto-method},
   :show.legend [nil],
   :mapping nil,
   :super :ggproto-method,
   :inherit.aes [true],
   :geom_params {:na.rm [false]},
   :geom
   {:non_missing_aes ["size" "shape" "colour"],
    :draw_key :ggproto-method,
    :default_aes
    {:shape [19.0],
     :colour ["black"],
     :size [1.5],
     :fill [nil],
     :alpha [nil],
     :stroke [0.5]},
    :super :ggproto-method,
    :required_aes ["x" "y"],
    :draw_panel :ggproto-method},
   :stat_params {:na.rm [false]},
   :constructor [geom_point],
   :position {:compute_layer :ggproto-method, :super :ggproto-method},
   :data []}
  {:aes_params [],
   :stat
   {:extra_params ["na.rm" "orientation"],
    :super :ggproto-method,
    :compute_group :ggproto-method,
    :required_aes ["x" "y"],
    :setup_params :ggproto-method,
    :dropped_aes ["weight"]},
   :show.legend [nil],
   :mapping nil,
   :super :ggproto-method,
   :inherit.aes [true],
   :geom_params {:se [true], :na.rm [false], :orientation [nil]},
   :geom
   {:setup_params :ggproto-method,
    :super :ggproto-method,
    :draw_key :ggproto-method,
    :extra_params ["na.rm" "orientation"],
    :required_aes ["x" "y"],
    :draw_group :ggproto-method,
    :optional_aes ["ymin" "ymax"],
    :rename_size [true],
    :setup_data :ggproto-method,
    :default_aes
    {:colour ["#3366FF"],
     :fill ["grey60"],
     :linewidth [1.0],
     :linetype [1.0],
     :weight [1.0],
     :alpha [0.4]}},
   :stat_params
   {:na.rm [false],
    :method ["lm"],
    :n [80.0],
    :xseq nil,
    :orientation [nil],
    :level [0.95],
    :fullrange [false],
    :se [true],
    :formula nil,
    :method.args [],
    :span [0.75]},
   :constructor {: nil, :method ["lm"]},
   :position {:compute_layer :ggproto-method, :super :ggproto-method},
   :data []}]}

clj diff with previous

[[[:layers 1]
  :+
  {:aes_params [],
   :stat
   {:extra_params ["na.rm" "orientation"],
    :super :ggproto-method,
    :compute_group :ggproto-method,
    :required_aes ["x" "y"],
    :setup_params :ggproto-method,
    :dropped_aes ["weight"]},
   :show.legend [nil],
   :mapping nil,
   :super :ggproto-method,
   :inherit.aes [true],
   :geom_params {:se [true], :na.rm [false], :orientation [nil]},
   :geom
   {:setup_params :ggproto-method,
    :super :ggproto-method,
    :draw_key :ggproto-method,
    :extra_params ["na.rm" "orientation"],
    :required_aes ["x" "y"],
    :draw_group :ggproto-method,
    :optional_aes ["ymin" "ymax"],
    :rename_size [true],
    :setup_data :ggproto-method,
    :default_aes
    {:colour ["#3366FF"],
     :fill ["grey60"],
     :linewidth [1.0],
     :linetype [1.0],
     :weight [1.0],
     :alpha [0.4]}},
   :stat_params
   {:na.rm [false],
    :method ["lm"],
    :n [80.0],
    :xseq nil,
    :orientation [nil],
    :level [0.95],
    :fullrange [false],
    :se [true],
    :formula nil,
    :method.args [],
    :span [0.75]},
   :constructor {:_ nil, :method ["lm"]},
   :position {:compute_layer :ggproto-method, :super :ggproto-method},
   :data []}]]

A scatterplot with colours, smoothing, and facets

R code

(ggplot(mpg, aes(cty, hwy, color=factor(cyl)))
         + geom_point()
         + stat_smooth(method="lm")
         + facet_wrap(~cyl))

plot

clj data

{:labels {:x ["cty"], :y ["hwy"], :colour ["factor(cyl)"]},
 :coordinates
 {:expand [true],
  :clip ["on"],
  :limits {:x nil, :y nil},
  :super :ggproto-method,
  :default [true]},
 :layout {:super :ggproto-method},
 :mapping {:x [~ cty], :y [~ hwy], :colour [~ [factor cyl]]},
 :facet
 {:params
  {:axis_labels {:x [true], :y [true]},
   :dir ["h"],
   :draw_axes {:x [false], :y [false]},
   :nrow nil,
   :as.table [true],
   :free {:x [false], :y [false]},
   :drop [true],
   :strip.position ["top"],
   :ncol nil,
   :facets {:cyl [~ cyl]},
   :labeller
   "function (labels, multi_line = TRUE) \n{\n    labels <- lapply(labels, as.character)\n    if (multi_line) {\n        labels\n    }\n    else {\n        collapse_labels_lines(labels)\n    }\n}\n<bytecode: 0x55df1c1a7660>\n<environment: namespace:ggplot2>\nattr(,\"class\")\n[1] \"function\" \"labeller\"\n"},
  :shrink [true],
  :super :ggproto-method},
 :scales {:scales [], :super :ggproto-method},
 :theme [],
 :guides {:guides nil, :super :ggproto-method},
 :layers
 [{:aes_params [],
   :stat {:compute_layer :ggproto-method, :super :ggproto-method},
   :show.legend [nil],
   :mapping nil,
   :super :ggproto-method,
   :inherit.aes [true],
   :geom_params {:na.rm [false]},
   :geom
   {:non_missing_aes ["size" "shape" "colour"],
    :draw_key :ggproto-method,
    :default_aes
    {:shape [19.0],
     :colour ["black"],
     :size [1.5],
     :fill [nil],
     :alpha [nil],
     :stroke [0.5]},
    :super :ggproto-method,
    :required_aes ["x" "y"],
    :draw_panel :ggproto-method},
   :stat_params {:na.rm [false]},
   :constructor [geom_point],
   :position {:compute_layer :ggproto-method, :super :ggproto-method},
   :data []}
  {:aes_params [],
   :stat
   {:extra_params ["na.rm" "orientation"],
    :super :ggproto-method,
    :compute_group :ggproto-method,
    :required_aes ["x" "y"],
    :setup_params :ggproto-method,
    :dropped_aes ["weight"]},
   :show.legend [nil],
   :mapping nil,
   :super :ggproto-method,
   :inherit.aes [true],
   :geom_params {:se [true], :na.rm [false], :orientation [nil]},
   :geom
   {:setup_params :ggproto-method,
    :super :ggproto-method,
    :draw_key :ggproto-method,
    :extra_params ["na.rm" "orientation"],
    :required_aes ["x" "y"],
    :draw_group :ggproto-method,
    :optional_aes ["ymin" "ymax"],
    :rename_size [true],
    :setup_data :ggproto-method,
    :default_aes
    {:colour ["#3366FF"],
     :fill ["grey60"],
     :linewidth [1.0],
     :linetype [1.0],
     :weight [1.0],
     :alpha [0.4]}},
   :stat_params
   {:na.rm [false],
    :method ["lm"],
    :n [80.0],
    :xseq nil,
    :orientation [nil],
    :level [0.95],
    :fullrange [false],
    :se [true],
    :formula nil,
    :method.args [],
    :span [0.75]},
   :constructor {: nil, :method ["lm"]},
   :position {:compute_layer :ggproto-method, :super :ggproto-method},
   :data []}]}

clj diff with previous

[[[:facet :params]
  :+
  {:axis_labels {:x [true], :y [true]},
   :dir ["h"],
   :draw_axes {:x [false], :y [false]},
   :nrow nil,
   :as.table [true],
   :free {:x [false], :y [false]},
   :drop [true],
   :strip.position ["top"],
   :ncol nil,
   :facets {:cyl [~cyl]},
   :labeller
   "function (labels, multi_line = TRUE) \n{\n    labels <- lapply(labels, as.character)\n    if (multi_line) {\n        labels\n    }\n    else {\n        collapse_labels_lines(labels)\n    }\n}\n<bytecode:_ 0x55df1c1a7660>\n<environment:_ namespace:ggplot2>\nattr(,\"class\")\n[1] \"function\" \"labeller\"\n"}]]
source: projects/datavis/ggplot/notebooks/comparing.clj