Load data
library(tidyverse)
library(DT) # library to create tables
library(scales) # library to format dollars
library(RColorBrewer)
is_outlier <- function(x) {
return(x < quantile(x, 0.25, na.rm = T) - 1.5 * IQR(x, na.rm = T) | x > quantile(x, 0.75, na.rm = T) + 1.5 * IQR(x, na.rm = T))
}
daily_full <- read.csv("./output/kwh_daily_2026-03-12.csv") %>%
mutate(date = as_date(date)) # convert back to date
joined_full <- read.csv("./output/kwh_annual_2026-03-12.csv")
total <- joined_full %>%
filter(meter != "Submeter" & type != "Res Hall - U" & type != "Production") %>%
summarize(kwh = sum(kwh, na.rm = T),
kwh_corr = sum(kwh_corr, na.rm = T),
sqft = sum(sqft, na.rm = T)) %>%
mutate(kwh_sqft = kwh_corr/sqft,
meter = "Total")
buildings <- read.csv("./keys/fy25_building_list_updated.csv") %>%
mutate(meter = ifelse(weis_meter == 1, "Weis Meter",
ifelse(main_meter == 0 & weis_meter == 0, "Individually Metered", "Main Meter")))
# store conversion factors
dollars_kwh <- 0.08138507
co2_kg_kwh <- 0.30082405
# summarize # buildings by meter status
bldg_sum <- buildings %>%
group_by(meter) %>%
summarize(number = n())
bldg_tot <- bldg_sum %>%
summarize(number = sum(number)) %>%
mutate(meter = "Total")
bldg_comb <- rbind(bldg_sum, bldg_tot)
# generate summary for Main, Weis, and Individual meters
joined_agg <- joined_full %>%
ungroup() %>%
filter(meter != "Submeter" & type != "Res Hall - U" & type != "Production") %>%
group_by(meter) %>%
summarize(kwh = sum(kwh, na.rm = T),
kwh_corr = sum(kwh_corr, na.rm = T),
sqft = sum(sqft, na.rm = T)) %>%
mutate(kwh_sqft = kwh_corr/sqft) %>%
rbind(total) %>%
mutate(dollars = kwh_corr*dollars_kwh,
ghg_MTCO2 = (kwh_corr*co2_kg_kwh)/1000) %>%
select(-kwh) %>%
arrange(kwh_corr)
joined_agg$meter <- factor(joined_agg$meter,
levels = c("Main Meter - Total",
"Weis Meter - Total",
"Individual", "Total"),
labels = c("Main Meter", "Weis Meter",
"Individually Metered","Total"))
joined_tot <- joined_agg %>%
left_join(bldg_comb, by = "meter")
# generate summary by building category for individually metered buildings
joined_cat <- joined_full %>%
filter(meter %in% c("Individual","Submeter")) %>%
mutate(kwh_sqft = kwh_corr/sqft, # calculate kwh per sqft
kwh_person = kwh_corr/occupants,
dollars = kwh_corr*dollars_kwh,
ghg_kgCO2 = kwh_corr*co2_kg_kwh) %>%
group_by(type) %>%
summarize(n = n(),
kwh = sum(kwh_corr),
dollars = sum(dollars),
ghg_kgCO2 = sum(ghg_kgCO2),
sqft = median(sqft, na.rm = T),
med_kwh_sqft = median(kwh_sqft, na.rm = T),
kwh_sqft_25 = quantile(kwh_sqft, .25, na.rm = T),
kwh_sqft_75 = quantile(kwh_sqft, .75, na.rm = T)) %>%
arrange(-kwh)
Electricity use summary
joined_pretty_tot <- joined_tot %>%
mutate(kwh = round(kwh_corr, digits = 0),
dollars = paste("$",round(dollars, digits = 0)),
ghg_MTCO2 = round(ghg_MTCO2, digits = 0),
sqft = round(sqft, digits = 0),
kwh_sqft = round(kwh_sqft, digits = 1)) %>%
select(meter, number, sqft, kwh, dollars, ghg_MTCO2, kwh_sqft) %>%
arrange(kwh)
joined_pretty_cat <- joined_cat %>%
mutate(kwh = round(kwh, digits = 0),
dollars = paste("$",round(dollars, digits = 0)),
ghg_MTCO2 = round(ghg_kgCO2/1000, digits = 0),
sqft = round(sqft, digits = 0),
med_kwh_sqft = round(med_kwh_sqft, digits = 1),
kwh_sqft_25 = round(kwh_sqft_25, digits = 1),
kwh_sqft_75 = round(kwh_sqft_75, digits = 1)) %>%
select(type, n, sqft, kwh, dollars, ghg_MTCO2, med_kwh_sqft, kwh_sqft_25, kwh_sqft_75) %>%
arrange(desc(med_kwh_sqft))
Aggregate meters
datatable(joined_pretty_tot,
rownames = FALSE,
colnames = c("Meter status","Buildings", "Square\nfootage", "kWh", "Est. cost",
"CO2e\n(MT)", "kWh per\nsqft"),
filter = "none",
class = "compact",
options = list(pageLength = 4, autoWidth = TRUE, dom = 't'),
caption = "Table 1. Totals for annual electricity use by meter type. Annual estimates for each meter were adjusted to account for missing days of electricity data.")
Individually metered buildings
datatable(joined_pretty_cat,
rownames = FALSE,
colnames = c("Building\ntype","Buildings\nwith data", "Median\nsquare\nfootage", "kWh",
"Est. cost", "CO2e\n(MT)", "Median\nkWh\nper sqft",
"25th Perc.", "75th Perc."),
filter = "none",
class = "compact",
options = list(pageLength = 11, autoWidth = TRUE, dom = 't'),
caption = "Table 2. Descriptive statistics for annual electricity use by building type for buildings with individual electricity use data. Annual estimates for each meter were adjusted to account for missing days of electricity data.")
Electricity use over the year
Total
daily_graph <- daily_full %>%
mutate(date = as_date(date),
month = month(date, label = TRUE),
day = wday(date, label = TRUE),
type_brief = recode(type,
'Res Hall - U' = 'Res Hall',
'Res Hall - S' = 'Res Hall',
'Res Hall - M' = 'Res Hall',
'Res Hall - L' = 'Res Hall')) %>%
filter(!is.na(month))
ggplot(filter(daily_graph, meter != "Submeter"),
aes(x = month, y = kwh/10^6, fill = reorder(type_brief, kwh, FUN = sum))) +
geom_col(position = "stack") +
scale_fill_brewer(type = "qual", palette = "Paired") +
theme_bw() +
labs(x = "", y = "Electricity use (million kWh)", fill = "",
title = "")
Past versions of "stacked bar-1.png"
Version
Author
Date
cd016a6
maggiedouglas
2026-03-07
92fcd5c
maggiedouglas
2026-03-04
Electricity intensity
to_exclude <- filter(joined_full, days_perc < 90)
intensity <- joined_full %>%
filter(!(type %in% c("Res Hall - U","Production", "Non-building"))) %>%
mutate(kwh_sqft = kwh_corr/sqft,
meter_type = ifelse(type %in% c("Main Meter","Weis Meter"), "Aggregate", "Individual Meter"),
outlier = case_when(
NAME == "King House" ~ "King House",
NAME == "Kisner - Woodward" ~ "K-W",
NAME == "Factory Apts." ~ "Factory",
NAME == "Rector Science Center" ~ "Rector",
NAME == "Quarry, The " ~ "Quarry",
NAME == "27 W. High St." ~ "27 W. High"
))
# median and IQR come from EIA (2022) table, annual kWh per square foot for Colleges/Universities
# https://www.eia.gov/consumption/commercial/data/2018/ce/pdf/c22.pdf
ggplot(intensity,
aes(x = reorder(type, kwh_sqft, FUN = "median"),
y = kwh_sqft, fill = type)) +
annotate("rect", xmin = -Inf, xmax = Inf, ymin = 7.4, ymax = 14.3, color = "lightgray", alpha = 0.3) +
geom_hline(yintercept = 10.3, linetype = "dashed", color = "white") +
facet_grid(meter_type ~ ., scales = "free_y", space = "free_y") +
geom_boxplot() +
geom_label(aes(label = outlier), na.rm = TRUE, nudge_x = -0.25, nudge_y = 0.5,
color = "black", fill = "white", size = 2, alpha = 0, label.size = NA) +
coord_flip() +
theme_bw() +
theme(legend.position = "none") +
labs(x = "", y = "kWh per sqft per year",
title = "")
Past versions of intensity-1.png
Version
Author
Date
cd016a6
maggiedouglas
2026-03-07
92fcd5c
maggiedouglas
2026-03-04
Session information
sessionInfo()
R version 4.5.2 (2025-10-31)
Platform: x86_64-apple-darwin20
Running under: macOS Ventura 13.7.8
Matrix products: default
BLAS: /Library/Frameworks/R.framework/Versions/4.5-x86_64/Resources/lib/libRblas.0.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.5-x86_64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
time zone: America/New_York
tzcode source: internal
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] RColorBrewer_1.1-3 scales_1.4.0 DT_0.34.0 lubridate_1.9.5
[5] forcats_1.0.1 stringr_1.6.0 dplyr_1.2.0 purrr_1.2.1
[9] readr_2.2.0 tidyr_1.3.2 tibble_3.3.1 ggplot2_4.0.2
[13] tidyverse_2.0.0
loaded via a namespace (and not attached):
[1] sass_0.4.10 generics_0.1.4 stringi_1.8.7 hms_1.1.4
[5] digest_0.6.39 magrittr_2.0.4 timechange_0.4.0 evaluate_1.0.5
[9] grid_4.5.2 fastmap_1.2.0 rprojroot_2.1.1 workflowr_1.7.2
[13] jsonlite_2.0.0 whisker_0.4.1 promises_1.5.0 crosstalk_1.2.2
[17] jquerylib_0.1.4 cli_3.6.5 rlang_1.1.7 withr_3.0.2
[21] cachem_1.1.0 yaml_2.3.12 otel_0.2.0 tools_4.5.2
[25] tzdb_0.5.0 httpuv_1.6.16 vctrs_0.7.1 R6_2.6.1
[29] lifecycle_1.0.5 git2r_0.36.2 htmlwidgets_1.6.4 fs_1.6.7
[33] pkgconfig_2.0.3 pillar_1.11.1 bslib_0.10.0 later_1.4.8
[37] gtable_0.3.6 glue_1.8.0 Rcpp_1.1.1 xfun_0.56
[41] tidyselect_1.2.1 rstudioapi_0.18.0 knitr_1.51 farver_2.1.2
[45] htmltools_0.5.9 labeling_0.4.3 rmarkdown_2.30 compiler_4.5.2
[49] S7_0.2.1