diff --git a/13-build-plot.Rmd b/13-build-plot.Rmd index 5b94764..1acbbdf 100644 --- a/13-build-plot.Rmd +++ b/13-build-plot.Rmd @@ -458,6 +458,9 @@ p4<-ggplot(mpg, aes(cty, hwy)) + p3+p4 ``` +```{r include=FALSE} +rm(class, map) # Clean up so these objects don't confuse later chapters. +``` ## Meeting Videos diff --git a/19-ggplot2-internals.Rmd b/19-ggplot2-internals.Rmd index 0a1c8c3..0a7cb62 100644 --- a/19-ggplot2-internals.Rmd +++ b/19-ggplot2-internals.Rmd @@ -7,24 +7,36 @@ - What the division of labor between `{ggplot2}` and `{grid}`? - What is the basic structure of/motivation for ggproto? -```{r 20-01, message=FALSE} +
+Libraries and Helper Functions + +```{r 19-01, message=FALSE} library(ggplot2) library(ggtrace) # remotes::install_github("yjunechoe/ggtrace") library(purrr) library(dplyr) + +# source("utilities/workflows-inspect.R") +# source("utilities/aliases.R") + +obj_byte <- function(x) { + scales::label_bytes()(as.numeric(object.size(x))) +} ``` -#### Introduction (the existence of internals) +
+ +## Introduction (the existence of internals) The **user-facing code** that _defines_ a ggplot on the surface is not the same as the **internal code** that _creates_ a ggplot under the hood. In this chapter, we'll learn about how the internal code operates and develop some intuitions about thinking about the internals, starting with these two simple examples of mismatches between surface and underlying form: -#### Case 1: Order +## Case 1: Order You can change the order of some "layers" without change to the graphical output. For example, `scale_*()` can be added anywhere and always ends up applying for the whole plot: -```{r 20-02, fig.show='hold', out.width='50%'} +```{r 19-02, fig.show='hold', out.width='50%'} ggplot(mtcars, aes(mpg, hp, color = as.factor(am))) + scale_x_log10() + #< scale first geom_point() + @@ -38,7 +50,7 @@ ggplot(mtcars, aes(mpg, hp, color = as.factor(am))) + Though the order of `geom_*()` and `stat_*()` matters for order of drawing: -```{r 20-03, fig.show='hold', out.width='50%'} +```{r 19-03, fig.show='hold', out.width='50%'} ggplot(mtcars, aes(mpg, hp, color = as.factor(am))) + geom_point() + geom_smooth(fill = "black") @@ -48,18 +60,18 @@ ggplot(mtcars, aes(mpg, hp, color = as.factor(am))) + geom_point() ``` -#### Case 2: Modularity +## Case 2: Modularity We know that user-facing "layer" code that we add to a ggplot with `+` are stand-alone functions: -```{r 20-04} +```{r 19-04} lm_smooth <- geom_smooth(method = "lm", formula = y ~ x) lm_smooth ``` When we add this object to different ggplots, it _materializes_ in different ways: -```{r 20-05} +```{r 19-05} ggplot(mtcars, aes(mpg, hp)) + lm_smooth @@ -69,11 +81,13 @@ ggplot(mtcars, aes(wt, disp)) + ## The `plot()` method +### `ggplot` structure + The user-facing code and internal code is also separated by _when_ they are evaluated. The user-facing code like `geom_smooth()` is evaluated immediately to give you a ggplot object, but the internal code is only evaluated when a ggplot object is printed or plotted, via `print()` and `plot()`. The following code simply creates a ggplot object from user-facing code, and **DOES NOT** print or plot the ggplot (yet). -```{r 20-06} +```{r 19-06} p <- ggplot(mpg, aes(displ, hwy, color = drv)) + geom_point(position = position_jitter(seed = 2022)) + geom_smooth(method = "lm", formula = y ~ x) + @@ -83,14 +97,16 @@ p <- ggplot(mpg, aes(displ, hwy, color = drv)) + The ggplot object is actually just a list under the hood: -```{r 20-07} +```{r 19-07} class(p) typeof(p) ``` +### Display + Evaluating the ggplot is what gives you the actual points, rectangles, text, etc. that make up the figure (and you can also do so explicitly with `print()`/`plot()`) -```{r 20-08} +```{r 19-08} p # print(p) # plot(p) @@ -98,7 +114,7 @@ p These are two separate processes, but we often think of them as one monolithic process: -```{r 20-09, message=FALSE, fig.show='hide'} +```{r 19-09, message=FALSE, warning = FALSE, fig.show='hide'} defining_benchmark <- bench::mark( # Evaluates user-facing code to define ggplot, # but does not call plot/print method @@ -120,16 +136,23 @@ bind_rows( ) ``` +## Steps + The plot that gets rendered from a ggplot object is actually a **side effect** of evaluating the ggplot object: -```{r 20-10} +
+ggplot object + +```{r 19-10} # Same as ggplot2:::print.ggplot ggplot2:::plot.ggplot ``` +
+ The above code can be simplified to this: -```{r 20-11} +```{r 19-11} ggprint <- function(x) { data <- ggplot_build(x) gtable <- ggplot_gtable(data) @@ -143,7 +166,7 @@ ggprint(p) Roughly put, you first start out as the ggplot object, which then gets passed to `ggplot_build()`, result of which in turn gets passed to `ggplot_gtable()` and finally drawn with `{grid}` -```{r 20-12} +```{r 19-12} library(grid) grid.newpage() # Clear display p %>% @@ -154,11 +177,7 @@ p %>% At each step, you get closer to the low-level information you need to draw the actual plot -```{r 20-13} -obj_byte <- function(x) { - scales::label_bytes()(as.numeric(object.size(x))) -} - +```{r 19-13} # ggplot object p %>% obj_byte() @@ -176,23 +195,32 @@ ggsave( ) %>% file.size() %>% {scales::label_bytes()(.)} ``` -The rest of the chapter focuses what happens in this pipeine - the `ggplot_build()` step and the `ggplot_gtable()` step. +The rest of the chapter focuses what happens in this pipeline - the `ggplot_build()` step and the `ggplot_gtable()` step. + ## The build step -This is the function body of `ggplot_build()`: +
+function body of `ggplot_build()` -```{r 20-14} +```{r 19-14} ggplot2:::ggplot_build.ggplot ``` +
+ It takes the ggplot object as input, and transforms the user-provided data to a drawing-ready data (+ some other auxiliary/meta-data like information about the layout). You can see that the drawing-ready data `data` is built up incrementally (much like data wrangling minus pipes): +
+incremental list view -```{r 20-15} +```{r 19-15} as.list(body(ggplot2:::ggplot_build.ggplot)) ``` +
+ + ### Data preparation The data from the ggplot is prepared in a special format for each layer (essentially, just a dataframe with a predictable set of column names). @@ -203,7 +231,7 @@ A layer (specifically, the output of `ggplot2::layer()`) can provide data in one * Supplied directly from the layer's `data` argument * A function that returns a data when applied to the global data -```{r 20-16} +```{r 19-16} data_demo_p <- ggplot(mtcars, aes(disp, cyl)) + # 1) Inherited data geom_point(color = "blue") + @@ -226,15 +254,23 @@ data_demo_p Inside the `layers` element of the ggplot are `Layer` objects which hold information about each layer: -```{r 20-17, eval = FALSE} +
+Layer objects + +```{r 19-17} data_demo_p$layers -map( data_demo_p$layers, class ) +purrr::map( data_demo_p$layers, class ) ``` +
+ And the calculated data from each layer can be accessed with `layer_data()` method of the `Layer` object: -```{r 20-18} +
+Layer data + +```{r 19-18} ggplot2:::Layer$layer_data data_demo_p$layers[[1]]$layer_data(data_demo_p$data) @@ -242,129 +278,139 @@ data_demo_p$layers[[2]]$layer_data(data_demo_p$data) data_demo_p$layers[[3]]$layer_data(data_demo_p$data) ``` +
+ This is where the data transformation journey begins inside the plot method: -```{r 20-19} +```{r 19-19} body(ggplot2:::ggplot_build.ggplot)[[5]] body(ggplot2:::ggplot_build.ggplot)[[8]] ``` For `data_demo_p`, the `data` variable after step 8 looks like this: -```{r 20-20} -ggtrace_inspect_vars( - x = data_demo_p, - method = ggplot2:::ggplot_build.ggplot, - at = 9, - vars = "data" -) +
+Step 8 + +```{r 19-20} +body(ggplot2:::ggplot_build.ggplot)[[9]] + +# ggtrace_inspect_vars( +# x = data_demo_p, +# method = ggplot2:::ggplot_build.ggplot, +# at = 9, +# vars = "data" +# ) ``` For the expository plot `p` from the book, the `data` variable after step 8 looks like the original `mpg` data: -```{r 20-21, eval = FALSE} +```{r 19-21, eval = FALSE} ggtrace_inspect_vars( x = p, method = ggplot2:::ggplot_build.ggplot, at = 9, vars = "data" ) %>% - map(head) + purrr::map(head) ``` +
+ + ### Data transformation #### PANEL variable and aesthetic mappings Continuing with the book example, the data is augmented with the `PANEL` variable at Step 11: -```{r 20-22, eval = FALSE} +```{r 19-22} body(ggplot2:::ggplot_build.ggplot)[[11]] -ggtrace_inspect_vars( - x = p, - method = ggplot2:::ggplot_build.ggplot, - at = 12, - vars = "data" -) %>% - map(head) +# ggtrace_inspect_vars( +# x = p, +# method = ggplot2:::ggplot_build.ggplot, +# at = 12, +# vars = "data" +# ) %>% +# map(head) ``` And then the `group` variable appears at Step 12, which is also when aesthetics get "mapped" (= just `mutate()`, essentially): -```{r 20-23, eval = FALSE} +```{r 19-23} body(ggplot2:::ggplot_build.ggplot)[[12]] -ggtrace_inspect_vars( - x = p, - method = ggplot2:::ggplot_build.ggplot, - at = 13, - vars = "data" -) %>% - map(head) +# ggtrace_inspect_vars( +# x = p, +# method = ggplot2:::ggplot_build.ggplot, +# at = 13, +# vars = "data" +# ) %>% +# map(head) ``` #### Scales Then, scales are applied in Step 13. This leaves the data unchanged for the original plot: -```{r 20-24, eval = FALSE} +```{r 19-24} body(ggplot2:::ggplot_build.ggplot)[[13]] -ggtrace_inspect_vars( - x = p, - method = ggplot2:::ggplot_build.ggplot, - at = 14, - vars = "data" -) %>% - map(head) +# ggtrace_inspect_vars( +# x = p, +# method = ggplot2:::ggplot_build.ggplot, +# at = 14, +# vars = "data" +# ) %>% +# map(head) ``` But the effect can be seen with something like `scale_x_log10()`: -```{r 20-25, eval = FALSE} -ggtrace_inspect_vars( - x = p + scale_x_log10(), - method = ggplot2:::ggplot_build.ggplot, - at = 14, - vars = "data" -) %>% - map(head, 3) +```{r 19-25, eval = FALSE} +# ggtrace_inspect_vars( +# x = p + scale_x_log10(), +# method = ggplot2:::ggplot_build.ggplot, +# at = 14, +# vars = "data" +# ) %>% +# map(head, 3) ``` Out-of-bounds handling happens down the line, at Step 17: -```{r 20-26, eval = FALSE} +```{r 19-26} body(ggplot2:::ggplot_build.ggplot)[[17]] -ggtrace_inspect_vars( - x = p + xlim(2, 8), # or scale_x_continuous(oob = scales::oob_censor) - method = ggplot2:::ggplot_build.ggplot, - at = 18, - vars = "data" -) %>% - map(head, 3) +# ggtrace_inspect_vars( +# x = p + xlim(2, 8), # or scale_x_continuous(oob = scales::oob_censor) +# method = ggplot2:::ggplot_build.ggplot, +# at = 18, +# vars = "data" +# ) %>% +# map(head, 3) ``` #### Stat Stat transformation happens right after, at Step 18 (this is why understanding out-of-bounds handling and scale transformation is important!) -```{r 20-27, eval = FALSE} +```{r 19-27} body(ggplot2:::ggplot_build.ggplot)[[18]] -ggtrace_inspect_vars( - x = p, - method = ggplot2:::ggplot_build.ggplot, - at = 19, - vars = "data" -) %>% - map(head, 3) +# ggtrace_inspect_vars( +# x = p, +# method = ggplot2:::ggplot_build.ggplot, +# at = 19, +# vars = "data" +# ) %>% +# map(head, 3) ``` Note how this point on the data for two layers look different. This is because `geom_point()` and `geom_smooth()` have different **Stat**s. -```{r 20-28} +```{r 19-28} class( geom_point()$stat ) class( geom_smooth()$stat ) ``` @@ -373,49 +419,59 @@ class( geom_smooth()$stat ) At Step 22, positions are adjusted (jittering, dodging, stacking, etc.). We gave `geom_point()` a jitter so we see that reflected for the first layer: -```{r 20-29, eval = FALSE} +```{r 19-29} body(ggplot2:::ggplot_build.ggplot)[[22]] -ggtrace_inspect_vars( - x = p, - method = ggplot2:::ggplot_build.ggplot, - at = 23, - vars = "data" -) %>% - map(head, 3) +# ggtrace_inspect_vars( +# x = p, +# method = ggplot2:::ggplot_build.ggplot, +# at = 23, +# vars = "data" +# ) %>% +# map(head, 3) ``` #### Geom Variables relevant for drawing each layer's geometry are added in by the Geom, at Step 29: -```{r 20-30, eval = FALSE} +```{r 19-30} body(ggplot2:::ggplot_build.ggplot)[[29]] -ggtrace_inspect_vars( - x = p, - method = ggplot2:::ggplot_build.ggplot, - at = 30, - vars = "data" -) %>% - map(head, 3) +# ggtrace_inspect_vars( +# x = p, +# method = ggplot2:::ggplot_build.ggplot, +# at = 30, +# vars = "data" +# ) %>% +# map(head, 3) ``` ### Output The final state of the data after `ggplot_build()` is stored in the `data` element of the output of `ggplot_build()`: -```{r 20-31, eval = FALSE} +
+Output + +```{r 19-31} ggplot_build(p)$data %>% - map(head, 3) + purrr::map(head, 3) ``` +
+ `ggplot_build()` also returns the trained layout of the plot (scales, panels, etc.) in the `layout` element, as well as the original ggplot object in the `plot` element: -```{r 20-32, eval = FALSE} +
+Layout element + +```{r 19-32} lapply( ggplot_build(p), class ) ``` +
+ ### Explore
@@ -442,48 +498,54 @@ ggtrace_inspect_vars( ```
+ ## The gtable step Again, still working with our plot `p` -```{r 20-06, eval=FALSE} +```{r 19-06, eval=FALSE} ``` -```{r 20-08} +```{r 19-08} ``` The return value of `ggplot_build()` contains the computed data associated with each layer and a `Layout` ggproto object which holds information about data other than the layers, including the scales, coordinate system, facets, etc. -```{r 20-33} +```{r 19-33} names(ggplot_build(p)) ``` +
+Layout data -```{r 20-34, eval = FALSE} -ggplot_build(p)$data %>% map(head, 3) +```{r 19-34, eval = FALSE} +ggplot_build(p)$data %>% purrr::map(head, 3) ``` -```{r 20-35} +
+ + +```{r 19-35} class(ggplot_build(p)$layout) ``` The output of `ggplot_build()` is then passed to `ggplot_gtable()` to be converted into graphical elements before being drawn: -```{r 20-36} +```{r 19-36} ggplot2:::plot.ggplot ``` -### Rendering the panels +## Rendering the panels > First, each layer is converted into a list of graphical objects (`grobs`) ... -```{r 20-37} +```{r 19-37} body(ggplot2:::ggplot_gtable.ggplot_built)[[6]] ``` This step draws loops through each layer, taking the layer object `l` and the data associated with that layer `d` and using the Geom from the layer to draw the data. -```{r 20-38} +```{r 19-38} geom_grobs <- ggtrace_inspect_vars( x = p, method = ggplot2:::ggplot_gtable.ggplot_built, at = 7, vars = "geom_grobs" @@ -493,7 +555,7 @@ geom_grobs The `geom_grobs` calculated at this step can also be accessed using the `layer_grob()` function on the ggplot object, which is similar to the `layer_data()` function: -```{r 20-39} +```{r 19-39} list( layer_grob(p, i = 1), layer_grob(p, i = 2) @@ -502,7 +564,7 @@ list( Each element of `geom_grobs` is a list of graphical objects representing a layer's data in a facet. For example, this draws the data plotted by the first layer in the first facet -```{r 20-40, eval = FALSE} +```{r 19-40, eval = FALSE} grid.newpage() pushViewport(viewport()) grid.draw(geom_grobs[[1]][[1]]) @@ -512,11 +574,11 @@ grid.draw(geom_grobs[[1]][[1]]) The graphical representation of each layer in each facet are combined with other "non-data" elements of the plot at this step, where the `plot_table` variable is defined. -```{r 20-41} +```{r 19-41} body(ggplot2:::ggplot_gtable.ggplot_built)[[8]] ``` -```{r 20-42} +```{r 19-42} plot_table <- ggtrace_inspect_vars( x = p, method = ggplot2:::ggplot_gtable.ggplot_built, at = 9, vars = "plot_table" @@ -525,36 +587,48 @@ plot_table <- ggtrace_inspect_vars( `plot_table` is a special `grob` called a `gtable`, which is the same structure as the final form of the ggplot figure before it's sent off to the rendering system to get drawn: -```{r 20-43} +
+plot_table + +```{r 19-43} plot_table ``` +
+ When it is first defined, it's only a partially complete representation of the plot - title, legend, margins, etc. are missing: -```{r 20-44, eval = FALSE} +
+the panels so far + +```{r 19-44, eval = FALSE} grid.newpage() grid.draw(plot_table) ``` + +
+ + Recall that `plot_table` is the output of `layout$render`: -```{r 20-45} +```{r 19-45} body(ggplot2:::ggplot_gtable.ggplot_built)[[8]] ``` This is the load-bearing step that computes/defines a bunch of smaller components internally: -```{r 20-46} +```{r 19-46} ggplot_build(p)$layout$render ``` We can inspect these individual components: -```{r 20-47} +```{r 19-47} layout_render_env <- ggtrace_capture_env(p, ggplot2:::Layout$render) ``` -```{r 20-48} +```{r 19-48} # grob in between the Coord's background and the layer for each panel layout_render_env$facet_bg # grob in between the Coord's foreground and the layer for each panel @@ -571,7 +645,7 @@ layout_render_env$labels The rest of the gtable step is just updating this `plot_table` object. -```{r 20-49} +```{r 19-49} all_plot_table_versions <- ggtrace_inspect_vars( x = p, method = ggplot2:::ggplot_gtable.ggplot_built, at = "all", vars = "plot_table" @@ -579,7 +653,7 @@ all_plot_table_versions <- ggtrace_inspect_vars( names(all_plot_table_versions) ``` -```{r 20-50, eval=FALSE} +```{r 19-50, eval=FALSE} lapply(seq_along(all_plot_table_versions), function(i) { ggsave(tempfile(sprintf("plot_table_%02d_", i), fileext = ".png"), all_plot_table_versions[[i]]) }) @@ -591,7 +665,7 @@ dir(tempdir(), "plot_table_.*png", full.names = TRUE) %>% ![plot_table_animation1](images/plot_table_animation1.gif) -```{r 20-51, eval=FALSE} +```{r 19-51, eval=FALSE} all_plot_table_versions2 <- ggtrace_inspect_vars( x = p + labs( @@ -615,15 +689,15 @@ dir(tempdir(), "plot_table2_.*png", full.names = TRUE) %>% ![plot_table_animation2](images/plot_table_animation2.gif) -### Adding guides +## Adding guides The legend (`legend_box`) is first defined in Step 11: -```{r 20-52} +```{r 19-52} body(ggplot2:::ggplot_gtable.ggplot_built)[[11]] ``` -```{r 20-53, eval = FALSE} +```{r 19-53, eval = FALSE} legend_box <- ggtrace_inspect_vars( x = p, method = ggplot2:::ggplot_gtable.ggplot_built, at = 12, vars = "legend_box" @@ -634,11 +708,11 @@ grid.draw(legend_box) It then undergoes some edits/tweaks, including resolving the `legend.position` theme setting, and then finally gets added to the plot in Step 15: -```{r 20-54} +```{r 19-54} body(ggplot2:::ggplot_gtable.ggplot_built)[[15]] ``` -```{r 20-55, eval = FALSE} +```{r 19-55, eval = FALSE} p_with_legend <- ggtrace_inspect_vars( x = p, method = ggplot2:::ggplot_gtable.ggplot_built, at = 16, vars = "plot_table" @@ -649,11 +723,11 @@ grid.draw(p_with_legend) The bulk of the work was done in Step 11, with the `build_guides()` function. That in turn calls `guides_train()` and `guides_gengrob()` which in turn calls `guide_train()` and `guide_gengrob` for each scale (including positional aesthetics like x and y). -Why scale? The scale is actually what holds information about guide. They're two sides of the same coin - the scale translates the underlying data to some defined space, and the guide reverses that (translates a space to data). One's for drawing, the other is for reading. +* Why scale? *The scale is actually what holds information about guide*. They're two sides of the same coin - the scale translates the underlying data to some defined space, and the guide reverses that (translates a space to data). One's for drawing, the other is for reading. -This is also why all `scale_*()` functions take a `guide` argument. Positional scales use `guide_axis()` as default, and non-positional scales use `guide_legend()` as default. +* This is also why all `scale_*()` functions take a `guide` argument. Positional scales use `guide_axis()` as default, and non-positional scales use `guide_legend()` as default. -```{r 20-56} +```{r 19-56} class(guide_legend()) # This explicitly spells out the default p + @@ -662,7 +736,7 @@ p + This is the output of the `guide_train()` method defined for `guide_legend()`. The most important piece of it is `key`, which is the data associated with the legend. -```{r 20-57, eval = FALSE} +```{r 19-57, echo = FALSE, eval = FALSE} # TODO: The unexported function no longer exists, so we had to turn off eval. names( ggtrace_inspect_return(p, ggplot2:::guide_train.legend) ) ggtrace_inspect_return(p, ggplot2:::guide_train.legend)$key @@ -670,14 +744,14 @@ ggtrace_inspect_return(p, ggplot2:::guide_train.legend)$key The output of `guide_train()` is passed to `guide_gengrob()`. This is the output of the `guide_gebgrob()` method defined for `guide_legend()`: -```{r 20-58, eval = FALSE} +```{r 19-58, echo = FALSE, eval = FALSE} # TODO: The unexported function no longer exists, so we had to turn off eval. legend_gengrob <- ggtrace_inspect_return(p, ggplot2:::guide_gengrob.legend) grid.newpage() grid.draw(legend_gengrob) ``` -### Adding adornment +## Adding adornment It's everything else after the legend step that we saw in the gifs above. It looks trivial but this step we're glossing over is [~150 lines of code](https://github.com/tidyverse/ggplot2/blob/main/R/plot-build.r#L258-L398). But it's not super complicated - just a lot of if-else statements and a handful of low-level {grid} and {gtable} functions. @@ -685,7 +759,7 @@ It's everything else after the legend step that we saw in the gifs above. It loo To put it all together: -```{r 20-59} +```{r 19-59} p_built <- ggplot_build(p) p_gtable <- ggplot_gtable(p_built) grid.newpage() @@ -696,7 +770,7 @@ grid.draw(p_gtable) It's essentially a list of functions -```{r 20-60} +```{r 19-60} String <- list( add = function(x, y) paste0(x, y), subtract = function(x, y) gsub(y, "", x, fixed = TRUE), @@ -709,13 +783,13 @@ Number <- list( ) ``` -```{r 20-61} +```{r 19-61} String$add("a", "b") String$subtract("june", "e") String$show("ggplot", "bookclub") ``` -```{r 20-62} +```{r 19-62} Number$add(1, 2) Number$subtract(10, 5) Number$show(1, 2) @@ -725,7 +799,7 @@ Number$show(1, 2) From the book: -```{r 20-63} +```{r 19-63} Person <- ggproto("Person", NULL, first = "", last = "", diff --git a/20-Extending-ggplot2.Rmd b/20-Extending-ggplot2.Rmd index 193e626..4f2808a 100644 --- a/20-Extending-ggplot2.Rmd +++ b/20-Extending-ggplot2.Rmd @@ -22,7 +22,7 @@ In this chapter we see how to extend the graphics of a plot, in particular we wi --- -```{r 21-01,message=FALSE, warning=FALSE, include=FALSE, paged.print=FALSE} +```{r 20-01,message=FALSE, warning=FALSE, include=FALSE, paged.print=FALSE} library(tidyverse) library(patchwork) ``` @@ -41,7 +41,7 @@ Use the `print()` function on a theme_<...> to see its specifications, the `%+re print(theme_grey) print(theme_minimal) and %+replace% operator -```{r 21-02,echo=FALSE} +```{r 20-02,echo=FALSE} df<-data.frame(x=seq(1,10,1),y=rnorm(100)) tg<-ggplot(data=df,aes(x,y))+ geom_blank()+ @@ -62,11 +62,11 @@ tg|bw|tm ``` -```{r 21-03} +```{r 20-03} print(theme_bw) ``` -```{r 21-04} +```{r 20-04} print(theme_minimal) ``` @@ -92,7 +92,7 @@ Creating new stats *stat* with these extension functions: The logic of a **stat** is made of subsequent calls: -```{r 21-05,echo=FALSE, fig.align='center', fig.dim="100%"} +```{r 20-05,echo=FALSE, fig.align='center', fig.dim="100%"} DiagrammeR::mermaid(" graph LR A(compute_layer)-->B(compute_panel) @@ -100,7 +100,7 @@ B-->C(compute_group) ",height = '100%', width = '100%') ``` -```{r 21-06,echo=FALSE, fig.align='center', fig.dim="100%"} +```{r 20-06,echo=FALSE, fig.align='center', fig.dim="100%"} DiagrammeR::mermaid(" graph TB A(compute_layer)---B(split the data by the PANEL column) @@ -119,7 +119,7 @@ In general the transformation is done to single group starting at the `compute_g Before `compute_*()` calls are the`setup_*()` functions which allows the Stat to react and modify itself in response to the given parameters. -```{r 21-07,echo=FALSE, fig.align='center', fig.dim="100%"} +```{r 20-07,echo=FALSE, fig.align='center', fig.dim="100%"} DiagrammeR::mermaid(" graph TB A(setup_params)-->B(receives the parameters input) @@ -132,7 +132,7 @@ E-->F( returns the modified layer data) >Sometimes, with related stats, all that is necessary is to make a subclass and provide new setup_params()/setup_data() methods. -```{r 21-08} +```{r 20-08} print(stat_bin()) ``` @@ -148,7 +148,7 @@ print(stat_bin()) The logic of a **geom** is made of subsequent calls: -```{r 21-09,echo=FALSE, fig.align='center', fig.dim="100%"} +```{r 20-09,echo=FALSE, fig.align='center', fig.dim="100%"} DiagrammeR::mermaid(" graph LR A(draw_layer)-->B(draw_panel) @@ -163,7 +163,7 @@ Implementation is easier for `draw_group()` **Example** Reparameterisation of `geom_segment()` with `geom_spoke()` -```{r 21-10} +```{r 20-10} print(GeomSpoke$setup_data) ``` @@ -172,7 +172,7 @@ print(GeomSpoke$setup_data) - preparing the data for each of the geoms inside the `draw_*()` -```{r 21-11} +```{r 20-11} print(GeomSmooth$draw_group) ``` @@ -187,10 +187,10 @@ Coords takes care of rendering the axes, axis labels, and panel foreground and b - `transform()` **Example** -```{r 21-12} +```{r 20-12} print(CoordCartesian$transform) ``` -```{r 21-13,eval=FALSE, include=T} +```{r 20-13,eval=FALSE, include=T} print(coord_sf) ``` @@ -201,7 +201,7 @@ print(coord_sf) **Example** Build a wrapper for a new palette to an existing scale. This is done by providing a new palette scale into the relevant basic scale. -```{r 21-14} +```{r 20-14} print(scale_fill_viridis_c) ``` @@ -212,7 +212,7 @@ print(scale_fill_viridis_c) The Position class is slightly simpler than the other ggproto classes. -```{r 21-15,echo=FALSE, fig.align='center', fig.dim="100%"} +```{r 20-15,echo=FALSE, fig.align='center', fig.dim="100%"} DiagrammeR::mermaid(" graph LR A(compute_layer)-->B(compute_panel) diff --git a/DESCRIPTION b/DESCRIPTION index 69356c9..72c4f70 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: ggplot2club Title: ggplot2 Book Club -Version: 0.0.0.9000 +Version: 0.0.2.9000 Authors@R: c( person("Data Science Learning Community", role = c("aut", "cre", "cph")) )