library(rio)library(data.table)library(ggplot2)library(forcats)library(waffle)library(ggtext)library(showtext)library(patchwork)library(ggsankey)library(dplyr) # somehow ggsankey needs dplyr and does not import it# get datadat <-import("https://nyc3.digitaloceanspaces.com/owid-public/data/energy/owid-energy-data.csv")setDT(dat)# round down to the nearest decaderound_to_decade <-function(year) {return(year - year %%10)}# energy sources and colorsenergy_sources <-c("Coal"="coal_consumption","Oil"="oil_consumption","Gas"="gas_consumption","Hydro"="hydro_consumption","Nuclear"="nuclear_consumption","Biofuel"="biofuel_consumption","Solar"="solar_consumption","Wind"="wind_consumption","Other Renewables"="other_renewable_consumption")energy_colors =c("Coal"="#444239FF", # very dark coal grey"Oil"="#035F72FF","Gas"="#D77186FF","Hydro"="#A4B7E1FF","Nuclear"="#E69F00","Biofuel"="#B0986CFF","Solar"="#F8D564FF","Wind"="#56B4E9","Other Renewables"="#1BB6AFFF")#------ Fontsfont_add_google("Roboto Condensed", "Roboto Condensed")showtext_auto()showtext_opts(dpi =600)body_font <-"Roboto Condensed"title_font <-"Roboto Condensed"#------ WAFFLE PLOT (original)# sum consumption for France by source, every 10 years from 1960 to 2020dat_sum <- dat[ year >=1960& year <=2020& country =="France",lapply(.SD, function(x) sum(x, na.rm =TRUE)), .SDcols =c("biofuel_consumption","coal_consumption","gas_consumption","hydro_consumption","nuclear_consumption","oil_consumption","other_renewable_consumption","solar_consumption","wind_consumption" ), by = .(country, decade =round_to_decade(year))]# pivot longerdat_sum <-melt(dat_sum, id.vars =c("country", "decade"))# Ccnsumption per year as perc of totaldat_sum[, perc := (value /sum(value)) *100, by = .(country, decade)]# Rrmove NAdat_sum <-na.omit(dat_sum, cols ="perc")# ensure sum=100 for each decadedat_sum[, perc_int :=as.integer(round(perc))][, perc_int := { current_sum <-sum(perc_int)if (current_sum !=100) { diff <-100- current_sum perc_int[which.max(value)] <- perc_int[which.max(value)] + diff } perc_int }, by = decade][ perc_int >0]
country decade variable value perc perc_int
<char> <num> <fctr> <num> <num> <int>
1: France 2010 biofuel_consumption 312.373 1.1008956 1
2: France 2020 biofuel_consumption 30.800 1.2616927 1
3: France 1960 coal_consumption 2384.688 32.1562993 32
4: France 1970 coal_consumption 3588.287 17.0100900 17
5: France 1980 coal_consumption 2907.669 12.1153299 12
6: France 1990 coal_consumption 1938.677 6.6809346 7
7: France 2000 coal_consumption 1535.992 4.9443497 5
8: France 2010 coal_consumption 1143.226 4.0290694 4
9: France 2020 coal_consumption 55.982 2.2932493 2
10: France 1960 gas_consumption 319.189 4.3041006 4
11: France 1970 gas_consumption 1709.201 8.1023795 8
12: France 1980 gas_consumption 2718.536 11.3272730 11
13: France 1990 gas_consumption 3500.476 12.0630982 12
14: France 2000 gas_consumption 4509.500 14.5160554 15
15: France 2010 gas_consumption 4366.272 15.3880448 15
16: France 2020 gas_consumption 405.828 16.6243576 17
17: France 1960 hydro_consumption 732.836 9.8819190 10
18: France 1970 hydro_consumption 1709.349 8.1030811 8
19: France 1980 hydro_consumption 1967.835 8.1993412 8
20: France 1990 hydro_consumption 1956.482 6.7422929 7
21: France 2000 hydro_consumption 1741.802 5.6068509 6
22: France 2010 hydro_consumption 1576.686 5.5567117 6
23: France 2020 hydro_consumption 162.052 6.6383059 7
24: France 1970 nuclear_consumption 514.926 2.4409802 2
25: France 1980 nuclear_consumption 5488.373 22.8683009 23
26: France 1990 nuclear_consumption 10397.571 35.8313899 36
27: France 2000 nuclear_consumption 12001.427 38.6325267 39
28: France 2010 nuclear_consumption 10915.617 38.4698900 38
29: France 2020 nuclear_consumption 891.721 36.5285018 37
30: France 1960 oil_consumption 3938.314 53.1061521 54
31: France 1970 oil_consumption 13527.223 64.1251052 65
32: France 1980 oil_consumption 10865.304 45.2722585 46
33: France 1990 oil_consumption 11135.164 38.3732319 38
34: France 2000 oil_consumption 10987.830 35.3697636 35
35: France 2010 oil_consumption 9127.721 32.1688112 32
36: France 2020 oil_consumption 728.389 29.8377619 30
37: France 2010 other_renewable_consumption 221.419 0.7803466 1
38: France 2020 other_renewable_consumption 28.128 1.1522367 1
39: France 2010 solar_consumption 171.060 0.6028665 1
40: France 2020 solar_consumption 33.396 1.3680353 1
41: France 2010 wind_consumption 540.069 1.9033642 2
42: France 2020 wind_consumption 104.869 4.2958587 4
country decade variable value perc perc_int
Code
# add levels and order by energy_sourcesdat_sum <- dat_sum[, variable :=factor(fct_recode(variable, !!!energy_sources),levels =names(energy_sources) )]setorder(dat_sum, decade, variable)# Create waffle plotwaffle_plot <-ggplot(dat_sum, aes(fill = variable, values = perc_int)) +geom_waffle(color ="white",size =0.2,n_rows =5,flip =TRUE,make_proportional =FALSE ) +facet_wrap(~decade, nrow =1, strip.position ="bottom") +theme_minimal() +labs(title ="A Proportional Picture: France's Energy Mix by Decade ...",y ="Percentage (%)" ) +scale_x_discrete() +scale_y_continuous(labels =function(x) x *5,expand =c(0, 0) ) +scale_fill_manual(values = energy_colors,breaks =names(energy_sources),name ="Energy Source",drop =FALSE ) +theme(text =element_text(family = body_font),panel.grid =element_blank(),axis.title =element_blank(),axis.text.x =element_text(family = body_font, size =10),strip.text =element_text(family = body_font, size =10),legend.position ="none",plot.title =element_textbox_simple(hjust =0.5,size =12,family = title_font,margin =margin(b =30) ),plot.background =element_rect(color ="white", fill ="white"),plot.margin =unit(c(30, 30, 30, 30), "pt") )#------ YEARLY FOSSIL ENERGY PLOTS# prep yearly data for all sourcesyearly_all <- dat[ year >=1960& year <=2020& country =="France",lapply(.SD, function(x) sum(x, na.rm =TRUE)), .SDcols = energy_sources, by = .(year)]# melt to long formatyearly_long <-melt( yearly_all,id.vars ="year",measure.vars = energy_sources,variable.name ="energy_type",value.name ="consumption")yearly_long[, energy_type :=factor( energy_type,levels = energy_sources,labels =names(energy_sources) )]# assign color: fossil in color, others greyfossil_types <-c("Coal", "Oil", "Gas", "Nuclear")# factor for energy_type with non-fossils first, fossils lastyearly_long$energy_type <-factor( yearly_long$energy_type,levels =c(setdiff(levels(yearly_long$energy_type), fossil_types), fossil_types ))# reorder the data so non-fossils come first, fossils lastyearly_long <- yearly_long[order(yearly_long$energy_type), ]color_map <-setNames(ifelse(names(energy_sources) %in% fossil_types, energy_colors[names(energy_sources)],"grey80" ),names(energy_sources))# calculate percentage of each source in total per yearyearly_long[, perc :=100* consumption /sum(consumption), by = year]# area chart (actually a sankey): absolute consumption by type (fossil in color, rest grey)area_plot <-ggplot( yearly_long[year %in%c(1960, 1970, 1980, 1990, 2000, 2010, 2020)],aes(x = year,node = energy_type,fill = energy_type,value = consumption )) +geom_sankey_bump(space =0,type ="alluvial",color ="transparent",smooth =6,alpha =0.8 ) +scale_fill_manual(values = color_map) +scale_x_continuous(breaks = scales::pretty_breaks(), expand =c(0, 0)) +scale_y_continuous(labels = scales::comma, expand =c(0, 0)) +labs(title ="... Eventually, Proportions Hinder Gross Total Consumption Increase (or Not-So-Much Decrease)",x =NULL,y ="Consumption (TWh)" ) +theme_minimal() +theme(text =element_text(family = body_font),axis.text =element_text(size =10),panel.grid.minor =element_blank(),plot.title =element_textbox_simple(hjust =0.5,size =12,family = title_font,margin =margin(b =20) ),legend.position ="none",plot.margin =unit(c(30, 30, 30, 30), "pt") )# line chart: share of each energy source in total (fossil + nuclear in color, rest grey)line_plot <-ggplot(yearly_long, aes(x = year, y = perc, color = energy_type)) +geom_line(size =1) +scale_color_manual(values = color_map) +scale_x_continuous(breaks = scales::pretty_breaks(), expand =c(0, 0)) +labs(title ="... Visualizing The Proportional Shift Differently: The Decline of Coal and Oil, the Rise of Gas, and the Rapid Expansion of Nuclear ...",x =NULL,y ="Percentage (%)" ) +theme_minimal() +theme(text =element_text(family = body_font),axis.text =element_text(size =10),panel.grid.minor =element_blank(),plot.title =element_textbox_simple(hjust =0.5,size =12,family = title_font,margin =margin(b =20) ),legend.position ="none",plot.margin =unit(c(30, 30, 30, 30), "pt") )#------ Title and text# old subtitlesubtitle_text <- glue::glue("In the 1960s, only <span style='color:{energy_colors['Coal']};'><strong>coal</strong></span>, <span style='color:{energy_colors['Oil']};'><strong>oil</strong></span>, <span style='color:{energy_colors['Gas']};'><strong>gas</strong></span>, and <span style='color:{energy_colors['Hydro']};'><strong>hydro</strong></span> were part of the French primary energy consumption mix. By the 2020s, <span style='color:{energy_colors['Nuclear']};'><strong>nuclear</strong></span> energy became a player for almost 40%, and other sources appeared such as <span style='color:{energy_colors['Biofuel']};'><strong>biofuel</strong></span>, <span style='color:{energy_colors['Solar']};'><strong>solar</strong></span>, <span style='color:{energy_colors['Wind']};'><strong>wind</strong></span>, and <span style='color:{energy_colors['Other Renewables']};'><strong>other renewable energy</strong></span>. The French model for energy is singular. In 1973, nuclear power already accounted for 8% of the production of French electricity.")# captioncaption_text <- glue::glue(" <span style='font-size:11pt; color:#777777'> Each square on the right chart represents 1% of total energy consumption for each decade from 1960 to 2020. These are proportions of total terawatt hours (TWh) consumed. Data: Our World in Data | Viz: @gnoblet </span>")# rectangles paramymin_1stline <-0.20ymax_1stline <-0.24ymin_2ndline <-0.08ymax_2ndline <-0.13text_y_1stline <-0.18text_y_2ndline <-0.07text_size <-3.5# overall title and text paneltext_panel <-ggplot() +geom_textbox(aes(x =0,y =1,halign =0,valign =1,label = glue::glue("<span style='font-size:22pt; font-weight:bold'>60 Years of France's Primary Energy Consumption </span> <br><br> <span style='font-size:14pt'> Primary energy consumption measures the total energy used within a country, based on energy sources at the point of extraction or generation, and covers direct uses like electricity, heating, and transport. It does <b>not</b> include the energy embedded in imported goods and services. <br><br> {subtitle_text} <br><br> {caption_text} <br><br> <span style='font-size:12pt;font-weight:bold'>Primary energy sources:</span>" ),box.color =NA ),box.padding =unit(c(0, 0, 0, 0), "pt"),box.margin = grid::unit(c(0, 0, 0, 0), "pt"),box.r =unit(0, "pt"),fill =NA,hjust =0,vjust =1,lineheight =1.1,width =unit(0.95, "npc"),family = body_font ) +# Add rectangle legends - Row 1annotate("rect",xmin =0.1,xmax =0.17,ymin = ymin_1stline,ymax = ymax_1stline,fill = energy_colors["Coal"] ) +annotate("rect",xmin =0.25,xmax =0.32,ymin = ymin_1stline,ymax = ymax_1stline,fill = energy_colors["Oil"] ) +annotate("rect",xmin =0.4,xmax =0.47,ymin = ymin_1stline,ymax = ymax_1stline,fill = energy_colors["Gas"] ) +annotate("rect",xmin =0.55,xmax =0.62,ymin = ymin_1stline,ymax = ymax_1stline,fill = energy_colors["Hydro"] ) +annotate("rect",xmin =0.7,xmax =0.77,ymin = ymin_1stline,ymax = ymax_1stline,fill = energy_colors["Nuclear"] ) +# Row 2annotate("rect",xmin =0.1,xmax =0.17,ymin = ymin_2ndline,ymax = ymax_2ndline,fill = energy_colors["Biofuel"] ) +annotate("rect",xmin =0.25,xmax =0.32,ymin = ymin_2ndline,ymax = ymax_2ndline,fill = energy_colors["Solar"] ) +annotate("rect",xmin =0.4,xmax =0.47,ymin = ymin_2ndline,ymax = ymax_2ndline,fill = energy_colors["Wind"] ) +annotate("rect",xmin =0.55,xmax =0.62,ymin = ymin_2ndline,ymax = ymax_2ndline,fill = energy_colors["Other Renewables"] ) +# Labels - Row 1annotate("text",x =0.135,y = text_y_1stline,label ="Coal",color = energy_colors["Coal"],size = text_size,fontface ="bold",family = body_font,vjust =1 ) +annotate("text",x =0.285,y = text_y_1stline,label ="Oil",color = energy_colors["Oil"],size = text_size,fontface ="bold",family = body_font,vjust =1 ) +annotate("text",x =0.435,y = text_y_1stline,label ="Gas",color = energy_colors["Gas"],size = text_size,fontface ="bold",family = body_font,vjust =1 ) +annotate("text",x =0.585,y = text_y_1stline,label ="Hydro",color = energy_colors["Hydro"],size = text_size,fontface ="bold",family = body_font,vjust =1 ) +annotate("text",x =0.735,y = text_y_1stline,label ="Nuclear",color = energy_colors["Nuclear"],size = text_size,fontface ="bold",family = body_font,vjust =1 ) +# Labels - Row 2annotate("text",x =0.135,y = text_y_2ndline,label ="Biofuel",color = energy_colors["Biofuel"],size = text_size,fontface ="bold",family = body_font,vjust =1 ) +annotate("text",x =0.285,y = text_y_2ndline,label ="Solar",color = energy_colors["Solar"],size = text_size,fontface ="bold",family = body_font,vjust =1 ) +annotate("text",x =0.435,y = text_y_2ndline,label ="Wind",color = energy_colors["Wind"],size = text_size,fontface ="bold",family = body_font,vjust =1 ) +annotate("text",x =0.585,y = text_y_2ndline,label ="Other\nRenewables",color = energy_colors["Other Renewables"],size = text_size,fontface ="bold",family = body_font,vjust =1 ) +theme_void() +theme(plot.background =element_rect(fill ="white", color =NA),plot.margin =unit(c(0, 0, 0, 0), "pt"),axis.title =element_blank(),axis.text =element_blank(),axis.ticks =element_blank() ) +coord_cartesian(xlim =c(0, 1), ylim =c(0, 1), expand =FALSE)#------ Combine all plots with patchwork# 2x2 layoutcombined_plot <- (text_panel + waffle_plot) / (line_plot + area_plot)plot_annotation(theme =theme(plot.background =element_rect(fill ="white", color =NA) ))
This visualization presents France’s primary energy consumption over 60 years (1960-2020) using multiple complementary chart types to highlight different aspects of the same data.
Data source: Our World in Data - Energy Consumption
The visualization combines four different panels to tell a complete story about energy consumption trends: a text panel explaining the context, a waffle chart showing proportional energy mix by decade, a line chart tracking the percentage contribution of each energy source over time, and an area chart displaying absolute consumption values. This multi-chart approach addresses the limitations of proportional visualizations by showing both relative and absolute changes simultaneously, highlighting how the French energy model’s transition to nuclear power has evolved since the 1970s.