Rendering Pipeline

How does the function call

df = dataset("ggplot2", "diamonds")
p = plot(df,
         x = :Price, color = :Cut,
		 Stat.histogram,
		 Geom.bar)

actually get turned into the following plot?

Price 0 5.00×10³ 1.00×10⁴ 1.50×10⁴ 2.00×10⁴ 0 1.00×10³ 2.00×10³ 3.00×10³ 4.00×10³ 5.00×10³ 6.00×10³ 7.00×10³ 8.00×10³ 9.00×10³ 1.00×10⁴ 1.10×10⁴ 1.20×10⁴ 1.30×10⁴ 1.40×10⁴ 1.50×10⁴ 1.60×10⁴ 1.70×10⁴ 1.80×10⁴ 1.90×10⁴ 2.00×10⁴ 0 1.000×10² 2.000×10² 3.000×10² 4.000×10² 5.000×10² 6.000×10² 7.000×10² 8.000×10² 9.000×10² 1.000×10³ 1.100×10³ 1.200×10³ 1.300×10³ 1.400×10³ 1.500×10³ 1.600×10³ 1.700×10³ 1.800×10³ 1.900×10³ 2.000×10³ 2.100×10³ 2.200×10³ 2.300×10³ 2.400×10³ 2.500×10³ 2.600×10³ 2.700×10³ 2.800×10³ 2.900×10³ 3.000×10³ 3.100×10³ 3.200×10³ 3.300×10³ 3.400×10³ 3.500×10³ 3.600×10³ 3.700×10³ 3.800×10³ 3.900×10³ 4.000×10³ 4.100×10³ 4.200×10³ 4.300×10³ 4.400×10³ 4.500×10³ 4.600×10³ 4.700×10³ 4.800×10³ 4.900×10³ 5.000×10³ 5.100×10³ 5.200×10³ 5.300×10³ 5.400×10³ 5.500×10³ 5.600×10³ 5.700×10³ 5.800×10³ 5.900×10³ 6.000×10³ 6.100×10³ 6.200×10³ 6.300×10³ 6.400×10³ 6.500×10³ 6.600×10³ 6.700×10³ 6.800×10³ 6.900×10³ 7.000×10³ 7.100×10³ 7.200×10³ 7.300×10³ 7.400×10³ 7.500×10³ 7.600×10³ 7.700×10³ 7.800×10³ 7.900×10³ 8.000×10³ 8.100×10³ 8.200×10³ 8.300×10³ 8.400×10³ 8.500×10³ 8.600×10³ 8.700×10³ 8.800×10³ 8.900×10³ 9.000×10³ 9.100×10³ 9.200×10³ 9.300×10³ 9.400×10³ 9.500×10³ 9.600×10³ 9.700×10³ 9.800×10³ 9.900×10³ 1.000×10⁴ 1.010×10⁴ 1.020×10⁴ 1.030×10⁴ 1.040×10⁴ 1.050×10⁴ 1.060×10⁴ 1.070×10⁴ 1.080×10⁴ 1.090×10⁴ 1.100×10⁴ 1.110×10⁴ 1.120×10⁴ 1.130×10⁴ 1.140×10⁴ 1.150×10⁴ 1.160×10⁴ 1.170×10⁴ 1.180×10⁴ 1.190×10⁴ 1.200×10⁴ 1.210×10⁴ 1.220×10⁴ 1.230×10⁴ 1.240×10⁴ 1.250×10⁴ 1.260×10⁴ 1.270×10⁴ 1.280×10⁴ 1.290×10⁴ 1.300×10⁴ 1.310×10⁴ 1.320×10⁴ 1.330×10⁴ 1.340×10⁴ 1.350×10⁴ 1.360×10⁴ 1.370×10⁴ 1.380×10⁴ 1.390×10⁴ 1.400×10⁴ 1.410×10⁴ 1.420×10⁴ 1.430×10⁴ 1.440×10⁴ 1.450×10⁴ 1.460×10⁴ 1.470×10⁴ 1.480×10⁴ 1.490×10⁴ 1.500×10⁴ 1.510×10⁴ 1.520×10⁴ 1.530×10⁴ 1.540×10⁴ 1.550×10⁴ 1.560×10⁴ 1.570×10⁴ 1.580×10⁴ 1.590×10⁴ 1.600×10⁴ 1.610×10⁴ 1.620×10⁴ 1.630×10⁴ 1.640×10⁴ 1.650×10⁴ 1.660×10⁴ 1.670×10⁴ 1.680×10⁴ 1.690×10⁴ 1.700×10⁴ 1.710×10⁴ 1.720×10⁴ 1.730×10⁴ 1.740×10⁴ 1.750×10⁴ 1.760×10⁴ 1.770×10⁴ 1.780×10⁴ 1.790×10⁴ 1.800×10⁴ 1.810×10⁴ 1.820×10⁴ 1.830×10⁴ 1.840×10⁴ 1.850×10⁴ 1.860×10⁴ 1.870×10⁴ 1.880×10⁴ 1.890×10⁴ 1.900×10⁴ 1.910×10⁴ 1.920×10⁴ 1.930×10⁴ 1.940×10⁴ 1.950×10⁴ 1.960×10⁴ 1.970×10⁴ 1.980×10⁴ 1.990×10⁴ 2.000×10⁴ 0 2.0×10⁴ Ideal Premium Good Very Good Fair Cut h,j,k,l,arrows,drag to pan i,o,+,-,scroll,shift-drag to zoom r,dbl-click to reset c for coordinates ? for help ? 0 1000 2000 3000 4000 0 200 400 600 800 1000 1200 1400 1600 1800 2000 2200 2400 2600 2800 3000 3200 3400 3600 3800 4000 0 20 40 60 80 100 120 140 160 180 200 220 240 260 280 300 320 340 360 380 400 420 440 460 480 500 520 540 560 580 600 620 640 660 680 700 720 740 760 780 800 820 840 860 880 900 920 940 960 980 1000 1020 1040 1060 1080 1100 1120 1140 1160 1180 1200 1220 1240 1260 1280 1300 1320 1340 1360 1380 1400 1420 1440 1460 1480 1500 1520 1540 1560 1580 1600 1620 1640 1660 1680 1700 1720 1740 1760 1780 1800 1820 1840 1860 1880 1900 1920 1940 1960 1980 2000 2020 2040 2060 2080 2100 2120 2140 2160 2180 2200 2220 2240 2260 2280 2300 2320 2340 2360 2380 2400 2420 2440 2460 2480 2500 2520 2540 2560 2580 2600 2620 2640 2660 2680 2700 2720 2740 2760 2780 2800 2820 2840 2860 2880 2900 2920 2940 2960 2980 3000 3020 3040 3060 3080 3100 3120 3140 3160 3180 3200 3220 3240 3260 3280 3300 3320 3340 3360 3380 3400 3420 3440 3460 3480 3500 3520 3540 3560 3580 3600 3620 3640 3660 3680 3700 3720 3740 3760 3780 3800 3820 3840 3860 3880 3900 3920 3940 3960 3980 4000 0 5000

The rendering pipeline transforms a plot specification into a Compose scene graph that contains a set of guides (e.g. axis ticks, color keys) and one or more layers of geometry (e.g. points, lines). The specification of each layer has

  • a data source (e.g. dataset("ggplot2", "diamonds"))
  • a geometry to represent the layer's data (e.g. point, line, etc.)
  • mappings to associate aesthetics of the geometry with elements of the data source (e.g. :color => :Cut)
  • layer-wise statistics (optional) to be applied to the layer's data

All layers of a plot share the same

A full plot specification must describe these shared elements as well as all the layer specifications. In the example above, we see that only the data source, statistics, geometry, and mapping are specified. The missing elements are either inferred from the data (e.g. categorical values in df.Cut implies a discrete color scale), or assumed using defaults (e.g. continuous x-axis scale). For example, invoking plot with all the elements will look something like

p = plot(layer(df,
               x = :Price, color = :Cut,
		       Stat.histogram,
		       Geom.bar),
	  	 Scale.x_continuous,
		 Scale.color_discrete,
		 Coord.cartesian,
		 Guide.xticks, Guide.yticks,
		 Guide.xlabel("Price"),
		 Guide.colorkey(title="Cut"))

Once a full plot specification is filled out, the rendering process proceeds as follows:

  1. For each layer in the plot, we first map subsets of the data source to a Data object. The Price and Cut columns of the diamond dataset are mapped to the :x and :color fields of Data, respectively.

  2. Scales are applied to the data to obtain plottable aesthetics. Scale.x_continuous keeps the values of df.Price unchanged, while Scale.color_discrete_hue maps the unique elements of df.Cut (an array of strings) to actual color values.

  3. The aesthetics are transformed by layer-wise and plot-wise statistics, in order. Stat.histogram replaces the x field of the aesthetics with bin positions, and sets the y field with the corresponding counts.

  4. Using the position aesthetics from all layers, we create a Compose context with a coordinate system that fits the data to screen coordinates. Coord.cartesian creates a Compose context that maps a vertical distance of 3000 counts to about two inches in the rendered plot.

  5. Each layer renders its own geometry.

  6. Finally, we compute the layout of the guides and render them on top of the plot context.