Search code examples
rggplot2plot

How to create a plot with dual X-axes using ggplot2 in R?


I am trying to create a plot in R that displays two overlapping X-axes:

  • One for Semana TW (Weeks of This Year).
  • One for Semana LY (Weeks of Last Year). The goal is to compare the sales from the last 7 weeks with the sales from the same weeks in the previous year, but shifted 3 weeks forward (this is why I have three zero sales in the Semana TW column).

I was able to create this chart in Python using matplotlib, but I need to replicate it in R using ggplot2 or another plotting library. Here is the chart I generated in Python: enter image description here

And this is the data table I used:

Semana TW Semana LY Venta TW Venta LY
W1 WA 1000 1100
W2 WB 800 700
W3 WC 900 1000
W4 WD 1000 1100
W5 WE 1100 1000
W6 WF 1000 1100
W7 WG 900 1000
W8 WH 0 1100
W9 WI 0 1000
W10 WJ 0 1200

In R i tried this code, that gives me a similar result, but its not what im looking for:

library(ggplot2)
library(tidyr)

# Data setup with correct sorting for Semana TW
Semana_TW <- factor(c('W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8', 'W9', 'W10'), levels = c('W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8', 'W9', 'W10'))
Semana_LY <- c('WA', 'WB', 'WC', 'WD', 'WE', 'WF', 'WG', 'WH', 'WI', 'WJ')
Venta_TW <- c(1000, 800, 900, 1000, 1100, 1000, 900, 0, 0, 0)
Venta_LY <- c(1100, 700, 1000, 1100, 1000, 1100, 1000, 1100, 1000, 1200)

# Create the initial data frames for Semana TW and Semana LY
df_TW <- data.frame(Semana = Semana_TW, Ventas_TW = Venta_TW)
df_LY <- data.frame(Semana = Semana_LY, Ventas_LY = Venta_LY)

# Merge the two datasets
df_combined <- data.frame(
  Semana_TW = Semana_TW,
  Semana_LY = Semana_LY,
  Ventas_TW = Venta_TW,
  Ventas_LY = Venta_LY
)

# Convert the data into long format for ggplot (for easy plotting of both series)
df_combined_long <- pivot_longer(df_combined, cols = c("Ventas_TW", "Ventas_LY"), 
                                 names_to = "Tipo_Venta", values_to = "Ventas")

# Create the plot using ggplot2
ggplot(df_combined_long, aes(x = Semana_TW, y = Ventas, color = Tipo_Venta, group = Tipo_Venta)) +
  geom_line() + # Create the line connecting the points
  geom_point() + # Add points for each week
  labs(title = "Ventas Semanas TW vs LY", x = "Semana TW", y = "Ventas") +
  theme_minimal() +
  scale_color_manual(values = c("Ventas_TW" = "blue", "Ventas_LY" = "red")) +
  geom_text(aes(label = Semana_LY), vjust = -1, hjust = 1.1, angle = 45) + # Annotate with Semana LY values
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

enter image description here


Solution

  • We can use a continuous x-scale with the sec.axis argument:

    ggplot(
      df_combined_long, 
      aes(x = as.numeric(Semana_TW), y = Ventas, color = Tipo_Venta, group = Tipo_Venta)
    ) +
      geom_line() + # Create the line connecting the points
      geom_point() + # Add points for each week
      labs(title = "Ventas Semanas TW vs LY", x = "Semana TW", y = "Ventas") +
      theme_minimal() +
      scale_color_manual(values = c("Ventas_TW" = "blue", "Ventas_LY" = "red")) +
      scale_x_continuous(
        breaks = 1:nlevels(Semana_TW),
        labels = Semana_TW,
        sec.axis = sec_axis(I, breaks = 1:nlevels(Semana_TW), labels = Semana_LY)
      ) +
        theme(
        axis.text.x = element_text(angle = 45, hjust = 1),
        axis.text.x.top = element_text(angle = 45, hjust = 0)
      )
    

    enter image description here