I'm trying to build a plot in R with 2 Y-axis. It is a rather regular task in Excel, but a good adventure in R.
So, here is my dataset:
| Date | Latvia | Lithuania | Poland | Russian Federation | Ukraine |
|---|---|---|---|---|---|
| 2012 | 77.21 | 67.97 | 72.97 | 71.41 | 148.29 |
| 2013 | 75.40 | 65.62 | 72.83 | 71.03 | 149.45 |
| 2014 | 75.10 | 63.86 | 71.55 | 72.95 | 153.65 |
| 2015 | 68.77 | 59.54 | 65.86 | 71.61 | 162.92 |
| 2016 | 64.80 | 55.83 | 62.14 | 69.70 | 154.51 |
| 2017 | 63.81 | 54.14 | 60.80 | 70.29 | 153.99 |
| 2018 | 62.88 | 53.31 | 59.62 | 70.82 | 153.07 |
| 2019 | 62.36 | 51.94 | 58.12 | 71.18 | 150.26 |
| 2020 | 63.89 | 51.69 | 58.94 | 73.00 | 154.26 |
| 1Q2021 | 65.36 | 51.25 | 57.78 | 72.69 | 156.25 |
I need to build a chart with 5 lines:
- data points for Latvia, Lithuania, Poland and Russia on one Y axis,
- data points for Ukraine - on another.
I use the following part of the code to read and prepare the data for the chart:
- Rear data from the Excel file:
data_3.2 <- read.xlsx(
"BEO_charts.xlsx",
sheet = 22,
rows = c(25:33),
cols = c(2:7),
colNames = FALSE,
skipEmptyRows = TRUE,
skipEmptyCols = TRUE,
detectDates = TRUE
)
colnames(data_3.2) <- c(
"date",
"Latvia",
"Lithuania",
"Poland",
"RF",
"Ukraine"
)
- Then I prepare a dataset for the part of the chart with 4 data points for the primary Y axis:
p3.2left <-
subset.data.frame(
data_3.2,
select = c(
"date",
"Latvia",
"Lithuania",
"Poland",
"RF")
) %>%
melt(
id.vars = 'date',
variable.name = "GDP_var",
value.name = "GDP_val",
measure.vars = c(
"Latvia",
"Lithuania",
"Poland",
"RF")
) %>%
ggplot(
aes (
x = date,
y= GDP_val,
group = GDP_var,
colour = GDP_var
)
) +
scale_y_continuous(limits = c(50,80), breaks = seq(50,80,5), expand = c(0.025,0), position = "left")+
#scale_x_date(date_breaks = )
labs (x = "", y = "") +
geom_line(size = 1)+
scale_colour_manual (
guide = "legend",
name = NULL,
breaks = c(
"Latvia",
"Lithuania",
"Poland",
"RF"),
labels = c(
"Латвия (левая ось)",
"Литва (левая ось)",
"Польша (левая ось)",
"Россия (левая ось)"),
values = c(
"#332288",
"#88CCEE",
"#44AA99",
"#117733"
)) +
theme(
axis.text.x = element_text(angle = 90, vjust = .5, size = 5, colour = "black"),
axis.text.y = element_text(size = 5, colour = "black"),
panel.background = element_rect(fill = NA),
panel.grid = element_blank(),
axis.line.y = element_line(colour= "#ABABAB"),
axis.ticks.length = unit(0,"cm"),
axis.title.y = element_text(size = 5, angle = 90, colour = "black", margin = margin(t = 0, r = 0, b = 0, l = 0)),
legend.position = "bottom",
legend.direction = "vertical",
legend.title = element_blank(),
legend.spacing.x = unit(0,"cm"),
legend.key = element_blank(),
legend.key.height = unit(.5, "cm"),
legend.text = element_text(size = 5),
legend.background = element_rect(fill = "transparent", colour = NA),
legend.box.margin = unit (c(-9,1,1,1), "mm"),
plot.margin = unit (c(0,5,0,0), "mm")
)
- Then - for data points for the secondary Y axis:
p3.2right <-
subset.data.frame(
data_3.2,
select = c(
"date",
"Ukraine")
) %>%
ggplot(
aes (
x = date,
y= Ukraine,
colour = "#999933"
)
) +
scale_y_continuous(limits = c(145,165), breaks = seq(145,165,5), expand = c(0.025,0)) +
scale_x_date(date_labels = "%Y", date_breaks = "1 year") +
geom_line(size = 1)+
scale_colour_identity (
guide = "legend",
label = "Украина (правая ось)",
) +
labs(x=NULL, y=NULL) +
theme(
axis.text.x = element_text(angle = 90, vjust = .5, size = 5, colour = "black"),
axis.text.y = element_text(size = 5, colour = "black"),
panel.background = element_rect(fill = NA),
panel.grid = element_blank(),
axis.line.y = element_line(colour= "#ABABAB"),
axis.ticks.length = unit(0,"cm"),
axis.title.y = element_text(size = 5, angle = 90, colour = "black", margin = margin(t = 0, r = 0, b = 0, l = 0)),
legend.position = "bottom",
legend.direction = "vertical",
legend.title = element_blank(),
legend.spacing.x = unit(0,"cm"),
legend.key = element_blank(),
legend.key.height = unit(.5, "cm"),
legend.text = element_text(size = 5),
legend.box.margin = unit (c(0,1,1,1), "mm"),
plot.margin = unit (c(0,5,0,0), "mm")
)
- And finally I used the code that worked nicely before (but for some reasons stopped working now) that did what I need - put 2 plots on one chart:
# extract gtable
g1 <- ggplot_gtable(ggplot_build(p3.2left))
g2 <- ggplot_gtable(ggplot_build(p3.2right))
# overlap the panel of 2nd plot on that of 1st plot
pp <- c(subset(g1$layout, name == "panel", se = t:r))
g <- gtable_add_grob(g1, g2$grobs[[which(g2$layout$name == "panel")]], pp$t,
pp$l, pp$b, pp$l)
# axis tweaks
ia <- which(g2$layout$name == "axis-r")
ga <- g2$grobs[[ia]]
ax <- ga$children[[2]]
ax$widths <- rev(ax$widths)
ax$grobs <- rev(ax$grobs)
g <- gtable_add_cols(g, g2$widths[g2$layout[ia, ]$l], length(g$widths) - 1)
g <- gtable_add_grob(g, ax, pp$t, length(g$widths) - 1, pp$b)
#add legend to the code
leg1 <- g1$grobs[[which(g1$layout$name == "guide-box")]]
leg2 <- g2$grobs[[which(g2$layout$name == "guide-box")]]
leg = gtable:::cbind_gtable(leg1, leg2, "first")
leg$widths[5:6] = unit(0, "cm")
g$grobs[[which(g$layout$name == "guide-box")]] <-
gtable:::cbind_gtable(leg1, leg2, "first")
grid.draw(g)
I got the following error in the following line of the code:
g <- gtable_add_grob(g, ax, pp$t, length(g$widths) - 1, pp$b)
Error: grobs must either be a single grob or a list of grobs
I'm not good at 'gtable' package of R and would appreciate any support in correcting my code (or workflow) so that to finally build this chart and enhance my programming skills in R.
P.S. I use R (Version 1.4.1717) on Ubuntu 20.04.2 LTS

If all you want is a secondary y axis for the Ukraine data, then the following might solve the problem.
In order to make the main point more clear, I have simplified the code and removed the
scale_color_manualand thethemefrom the plotting code. Instead, I have created a variable for the color and a custom theme.The trick is to precompute a scaling factor
mult.Color
Custom theme
Data