简体   繁体   中英

Floating bar chart with trend line on secondary axis

I am just tarting out trying to create visualizations with R/GGPLOT2. The chart I am trying to acheive is a floating bar chart(one that has the bar go from one minimum to a maximum). However, overlayed on top of this I would like a trend line that is on a secondary axis. This has been my attempt so far:

# first, your data
table1 <- read.table(text = 'X  A  B  C  D  E  F  G  H  I  J  K  L
                  1      "BAR TOP" 31.5 31.8 30.3 28.0 24.9 24.4 21.7 20.9 24.5 25.4 26.0 28.7
                  2      "TREND VALUE" 1000 1345 1234 1456 1324 1765 1567 1345 1556 1334 1224 1556
                  3      "BAR BOTTOM"  4.0  5.6  4.1 -1.3  0.0 -3.1 -2.6 -1.4 -0.8  2.0  2.7  4.1', header =T)


library(reshape2)
library(ggplot2)
# reshape to wide format (basically transposing the data.frame)
w <- dcast(melt(table1), variable~X)
p<-ggplot(w, aes(x=variable,ymin = `BAR BOTTOM`, 
          ymax = `BAR TOP`, lower = `BAR BOTTOM`, 
          upper = `BAR TOP`, middle = `BAR BOTTOM`)) + 
geom_boxplot(stat = 'identity') 

p <- p + labs(y = "BAR RANGE",
          x = "VARIABLE",
          colour = "Parameter")
p <- p + theme(legend.position = c(0.8, 0.9))
p

This is getting my the bars how I want them, however I am having trouble using the value TREND VALUE as a trend line on a secondary axis. Any advice or direction?

I would suggest manually transform TREND VALUE into desired range and specify sec.axis with same transformation. I also will use geom_rect() instead of geom_boxplot() :

p <- ggplot(w) +
  aes(ymin = `BAR BOTTOM`,
      ymax = `BAR TOP`,
      xmin = as.numeric(variable) - .3,
      xmax = as.numeric(variable) + .3,
      x = as.numeric(variable),
      # Here we (roughly) transform `TREND VALUE` into range of BAR values
      y = `TREND VALUE`/100 
  ) +
  geom_rect(fill = 'white', col = 'black')+
  geom_line() + 
  scale_x_continuous(labels = levels(w$variable),
                     breaks = 1:nlevels(w$variable))+
  # Specification for secondary axis - inverse transform of `TREND VALUE`
  scale_y_continuous(sec.axis = ~.*100) 

Resulting plot:

p

在此输入图像描述

EDIT

Answering comment: we can specify almost any transformation:

Transform x values into range, mn - new minimum value, mx - new maximum:

trans_foo <- function(x, mn, mx) {
  (mx - mn)*((x - min(x))/(max(x) - min(x))) + mn
}

Back transformation:

itrans_foo <- function(y, min_x, max_x, mn, mx) {
  min_x + ((y - mn)*(max_x - min_x))/(mx - mn)
}

Now using this functions with mx = 0 and mn = 30 (minimum and maximum of the reversed BAR axis) & scale_y_reverse() , we will get the reversed primary axis and the normal secondary axis:

p <- ggplot(w) +
  aes(
    ymin = `BAR BOTTOM`,
    ymax = `BAR TOP`,
    xmin = as.numeric(variable) - .3,
    xmax = as.numeric(variable) + .3,
    x = as.numeric(variable),
    y = trans_foo(
      `TREND VALUE`,
      30, 0)
  ) +
  geom_rect(fill = "white", col = "black") +
  geom_line() +
  scale_x_continuous(
    labels = levels(w$variable),
    breaks = 1:nlevels(w$variable)) +
  labs(
    y = "BAR RANGE",
    x = "VARIABLE",
    colour = "Parameter") +
  # Using scale_y_reverse will reverse the primary axis and
  # reverse the reversed secondary axis making it normal
  scale_y_reverse(sec.axis = sec_axis(
    trans = ~itrans_foo(
      .,
      min(w$`TREND VALUE`),
      max(w$`TREND VALUE`),
      30, 0
    ),
    name = "TREND"))

p

在此输入图像描述

You can try to add a loess smoothed line with geom_smooth. In order to get it on the same axis, just rescale it.

    p<-ggplot(w, aes(x=variable,ymin = `BAR BOTTOM`, 
             ymax = `BAR TOP`, lower = `BAR BOTTOM`, 
             upper = `BAR TOP`, middle = `BAR BOTTOM`)) + 
             geom_boxplot(stat = 'identity') 
             + geom_smooth(aes(x = as.numeric(w$variable), y = w$`TREND VALUE`/100))

This will not result in a different axis, but dividing by 100 makes it easy to interpret still.

See example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM