Take the 2-minute tour ×

I just came by the following plot:

alt text

And wondered how can it be done in R? (or other softwares)

Update 10.03.11: Thank you everyone who participated in answering this question - you gave wonderful solutions! I've compiled all the solution presented here (as well as some others I've came by online) in a post on my blog.

share|improve this question

migrated from stats.stackexchange.com Sep 19 '12 at 14:18


This is maybe a stupid comment, but what does the position of dots suppose to mean? –  mbq Sep 1 '10 at 14:52
It wasn't a stupid comment because the answer to how to plot that is plot(x,y). I'm sure mbq was trying to get at the idea that what you're trying to do may be something other than a simple scatter plot. –  John Sep 1 '10 at 16:41
It's also something other than a simple violin plot since that's supposed to be symmetric around the vertical axis. –  John Sep 1 '10 at 17:01
@Tal, @John -- I know how standard vioplot works, but I can't figure out how those points were obtained (and as I see not only me, while it is crucial for producing good answer) -- some kind of stem? Or maybe someone just thought that filling vioplot with distorted polka dots is a good idea? –  mbq Sep 1 '10 at 19:51
OK, I found what the software was. It's a "column scatter plot" made in GraphPad Prism. See for instance graphpad.com/help/prism5/… . I found some reference to those also here: originlab.com/www/products/… –  nico Sep 2 '10 at 16:38

4 Answers 4

up vote 9 down vote accepted

Make.Funny.Plot does more or less what I think it should do. To be adapted according to your own needs, and might be optimized a bit, but this should be a nice start.

Make.Funny.Plot <- function(x){
    unique.vals <- length(unique(x))
    N <- length(x)
    N.val <- min(N/20,unique.vals)

      x <- ave(x,cut(x,N.val),FUN=min)
      x <- signif(x,4)
    # construct the outline of the plot
    outline <- as.vector(table(x))
    outline <- outline/max(outline)

    # determine some correction to make the V shape,
    # based on the range
    y.corr <- diff(range(x))*0.05

    # Get the unique values
    yval <- sort(unique(x))


    for(i in 1:length(yval)){
        n <- sum(x==yval[i])
        x.plot <- seq(-outline[i],outline[i],length=n)
        y.plot <- yval[i]+abs(x.plot)*y.corr

N <- 500
x <- rpois(N,4)+abs(rnorm(N))

EDIT : corrected so it always works.

share|improve this answer
Found one problem with it: If cut returns an empty level, you get an error. –  Joris Meys Sep 2 '10 at 13:03
Nice plot anyway! –  chl Sep 2 '10 at 13:10
+1 Good job! Still I think something is missing -- that original plot is asymmetric. –  mbq Sep 2 '10 at 13:17
@mbq? Something missing? I just optimized that original plot. It's not a bug, it's a feature! ;-) –  Joris Meys Sep 2 '10 at 13:20
@Joris Maybe try using cut2 from Hmisc instead of cut? –  chl Sep 2 '10 at 13:35

I recently came upon the beeswarm package, that bears some similarity.


Here's an example:

  beeswarm(time_survival ~ event_survival, data = breast,
    method = 'smile',
    pch = 16, pwcol = as.numeric(ER),
    xlab = '', ylab = 'Follow-up time (months)',
    labels = c('Censored', 'Metastasis'))
  legend('topright', legend = levels(breast$ER),
    title = 'ER', pch = 16, col = 1:2)

share|improve this answer
Wonderful finding! –  chl Oct 14 '10 at 15:56
Very interesting Shane, thank you. –  Tal Galili Oct 14 '10 at 16:05

I have come up with the code similar to Joris, still I think this is more than a stem plot; here I mean that they y value in each series is a absolute value of a distance to the in-bin mean, and x value is more about whether the value is lower or higher than mean.
Example code (sometimes throws warnings but works):


#Cutting in bins

#Calculate the means over bins
sapply(levels(p),function(i) mean(x[p==i]))->meansl;

#Calculate the mins over bins
sapply(levels(p),function(i) min(x[p==i]))->minl;

#Each dot is one value.
#X is an order of a value inside bin, moved so that the values lower than bin mean go below 0
for(e in levels(p)) X[p==e]<-(1:sum(p==e))-1-sum((x-means)[p==e]<0);
#Y is a bin minum + absolute value of a difference between value and its bin mean
share|improve this answer
Thank you mbq, I was wondering who's answer to pick. I choose Joris, simply since he wrapped it up. Either way - both answers are great and won my +1 vote. Cheers - Tal –  Tal Galili Sep 3 '10 at 11:24
@Tal I agree.... –  mbq Sep 3 '10 at 13:35

Try the vioplot package:


(with awful default color ;-)

There is also wvioplot() in the wvioplot package, for weighted violin plot, and beanplot, which combines violin and rug plots. They are also available through the lattice package, see ?panel.violin.

share|improve this answer
That doesn't produce a scatterplot, does it? –  Shane Sep 1 '10 at 13:58
@Shane no, it's just a variation of the boxplot with an added kernel density estimate –  chl Sep 1 '10 at 14:13
@Shane @Tal BTW, Box-percentile plot are better (bpplot in the Hmisc package). –  chl Sep 1 '10 at 14:16
Hi chl. Thank you for the answer. I remember coming by that function, but as Shane said - it doesn't produce the scatter plot element. I'll +1 for the good intentions - but will keep this question open :). Cheers, Tal –  Tal Galili Sep 1 '10 at 14:16
@Tal Well, I'll try to figure out myself how to make it in R; I think it would not be so difficult using stripchart() or a jittering procedure. –  chl Sep 1 '10 at 14:46

Your Answer


