Search code examples
rggplot2bubble-chart

Bubble chart where the only metric is size and colour


I want to make a bubble chart like the one attached below.

Bubble chart

The idea is to have a ggplot style bubble chart where all I really want to control is the size and colour of the chart, with no real control over the position. The bubbles should just be clustered around each other with a specified radius that should keep them from touching.

Is there a specific ggplot function or R package that can do this for me? I'm sure it's possible to make one with geom_point() but one has to imagine that there is an easier way and I'd rather not do trig at this time of day.

Any pointers?

Another solution might be to use physics. Have all the bubbles attracted to each other by "gravity" and then make them stop when they get too close to each other. That might mean less maths involved. Even if there is a package for it, a quickly coded up version of that by someone more adept at the type of work than me would be nice to see.

Input should be something like this:

birds <- c("Eagle", "Owl", "Falcon", "Ostrich", "Blue Jay", "Chaffinch")
values <- c(43, 23, 54, 112, 16, 12)

df <- data.frame(birds, values)

Edit: I am certain this is going to be labelled as a repeat question but I have done my jolly hardest to find what I'm looking for online and on stack and I haven't found it. Please only mark as repetitive if you are SURE that it is. If you're not sure, just let someone else answer it.


Solution

  • Using the circle packing library as commented by @JonSpring, code modified from documentation

    df <- data.frame(birds = c("Eagle", "Owl", "Falcon", "Ostrich", "Blue Jay", "Chaffinch"),
                     values = c(43, 23, 54, 112, 16, 12))
    
    library(ggplot2)
    install.packages("packcircles")
    library(packcircles)
    
    df$packing <- circleProgressiveLayout(df$values, sizetype='area')
    
    df.gg <- circleLayoutVertices(df$packing, npoints=50)
    
    ggplot() + 
      geom_polygon(data = df.gg, aes(x, y, group = id, fill=id), alpha = 0.6)+
      scale_fill_viridis_c()+
      geom_text(data = df, aes(x=packing$x, y=packing$y, label = birds), size=5, color="black") +
      theme_void() + 
      theme(legend.position="none", plot.margin=unit(c(0,0,0,0),"cm") ) + 
      coord_equal()
    

    enter image description here

    Original answer:

    From a reframe the question perspective, the wordcloud library can avoid overlapping text:

    df <- data.frame(birds = c("Eagle", "Owl", "Falcon", "Ostrich", "Blue Jay", "Chaffinch"),
                     values = c(43, 23, 54, 112, 16, 12))
    install.packages("wordcloud")
    library(wordcloud)
    wordcloud(df$birds, df$values, colors=brewer.pal(8,"Dark2"))
    

    enter image description here