---
title: "Help for ggplot extenders"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{extender-info}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r setup, message=FALSE, warning=FALSE, echo=FALSE}
library(ggdibbler)
```


## Your old ggplot extension *can* learn new tricks
The beauty of the broad solution `ggdibbler` provides is that it always works. It might not always look *good* or be exactly what you were looking for, but it always produces... something. To illustrate this, I included the `ggraph` example in the introduction to `ggdibbler`, but the idea can be implemented with extensions as well.

In the `ggraph` example, I illustrated how you can use the `ggdibbler` approach with a ggplot extension that isn't even aware `ggdibbler` exists. While that method works (well enough) it can be somewhat annoying to implement, and it doesn't give you access to the nested positions (as they use internal variables). I can understand fellow ggplot extenders might be chomping at the bit to see what their plots look like with uncertainty and nested positions. 

Sometimes, when making a `ggdibbler` version of a `ggplot2` base function, I would think to myself "What is the point of this, who on earth needs an uncertain version of `stat_unique`?". I still sometimes think that, but the reason we implemented it with *ALL* ggplot2 functions, is not for the users, but rather for the extenders. If there is a ggplot2 extension that is the child of a base `stat` or base position, a geom_*_sample variation of their function will simply be the child of the `ggdibbler` variation of the ggplot2 stat, instead of the original ggplot2 code. The only ggplot2 extension that might not work with `ggdibbler` is `ggdist` (for the obvious reason that is is the only other ggplot extension that is designed to take distributional input). 

Now, I have made all functions in base `ggplot2` accept uncertain inputs, go me, but the real power of ggplot2 comes from the wealth of extension packages. Now, as fun as I am sure it would be, I am not about to spend the next 5 years making pull requests on every `ggplot2` extension package so that they can all accept random variables. Largely because:

1) Going around making pull requests that forces dependency on *my* package sounds like the early warning signs of a personality disorder
2) (More importantly) that sounds really boring and I don't want to.

Thankfully, the `ggdibbler` approach is so easy if you are the author/maintainer of a `ggplot2` extension and you want it to accept random variables, you can just do it yourself. 

## How to extend your package to accept random variables (easiest to hardest)
### Geoms
As `ggdibbler` only doesn't actually implement any new geoms, the geoms are just wrappers for the stats. If you use an existing ggplot2 stat, `ggdibbler` should already have a variation of it, so you can just make the wrapper function using code that looks like this:

```{r, eval = FALSE}
geom_YOURGEOM_sample <- make_constructor(YOURGEOM, stat = "GGPLOT2STAT_sample",
                                         times = 10, seed = NULL)
```

### Stats
Stats are slightly more complicated, but still shockingly simple. There are two approaches to this. The first options is to make a YOURSTATSample child version of your stat, similar to the relationship between the base stats in ggplot and the sample stats implemented in `ggdibbler`. When making these functions in `ggdibbler` I literally had a template that I would copy and paste into the .R file. 

```{r, eval = FALSE}
#' @importFrom ggplot2 ggproto Stat***
#' @format NULL
#' @usage NULL
#' @export
Stat***Sample <- ggplot2::ggproto("Stat***Sample", ggplot2::Stat***,
                                  ### INCLUDE SETUP PARAMS IF IN PARENT STAT 
                                  setup_params = function(self, data, params) {
                                    # take one sample just to train the parameters
                                    times <- params$times
                                    params$times <- 1
                                    data <- dibble_to_tibble(data, params)
                                    params <- ggplot2::ggproto_parent(ggplot2::Stat***, self)$setup_params(data, params)
                                    params$times <- times
                                    params
                                  }
                                  ###  SETUP_DATA MUST BE IMPLEMENTED...
                                  setup_data = function(data, params) {
                                    dibble_to_tibble(data, params) 
                                    # BUT YOU ONLY NEED TO INCLUDE THIS LINE IF THE MAIN STAT USES SETUP DATA 
                                    ggproto_parent(Stat***, self)$setup_data(data, scales)
                                    },
                                  
                                  extra_params = c("na.rm", "times", "seed")
)

#' @export
#' @inheritParams ggplot2::stat_***
#' @param times A parameter used to control the number of values sampled from 
#' each distribution.
#' @param seed Set the seed for the layers random draw, allows you to plot the
#' same draw across multiple layers.
stat_***_sample <- make_constructor(Stat***Sample, geom = "***", 
                                    times = 10, seed = NULL)




```

The alternative option is if your stat is the child of an existing ggplot2 stat, you can just make a new version of your function that is a child of the `ggdibbler` version instead of the ggplot2 version. I haven't implemented this one, so I am not 100% sure how it would work, but the *only* thing that `ggdibbler` does (99% of the time) is do a setup_data step.

### Scales(TODO)
Honestly, if your package implements new scales, I would hold off on this one until the `ggdibbler` scales system is more built up. You can still try, if you want, but I am not making any promises on the usability of the function you spit out. So long as distributional can make a random variable of your scale's object type, you can make a nested scale of it.

(NOTE: actually fill out this section)


### Nested Positions (TODO)
The nested position system can't really be extended upon yet, but it is a future plan, sorry!

```{r, include=FALSE, eval=FALSE}
library(spelling)
qmd <- "D_extender-info.Rmd"
check_spelling <- spell_check_files(
  qmd,
  lang = "en_GB"
)
if (nrow(check_spelling) > 0) {
  print(check_spelling)
  stop("Check spelling in Qmd files!")
}
```
