library(tidyverse) library(patchwork)

air_monthly <- airquality %>% mutate( Month = factor( month.abb[Month], levels = month.abb[5:9] ) ) %>% group_by(Month) %>% summarise( Avg_Ozone = mean(Ozone, na.rm = TRUE), Avg_Temp = mean(Temp, na.rm = TRUE), .groups = “drop” )

scale_factor <- max(air_monthly\(Avg_Temp) / max(air_monthly\)Avg_Ozone)

dual_axis_chart <- ggplot(air_monthly, aes(x = Month)) + geom_col( aes(y = Avg_Temp, fill = “Average temperature”), width = 0.65, alpha = 0.75 ) + geom_line( aes( y = Avg_Ozone * scale_factor, color = “Average ozone”, group = 1 ), linewidth = 1.4 ) + geom_point( aes( y = Avg_Ozone * scale_factor, color = “Average ozone” ), size = 3 ) + scale_y_continuous( name = “Average temperature (°F)”, sec.axis = sec_axis( trans = ~ . / scale_factor, name = “Average ozone (ppb)” ) ) + scale_fill_manual( values = c(“Average temperature” = “#56B4E9”) ) + scale_color_manual( values = c(“Average ozone” = “#D55E00”) ) + labs( title = “Monthly Temperature and Ozone Levels”, subtitle = “Dual-axis bar and line chart”, x = NULL, fill = NULL, color = NULL, caption = “Source: R airquality dataset” ) + theme_minimal(base_size = 13) + theme( legend.position = “bottom”, panel.grid.minor = element_blank(), axis.title.y.left = element_text(color = “#0072B2”), axis.title.y.right = element_text(color = “#D55E00”) )

dual_axis_chart

temperature_chart <- ggplot( air_monthly, aes(x = Month, y = Avg_Temp) ) + geom_col( fill = “#56B4E9”, width = 0.65 ) + geom_text( aes(label = round(Avg_Temp, 1)), vjust = -0.4, size = 3.5 ) + scale_y_continuous( limits = c(0, 95), expand = expansion(mult = c(0, 0.08)) ) + labs( title = “Average Monthly Temperature”, x = NULL, y = “Temperature (°F)” ) + theme_minimal(base_size = 12) + theme( panel.grid.minor = element_blank(), axis.text.x = element_blank(), axis.ticks.x = element_blank() )

ozone_chart <- ggplot( air_monthly, aes(x = Month, y = Avg_Ozone, group = 1) ) + geom_area( fill = “#E69F00”, alpha = 0.25 ) + geom_line( color = “#D55E00”, linewidth = 1.3 ) + geom_point( color = “#D55E00”, size = 3 ) + geom_text( aes(label = round(Avg_Ozone, 1)), vjust = -0.8, size = 3.5 ) + scale_y_continuous( limits = c(0, 70), expand = expansion(mult = c(0, 0.1)) ) + labs( title = “Average Monthly Ozone”, x = “Month”, y = “Ozone (ppb)”, caption = “Source: R airquality dataset” ) + theme_minimal(base_size = 12) + theme( panel.grid.minor = element_blank() )

small_multiples_chart <- temperature_chart / ozone_chart + plot_annotation( title = “Monthly Temperature and Ozone Levels”, subtitle = “Aligned small-multiple combination chart” )

small_multiples_chart

ggsave( “dual_axis_airquality.png”, plot = dual_axis_chart, width = 10, height = 6, dpi = 300 )

ggsave( “small_multiples_airquality.png”, plot = small_multiples_chart, width = 10, height = 8, dpi = 300 )