# Introduction to memery

#### Matthew Leonawicz

The `memery` package is used for generating internet memes suited specifically to data analysts, combining the visual impact of an attention-grabbing meme with graphic results of data analysis. This vignette covers the basic usage of `memery` with several examples.

## Shiny example

Before getting to the code and other details, you can explore a quick visual example using the Shiny app packaged with `memery`. It displays an input meme background image and an inset plot which are combined to form the analyst’s meme. The app makes available any ggplot objects in the global environment created by the user to be used as inset plots for memes. If none exist, `memeApp` will generate a test plot ggplot object, `memery_testplot`, for the app session. Available plots populate the inset plot selection menu.

    library(memery)
    memeApp()

### magick suggested but not required

If the `magick` package is installed, `memeApp` will launch in complete mode and the default image will be an animated gif. If not installed, a simplified version of the example app will launch, and only jpg and png files can be used. It is only listed as a suggested package. Any package functionality that uses the `magick` package returns gracefully with a notification about the missing package. The only function in `memery` that uses `magick` is `meme_gif`.

## The meme

Now onto the core of the package. This consists of the background image and overlying text label(s). The image can be provided as a path to a local file or a URL. Below are examples of each, mixing up combinations of source file and output file format. `memery` also provides the classic meme font, Impact, as the default as well as the text shadow outline effect, which is available for any font you use.

### Note on fonts

Note that Impact is a Windows font. If using `memery` on Linux for example, you would have to first install the font if not already installed on the system. If Impact or any other font family passed to `meme`, e.g. `family = "Consolas"`, is not installed on an operating system, `meme` will ignore it and fall back on `family = "serif"` internally. If unfamiliar, explore the documentation and examples available for the `showtext` and `sysfonts` packages, which `memery` leverages.

    loc <- system.file("philosoraptor.jpg", package = "memery")
    web <- "https://imgflip.com/s/meme/Philosoraptor.jpg"
    lab <- c("What to call my R package?", "Perhaps...")
    meme(loc, lab[1], "meme1.jpg")
    meme(web, lab[1], "meme1.png")

There is sensible default label placement. If `label` is a vector of length two, `meme` will make a symmetrical top and bottom title/subtitle pair of text labels.

    meme(loc, lab, "meme2.jpg")

This is done using the default `lab_pos` argument, which calls `text_position`. This convenience function is only useful for one or two text labels. `meme` allows you to place an arbitrary number of labels on the plot with arbitrary positioning by passing your own list to `lab_pos` where each list element is the same length as `label`. You can see what to do by looking at the output of `text_position`.

    text_position(n = 2)
    #> $w
    #> [1] 0.9 0.9
    #>
    #> $h
    #> [1] 0.3 0.3
    #>
    #> $x
    #> [1] 0.5 0.5
    #>
    #> $y
    #> [1] 0.9 0.1

The label and shadow color can be controlled by `col` and `shadow`.

    clrs <- c("orange", "white")
    meme(loc, lab, "meme3.jpg", col = clrs[1], shadow = clrs[2])

The arguments `width` and `height` do not need to be provided. If missing, they are inferred from the dimensions of `img`. However, providing `width` and `height` overrides the source file dimension. This is useful for large source images. Whether or not `width` or `height` are provided, `mult` can also be used as an image dimensions multiplier. See below for details.

### Font size and image size

While the default `size` is set to 1, this is rather arbitrary. There is really no perfect default because the ideal size depends on several factors including the text string length, font family, and the output file dimensions, as well as subjective taste such as how much of the image width should the text cover, whether it will display with insufficient or excessive height, or whether it will block the view of important areas of the meme image. It makes sense to explicitly supply `size` for every meme. Note that, all else being equal, in general if you use an image scaled to, say, twice the width and height of another, doubling `size` will retain proportional label width coverage, but then height coverage will change. Text may also display slightly differently in png vs. jpg output files.

Avoid using `mult` to increase your image size as it will expand the shadow effect. Use a larger source image instead. `mult` is best for multipliers less than one, used to shrink an image. For example, a picture taken with your phone may have dimensions well in excess of what you need for a meme and it will be more efficient to produce a smaller output file. `width` and `height` are useful when you need to change the canvas size. These will not alter the aspect ratio. These will all affect the displayed label size in so much as it relates to the image dimensions.

## Optional plot overlay

In addition to drawing text labels on top of the background image, `meme` offers the ability to overlay an inset plot, a plot within the meme plot. This could be a thumbnail inset appearing in a corner of the plot. For example, it could be a logo. But generally speaking, this kind of behavior is directly accessible using the `grid` framework and `memery` does not attempt to duplicate this generality. Instead, it expects the `inset` argument to be any ggplot object; `inset is not for reading in a second image file. It is meant to be a plot.

By default, a ggplot object passed to `meme` via `inset` will take up approximately the lower two thirds of the plot and the full with, accounting for some margin space. It has a semi-transparent background so that it does not completely obscure the meme background image. These settings, background color, transparency, size and position, can all be specified in the call to `meme` as the following examples demonstrate.

    library(ggplot2)
    x <- seq(0, 2 * pi, length.out = 50)
    panels <- rep(paste("Philosoraptor's plot", c("A", "B")), each = 50)
    d <- data.frame(x = x, y = sin(x), grp = panels)
    txt <- c("Philosoraptor's plots", "I like to make plots", "Figure 1. (A) shows a plot and (B) shows another plot.")
    p <- ggplot(d, aes(x, y)) + geom_line(colour = "cornflowerblue", size = 2) +
        geom_point(colour = "orange", size = 4) + facet_wrap(~grp) + labs(title = txt[1],
        subtitle = txt[2], caption = txt[3])

    meme(loc, lab, "meme4a.jpg", inset = p)

Note the default semi-transparent background that allows the meme image to show through when the inset has a large coverage area. The style includes rounded corners. This is from the `grid` package. It is a rectangle layer in the same viewport as `p`; it is not part of the ggplot theme. The latter is separate and can be controlled by passing your own theme to `ggtheme` or setting this to `NULL`, which falls back on whatever theme is set for your plot `p`. The default theme for meme plots comes from `memetheme`. Naturally, the theme will need to be customized for many meme plots because underlying meme images are arbitrary.

### Alternate inset templates

The graph overlay does not fit well, namely the annotations. This will be adjusted in a moment. First, a quick look at other position templates. An opaque background for the inset is more suitable for a thumbnail image that does not get in the way of the meme. The following example shows a bottom left corner inset graphic. An empty theme is used since there is no room in the inset for plot annotations.

    set.seed(1)

    p2 <- ggplot(data.frame(x = rnorm(10000)), aes(x)) + geom_density(adjust = 2,
        colour = "white", size = 1)
    pos <- list(w = 0.2, h = 0.2, x = 0.125, y = 0.125)
    meme(loc, lab[1], "meme4b.jpg", inset = p2, inset_bg = list(fill = "dodgerblue",
        col = "black"), inset_pos = pos, ggtheme = theme_void())

Above, the size and position was specified explicitly with `pos`. However, the same could be done using `inset_position(type = "bl")`. The available position templates include the four corners via `tl`, `tr`, `br` and `bl` for top right, top left, bottom left and bottom right, respectively. There is also a `center` thumbnail option. `inset_position` also takes `size` and `margin` arguments to further specify the thumbnail placement.

    pos <- inset_position("bl", size = c(0.4, 0.2), margin = c(0.025, 0.05))
    meme(loc, lab[1], "meme4b2.jpg", inset = p2, inset_bg = list(fill = "firebrick1",
        col = "white"), inset_pos = pos, ggtheme = theme_void())

There are also four full quadrant templates. These are special cases of the corner thumbnails. They are specified by appending the letter `q` to the end of a corner template ID: `tlq`, `trq`, `brq`, and `blq`. The `size` argument is not applicable since these are fixed, full quadrant plots, but these templates still allow for `margin` control.

### Improved fit

Returning to the more complex graph, the philosoraptor image is a bit small for the first detailed plot shown above where the annotations go off the image. For convenience, it is enlarged below by simply using `mult = 2` when including the full graph again. For now, drop the second text label. It will be relocated later.

    meme(loc, lab[1], "meme4c.jpg", size = 2, inset = p, mult = 2)

Below is an example where the background panel is set to another semi-transparent color and the border color is no longer transparent.

    vp_bg <- list(fill = "#FF00FF50", col = "#FFFFFF80")
    meme(loc, lab[1], "meme4d.jpg", size = 2, inset = p, inset_bg = vp_bg, mult = 2)

You can also increase the radius of the rounded corners, with, e.g.

    list(r = unit(0.1, "snpc"))

Setting to zero will remove the rounding.

## Multiple labels and vector arguments

As shown, more than one text label can be drawn on the meme plot and assigned a different position. Other arguments are correspondingly vectorized. Each label can have unique text size, font family, font color, shadow color, and position arguments. Whereas the length of elements in `label_pos` must match the length of `label`, these other arguments are recycled if not as long as `label`.

    lab[2:3] <- c("Perhaps raptr... NO!!!", "Pfft. Figures.")
    lab_pos <- list(w = rep(0.9, 3), h = rep(0.3, 3), x = rep(0.5, 3), y = c(0.95,
        0.85, 0.3))
    meme(loc, lab, "meme5.jpg", size = c(1.25, 2.5, 1), family = c("serif", "Impact",
        "Impact"), col = clrs, shadow = rev(clrs), label_pos = lab_pos, inset = p,
        mult = 2)

## Animated gifs

If ImageMagick is installed on your system, animated gifs can be used for data analyst memes.

    d$grp <- gsub("Philosoraptor's", "Cat's", d$grp)
    p <- ggplot(d, aes(x, y)) + geom_line(colour = "white", size = 2) + geom_point(colour = "orange",
        size = 1) + facet_wrap(~grp) + labs(title = "The wiggles", subtitle = "Plots for cats",
        caption = "Figure 1. Gimme sine waves.")
    lab <- c("R plots for cats", "Sine wave sine wave...")
    pos <- list(w = rep(0.9, 2), h = rep(0.3, 2), x = rep(0.5, 2), y = c(0.9, 0.75))
    img <- "http://forgifs.com/gallery/d/228621-4/Cat-wiggles.gif"
    meme_gif(img, lab, "sine.gif", size = c(1.5, 0.75), label_pos = pos, inset = p,
        inset_bg = list(fill = "#00BFFF80"), fps = 20)

The generated file will look like this: