How to change scale during making a new geom using ggplot2 in R?

I'd like to make a new geom geom_spine() : This geom is similar with geom_bar() but the barwidth varies depending on the count.

Here is what I tried.

require(ggplot2)

"%||%" <- function(a, b) {
     if (!is.null(a)) a else b
}

geom_spine <- function(mapping = NULL, data = NULL,
                   stat = "count", position = "fill",
                   color="black",size=0.2,
                   ...,
                   width = NULL,
                   binwidth = NULL,
                   na.rm = FALSE,
                   show.legend = NA,
                   inherit.aes = TRUE) {

 layer(
      data = data,
      mapping = mapping,
      stat = stat,
      geom = GeomSpine,
      position = position,
      show.legend = show.legend,
      inherit.aes = inherit.aes,
      params = list(
           width = width,
           na.rm = na.rm,
           color=color,
           size=size,
           ...
      )
 )

}

colcount=function(data){
     result=c() 
     myx=unique(data$x)
     for(i in 1:length(myx)) result=c(result,sum(data[data$x==myx[i],"count"]))
     result                                     
 }
GeomSpine <- ggproto("GeomSpine", GeomRect,
                 required_aes = c("x", "y"),

                 setup_data = function(data, params) {

                      data$width <- data$width %||%
                           params$width %||% (resolution(data$x, FALSE) * 0.9)

                      sumc<-c(0,colcount(data))
                      sumc<-cumsum(sumc)
                      total<-sum(data$y)/(length(unique(data$x))+1)

                      data1<-transform(data,
                                       ymin = pmin(y, 0), ymax = pmax(y, 0),
                                       xmin=sumc[x]+(sumc[x+1]-sumc[x])*(1- width)/2,xmax=sumc[x+1]-sumc[x+1]*(1-width)/2)
                      data<-transform(data1,
                                       xmin=xmin/total,xmax=xmax/total,          
                                       x=(xmin+xmax)/(2*total), width=xmax-xmin
                      )
                      data

                 },

                 draw_panel = function(self, data, panel_scales, coord, width = NULL) {

                      ggproto_parent(GeomRect,self)$draw_panel(data, panel_scales, coord)
                 }
)

With this code, I am able to draw this plot. But I am not able to position the x labels in the middle of bar.

ggplot(data=mpg,aes(x=drv,fill=factor(cyl)))+geom_spine() + 
scale_fill_brewer(palette="Blues")

How to change to continuous scale with this geom?

This package might be a solution:
https://cran.r-project.org/web/packages/ggmosaic/vignettes/ggmosaic.html

1 Like

Hi @martin.R @cardiomoon,
I don't have an easy solution atm, but you might check out these two issues in the ggplot2 repo which are fairly similar, and the workarounds used (e.g. position dodging).

@mara, it was @cardiomoon who was asking!

1 Like

Whoops, sorry! See, this is why you should have profile pictures! It makes it much harder for me to mix up "brown-ish circle with letter in the middle" people…

Thanks, Martin.