Search code examples
rbubble-chart

Create bubble chart with biggest bubble at the center


I'm trying to create a bubble chart using a set of data as follows:

X --> 10
Y --> 20
Z --> 5
Q --> 10

I simply need to have the biggest bubble (based on its number) to be at the centre (give or take) and the rest of the bubbles be around it without overlapping.

All of the R examples I have seen require a two dimensional dataset, and since the data I have are only one dimensional, I like to know if it's at all possible to create such graphs in R.

It would be great if someone could suggest me some useful hints or so. By the way for this task I need to use a SA tools so something like d3js is out of options. However, I am open to using a tool other than R.

I wasn't quite sure if this question should be asked in On Stack Overflow or Cross Validated, so if moderators believe it doesn't belong here, I'll remove it.


Solution

  • This should do, the main idea being that you sort by the value of the radius, so the first is the biggest, then shift the values around it (odd on one side, even on the other) so that the values are decreasing both ways.

    Further explanations in the code.

    library(plotrix)
    library(RColorBrewer)
    
    # Set the random seed, to get reproducible results
    set.seed(54321)
    
    # Generate some random values for the radius
    num.circles <- 11
    rd <- runif(num.circles, 1, 20)
    
    df <- data.frame(labels=paste("Lbl", 1:num.circles), radius=rd)
    
    # Sort by descending radius. The biggest circle is always row 1
    df <- df[rev(order(df$radius)),]
    
    # Now we want to put the biggest circle in the middle and the others on either side
    # To do so we reorder the data frame taking the even values first reversed, then the odd values.
    # This ensure the biggest circle is in the middle
    
    df <- df[c(rev(seq(2, num.circles, 2)), seq(1, num.circles, 2)),]
    
    # Space between the circles. 0.2 * average radius seems OK
    space.between <- 0.2 * mean(df$radius)
    
    # Creat an empty plot
    plot(0, 0, "n", axes=FALSE, bty="n", xlab="", ylab="", 
         xlim=c(0, sum(df$radius)*2+space.between*num.circles),
         ylim=c(0, 2.5 * max(df$radius)))
    
    # Draw the circle at half the height of the biggest circle (plus some padding)
    xx <- 0
    mid.y <- max(df$radius) * 1.25
    
    # Some nice degrading tones of blue
    colors <- colorRampPalette(brewer.pal(8,"Blues"))(num.circles/2)
    
    for (i in 1:nrow(df))
      {
      row <- df[i,]
      x <- xx + row$radius + i*space.between
      y <- mid.y
    
      # Draw the circle
      draw.circle(x, y, row$radius, 
                  col=colors[abs(num.circles/2-i)])
      # Add the label
      text(x, y, row$labels, cex=0.6)
    
      # Update current x position
      xx <- xx + row$radius * 2
      }
    

    The result: circles

    Live version on RFiddle.