Classwork 2

Audit Solar Adoption Before Comparing Places

Guided R exploration of observed New York distributed-solar projects, geographic comparisons, denominators, and defensible claims.
Published

September 2, 2026

🎯 Research studio goal

This classwork applies Lecture 3: Solar Adoption Data.

Your final artifact is:

  • one audited statewide annual summary;
  • one ten-county table and figure for 2025;
  • one defensible descriptive sentence; and
  • one explicit statement of the missing denominator.

Work with a partner. One person drives the code while the other predicts the row grain and audits each denominator; switch roles before Part 5.

By the end, you should be able to:

  1. distinguish observed solar deployment from technical potential;
  2. audit a geographic aggregate before comparing places;
  3. separate project counts, project shares, capacity, and adoption rates;
  4. recognize a partial year and an unexpected geography; and
  5. write a claim that stays within the available evidence.

📥 Data and provenance

We will use the course extract nyserda_solar_county_year_2026-06-30.csv.

It is a county-by-year aggregation of NYSERDA’s open Statewide Distributed Solar Projects: Beginning 2000. The source describes interconnected distributed-solar projects; it does not measure every eligible roof or household.

The extract:

  • is based on data through June 30, 2026;
  • has no project IDs, addresses, ZIP codes, developers, substations, or coordinates;
  • contains 1,283 county-year rows; and
  • does not contain Google Solar API data.
Variable Meaning
data_through_date NYSERDA snapshot date
interconnection_year Calendar year of final grid interconnection
county County label reported by the source
source_rows Project-level source rows contributing to the aggregate
projects Sum of number_of_projects in those source rows
capacity_records Source rows with reported estimated capacity
capacity_kwdc Sum of estimated system size, in kWdc
production_records Source rows with reported estimated production
estimated_annual_kwh Sum of estimated annual production, in kWh
Warning

projects is an observed deployment count, not a household or building adoption rate. The extract contains no denominator for eligible roofs, buildings, households, or firms. Also, 2026 is incomplete because the source stops on June 30.

Setup

Run this code once.

library(tidyverse)

solar_path <- "https://bcdanl.github.io/data/nyserda_solar_county_year_2026-06-30.csv"

solar <- read_csv(
  solar_path,
  show_col_types = FALSE
) |>
  mutate(
    data_through_date = as.Date(data_through_date),
    interconnection_year = as.integer(interconnection_year)
  )

Before summarizing, complete the sentence:

One row represents one __________________ × __________________ aggregate.

🪜 Part 1 · Name the outcome before analyzing it

Classify each measure as technical potential, observed deployment, context, or measurement coverage.

Measure Classification
Modeled maximum panel count on a roof __________________
Interconnected NYSERDA project count __________________
Number of owner-occupied households __________________
Valid Google API building-match rate __________________

Write: Why is projects closer to observed deployment than to an adoption rate?

🧪 Part 2 · Audit before comparing places

2A. Produce one audit row

Predict the output grain, replace the blanks, and run the audit.

solar |>
  summarise(
    rows = ___,
    counties = n_distinct(___),
    first_year = min(___),
    last_year = max(___),
    source_rows = sum(___),
    projects = sum(___),
    capacity_missing_records = sum(___ - ___),
    production_missing_records = sum(___ - ___)
  )

Discuss:

  1. Why are source_rows and projects not exactly equal?
  2. Which result warns you that one capacity value is absent?
  3. Why does one audit row not change the observational unit of solar itself?

2B. Check the intended key

If one row should be one county × interconnection year, complete a pipeline that returns repeated keys only.

solar |>
  count(___, ___) |>
  filter(___ > 1)

Write: What can an empty result establish, and what can it not establish?

2C. Inspect geography and completeness

List every county label, then inspect aggregates with incomplete capacity or production records.

solar |>
  distinct(___) |>
  arrange(___)

solar |>
  filter(
    ___ < ___ |
      ___ < ___
  )

Identify:

  • the county label that is not a New York county; and
  • the county-year with one missing capacity record.

🗓️ Part 3 · Define a comparable analysis window

Create solar_complete for New York counties through the last complete calendar year. Document both exclusions in the code.

solar_complete <- solar |>
  filter(
    interconnection_year <= ___,  # exclude partial 2026
    county != ___                 # flag the out-of-state label
  )

Answer before continuing:

  1. Why would comparing all of 2025 with January–June 2026 be misleading?
  2. Why should the unexpected geography be documented rather than silently removed?

📈 Part 4 · Change the grain to one statewide year

Build one row per year. Keep the number of represented counties and the missing-capacity audit visible.

state_year <- solar_complete |>
  group_by(___) |>
  summarise(
    projects = sum(___),
    capacity_mw = sum(___) / 1000,
    counties = n_distinct(___),
    capacity_missing_records = sum(___ - ___),
    .groups = "drop"
  ) |>
  mutate(
    average_kwdc_per_project = 1000 * ___ / ___
  )

state_year

Before plotting, define the row grain:

One row in state_year represents ____________________________________________.

Then create a trend figure through 2025.

ggplot(state_year, aes(x = ___, y = ___)) +
  geom_col(fill = "#1c5d99") +
  labs(
    title = "New York distributed-solar projects by interconnection year",
    subtitle = "Observed project counts; 2026 excluded as a partial year",
    x = NULL,
    y = "Interconnected projects",
    caption = "Source: NYSERDA statewide distributed-solar projects; data through 2026-06-30"
  ) +
  theme_minimal(base_size = 13)

Write: What changed—the data’s row grain, the underlying project records, or both?

🗺️ Part 5 · Compare counties without inventing an adoption rate

The input already contains one row per county-year. Filter to 2025, compute each county’s share of statewide projects, and order counties by project count.

county_2025 <- solar_complete |>
  filter(___ == ___) |>
  mutate(
    statewide_projects = sum(___),
    project_share = ___ / ___,
    capacity_mw = ___ / 1000,
    average_kwdc_per_project = ___ / ___
  ) |>
  arrange(desc(___))

final_table <- county_2025 |>
  slice_head(n = ___) |>
  transmute(
    county,
    projects,
    project_share_percent = round(100 * ___, 1),
    capacity_mw = round(___, 1),
    average_kwdc_per_project = round(___, 1)
  )

final_table

Answer in words:

  1. What is the denominator of project_share?
  2. Why is project_share not a county adoption rate?
  3. Why can a county rank differently on projects and capacity?

📊 Part 6 · Produce the county figure and claim

Create a horizontal bar chart from final_table.

ggplot(
  final_table,
  aes(x = reorder(___, ___), y = ___)
) +
  geom_col(fill = "#2e7d5b") +
  coord_flip() +
  labs(
    title = "Ten counties with the most interconnected projects in 2025",
    subtitle = "Counts, not rates; no eligible-building denominator is available",
    x = NULL,
    y = "Projects",
    caption = "Source: NYSERDA statewide distributed-solar projects; data through 2026-06-30"
  ) +
  theme_minimal(base_size = 13)

Repair this claim:

Suffolk had the highest solar-adoption rate in New York in 2025.

Use this structure:

In the NYSERDA extract, ________ recorded ________ interconnected distributed-solar projects in 2025 (________% of the statewide project total). This describes ____________________, not ____________________, because ____________________.

🛡️ Part 7 · Peer audit

Exchange the table, figure, and sentence with another pair. Identify the exact code or wording that addresses each item.

Revise one line of code, one label, or one phrase after the audit. Record what changed and why.

🔭 Optional extension · Ask what an adoption rate would require

Choose one possible denominator:

  • households;
  • owner-occupied households;
  • residential buildings;
  • technically suitable roofs; or
  • electricity customers.

Write a proposed rate and list the additional source, geography, year, and join key you would need. Then explain one selection problem that would remain.

✅ Exit ticket

Submit or save:

  1. the audit row;
  2. final_table;
  3. the county figure;
  4. the revised one-sentence claim; and
  5. this completion:

The denominator changes the meaning of my result because ________________________________.

Sources

Back to top