Skip to content

Instantly share code, notes, and snippets.

@baptiste
Created July 7, 2021 08:13
Show Gist options
  • Save baptiste/fcd508cd72b9526f4140e327d4d514a3 to your computer and use it in GitHub Desktop.
Save baptiste/fcd508cd72b9526f4140e327d4d514a3 to your computer and use it in GitHub Desktop.
---
title: "A graphics workflow"
author: "baptiste"
date: 2018-20-05
---
Glyphs are positioned by x and y coordinates; other parameters are kept separate as they may differ from glyph to glyph and, crucially, compound glyphs contain nested glyphs with their own properties, requiring a flexible container.
The structure of a glyph is thus as follows,
- `x,y`: position
- `features`: mappings
- `type`: compound vs atomic type
- `meta`: optional properties such as drawing context, etc.
(this is partly inspired by Compose in Julia)
A glyph is stored as a tibble, with one element per row; note that compound glyphs may contain many sub-elements — this is similar to gtable's approach of assigning grobs to locations.
In the rendering step, glyphs are expanded recursively until an atomic type is reached; only atomic types can be understood by the rendering engine, e.g. svg's `<circle>` or `<text>`.
The expansion of a branch assigns a specific class to its subnodes, and collects the generic aesthetic properties up to that level. This means that a given branch corresponding to multiple coloured points will have their common properties stored in the class, avoiding repetition at each final leaf.
A compound glyph will typically define its own coordinate system for all children; a group of points will thus be expanded within a `<g>` element (with its own class, as per above), and the group itself is positioned at a given `x,y` position, such as a plot panel, while individual points scatter about this central position in the group's coordinate system.
https://www.sarasoueidan.com/blog/mimic-relative-positioning-in-svg/
```{r hl, echo=FALSE}
library(tidyverse)
.dummy <- I("<...stuff...>")
p <- tibble(glyph = "plot",
x = 1, y = 1,
attributes = list(.dummy))
g <- tibble(glyph = c("panel", "axis-l", "axis-b", "strip-t", "legend", "title"),
x = c(2,1,2,2,3,2), y = c(2,2,1,3,2,3),
attributes = list(.dummy))
```
## High-level description
Central to the objective of graphics is the _mapping_ of data to visuals. The proposed framework embeds this mapping in every aspect of a graphic — not only glyph properties within the main plot panel, but also facet annotations, legends, axes, etc. Because the syntax for explicit mappings would become unwiedly, default mappings are provided for most elements. The hierarchical structure of a plot requires methods to assemble blocks into larger graphical structures.
### Simplified example
subplot(1,2,1)
plot(x, y, col="red")
title("Plot")
embodies multiple mappings,
- the obvious x,y positions
- the fixed colour
but also,
- the legend
- the axes
- the title
- the subplot panel and its grid lines
- the subplot within the page
and at the highest level, the plot itself to the page.
All these elements form an Abstract Syntax Tree; our purpose is to:
- create and modify this tree with functions
- provide means to render this tree and export it to other formats
### Guides as subplots
### Assembly of block components
## Abstract Syntax Tree
The high-level description of mappings needs to be translated into a device-agnostic description of the graphical elements to be rendered. This intermediate step takes the form of an AST that can be subject to various transformations. It may be exported in various structured formats such as json, yaml, etc. for which transformers can provide a plot description in external rendering systems such as vega, vega-lite, or pgf-plots. Alternatively, the AST will be passed to low-level functions responsible for rendering, such as tikz/pgf commands, d3.js, or svg.
## Rendering
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment