Bubblecloud Plots in ggplot2

How to make a Bubblecloud Plots using ggplotly with Plotly.


New to Plotly?

Plotly is a free and open-source graphing library for R. We recommend you read our Getting Started guide for the latest installation or upgrade instructions, then move on to our Plotly Fundamentals tutorials or dive straight in to some Basic Charts tutorials.

Basic Text Graph

Sources: International IDEA for national turnout and European Parliament for European turnout, while regional classifications are based on EuroVoc.

recent_turnout <- read.csv("https://raw.githubusercontent.com/plotly/datasets/master/european_turnout.csv",stringsAsFactors = FALSE)
recent_turnout$region <- factor(recent_turnout$region, levels=c("British","Northern","Western","Mediterranean","Central/Eastern"))

library(plotly)
p <- recent_turnout %>%
  ggplot(aes(x=nat_turnout,y=euro_turnout)) + 
  geom_text(aes(size=population/3.5, label=abbreviation, colour=region), alpha=1) +
  labs(title = "Recent turnout in European Union countries",
       x = "Latest legislative or presidential election (whichever had higher turnout)",
       y = "May 2019 European Parliament election")
fig <- ggplotly(p)

fig

Overlaid Points

Colour-coding the text itself might present readability issues. Another possible use of geom_text is to keep the text grey, but overlay it on a coloured point graph.

Adding the text option within aes() allows us to control the text that appears when hovering over a point.

recent_turnout <- read.csv("https://raw.githubusercontent.com/plotly/datasets/master/european_turnout.csv",stringsAsFactors = FALSE)
recent_turnout$region <- factor(recent_turnout$region, levels=c("British","Northern","Western","Mediterranean","Central/Eastern"))

library(plotly)
p <- recent_turnout %>%
  ggplot(aes(x=nat_turnout,y=euro_turnout)) + 
  geom_point(aes(size=population, colour=region, text=paste("country:", country)), alpha=0.4) +
  geom_text(aes(size=population/3.5, label=abbreviation), colour="gray20", alpha=1) +
  labs(title = "Recent turnout in European Union countries",
       x = "Latest legislative or presidential election (whichever had higher turnout)",
       y = "May 2019 European Parliament election")
fig <- ggplotly(p)

fig

Customed Colour and Size Scale

Let's use the LaCroixColoR package to spruce up the colour scheme. In addition, by using scale_size_continuous, we can make sure that none of the text is too small.

recent_turnout <- read.csv("https://raw.githubusercontent.com/plotly/datasets/master/european_turnout.csv",stringsAsFactors = FALSE)
recent_turnout$region <- factor(recent_turnout$region, levels=c("British","Northern","Western","Mediterranean","Central/Eastern"))

library(plotly)
library(LaCroixColoR)
p <- recent_turnout %>%
  ggplot(aes(x=nat_turnout,y=euro_turnout)) + 
  geom_point(aes(size=population, colour=region, text=paste("country:", country)), alpha=0.4) +
  geom_text(aes(size=population/3.5, label=abbreviation), colour="gray20", alpha=1) +
  scale_colour_manual(values=lacroix_palette(n=6, name="PeachPear")) +
  scale_size_continuous(range = c(3, 8)) +
  labs(title = "Recent turnout in European Union countries",
       x = "Latest legislative or presidential election (whichever had higher turnout)",
       y = "May 2019 European Parliament election")
fig <- ggplotly(p)

fig

Adding a regression

Adding a regression line as well as a label. geom_smooth does not allow for adjusting the transparency of the line (using alpha), which is why stat_smooth is used here. annotate is used to include a single text label (geom_text would create one label for every data point, all overlapped with each other).

recent_turnout <- read.csv("https://raw.githubusercontent.com/plotly/datasets/master/european_turnout.csv",stringsAsFactors = FALSE)
recent_turnout$region <- factor(recent_turnout$region, levels=c("British","Northern","Western","Mediterranean","Central/Eastern"))
m <- lm(euro_turnout ~ nat_turnout, data = recent_turnout)

library(plotly)
library(LaCroixColoR)
p <- recent_turnout %>%
  ggplot(aes(x=nat_turnout,y=euro_turnout)) + 
  stat_smooth(geom="line", method="lm", alpha=0.3, se=FALSE) + 
  geom_point(aes(size=population, colour=region, text=paste("country:", country)), alpha=0.4) +
  geom_text(aes(size=population/3.5, label=abbreviation), colour="gray20", alpha=1) +
  scale_colour_manual(values=lacroix_palette(n=6, name="PeachPear")) +
  scale_size_continuous(range = c(3, 8)) +
  labs(title = "Recent turnout in European Union countries",
       x = "Latest legislative or presidential election (whichever had higher turnout)",
       y = "May 2019 European Parliament election") +
  annotate(geom="text", x=60, y=80, label = paste("European turnout = \n",
                                                  round(unname(coef(m)[2]),2),
                                                  "x national turnout",
                                                  round(unname(coef(m)[1]),1)))
fig <- ggplotly(p)

fig

Customized Formatting

Changed the font of the geom_text and of the graph (these must be done separately!), corrected the size label, centre-aligned the title.

recent_turnout <- read.csv("https://raw.githubusercontent.com/plotly/datasets/master/european_turnout.csv",stringsAsFactors = FALSE)
recent_turnout$region <- factor(recent_turnout$region, levels=c("British","Northern","Western","Mediterranean","Central/Eastern"))
m <- lm(euro_turnout ~ nat_turnout, data = recent_turnout)

library(plotly)
library(LaCroixColoR)
p <- recent_turnout %>%
  ggplot(aes(x=nat_turnout,y=euro_turnout)) + 
  stat_smooth(geom="line", method="lm", alpha=0.3, se=FALSE) + 
  geom_point(aes(size=population, colour=region, text=paste("country:", country)), alpha=0.4) +
  geom_text(aes(size=population/3.5, label=abbreviation), colour="gray20", alpha=1, family="Fira Sans") +
  scale_colour_manual(values=lacroix_palette(n=6, name="PeachPear")) +
  scale_size_continuous(range = c(3, 8)) +
  labs(title = "Recent turnout in European Union countries",
       x = "Latest legislative or presidential election (whichever had higher turnout)",
       y = "May 2019 European Parliament election",
       size = "") +
  annotate(geom="text", x=60, y=80, label = paste("European turnout = \n",
                                                  round(unname(coef(m)[2]),2),
                                                  "x national turnout",
                                                  round(unname(coef(m)[1]),1))) +
  theme(plot.title = element_text(hjust = 0.5)) +
  guides(size=guide_legend(""), fill = FALSE) +
  theme(text = element_text(family = 'Fira Sans'))
fig <- ggplotly(p)

fig

What About Dash?

Dash for R is an open-source framework for building analytical applications, with no Javascript required, and it is tightly integrated with the Plotly graphing library.

Learn about how to install Dash for R at https://dashr.plot.ly/installation.

Everywhere in this page that you see fig, you can display the same figure in a Dash for R application by passing it to the figure argument of the Graph component from the built-in dashCoreComponents package like this:

library(plotly)

fig <- plot_ly() 
# fig <- fig %>% add_trace( ... )
# fig <- fig %>% layout( ... ) 

library(dash)
library(dashCoreComponents)
library(dashHtmlComponents)

app <- Dash$new()
app$layout(
    htmlDiv(
        list(
            dccGraph(figure=fig) 
        )
     )
)

app$run_server(debug=TRUE, dev_tools_hot_reload=FALSE)