Skip to content

bmacGTPM/pubtheme

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pubtheme

The package pubtheme contains a ggplot theme theme_pub for creating data journalism-style data visualizations with color palettes and formatting similar to those used by media organizations like BBC, NY Times, and ESPN. Several templates for scatter plot, line plots, etc., are provided below for easy copying/pasting. A helpful function pub can be used to reduce then amount of code that needs to be typed when the user is comfortable with the default settings.

Organization-specific color palettes and logos can be used as well via the package orgthemes. See https://github.com/bmacGTPM/orgthemes.

Installation

If you don’t have the package devtools, install it using install.packages('devtools'). If you have devtools, you can install the GitHub version of pubtheme with:

devtools::install_github("bmacGTPM/pubtheme")

If you get an error about download method, try changing this option before installing.

options(download.file.method = 'libcurl')

Load the package using

library(pubtheme)

as usual. The theme will change some of your ggplot defaults the first time you use it. To change them back, restart R, or use

restore.ggplot.defaults()

at any time. It is recommended that you update your version of tidyverse and especially ggplot2 to use this package.

Scatter plot

dg = mtcars %>% 
  select(wt, mpg, cyl) %>%
  mutate(Cylinders = as.factor(cyl)) %>%
  rename(MPG = mpg)

title = "Title in Upper Lower" 
g = ggplot(dg, 
           aes(x     = wt, 
               y     = MPG, 
               color = Cylinders, 
               size  = MPG)) +
  geom_point() +
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption with more info, X handle, or shameless promotion of pubtheme",
       x = 'Horizontal Axis Label in Upper Lower',
       y = 'Vertical Axis Label in Upper Lower') +
  scale_x_continuous(limits = c(0, 6), 
                     breaks = c(0, 3, 6), 
                     oob    = squish, 
                     labels = comma) +
  scale_y_continuous(limits = c(0,40), 
                     breaks = c(0,20,40), 
                     oob    = squish, 
                     labels = comma) +
  scale_size(range = c(2, 6)) +
  coord_cartesian(clip   = 'off', 
                  expand = F) +
  theme_pub(type = 'scatter') 
print(g)

## Save to a file using base_size = 36
gg = g +
  scale_size(range = c(6, 18)) +
  theme_pub(type = 'scatter', 
            base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), 
       plot   = gg,
       width  = 20,   ## do not change
       height = 20,   ## can change from 20 if desired
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

g.scatter = g ## save for later

You must have a subfolder called img in order for the ggsave chunk above to work.

Note that the default is base_size = 12, which works well when viewing the image in RStudio. Use ggsave and base_size = 36 when saving an image instead of exporting from the RStudio viewer. Do not adjust the width = 20 in ggsave.

Do not change width = 20, units = 'in', or dpi = 72. Height can be adjusted if desired. A square image is often preferred, so when in doubt, keep height at 20.

Upper Lower means First letter of each word is capitalized. The option expand = FALSE removes the default padding. The option breaks=c(0, 3, 6) sets 3 lines at left, middle, and right. You can certainly add lines if there is a reason to, but when in doubt you can stick with just 3 lines (left/middle/right) only. Similarly, for the y-axis, top/middle/bottom only.

You’ll notice a scale_size(range = c(6, 18) when preparing the plot to be saved. If you are using size inside aes(), you’ll need that change the scale, otherwise the points will be too small.

pub function

We explicitly specified the scale* and coord_cartesian above. To use the default settings in pubtheme, you can save a lot of typing by using the function pub, which applies theme_pub and also automatically adds scale* and coord* similar to above. The function also aligns the legend with the left side of the title and subtitle.

title = "Title in Upper Lower" 
g = ggplot(dg, 
           aes(x     = wt, 
               y     = MPG, 
               color = Cylinders, 
               size  = MPG)) +
  geom_point() +
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x = 'Horizontal Axis Label in Upper Lower',
       y = 'Vertical Axis Label in Upper Lower')

g %>% 
  pub(xlim = c(0, 6),
      ylim = c(0, 40))

## Save to a file using base_size = 36
gg = g %>% 
  pub(xlim = c(0, 6), 
      ylim = c(0, 40), 
      base_size = 36)

ggsave(filename = paste0("img/", 
                         gsub("%", " Perc", title), 
                         ".jpg"), 
       plot   = gg,
       width  = 20,   ## do not change
       height = 20,   ## can change from 20 if desired
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

To save to a file, we again need base_size = 36. We simply copy and paste the pub code and add base_size = 36.

Correlation plot

Make a correlation plot in the look of pubtheme. Since corrplot gives a corrplot object, pub can’t be used with it, so we have to make a correlation plot from scratch using ggcorrplot.

We can instead use geom_tile.

## choose order of variables
cols = sort(unique(colnames(mtcars)))

corr <- round(cor(mtcars[,cols]), 2)
head(corr,2)
#>        am carb   cyl  disp  drat gear    hp   mpg  qsec    vs    wt
#> am   1.00 0.06 -0.52 -0.59  0.71 0.79 -0.24  0.60 -0.23  0.17 -0.69
#> carb 0.06 1.00  0.53  0.39 -0.09 0.27  0.75 -0.55 -0.66 -0.57  0.43


# title = "Title in Upper Lower"
# g = ggcorrplot(corr) + 
#   scale_fill_gradientn(colors = c('red4', 
#                                   pubred, 
#                                   publightred, 
#                                   pubbackgray, 
#                                   publightblue, 
#                                   pubblue, 
#                                   'navy'),
#                        na.value = pubmediumgray, ## same color as below
#                        oob      = squish,
#                        breaks   = c(-1, 0, 1),
#                        limits   = c(-1,    1)) +
#   labs(title    = title,
#        subtitle = 'Optional Subtitle In Upper Lower',
#        #caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
#        x    = 'Day (Optional Axis Label in Upper Lower)', 
#        y    = NULL, ## Optional
#        fill = 'Value') #+ 
# g
# 
# g %>% 
#   pub(type    = 'grid', base_size = 10) + 
#   theme(axis.text.x.top = element_text(angle = 90, 
#                                        hjust = 0, 
#                                        vjust = 0.7))


dg = corr %>%
  as.data.frame() %>%
  
  ## longer format
  rownames_to_column(var = 'x') %>%
  pivot_longer(cols      = -x, 
               names_to  = 'y', 
               values_to = 'value') %>%
  
  ## order them however you'd like
  mutate(x = factor(x, levels = rev(sort(unique(x)))), 
         y = factor(y, levels = sort(unique(y))))

title = "Title in Upper Lower"
g = ggplot(dg) + 
  geom_tile(aes(x    = x, 
                y    = y, 
               fill = value),
            linewidth   = 0.4, 
            show.legend = T, 
            color       = pubdarkgray) +
  scale_fill_gradientn(colors = c('red4', 
                                  pubred, 
                                  publightred, 
                                  'white', ## or 'pubbackgray'
                                  publightblue, 
                                  pubblue, 
                                  'navy'),
                       na.value = pubmediumgray, ## same color as below
                       oob      = squish,
                       breaks   = c(-1, 0, 1),
                       limits   = c(-1,    1)) +

  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x    = 'Day (Optional Axis Label in Upper Lower)', 
       y    = NULL, ## Optional
       fill = 'Value') 

g %>% 
  pub(type    = 'grid') + 
  theme(axis.text.x.top = element_text(angle = 90, 
                                   hjust = 0, 
                                   vjust = 0.3))

gg = g %>%
  pub(type      = 'grid', 
      base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), 
       plot   = gg,
       width  = 20,   ## do not change
       height = 24,   ## can change from 20 if desired. We use 12 here to make the tiles square
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

Adding rectangles around clusters, as is often done in corrplot.

# ## note that the function corrRect.hclust is used there
# corrplot::corrplot
# 
# ## note that this converts corr to a distance matrix, and then uses cutree to get the clusters
# corrplot::corrRect.hclust

corr = cor(mtcars)
ds = as.dist(1-corr)
dh = hclust(ds)
hc = cutree(dh, k = 4)

dr = data.frame(order = dh$order,
                cluster = hc) %>%
  mutate(cluster = factor(cluster, 
                          levels = c(1,3,4,2))) %>% ## this order looks better
  arrange(cluster, order) %>%
  mutate(x = 1:n(),
         y = n():1) ## gotta reverse the order
dr
#>      order cluster  x  y
#> drat     3       1  1 11
#> am       5       1  2 10
#> gear     9       1  3  9
#> mpg     11       1  4  8
#> vs       1       3  5  7
#> qsec     8       3  6  6
#> carb    10       4  7  5
#> hp       2       2  8  4
#> disp     4       2  9  3
#> cyl      6       2 10  2
#> wt       7       2 11  1

dg = corr %>%
  as.data.frame() %>%
  
  ## longer format
  rownames_to_column(var = 'x') %>%
  pivot_longer(cols      = -x, 
               names_to  = 'y', 
               values_to = 'value') %>%
  
  ## order them the same way as dr
  mutate(x = factor(x, levels =     rownames(dr)),
         y = factor(y, levels = rev(rownames(dr))))

polys = dr %>%
  group_by(cluster) %>%
  summarise(xmin = min(x),
            xmax = max(x),
            ymin = min(y),
            ymax = max(y)) %>%
  mutate(xmin = xmin - 0.5,
         xmax = xmax + 0.5,
         ymin = ymin - 0.5,
         ymax = ymax + 0.5, 
         linewidth = 1.5)
polys
#> # A tibble: 4 × 6
#>   cluster  xmin  xmax  ymin  ymax linewidth
#>   <fct>   <dbl> <dbl> <dbl> <dbl>     <dbl>
#> 1 1         0.5   4.5   7.5  11.5       1.5
#> 2 3         4.5   6.5   5.5   7.5       1.5
#> 3 4         6.5   7.5   4.5   5.5       1.5
#> 4 2         7.5  11.5   0.5   4.5       1.5

g = ggplot(dg) + 
  
  ## Tiles
  geom_tile(aes(x    = x, 
                y    = y, 
                fill = value),
            linewidth   = 0.4, 
            show.legend = T, 
            color       = pubdarkgray) +
  
  ## Rectangles
  geom_rect(data = polys,
            aes(xmin = xmin,
                xmax = xmax,
                ymin = ymin,
                ymax = ymax,
                group = cluster, 
                linewidth = linewidth),
            fill = NA,
            color = 'black', 
            linejoin = 'mitre',    ## mitre or round
            lineend = 'square') +  ## square or round
  
  guides(linewidth = 'none') +
  
  scale_fill_gradientn(colors = c('red4', 
                                  pubred, 
                                  publightred, 
                                  pubbackgray, 
                                  publightblue, 
                                  pubblue, 
                                  'navy'),
                       na.value = pubmediumgray, ## same color as below
                       oob      = squish,
                       breaks   = c(-1, 0, 1),
                       limits   = c(-1,    1)) +

  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x    = 'Day (Optional Axis Label in Upper Lower)', 
       y    = NULL, ## Optional
       fill = 'Value') 
  

g %>% 
  pub(type = 'grid') 


gg = g %>%
  pub(type      = 'grid', 
      base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), 
       plot   = gg,
       width  = 20,   ## do not change
       height = 24,   ## can change from 20 if desired. We use 12 here to make the tiles square
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

This could be made with ggcorrplot as well. I’m not sure if the method above or below will be more convenient, so I’m leaving both examples here for now.

library(ggcorrplot)
corr = cor(mtcars)
ds = as.dist(1-corr)
dh = hclust(ds)
hc = cutree(dh, k = 4)

dr = data.frame(order = dh$order,
                cluster = hc) %>%
  mutate(cluster = factor(cluster, 
                          levels = c(1,3,4,2))) %>% ## this order looks better
  arrange(cluster, order) %>%
  mutate(x = 1:n(),
         y = n():1) ## gotta reverse the order
dr
#>      order cluster  x  y
#> drat     3       1  1 11
#> am       5       1  2 10
#> gear     9       1  3  9
#> mpg     11       1  4  8
#> vs       1       3  5  7
#> qsec     8       3  6  6
#> carb    10       4  7  5
#> hp       2       2  8  4
#> disp     4       2  9  3
#> cyl      6       2 10  2
#> wt       7       2 11  1

polys = dr %>%
  group_by(cluster) %>%
  summarise(xmin = min(x),
            xmax = max(x),
            ymin = min(y),
            ymax = max(y)) %>%
  mutate(xmin = xmin - 0.5,
         xmax = xmax + 0.5,
         ymin = ymin - 0.5,
         ymax = ymax + 0.5, 
         linewidth = 1.5)
polys
#> # A tibble: 4 × 6
#>   cluster  xmin  xmax  ymin  ymax linewidth
#>   <fct>   <dbl> <dbl> <dbl> <dbl>     <dbl>
#> 1 1         0.5   4.5   7.5  11.5       1.5
#> 2 3         4.5   6.5   5.5   7.5       1.5
#> 3 4         6.5   7.5   4.5   5.5       1.5
#> 4 2         7.5  11.5   0.5   4.5       1.5

corr = corr[    rownames(dr), 
            rev(rownames(dr))]


title = "Title in Upper Lower"
g = ggcorrplot(corr, 
               outline.color = pubbackgray) + 
  geom_rect(data = polys,
            aes(x = NULL, 
                y = NULL, 
                xmin = xmin,
                xmax = xmax,
                ymin = ymin,
                ymax = ymax,
                group = cluster, 
                linewidth = linewidth
                ),
            fill = NA,
            color = 'black', 
            linejoin = 'mitre',    ## mitre or round
            lineend = 'square') +  ## square or round
  
  guides(linewidth = 'none') +
  
  scale_fill_gradientn(colors = c('red4', 
                                  pubred, 
                                  publightred, 
                                  pubbackgray, 
                                  publightblue, 
                                  pubblue, 
                                  'navy'),
                       na.value = pubmediumgray, ## same color as below
                       oob      = squish,
                       breaks   = c(-1, 0, 1),
                       limits   = c(-1,    1)) +
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       #caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x    = 'Day (Optional Axis Label in Upper Lower)', 
       y    = NULL, ## Optional
       fill = 'Value') #+ 

g %>% 
  pub(type    = 'grid', base_size = 10) #+ 
  # theme(axis.text.x.top = element_text(angle = 90, 
  #                                      hjust = 0, 
  #                                      vjust = 0.7))

gg = g %>%
  pub(type      = 'grid', 
      base_size = 36) #+ 
  # theme(axis.text.x.top = element_text(angle = 90, 
  #                                      hjust = 0, 
  #                                      vjust = 0.7))

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), 
       plot   = gg,
       width  = 20,   ## do not change
       height = 24,   ## can change from 20 if desired. We use 12 here to make the tiles square
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

Pairs plot

library(GGally) ## Needed for ggpairs function
dg = mtcars %>%
  select(mpg, cyl, wt, carb) %>%
  mutate(Cylinders = factor(cyl))

title = 'Title in Upper Lower'
g = ggpairs(dg, 
            aes(color = Cylinders, 
                fill  = Cylinders), 
            columns = c('mpg', 'wt', 'carb'),
            diag    = list(continuous = pub.density)) +
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x     = 'Horizontal Axis Label in Upper Lower',
       y     = 'Vertical Axis Label in Upper Lower') +
  theme_pub(type = 'pairs')
print(g)

## Save to a file using base_size = 36
gg = g +
  theme_pub(type      = 'pairs', 
            base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), 
       plot   = gg,
       width  = 20,   ## do not change
       height = 20,   ## can change from 20 if desired
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

Note that since the object g resulting from using ggpairs is not a ggplot object, pub can’t be used with it.

Line plot

Since name and value will be more common column names when using these in the wild, we’ll rename some columns to be name and value, to simplify copying and pasting later.

Continuous variables for x seem to be more common, so we’ll convert date to days for this example, so that copying and pasting later becomes easier. We’ll use toupper() to avoid using variables with all lowercase letters in the legend.

dg = economics_long %>%
  mutate(name  = toupper(variable), 
         days  = as.numeric(date - min(date)), 
         value = value01) %>%
  select(date, days, name, value)
head(dg)
#> # A tibble: 6 × 4
#>   date        days name     value
#>   <date>     <dbl> <chr>    <dbl>
#> 1 1967-07-01     0 PCE   0       
#> 2 1967-08-01    31 PCE   0.000265
#> 3 1967-09-01    62 PCE   0.000762
#> 4 1967-10-01    92 PCE   0.000471
#> 5 1967-11-01   123 PCE   0.000916
#> 6 1967-12-01   153 PCE   0.00157

title = "Title in Upper Lower" 
g = ggplot(dg, 
           aes(x     = days, 
               y     = value, 
               color = name)) +
  geom_line() +
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x     = 'Horizontal Axis Label in Upper Lower', 
       y     = 'Vertical Axis Label in Upper Lower', 
       color = 'Legend Label') +
  guides(color = guide_legend(nrow = 2))

g %>% 
  pub(type = 'line', 
      ylim = c(0, 1)) + 
  theme(legend.text.align = 0)

## Save to a file using base_size = 36
gg = g %>% 
  pub(type = 'line', 
      ylim = c(0, 1), 
      base_size = 36) + 
  theme(legend.text.align = 0)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), ## must have a subfolder called 'img'
       plot   = gg,
       width  = 20,   ## do not change
       height = 20,   ## can change from 20 if desired
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change  

Note that once again we set breaks for the y-axis at the top, middle, and bottom.

Line plot with date

You can use the same code as Line Plot above (except use x = date), and pub will detect the date scale and format appropriately. You can change the format of the labels as shown below with xlabels.

title = "Title in Upper Lower" 
g = ggplot(dg, 
           aes(x     = date, 
               y     = value, 
               color = name)) +
  geom_line() +
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x     = 'Horizontal Axis Label in Upper Lower', 
       y     = 'Vertical Axis Label in Upper Lower', 
       color = 'Legend Label') +
  guides(color = guide_legend(nrow = 2))

g %>% 
  pub(type = 'line', 
      ylim = c(0, 1), 
      xbreaks = as.Date(c('1970-01-01', 
                          '1990-01-01', 
                          '2010-01-01')), ## optional
      xlabels = function(x) format(x, '%b%e, %Y')) + ## optional
  theme(legend.text.align = 0)

Histogram

dg = economics %>%
  filter(date <= '2008-01-01') %>%
  rename(value = unemploy)

title = "Title in Upper Lower" 
g  = ggplot(dg, 
            aes(x = value)) +
  geom_histogram(fill     = pubblue, 
                 color    = pubbackgray, 
                 binwidth = 500) + ## set a reasonable binwidth
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x = 'Horizontal Axis Label in Upper Lower', ## Required.
       y = 'Count') 

g %>% 
  pub(type = 'hist')

## Save to a file using base_size = 36
gg = g %>% 
  pub(type = 'hist', 
      base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), 
       plot   = gg,
       width  = 20,   ## do not change
       height = 20,   ## can change from 20 if desired
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

The binwidth will almost surely need to be changed for your data.

Bar plot

We’ll use the mtcars data again, with some modifications. For cylinder, we’ll add -cylinder to the numbers so it looks nice. We’ll then convert it a factor so that we can specify the order. We’ll also create a column called max which controls the length of the lightgray bars in the background. Finally, we’ll rename cyl and mpg to name and value, which will be convenient when copying and pasting this code.

dg = mtcars %>%
  group_by(cyl) %>%
  summarise(mpg = mean(mpg)) %>%
  mutate(cyl = paste0(cyl, '-cylinder'),
         cyl = factor(cyl, 
                      levels = c('8-cylinder', 
                                 '6-cylinder', 
                                 '4-cylinder'))) %>% ## for background cars
  rename(name  = cyl, 
         value = mpg) 

title = "Title in Upper Lower" 
g = ggplot(dg, 
           aes(x = value, 
               y = name, 
               label = round(value,2))) +
  geom_col(aes(x = 30), 
           fill = publightgray, 
           width = 0.8) + ## optional background bars. 
  geom_col(width = 0.8) + 
  geom_text(hjust = -0.1) + ## optional numbers with reasonable number of digits
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x        = 'Horizontal Axis Label in Upper Lower', ## Optional. 
       y        = NULL)  ## Optional. Upper Lower.

g %>%
  pub(type = 'bar')

## Save to a file using base_size = 36
gg = g %>%
  pub(type      = 'bar',
      base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), ## must have a subfolder called 'img'
       plot   = gg,
       width  = 20,   ## do not change
       height = 15,   ## can change from 20 if desired. We use 15 here b/c there are only 3 bars
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

If you are using digits next to the bars, you can increase the max so the text fits.

You may want to remove x and y axis titles. If not used, use x = NULL and/or y = NULL above. Do not use x = '' and/or y = ''. If you do use axes titles, they should be in Upper Lower.

Grid plot

dg = airquality %>%
  mutate(Month = month.abb[Month],
         Month = factor(Month, levels = rev(month.abb[month.abb %in% Month])), 
         Day   = factor(Day, levels = 1:31)) %>% 
  rename(x = Day,
         y = Month,
         value = Temp)

## Do this so that all combos have a tile
dg = dg %>%
  complete(x, 
           y, 
           fill = list(value = NA))
head(dg)
#> # A tibble: 6 × 6
#>   x     y     Ozone Solar.R  Wind value
#>   <fct> <fct> <int>   <int> <dbl> <int>
#> 1 1     Sep      96     167   6.9    91
#> 2 1     Aug      39      83   6.9    81
#> 3 1     Jul     135     269   4.1    84
#> 4 1     Jun      NA     286   8.6    78
#> 5 1     May      41     190   7.4    67
#> 6 2     Sep      78     197   5.1    92

title = "Title in Upper Lower"
g = ggplot(dg, 
           aes(x    = x, 
               y    = y, 
               fill = value, 
               alpha = '')) + ## hacky way to add a legend for NA values. See below
  geom_tile(linewidth   = 0.4, 
            show.legend = T, 
            color       = pubdarkgray) +
  scale_fill_gradient(low      = pubgradgray,
                      high     = pubblue, 
                      na.value = pubmediumgray, ## same color as below
                      oob      = squish, 
                      breaks   = c(60, 75, 90)) +
  
  ## hacky way to add a legend for NA values
  scale_alpha_manual(values = NA) +              
  guides(alpha = guide_legend(
    title = "No data",
    override.aes = list(fill = pubmediumgray))) + ## same color as above
    
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x    = 'Day (Optional Axis Label in Upper Lower)', 
       y    = NULL, ## Optional
       fill = 'Value') 

g %>% 
  pub(type    = 'grid',
      xbreaks = seq(2, 32, by = 2))

## Save to a file using base_size = 36
gg = g %>%
  pub(type      = 'grid', 
      xbreaks   = seq(2, 32, by=2),
      base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), 
       plot   = gg,
       width  = 20,   ## do not change
       height = 12,   ## can change from 20 if desired. We use 12 here to make the tiles square
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

Slope Chart

dg = economics_long %>%
  mutate(name = toupper(variable), 
         days = as.numeric(date - min(date)), 
         y= value01, 
         x = as.character(date)) %>%
  select(x, name, y) %>%
  filter(x %in% range(x), 
         name != 'PCE') %>% ## keep first and last date
  mutate(time = ifelse(x == min(x), "", "end")) %>%
  pivot_wider(names_from = time, 
              values_from = c(x, y), 
              names_sep = '') %>%
  mutate(diff = yend - y, 
         perc = diff/y*100, 
         label1 = paste0(name, ', ', 
                         round(y, 2)),
         label2 = paste0(
           round(yend, 2), ' (',
           sprintf("%+.2f", diff), '), ', ## show a plus when positive
           name
           ))
title = "Title in Upper Lower" 
g = ggplot(dg, 
           aes(x = x,
               y = y, 
               color = name, 
               size = 4, 
               linewidth = .25)) +
  
  ## lines
  geom_segment(aes(xend = xend,
                   yend = yend)) +

  ## text labels
  geom_text_repel(aes(label = label1, 
                      color = name),
                  #color = pubtextgray,
                  nudge_x   =  -0.08,
                  hjust     =  1, 
                  vjust     = 0.5,
                  direction = 'y', 
                  min.segment.length = 1) +
  
  geom_text_repel(aes(x     = xend,
                      y     = yend,
                      label = label2, 
                      color = name), 
                  #color = pubtextgray,
                  nudge_x = 0.08,
                  hjust   = 0, 
                  vjust   = 0.5,
                  direction = 'y', 
                  min.segment.length = 1) +
  
  ## points
  geom_point(show.legend = F) + 
  geom_point(show.legend = F, 
             aes(x = xend, 
                 y = yend)) + 
  
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x = 'Horizontal Axis Label in Upper Lower', ## Optional. 
       y = NULL)  +  ## Optional. Upper Lower.
  
  guides(size      = 'none', 
         linewidth = 'none', 
         color     = 'none') 

g %>% 
  pub(type = 'slope') 
 
## Save to a file using base_size = 36
gg = g %>%
  pub(type = 'slope',
      base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), ## must have a subfolder called 'img'
       plot   = gg,
       width  = 20,   ## do not change
       height = 20,   ## can change from 20 if desired. We use 15 here because there are only 5 barbells
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

Lollipop plot

We’ll make a horizontal lollipop plot. It can be used an alternative to a bar plot, and it is often preferred, especially when the visualization will eventually be printed since the lollipop plot used far less ink/toner.

dg = airquality %>%
  mutate(Month = month.abb[Month],
         Month = factor(Month, 
                        levels = rev(month.abb))) %>% 
  group_by(Month) %>%
  summarise(Temp = mean(Temp)) %>%
  rename(name  = Month,
         value = Temp)


title = "Title in Upper Lower" 
g = ggplot(dg, 
           aes(x     = value, 
               y     = name, 
               label = round(value,2), 
               size  = 1,         ## these are constant put these in aes() anyway
               linewidth = .75)) +  ## so they change when base_size changes
  geom_segment(aes(x    = 0, 
                   xend = value, 
                   y    = name, 
                   yend = name), 
               color = pubred) +
  geom_point(color = pubred, 
             show.legend = F) + 
  geom_text(hjust = -0.3) + ## optional numbers with reasonable number of digits
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x = 'Horizontal Axis Label in Upper Lower', ## Optional. 
       y = NULL) +  ## Optional. Upper Lower.
  guides(size      = 'none', 
         linewidth = 'none')

g %>%
  pub(type = 'pop', 
      xlim = c(0, 120)) 

## Save to a file using base_size = 36
gg = g %>% 
  pub(type      = 'pop',
      xlim      = c(0, 120),
      base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), ## must have a subfolder called 'img'
       plot   = gg,
       width  = 20,   ## do not change
       height = 12,   ## can change from 20 if desired. We use 12 here because there are only 5 lollipops
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

Same plot using geom_linerange instead of geom_segment. We have to switch the x and y aesthetics and use coord_flip.

# title = "Title in Upper Lower" 
# g = ggplot(dg, 
#            aes(x     = name, 
#                y     = value, 
#                label = round(value,2), 
#                size  = 1,         ## these are constant put these in aes() anyway
#                linewidth = .75)) +  ## so they change when base_size changes
#   geom_linerange(aes(ymin = 0, 
#                      ymax = value), 
#                color = pubred) #+
#   # geom_point(color = pubred, 
#   #            show.legend = F) + 
#   # geom_text(vjust = -0.3) + ## optional numbers with reasonable number of digits
#   # coord_flip() + 
#   # labs(title    = title,
#   #      subtitle = 'Optional Subtitle In Upper Lower',
#   #      caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
#   #      x = 'Horizontal Axis Label in Upper Lower', ## Optional. 
#   #      y = NULL) +  ## Optional. Upper Lower.
#   # guides(size      = 'none', 
#   #        linewidth = 'none')
# 
# g %>%
#   pub(type = 'pop', 
#       xlim = c(0, 120), ) 
# 
# ## Save to a file using base_size = 36
# gg = g %>% 
#   pub(type      = 'pop',
#       xlim      = c(0, 120),
#       base_size = 36)
# 
# ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), ## must have a subfolder called 'img'
#        plot   = gg,
#        width  = 20,   ## do not change
#        height = 12,   ## can change from 20 if desired. We use 12 here because there are only 5 lollipops
#        units  = 'in', ## do not change
#        dpi    = 72)   ## do not change

Lollipop for discrete distributions

This still uses type = 'pop' but we’ll use a different template for copying/pasting.

dg = data.frame(name  = 0:10, 
                value = dbinom(0:10, 10, .5))

title = "Title in Upper Lower" 
g = ggplot(dg, 
           aes(x     = name, 
               y     = value, 
               label = round(value,2), 
               size  = 5, 
               linewidth = 0.5)) +
  geom_point(color = pubred) + 
  geom_segment(aes(x    = name, 
                   xend = name, 
                   y    = 0, 
                   yend = value), 
               color = pubred) +
  geom_text(vjust = -1) + ## optional numbers with reasonable number of digits
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x = 'Horizontal Axis Label in Upper Lower', ## Optional. 
       y = NULL) +  ## Optional. Upper Lower.
  guides(size = 'none', 
         linewidth = 'none')
  
g %>% 
  pub(type    = 'pop', 
      xlim    = c(0, 10), 
      ylim    = c(0, .3), 
      xbreaks = 0:10)

## Save to a file using base_size = 36
gg = g %>% 
  pub(type      = 'pop', 
      xlim      = c(0, 10), 
      ylim      = c(0, .3), 
      xbreaks   = 0:10,
      base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), ## must have a subfolder called 'img'
       plot   = gg,
       width  = 20,   ## do not change
       height = 15,   ## can change from 20 if desired. We choose 15 here b/c the extra space isn't needed
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

Barbell plot

This still uses type = 'pop' but we’ll use a different template for copying/pasting.

dg = airquality %>%
  mutate(Month = month.abb[Month],
         Month = factor(Month, 
                        levels = rev(month.abb))) %>% 
  group_by(Month) %>%
  summarise(x    = min(Temp), 
            xend = max(Temp)) %>%
  rename(name = Month)


title = "Title in Upper Lower" 
g = ggplot(dg, 
           aes(x = x,
               y = name, 
               size = 4, 
               linewidth = .5)) +
  geom_point(color = pubred) + 
  geom_point(color = pubred, 
             aes(x = xend)) + 
  geom_segment(aes(xend = xend, 
                   yend = name), 
               color = pubred) +
  geom_text(aes(label = round(x, 2)), 
            hjust = 1.5) + ## optional numbers with reasonable number of digits
  geom_text(aes(x     = xend, 
                label = round(xend, 2)), 
            hjust = -0.5) + ## optional numbers with reasonable number of digits
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x = 'Horizontal Axis Label in Upper Lower', ## Optional. 
       y = NULL) +  ## Optional. Upper Lower.
  guides(size      = 'none', 
         linewidth = 'none')

g %>% 
  pub(type = 'pop', 
      xlim = c(0, 120))

## Save to a file using base_size = 36
gg = g %>% 
  pub(type = 'pop', 
      xlim = c(0, 120), 
      base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), ## must have a subfolder called 'img'
       plot   = gg,
       width  = 20,   ## do not change
       height = 15,   ## can change from 20 if desired. We use 15 here because there are only 5 barbells
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

Dot and Whiskers Plot

It is often desirable to visualize regression coefficients using a dot and whiskers plot instead of showing a table of coefficients and standard errors. We’ll make up a regression model and demonstrate that here.

This still uses type = 'pop' but we’ll use a different template for copying/pasting.

## standardize predictors so they are roughly the same scale
d = mtcars %>%
  mutate(wt   = scale(wt),  
         cyl  = scale(cyl), 
         disp = scale(disp), 
         hp   = scale(hp))

m1 = lm(mpg ~ wt + cyl + disp +  hp, 
        data = d)

#summary(m1)

dg = summary(m1)$coefficients %>% 
  as.data.frame() %>%
  rownames_to_column(var = 'var') %>%
  rename(coef = Estimate, 
         se   = `Std. Error`) %>%
  select(var, 
         coef, 
         se) %>%
  filter(var != '(Intercept)') %>%
  mutate(var = toupper(var))

title = "Title in Upper Lower" 
g = ggplot(dg, 
           aes(x         = coef, 
               y         = var, 
               size      = 4, 
               linewidth = 0.5)) +
  geom_segment(aes(x     = coef - se, 
                   xend  = coef + se,
                   y     = var, 
                   yend  = var), 
               color = pubred) +
  geom_point(color = pubred) +
  geom_text(aes(label = round(coef, 2)), 
            vjust = -1, 
            nudge_y = 0) + 
  geom_vline(xintercept = 0, 
             color      = pubmediumgray) +
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x = 'Coefficient', 
       y = NULL) + ## Optional. 
  guides(size      = 'none', 
         linewidth = 'none')
 
g %>% 
  pub(type = 'dot', 
      xlim = c(-5, 5))

## Save to a file using base_size = 36
gg = g %>% 
  pub(type      = 'dot', 
      xlim      = c(-5, 5),
      base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), 
       plot   = gg,
       width  = 20,   ## do not change
       height = 10,   ## can change from 20 if desired. We use 10 here because there are only 4 coefficients.
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

Error bars

Use the same data as above

## standardize predictors so they are roughly the same scale
d = mtcars %>%
  mutate(wt   = scale(wt),  
         cyl  = scale(cyl), 
         disp = scale(disp), 
         hp   = scale(hp))

m1 = lm(mpg ~ wt + cyl + disp +  hp, 
        data = d)

#summary(m1)

dg = summary(m1)$coefficients %>% 
  as.data.frame() %>%
  rownames_to_column(var = 'var') %>%
  rename(coef = Estimate, 
         se   = `Std. Error`) %>%
  select(var, 
         coef, 
         se) %>%
  filter(var != '(Intercept)') %>%
  mutate(var = toupper(var))
  

title = "Title in Upper Lower" 
g = ggplot(dg, 
           aes(x         = coef, 
               y         = var, 
               size      = 4, 
               linewidth = 0.5)) +
  geom_errorbarh(aes(xmin = coef - se, 
                     xmax = coef + se), 
                 color = pubred, 
                 height = 0.2) +
  geom_point(color = pubred) +
  geom_text(aes(label = round(coef, 2)), 
            vjust = -1, 
            nudge_y = 0) + 
  geom_vline(xintercept = 0, 
             color      = pubmediumgray) +
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x = 'Coefficient', 
       y = NULL) + ## Optional. 
  guides(size      = 'none', 
         linewidth = 'none')
 
g %>% 
  pub(type = 'dot', 
      xlim = c(-5, 5))

## Save to a file using base_size = 36
gg = g %>% 
  pub(type      = 'dot', 
      xlim      = c(-5, 5),
      base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), 
       plot   = gg,
       width  = 20,   ## do not change
       height = 12,   ## can change from 20 if desired. We use 10 here because there are only 4 coefficients.
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

For vertical error bars, use geom_errorbar() instead of geom_errorbarh().

Faceting

We’ll use our scatter plot example, but with facet_wrap to make separate plots for each cyl, and we add a facet = T argument to make some formatting more appropriate for faceted plots.

dg = mtcars %>%
  select(wt, 
         mpg, 
         cyl) %>%
  mutate(cyl = paste0(cyl, '-cylinder')) %>%
  rename(name = cyl)

title = "Title in Upper Lower" ## to be used by ggplot and ggsave
g = ggplot(dg, 
           aes(x     = wt, 
               y     = mpg, 
               size  = mpg, 
               color = name)) +
  geom_point(show.legend = F) +
  facet_wrap(~name, 
             nrow = 1) +
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x = 'Horizontal Axis Label in Upper Lower',
       y = 'Vertical Axis Label in Upper Lower')

g %>% 
  pub(xlim  = c(0, 6), 
      ylim  = c(0, 40), 
      facet = T)

## Save to a file using base_size = 36
gg = g %>%
  pub(xlim      = c(0, 6), 
      ylim      = c(0, 40), 
      facet     = T, 
      base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), ## must have a subfolder called 'img'
       plot   = gg,
       width  = 20,   ## do not change
       height = 13,   ## can change from 20 if desired. Here we choose 13 so each subplot is square
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

Timeline

Let’s make up some data. Let’s also define a new “reverse_trans” function called reverse2_trans.

current.year = as.numeric(format(Sys.Date(), "%Y"))

dg = data.frame(date = 
                  as.Date(
                    c(paste0(current.year,
                             c('-01-01', 
                               '-07-04', 
                               '-12-25', 
                               '-12-31')),
                      paste0(current.year + 1,                                        
                             c('-01-01', 
                               '-07-04', 
                               '-12-25', 
                               '-12-31')))), 
                text = c("New Year's Day", 
                         "Independence Day",
                         "Christmas Day",
                         "New Year's Eve", 
                         "New Year's Day", 
                         "Independence Day",
                         "Christmas Day",
                         "New Year's Eve")) %>%
  mutate(text = paste0(text, ', ', date), 
         name = case_when(grepl('Christmas', text) ~ 'Christmas', 
                          grepl('Indep'    , text) ~ 'Indep', 
                          TRUE ~ 'Other'), 
         name = factor(name, levels = c('Christmas', 
                                        'Indep', 
                                        'Other')))
dg
#>         date                         text      name
#> 1 2024-01-01   New Year's Day, 2024-01-01     Other
#> 2 2024-07-04 Independence Day, 2024-07-04     Indep
#> 3 2024-12-25    Christmas Day, 2024-12-25 Christmas
#> 4 2024-12-31   New Year's Eve, 2024-12-31     Other
#> 5 2025-01-01   New Year's Day, 2025-01-01     Other
#> 6 2025-07-04 Independence Day, 2025-07-04     Indep
#> 7 2025-12-25    Christmas Day, 2025-12-25 Christmas
#> 8 2025-12-31   New Year's Eve, 2025-12-31     Other

## Now make the timeline using ggrepel for the text
library(ggrepel) ## for  geom_text_repel() or geom_label_repel()

## Function for reverse date axes 
## Copied from https://github.com/tidyverse/ggplot2/issues/4014
## Will be used by pub. If you are using theme_pub instead of pub, 
## you will need this function and scale_y_continuous(trans = 'reverse2'). 
reverse2_trans <- function() {
  trans_new(
    "reverse2",
    function(x) -1 * as.numeric(x), # Force values to be numeric for Date objects
    function(x) -1 * as.numeric(x)
  )
}

## Define breaks, title, and plot
breaks = as.Date(paste0(current.year + 0:2, 
                        '-01-01'))

title = "Title in Upper Lower" ## to be used by ggplot and ggsave
g = ggplot(dg, 
           aes(x     = 0, 
               y     = date, 
               color = name, 
               label = text)) +
  geom_segment(aes(x    = 0, 
                   xend = 0, 
                   y    = min(date), 
                   yend = max(date)), 
               show.legend = F, 
               color       = publightgray) +
  geom_point(show.legend = F) +
  geom_label_repel(nudge_x     = 1,
                   hjust       = 0, 
                   direction   = 'y',
                   show.legend = F) +
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption, X handle, or shameless promotion of pubtheme",
       x = '',
       y = '') 

g %>% 
  pub(type    = 'timeline', 
      xlim    = c(0, 5), 
      ybreaks = breaks,
      ylabels = function(x) format(x, '%b %d, %Y'), 
      ytrans  = 'reverse2')

## Save to a file using base_size = 36
gg = g %>%
  pub(type      = 'timeline', 
      xlim      = c(0, 5), 
      ybreaks   = breaks,
      ylabels   = function(x) format(x, '%b %d, %Y'), 
      ytrans    = 'reverse2',
      base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), ## must have a subfolder called 'img'
       plot   = gg,  
       width  = 20,   ## do not change
       height = 30,   ## can change if you want. Here we made it longer to have more space
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

Default colors

This theme changes your default ggplot colors to those found in colors.r. The palette for discrete color scales scale_colour_discrete and scale_fill_discrete consists of red, blue, gray, light red, and light blue, as seen in the Line Plot above. Recall that if you want to undo the changes made by this theme, you can use restore.ggplot.defaults() at any time.

If more than 5-6 colors are needed, a 14-color colorblind friendly palette cb.pal can be used by adding + scale_color_manual(values = cb.pal) or + scale_fill_manual( values = cb.pal) to a plot. For example,

dg = mtcars %>%
  mutate(gear = paste0(gear, ' gear'), 
         cyl  = paste0(cyl , ' cyl'  ), 
         name = paste0(gear, ', ', cyl)) 

title = "Title in Upper Lower" ## to be used by ggplot and ggsave

g = ggplot(dg, 
           aes(x = wt, 
               y = mpg, 
               color = name)) +
  geom_point() +
  facet_grid(cyl ~ gear) +
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x     = 'Horizontal Axis Label in Upper Lower',
       y     = 'Vertical Axis Label in Upper Lower', 
       color = 'Gears and Cylinders') +
  scale_color_manual(values = cb.pal) +
  guides(color = guide_legend(nrow = 3))

g %>% 
  pub(xlim  = c(0, 6), 
      ylim  = c(0, 40), 
      facet = T)

Maps

dg = data.frame(city = c('New York', 'Los Angeles'), 
                lat  = c( 40.7128,   34.0522),
                lon  = c(-74.0060, -118.2437))

title = "Title in Upper Lower"
g = ggplot(dg, 
           aes(x = lon, 
               y = lat)) +
  borders('state', 
          colour = publightgray) +
  geom_point(color = pubred) +
  labs(title    = title, 
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme") 

g %>% 
  pub(type = 'map')

Hex bins

The function geom_hex can be used for making a heat map with hexagonal bins. Those can be colored by count.

dg = economics

title = 'Title in Upper Lower'

g = ggplot(dg, 
           aes(x = psavert, 
               y = uempmed)) +
  geom_hex(color = pubbackgray,
           bins  = 20, 
           show.legend = TRUE) +
  scale_fill_gradient(low      = pubbackgray,
                      high     = pubblue,
                      na.value = pubmediumgray,
                      oob      = squish,
                      limits = c(0,20),
                      breaks = c(0, 10, 20)
                      ) +
  guides(fill = guide_colourbar())+
  labs(title    = title, 
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme", 
       x    = 'Personal Savings Rate', 
       y    = 'Median Duration of Unemployment', 
       fill = 'Observations')

g %>% 
  pub(xlim = c(0, 20), 
      ylim = c(0, 30)) 

## Save to a file using base_size = 36
gg = g %>%
  pub(xlim      = c(0, 20), 
      ylim      = c(0, 30),
      base_size = 36)

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), ## must have a subfolder called 'img'
       plot   = gg,   
       width  = 20,   ## do not change
       height = 20,   ## can change from 20 if desired
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

If you want to size the hexagons by count, and color by another variable, the only way I know is to use geom_star with starshape = 'hexagon'. The following code creates some data with cell ID, cell location x and y, the count to be used for size, and a column mean.pop to be used for fill. This is a reasonable solution but it is not ideal and is still under development.

library(hexbin)
library(ggstar)

df = economics

h = hexbin(x     = df$psavert,
           y     = df$uempmed,
           xbins = 20, 
           IDs   = TRUE)

hh =  data.frame(hcell2xy(h),
                 cell  = h@cell,
                 count = h@count, 
                 xcm   = h@xcm, 
                 ycm   = h@ycm)
head(hh)
#>         x        y cell count      xcm  ycm
#> 1  9.7500 4.000000   11     2  9.90000 4.10
#> 2 10.5050 4.000000   12     4 10.40000 4.25
#> 3 11.2600 4.000000   13     3 11.23333 4.40
#> 4 12.0150 4.000000   14     3 11.83333 4.30
#> 5 13.5250 4.000000   16     1 13.30000 4.10
#> 6  4.8425 4.917987   25     1  4.50000 5.20

df$cell = h@cID

dg <- df %>%
  group_by(cell) %>%
  summarise(n   = n(),           ## for size
            pop = sum(pop)) %>%  ## for fill
  ungroup() %>%
  mutate(mean.pop = pop/n) %>%
  right_join(hh, 
             by = "cell") %>%
  select(cell, x, y, 
         count, n, 
         pop, mean.pop)

title = 'Title in Upper Lower'
g = ggplot(dg, 
           aes(x = x, 
               y = y, 
               fill = mean.pop, 
               size = n)) +
  geom_star(colour      = pubbackgray,
            starshape   = 'hexagon',
            show.legend = T) +
  labs(title    = title, 
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme", 
       x    = 'Personal Savings Rate', 
       y    = 'Median Duration of Unemployment', 
       size = 'Observations', 
       fill = 'Mean Population') +
  scale_fill_gradient(guide = 'legend', 
                      low   = publightgray, 
                      high  = pubblue) +
  guides(size = guide_legend(nrow = 3, 
                             override.aes = list(fill = pubdarkgray)), 
         fill = guide_legend(nrow = 2, 
                             override.aes = list(size = 5)))

g %>% 
  pub(xlim = c(0, 20), 
      ylim = c(0, 30)) +
  scale_size(range = c(1, 5)) ## adjust the max, and maybe the min, manually 

## Save to a file using base_size = 36
gg = g %>%
  pub(xlim      = c(0, 20), 
      ylim      = c(0, 30),
      base_size = 36) + 
  scale_size(range = c(1, 5)*3) ## same as above, but times 3

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), ## must have a subfolder called 'img'
       plot   = gg,   
       width  = 20,   ## do not change
       height = 20,   ## can change, but hexagons may look distorted
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

Images as labels

Let’s use the ggtext https://wilkelab.org/ggtext/ package to add images as labels.

First let’s choose a couple of images, and create a data frame with the image URLs, the country name and GDP per capita (taken from https://en.wikipedia.org/wiki/List_of_countries_by_GDP_(nominal)_per_capita on 11/21/2023).

First, let’s get a couple of PNG files from the web.

# us = 'https://upload.wikimedia.org/wikipedia/en/thumb/a/a4/Flag_of_the_United_States.svg/35px-Flag_of_the_United_States.svg.png'
# can = 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d9/Flag_of_Canada_%28Pantone%29.svg/35px-Flag_of_Canada_%28Pantone%29.svg.png'
# download.file(url = us , destfile = "img/US.png" , method='curl')
# download.file(url = can, destfile = "img/CAN.png", method='curl')

## if you need to write a PNG file from an image you can use `writePNG`
# us  = png::readPNG(us )
# can = png::readPNG(can)
# writePNG('img/US.png')
# writePNG('img/CAN.png')
library(ggtext)
us = 'img/US.png'
can = 'img/CAN.png'
df = data.frame(country = c('USA', 'Canada'), 
                GDP.per.cap = c(80412, 53247), 
                image   = c(us, can))
df
#>   country GDP.per.cap       image
#> 1     USA       80412  img/US.png
#> 2  Canada       53247 img/CAN.png

Now create some HTML code to display the images with the country names. You will likely need to change the width and height, but note that after saving the visualization to a file, the image will appear smaller than it appears on screen.

df = df %>% 
  mutate(label = paste0("<img src='", 
                          image, 
                          "' style = 'display:inline-block; vertical-align:middle' width='72' height='36'/>"))
df
#>   country GDP.per.cap       image
#> 1     USA       80412  img/US.png
#> 2  Canada       53247 img/CAN.png
#>                                                                                                   label
#> 1  <img src='img/US.png' style = 'display:inline-block; vertical-align:middle' width='72' height='36'/>
#> 2 <img src='img/CAN.png' style = 'display:inline-block; vertical-align:middle' width='72' height='36'/>

One way to add images is to use geom_image from ggimage. This results in a stretched looking image, but we’ll leave it here anyway.

library(ggimage)
title = "Title in Upper Lower" 
g = ggplot(df, 
           aes(x     = GDP.per.cap, 
               y     = country, 
               size  = .5,         ## these are constant put these in aes() anyway
               linewidth = .5)) +  ## so they change when base_size changes
  geom_point(color = pubred, 
             show.legend = F) + 
  geom_segment(aes(x    = 0, 
                   xend = GDP.per.cap, 
                   y    = country, 
                   yend = country), 
               color = pubred) +
  geom_image(aes(image = image), 
             size = .05, 
             by = 'height', 
             nudge_x = 12000) + 
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x = 'Horizontal Axis Label in Upper Lower', ## Optional. 
       y = NULL) +  ## Optional. Upper Lower.
  guides(size      = 'none', 
         linewidth = 'none')

g %>%
  pub(type = 'pop', 
      xlim = c(0, 100000)) 

## Save to a file using base_size = 36
gg = g %>%
  pub(type = 'pop', 
      xlim = c(0, 100000),
      base_size = 36) 

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), ## must have a subfolder called 'img'
       plot   = gg,
       width  = 20,   ## do not change
       height = 20,   ## can change from 20 if desired. We use 12 here because there are only 5 lollipops
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

Now we’ll use geom_richtext instead of geom_text to add labels to points. These images have a better aspect ratio.

title = "Title in Upper Lower" 
g = ggplot(df, 
           aes(x     = GDP.per.cap, 
               y     = country, 
               label = label, 
               size  = 10,         ## these are constant put these in aes() anyway
               linewidth = .5)) +  ## so they change when base_size changes
  geom_point(color = pubred, 
             show.legend = F) + 
  geom_segment(aes(x    = 0, 
                   xend = GDP.per.cap, 
                   y    = country, 
                   yend = country), 
               color = pubred) +
  geom_richtext(hjust = -0.2, 
                fill = NA, 
                label.color = NA) + 
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x = 'Horizontal Axis Label in Upper Lower', ## Optional. 
       y = NULL) +  ## Optional. Upper Lower.
  guides(size      = 'none', 
         linewidth = 'none')

g %>%
  pub(type = 'pop', 
      xlim = c(0, 100000),
      base_size = 12) + 
  theme(axis.text.y = element_markdown()) ## render the HTML code

## Save to a file using base_size = 36
gg = g %>%
  pub(type = 'pop', 
      xlim = c(0, 100000),
      base_size = 36) +
  theme(axis.text.y = element_markdown()) 

ggsave(filename = "img/flag.example.jpg", ## must have a subfolder called 'img'
       plot   = gg,
       width  = 20,   ## do not change
       height = 12,   ## can change from 20 if desired. We use 12 here because there are only 5 lollipops
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

The images are smaller and less fuzzy when saved using ggsave:

!(img/flag.example.jpg)

Images as axes labels

For this we can use label as the y-axis label and use theme(axis.text.y = element_markdown()) to render the HTML code.

title = "Title in Upper Lower" 
g = ggplot(df, 
           aes(x     = GDP.per.cap, 
               y     = label, 
               label = round(GDP.per.cap,2), 
               size  = 12,         ## these are constant put these in aes() anyway
               linewidth = .5)) +  ## so they change when base_size changes
  geom_point(color = pubred, 
             show.legend = F) + 
  geom_segment(aes(x    = 0, 
                   xend = GDP.per.cap, 
                   y    = label, 
                   yend = label), 
               color = pubred) +
  geom_text(hjust = -0.3) + ## optional numbers with reasonable number of digits
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x = 'Horizontal Axis Label in Upper Lower', ## Optional. 
       y = NULL) +  ## Optional. Upper Lower.
  guides(size      = 'none', 
         linewidth = 'none')

g %>%
  pub(type = 'pop', 
      xlim = c(0, 100000),
      base_size = 12) +
  theme(axis.text.y = element_markdown())

## Save to a file using base_size = 36
gg = g %>%
  pub(type = 'pop', 
      xlim = c(0, 100000),
      base_size = 36) +
  theme(axis.text.y = element_markdown())

ggsave(filename = paste0("img/", gsub("%", " Perc", title), ".jpg"), ## must have a subfolder called 'img'
       plot   = gg,
       width  = 20,   ## do not change
       height = 12,   ## can change from 20 if desired. We use 12 here because there are only 5 lollipops
       units  = 'in', ## do not change
       dpi    = 72)   ## do not change

plotly

You can use layout_pub to get similar formatting for plotly figures that use ggplotly or plot_ly. This is under development. Only using type = 'scatter' with plot_ly is currently supported. Others may work and will be added “soon”, according to some definition of “soon”.

Here is an example using plot_ly:

library(htmlwidgets)
dg = mtcars %>% 
  select(wt, 
         mpg, 
         cyl) %>%
  mutate(cyl = factor(cyl)) %>%
  rownames_to_column('name')

base_size = 12
p = plot_ly(data = dg,
            width  = 1440*base_size/36, 
            height = 1440*base_size/36) %>%
  add_trace(type   = 'scatter', 
            mode   = 'markers',
            x      = ~wt, 
            y      = ~mpg, 
            color  = ~cyl, 
            size   = ~mpg,
            text   = ~name,
            colors = default.pal[1:3], ## change 3 to number of categories
            marker = list(opacity = 1),# add size = 30*base_size/36 if no size above
            hovertemplate = paste0( 
              "<b>%{text}</b><br>",
              "%{yaxis.title.text}: %{y:,.3f}<br>",
              "%{xaxis.title.text}: %{x:,.2f}<br>",
              "<extra></extra>")) %>%
  layoutpub(type        = 'scatter', 
            base_size   = base_size, 
            subtitle    = T, 
            caption     = F, 
            legend.rows = 1) %>%
  layout(
    title = list(text = maketitle(title     = 'Title In Upper Lower',
                                  subtitle  = 'Optional Subtitle in Upper Lower',
                                  base_size = base_size)), 
    xaxis = list(title    = list(text = 'Wt'),
                 range    = c(0,    6),
                 tickvals = c(0, 3, 6)),
    yaxis = list(title    = list(text = 'MPG'), 
                 range    = c(0,     40), 
                 tickvals = c(0, 20, 40)), 
    legend = list(title = list(text = 'Cylinders'))
    )
print(p)

htmlwidgets::saveWidget(widget = p,
                        file   = paste0("img/", gsub("%", " Perc", title), ".html"),
                        libdir = "lib", 
                        selfcontained = F)

Click here or click on the image below to view the interactive version of the plot.

knitr::include_url("https://bmacgtpm.github.io/pubtheme/img/Title%20in%20Upper%20Lower.html")

Note that the subtitle and the caption at the bottom of the plot are currently not functioning properly.

ggplotly

Here is an example using ggplotly.

dg = mtcars %>% 
  select(wt, 
         mpg, 
         cyl) %>%
  mutate(Cylinders = as.factor(cyl)) %>%
  rename(MPG    = mpg, 
         Weight = wt) %>%
  rownames_to_column('name')

g = ggplot(dg,
           aes(x     = Weight, 
               y     = MPG, 
               color = Cylinders, 
               text  = name)) +
  geom_point() +
  labs(title    = title,
       subtitle = 'Optional Subtitle In Upper Lower',
       caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
       x    = 'Horizontal Axis Label in Upper Lower',
       y    = 'Vertical Axis Label in Upper Lower', 
       size = "MPG")

## Convert g to plotly using ggplotly
base_size = 12
p = g %>% 
  #labs(title = paste0('<b>', title, '</b>'))
  pub(xlim = c(0, 6),
      ylim = c(0, 40)) %>%
  ggplotly(width   = 1440*base_size/36, 
           height  = 1440*base_size/36, 
           tooltip = c('x', 'y', 'color', 'text')) %>%
  layoutpub(type      = 'scatter', 
            base_size = base_size, 
            subtitle  = T, 
            caption   = F, 
            legend.rows = 1) %>%
  style(marker.sizeref = 1.5)
p

htmlwidgets::saveWidget(widget = p,
                        file   = paste0("img/", gsub("%", " Perc", title), ".html"),
                        libdir = "lib",
                        selfcontained = F)

The plot isn’t interactive here. Run the code to see the interactive plot.

Note that the subtitle does not currently display. And the points in the legend are different sizes for some reason #shrugs.

As with non-interactive plots above, you can use pub to save a lot of typing if you are ok with accepting more default settings. If you use pub with int = TRUE (int for interactive), the ggplot object will be converted to a plotly object using the ggplotly and layoutpub code above. You’ll just need to specify the arguments subtitle, caption and legend.rows required by layoutpub. This is in development and works for this example but may not work for other plots.

g %>% 
  pub(xlim = c(0, 6),
      ylim = c(0, 40), 
      int  = T,
      tooltip = c('x', 'y', 'color', 'text'), 
      subtitle  = T, 
      caption   = F, 
      legend.rows = 1) 

If you want to customize the tooltip (e.g. when you are unable to specify the order that you want), you can create a text column that has the information you want, in the order that you want. You can also include HTML code to format the text.

In the example below, the car name is bolded using <b> </b>, and Weight, MPG, and Cylinders appear as additional information. The function tooltip.text helps make it easier. You can list unquoted column names in the order you want them. The entries in the tooltip are typically of the from “ColumnName: Value”. If there is a name column listed, it automatically makes it bold and removes name: from the tooltip, like this:

Toyota Corolla
Weight: 1.835
MPG: 33.9
Cylinders: 4

dg = mtcars %>% 
  select(wt, 
         mpg, 
         cyl) %>%
  mutate(Cylinders = as.factor(cyl)) %>%
  rename(MPG   = mpg, 
         Weight = wt) %>%
  rownames_to_column('name') %>%
  mutate(text = tooltip.text(name, 
                             Weight, 
                             MPG, 
                             Cylinders))

g = ggplot(dg,
           aes(x = Weight, 
               y = MPG, 
               color = Cylinders, 
               #size = MPG, ## this messes up the legend position or margins
               text = text)) +
geom_point() +
labs(title    = title,
     subtitle = 'Optional Subtitle In Upper Lower',
     caption  = "Optional caption giving more info, X handle, or shameless promotion of pubtheme",
     x    = 'Horizontal Axis Label in Upper Lower',
     y    = 'Vertical Axis Label in Upper Lower', 
     #size = "MPG"
     )

g %>% 
  pub(xlim        = c(0, 6),
      ylim        = c(0, 40), 
      int         = T,
      tooltip     = 'text',
      subtitle    = T, 
      caption     = F, 
      legend.rows = 1) %>%
  layout(legend = list(itemsizing = 'constant'))

About

`ggplot` and `plotly` themes for creating publication quality visualizations for web and mobile.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published