Ggplot With 2 Y Axes on Each Side and Different Scales

ggplot with 2 y axes on each side and different scales

Sometimes a client wants two y scales. Giving them the "flawed" speech is often pointless. But I do like the ggplot2 insistence on doing things the right way. I am sure that ggplot is in fact educating the average user about proper visualization techniques.

Maybe you can use faceting and scale free to compare the two data series? - e.g. look here: https://github.com/hadley/ggplot2/wiki/Align-two-plots-on-a-page

ggplot with 2 y axes on each side and different scales for different data

You should try this:

geom_line(aes(y = INJ*15, color = UWI))

You will get:

output

It is hard to distinguish 34 shades of color in my plot. Also, you can try multiplying by 10 or 20.

two y-axes with different scales for two datasets in ggplot2

Up front, this type of graph is a good example of why it took so long to get a second axis into ggplot2: it can very easily be confusing, leading to mis-interpretations. As such, I'll go to pains here to provide multiple indicators of what goes where.

First, the use of sec_axis requires a transformation on the original axis. This is typically done in the form of an intercept/slope formula such as ~ 2*. + 10, where the period indicates the value to scale. In this case, I think we could get away with simply ~ 2*.

However, this implies that you need to plot all data on the original axis, meaning you need d2$y to be pre-scaled to d1$y's limits. Simple enough, you just need the reverse transformation as what will be used in sec_axis.

I'm going to combine the data into a single data.frame, though, in order to use ggplot2's grouping.

d1 = data.frame(x=c(100, 200, 300, 400), y=seq(0.1, 0.4, by=0.1)) # 1st dataset
d2 = data.frame(x=c(100, 200, 300, 400), y=seq(0.8, 0.5, by=-0.1)) # 2nd dataset
d1$z <- "data1"
d2$z <- "data2"
d3 <- within(d2, { y = y/2 })
d4 <- rbind(d1, d3)
d4
# x y z
# 1 100 0.10 data1
# 2 200 0.20 data1
# 3 300 0.30 data1
# 4 400 0.40 data1
# 5 100 0.40 data2
# 6 200 0.35 data2
# 7 300 0.30 data2
# 8 400 0.25 data2

In order to control color in all components, I'll set it manually:

mycolors <- c("data1"="blue", "data2"="red")

Finally, the plot:

library(ggplot2)
ggplot(d4, aes(x=x, y=y, group=z, color=z)) +
geom_path() +
geom_point() +
scale_y_continuous(name="data1", sec.axis = sec_axis(~ 2*., name="data2")) +
scale_color_manual(name="z", values = mycolors) +
theme(
axis.title.y = element_text(color = mycolors["data1"]),
axis.text.y = element_text(color = mycolors["data1"]),
axis.title.y.right = element_text(color = mycolors["data2"]),
axis.text.y.right = element_text(color = mycolors["data2"])
)

sample graphic with two axes

Frankly, though, I don't like the different slopes. That is, two blocks on the blue axis are 0.1, whereas on the red axis they are 0.2. If you're talking about two vastly different "things", then this may be fine. If, however, the slopes of the two lines are directly comparable, then you might prefer to keep the size of each block to be the same. For this, we'll use a transformation of just an intercept, no change in slope. That means the in-data.frame transformation could be y = y - 0.4, and the plot complement ~ . + 0.4, producing:

another sample graphic with two axes

PS: hints taken from https://stackoverflow.com/a/45683665/3358272 and https://stackoverflow.com/a/6920045/3358272

How to draw dual y-axis in ggplot with different y ranges?

Does this do what you want?
ggplot2 is an opinionated framework, and one of those opinions is that secondary axes should be avoided. While it allows them, it requires some manual work from the user to put all series in terms of the main axis, and then allows a secondary axis as an annotation.

ggplot(data=data, aes(x = x)) +
geom_line(aes(y = y1), colour="red") +
geom_line(aes(y = y2 / 15), colour="blue") +
scale_y_continuous(sec.axis = ~.*15)+
theme(axis.text.y.left = element_text(color = "red"),
axis.text.y.right = element_text(color = "blue"))

Sample Image

Data on secondary axis in GGPlot

Thanks to the link provided, I was able to answer the question. The code here worked:

ggplot with 2 y axes on each side and different scales

R - How to plot ggplot2 with two y axes on different scales *with time variables

One approach would be to convert the time to decimal hours (or minutes, etc.) and adjust the scale labels:

library(dplyr);  library(lubridate)
a %>%
# tidyr::gather(type, time, -date) %>%
tidyr::pivot_longer(-date, "type", "time") %>% # Preferred syntax since tidyr 1.0.0
mutate(time_dec = hour(value) + minute(value)/60 + second(value)/3600,
time_scaled = time_dec * if_else(type == "mile", 30, 1)) %>%
ggplot() +
geom_point(aes(x=date, y=time_scaled, group=value, color = type)) +
scale_y_continuous(breaks = 0:3,
labels = c("0", "1:00", "2:00", "3:00"),
name = "Marathon",
sec.axis = sec_axis(~./30,
name = "Mile",
breaks = (1/60)*0:100,
labels = 0:100)) +
expand_limits(y = c(1.5,3)) +
transition_reveal(date)

Sample Image

How to plot a second y axis for one category in the data?

The way to think about a secondary axis is that it is just an annotation. The actual data you are plotting needs to be transformed so it fits in the same scale as the rest of your data.

In your case, this means you need to divide all the c values by 100 to plot them, and draw a secondary axis that is transformed to show numbers 100 times larger:

ggplot(within(df.melt, value[variable == 'c'] <- value[variable == 'c']/100),
aes(xVal, value, colour = variable)) +
geom_point() +
geom_line() +
scale_y_continuous(sec.axis = sec_axis(~.x*100, name = "Values (c)")) +
theme(axis.text.y.right = element_text(color = "red"),
axis.ticks.y.right = element_line(color = "red"),
axis.title.y.right = element_text(color = "red"))

Sample Image



Related Topics



Leave a reply



Submit