How to draw gauge chart in R?

后端 未结 4 895
臣服心动
臣服心动 2021-01-30 19:08

How can i draw a following plot in R?

  Red = 30
  Yellow = 40
  Green = 30 

  Needle at 52. 

Pls help me out as i am in great need.

4条回答
  •  你的背包
    2021-01-30 19:28

    Here's a very quick and dirty implementation using grid graphics

    library(grid)
    
    draw.gauge<-function(x, from=0, to=100, breaks=3, 
        label=NULL, axis=TRUE, cols=c("red","yellow","green")) {
    
        if (length(breaks)==1) {
            breaks <- seq(0, 1, length.out=breaks+1)
        } else {
            breaks <- (breaks-from)/(to-from)
        }
        stopifnot(length(breaks) == (length(cols)+1))
    
        arch<-function(theta.start, theta.end, r1=1, r2=.5, col="grey", n=100) {
            t<-seq(theta.start, theta.end, length.out=n)
            t<-(1-t)*pi
            x<-c(r1*cos(t), r2*cos(rev(t)))
            y<-c(r1*sin(t), r2*sin(rev(t)))
            grid.polygon(x,y, default.units="native", gp=gpar(fill=col))
        }
        tick<-function(theta, r, w=.01) {
            t<-(1-theta)*pi
            x<-c(r*cos(t-w), r*cos(t+w), 0) 
            y<-c(r*sin(t-w), r*sin(t+w), 0) 
            grid.polygon(x,y, default.units="native", gp=gpar(fill="grey"))
        }
        addlabel<-function(m, theta, r) {
            t<-(1-theta)*pi      
            x<-r*cos(t)
            y<-r*sin(t) 
            grid.text(m,x,y, default.units="native")
        }
    
        pushViewport(viewport(w=.8, h=.40, xscale=c(-1,1), yscale=c(0,1)))
        bp <- split(t(embed(breaks, 2)), 1:2)
        do.call(Map, list(arch, theta.start=bp[[1]],theta.end=bp[[2]], col=cols))
        p<-(x-from)/(to-from)
        if (!is.null(axis)) {
                if(is.logical(axis) && axis) {
                m <- round(breaks*(to-from)+from,0)
                } else if (is.function(axis)) {
                m <- axis(breaks, from, to)
                } else if(is.character(axis)) {
                m <- axis
                } else {
                       m <- character(0)
                }
            if(length(m)>0) addlabel(m, breaks, 1.10)
        }
        tick(p, 1.03)
        if(!is.null(label)) {
                if(is.logical(label) && label) {
                m <- x
                } else if (is.function(label)) {
                m <- label(x)
                } else {
                m <- label
                }
                addlabel(m, p, 1.15)
        }
        upViewport()
    }
    

    This function can be used to draw one gauge

    grid.newpage()
    draw.gauge(100*runif(1))
    

    or many gauges

    grid.newpage()
    pushViewport(viewport(layout=grid.layout(2,2)))
    for(i in 1:4) {
        pushViewport(viewport(layout.pos.col=(i-1) %/%2 +1, layout.pos.row=(i-1) %% 2 + 1))
        draw.gauge(100*runif(1))
        upViewport()
    }
    popViewport()
    

    It's not too fancy so it should be easy to customize.

    enter image description here

    You can now also add a label

    draw.gauge(75, label="75%")
    

    enter image description here

    I've added another update to allow for drawing an "axis". You can set it to TRUE to use default values, or you can pass in a character vector to give whatever labels you want, or you can pass in a function that will take the breaks (scaled 0-1) and the from/to values and should return a character value.

    grid.newpage()
    draw.gauge(100*runif(1), breaks=c(0,30,70,100), axis=T)
    

    enter image description here

提交回复
热议问题