Spring 2026 Dashboard

Pick a department to see what's happening — where students are growing, what interests they bring, and where there's more to discover.

Students


↑ Above Average This Term

Courses running higher than their historical average enrollment for the same term type (fall vs. fall, spring vs. spring). Requires at least 2 prior same-season offerings. Each row shows current enrollment, then the difference vs. the historical average — e.g., "+8 (+22%) vs avg 36" means 44 enrolled this term, average was 36.

↓ Below Average This Term

Courses running lower than their historical average for the same term type. The historical average is the mean enrollment across all prior offerings in the same season (e.g., all prior falls). Only courses with at least 2 prior same-season terms appear. Example: "−5 (−12%) vs avg 41" means 36 enrolled this term, average was 41.


✨ New This Term

Courses whose course number has never appeared in the historical data — genuinely new to the schedule (or returning after a long absence). For topics courses (T: prefix), each distinct title counts as a new course even if the course number is familiar. Topics rows also show a "slot avg" — average enrollment across all prior T: offerings under that same course number, so you can see what demand for that slot typically looks like.

⏸ Missing vs. Two Years Ago

Courses that ran in this same term type two years ago but are not scheduled this term. Each row shows the course and its recent enrollment history (last 1–3 prior offerings with enrollment counts), so you can judge whether this is a routine gap or a course that quietly stopped running.


Recurring Topics This Term

Topics courses (T: prefix) running this term that have been offered at least twice before under the same course number. Shows current enrollment alongside a recent history of prior offerings so you can see whether this topic draws consistently or is gaining/losing interest. Useful for evaluating which rotating topics might warrant their own permanent course number.


Drop Rates This Term

Drop rate = drops ÷ class list total, expressed as a percentage. Compared against each course’s own historical average for the same term type (fall vs. fall, etc.), using at least 2 prior same-season terms. Only courses with ≥10 students on the class list and ≥3 total drops appear. Courses are grouped by level (lower/upper/grad); the level average shown in the section header is the historical mean rate across all courses in that division.

Early drops (pre-census DR) = students who withdrew before the census date. These are often course-fit adjustments and cost the student nothing academically. High early drop rates can signal scheduling problems, unclear course descriptions, or prerequisite mismatches. Late drops (DW/DG) = drops after the census date. These appear on the transcript and may affect financial aid. Elevated late drop rates are a stronger signal of course difficulty, pacing, or support gaps. The “Diff” column shows how much this term’s rate differs from the course’s own historical average — e.g., “+4.2” means the rate is 4.2 percentage points above normal.

Early Drops (pre-census DR)

Late Drops (DW/DG)

Where Your Majors Also Study

Minors declared by students in this department.

Credit Hour Production by Course Level

Five-year trend in student credit hours earned.


Who's in your Courses?

Major and class-standing breakdown for home-dept sections, lower and upper division only.

By Major

Lower Div — Current term

Upper Div — Current term

By Class Standing

Lower Div — Current term

Upper Div — Current term


Your department's home/primary sections, plus non-crosslisted courses. Crosslisted sections show their partner course(s) in the Partners column.

Sections crosslisted across the undergraduate/graduate divide (upper-division paired with a graduate section of the same course).

Your department's sections that also appear under another department's course number.

Sections owned by another department but crosslisted under your department's number.

All sections including every crosslist partner.

Thresholds:



Crosslisted courses that span the undergraduate/graduate boundary (at least one section ≤499 and one ≥500). The Sections column shows all partner courses in the group. Enrollment is the combined total.



How Low Enrollment works

  • Thresholds — set per-level minimums above. A section appears in alerts mode when its combined enrollment falls below its level's threshold.
  • Home sections only — only the administrative home section of a crosslisted course appears; the combined enrollment across all partner sections is shown.
  • Excluded courses — independent studies, thesis credits, and similar special-enrollment courses are excluded by default (see below).

Excluded courses

Certain courses — independent studies, thesis credits, dissertation credits, honors credits, and similar special-enrollment courses — are excluded from the low enrollment analysis. These courses are expected to have very low or individually-arranged enrollment and would otherwise dominate the results. The excluded list is maintained in R/lists/excluded_courses.R and currently contains approximately 200 course codes.

Home section — what it means and how it's determined

When a course is crosslisted, only the home (primary) section appears in the tables — the section that is administratively responsible for the course. Showing every crosslisted row would double- or triple-count courses.

Home section is identified using the SHORT_TEXT field from MyReports, which contains a note like "HIST home 202610" identifying which department owns the crosslist. This is the registrar-authoritative signal.

When SHORT_TEXT is absent (roughly 85% of crosslist groups, particularly same-department split-level courses), the section with the highest section-level enrollment is treated as home. Ties are broken alphabetically by subject code.

When a department with lower enrollment appears as home, it is because SHORT_TEXT explicitly identified it — not an error in the data.

Course levels

  • Lower division: course numbers below 300 (and 1000+)
  • Upper division: course numbers 300–499
  • Graduate: course numbers 500–699
  • Split-level: a crosslisted group spanning the undergraduate/graduate boundary (at least one section ≤499 and at least one ≥500). Sections retain their original level (upper/grad) but are flagged as split-level and appear in the Split-Level tab with a separate, lower threshold. The Split Partners column shows all partner courses in the group (e.g., 'BIOL 402 / BIOL 502').

Lab sections (course numbers ending in L, e.g., EDUC 331L) are classified by their numeric base (331 → upper division).

Section counts and course totals

The Sects column shows the number of active home sections of that course in the selected term and campus. Course Total is the sum of total_enrl across those sections. Both are computed from sections where status = 'A' and crosslist_primary = TRUE , grouped by term, course, and campus.

Thresholds

Each level has its own threshold. In alerts mode, a section appears when total_enrl < threshold . In concerns mode, a course appears when avg_enrl < threshold + 5 (the +5 buffer catches courses near the boundary) or when the course has no prior history. Defaults (15 / 15 / 10 / 5) reflect typical minimum viability targets, not institutional policy — adjust as needed using the Thresholds fields above the tabs.

Future Term: Historical Enrollment Concerns

When you select a term that is beyond the current term ( cedar_current_term in config), CEDAR switches to concerns mode . Instead of flagging courses with low current enrollment, it identifies courses on the future schedule whose historical enrollment pattern suggests they may struggle to meet minimum viability targets.

How historical averages are computed
  1. The system identifies all prior terms of the same type (e.g., all past falls for a Fall 2026 schedule). Only terms in the DESR data are included.
  2. For each course on the future schedule, it sums total_enrl across all home sections ( crosslist_primary = TRUE ) in each prior term, then averages the last 4 available terms.
  3. Courses are matched by subject_course and campus — history for HIST 1105 at ABQ is computed separately from HIST 1105 at Valencia.
  4. Only active terms (those with at least one active section) contribute to the average and trend. Cancelled terms appear in the history column as 'C' but do not affect the average.
  5. The historical average is compared against the same per-level thresholds used for actual enrollment alerts, with a +5 student buffer zone (see Thresholds above).
What's excluded from history
  • Shell/placeholder sections: Sections that are active (status A) with zero enrollment and no instructor assigned are excluded. These are sections left in the schedule build that were never genuinely offered.
  • Cancelled sections: Sections with status 'C' are included in the historical record so you can see when a course was scheduled but later cancelled (shown as 'C' in the Prior History column). However, cancelled terms do not contribute to the historical average or trend calculation.
Trend detection

A linear regression slope is computed across enrollment values from active (non-cancelled) historical terms. A slope greater than +1 student/term is labeled ↑ up ; less than −1 is ↓ down ; between −1 and +1 is ↔ stable . If fewer than 2 active terms are available, trend shows (insufficient data).

Color coding (concerns mode)
  • Red: Historical average is below 50% of the threshold. These courses have consistently underperformed.
  • Yellow: Historical average is 50–75% of the threshold. These are borderline courses.
  • Blue: Historical average is 75–100% of the threshold. Watch-list courses.
  • Green: Historical average meets or exceeds the threshold. Shown in the buffer zone (up to 5 students above threshold).
  • Gray: No prior history available (new course or first offering of this term type).
Limitations
  • Course-level totals: the analysis focuses on total enrollment per course, not individual section enrollment.
  • New courses with no prior history of the same term type appear with a 'No prior history' indicator and are always shown regardless of threshold.
  • The analysis does not account for changes in number of sections offered, delivery method shifts, or curricular changes that might affect enrollment.
  • History matching uses subject_course and campus only. If a course was renumbered or moved between departments, its prior history under the old number will not be linked.

Source: MyReports DESR data. Transformation pipeline: R/data-parsers/parse-DESR.RR/data-parsers/transform-to-cedar.R . Home section detection: transform-to-cedar.R . Excluded courses: R/lists/excluded_courses.R . Low enrollment functions: R/cones/enrl.R . Combined enrollment per section: total_enrl = max(ENROLLED, XL_TOTAL_ENROLLMENT) .

Multi-year enrollment trends across the last 6 offerings of each course. Select a single department to see results. A course is classified as “growing” or “declining” when a linear regression slope across its recent offerings exceeds ±1 student per term. Courses with fewer than 2 offerings are excluded.

Each row shows: average enrollment across the window, then early-window average vs. recent-window average (first half vs. second half of the 6-term window). For example: "avg 34 enrolled • +9 (+36%) over window" means the course averaged 34 students across 6 terms, and the recent 3-term average is 9 students higher than the early 3-term average — a 36% gain. Note that these trends mix term types (fall, spring, summer) unless you filter first.

↑ Growing Courses

Courses with a positive regression slope > 1 student/term across their last 6 offerings. Sorted by slope (steepest growth first).

↓ Worth a Look

Courses with a negative slope < −1 student/term. May reflect scheduling changes, curriculum shifts, prerequisite changes, or reduced demand. Sorted by steepest decline first.


Filter panel

The filter controls above apply to all tabs. Selections narrow the data before any grouping or enrollment calculation.

  • Campus / College / Department / Term / Course: Standard drill-down filters. Use Term to select a specific term or term type (e.g., 'Fall' to compare all fall semesters).
  • Group by: Collapses individual sections into grouped rows. Enrollment values are summed across the group. For example, grouping by subject_course shows one row per course with total enrollment across all its sections. Adding term alongside subject_course shows trends over time.
  • Exclude List: When checked, removes independent studies, thesis credits, dissertation credits, honors credits, and similar special-enrollment courses from results. The list is maintained in R/lists/excluded_courses.R and contains approximately 200 course codes. Uncheck to include these courses.
  • Level: Filters by course level (lower division, upper division, graduate).
  • Min / Max: Filters sections by enrollment count. Min defaults to 1, which excludes zero-enrollment sections (typically scheduling placeholders). Set Min to 0 to include them.

Enrollment counts: section vs. combined

MyReports records enrollment at the individual section level. A crosslisted course with 8 students in the HIST section and 5 students in the ANTH section shows 8 and 5 in separate rows — not 13. The dashboard uses total_enrl , defined as max(ENROLLED, XL_TOTAL_ENROLLMENT) per section. For non-crosslisted sections this simply equals the section's own enrollment count; for crosslisted sections it equals the combined enrollment across all partner sections (the registrar's XL_TOTAL_ENROLLMENT figure).

When you use Group by, enrollment values are summed from total_enrl across all matching sections. Crosslisted courses grouped by subject_course show the combined enrollment once (via the home section), not double-counted.

DESR vs. Classlist

DESR (Detail Enrollment Section Report) is section-level data from MyReports. Each row is one course section with its enrollment count, attributes, and crosslist information. Use DESR for section-level analysis, crosslist views, and low enrollment alerts.

Classlist is student-level data. Each row is one student enrollment in one section. Use Classlist when you need student-level detail — individual students, majors, class standings. Classlist does not include sections with zero enrollment.

Crosslist views (DESR tab)

  • Home: Your department's home/primary sections, plus non-crosslisted courses. Crosslisted sections show their partner course(s) in the Partners column.
  • Split-level: Sections crosslisted across the undergraduate/graduate divide (upper-division paired with a graduate section of the same course).
  • Crosslisted: Your department's sections that also appear under another department's course number.
  • Away: Sections owned by another department but crosslisted under your department's number.
  • All: All sections including every crosslist partner.

The Home view is the most common starting point for department-level analysis. It prevents double-counting by showing each crosslisted course once, under the administrative home department.


Source: MyReports DESR data. Transformation pipeline: R/data-parsers/parse-DESR.RR/data-parsers/transform-to-cedar.R . Combined enrollment per section: total_enrl = max(ENROLLED, XL_TOTAL_ENROLLMENT) .

Registration Statistics Dashboard

Download report

Pathways Analysis

Define a student population, then explore where they face enrollment barriers, which courses pose the biggest risk of departure or grade setback, and how they move through the curriculum over time.

Courses where population students are waitlisted but hold no registered seat — unmet enrollment demand. Hedged waitlisters (already registered in another section) are excluded.

Departure Risk

Courses where students who got a DFW were less likely to return the following fall or spring than students who passed — compared to the same pattern among all other students in those courses. This is a correlation, not a cause: the course may reflect a harder structural barrier rather than being the source of attrition. stopout_gap = DFW stop-out rate − pass stop-out rate. Sorted by impact_score = excess gap × DFW count — balances the size of the disproportionate penalty against how many students are affected. Baseline = all non-population students in the same courses. Graduates in their degree term are not counted as stopped out.

Grade Setback

Courses with the highest DFW rates among population students, regardless of whether they predict departure. A high DFW rate is a setback even for students who stay — it delays progress and often triggers a retake. Baseline columns show DFW rates for all non-population students in the same courses.

When in their academic career do population students take each course? Y-axis = course, sorted by median x-axis position. Cell = % of eligible students who took that course at that stage. Relative term: 1st, 2nd, 3rd enrolled term from each student's first semester. Classification: Freshman/Sophomore/Junior/Senior at time of enrollment.

Ordered course pairs: of population students who took Course A, what fraction later took Course B? Sorted by that fraction. Pairs more than max_gap relative terms apart are excluded. Non-ongoing students contribute only their enrollment through their last focal term.

Courses taken in the semester immediately before a student first appeared in the unit. Entered = students who eventually declared (any entry path); did not enter = students in the unit’s pool who never declared. Lift > 1: course is disproportionately associated with entry. This is a correlation — many factors shape program entry.

Major changes made by population students — consecutive terms where program_name differs. Only changes involving the focal major on at least one side are shown (arriving to or leaving from). Pre-major → declared transitions within the same major are not counted. Undergraduate → graduate transitions are excluded.

Changes by Term
Arriving from
Leaving for

Inflow / Outflow by Major

“Students arriving to” = changed INTO that major from somewhere else. “Students leaving” = changed OUT OF that major. A major can appear in both columns.


Common Pathways (A → B)

Each row is a from→to pair that occurred at least the minimum number of times. “Avg credits” is the average institutional credits the student had already attempted at the moment of the switch — a proxy for how far into their degree the change typically happened.


Change Event Detail (student-level)

How These Analyses Work

This page documents exactly how each analysis is computed, derived directly from the source code. Use it to interpret results correctly and spot anomalies.

1. Building a Student Group

File: R/branches/population.R
Functions: build_population()get_focal_programs(), get_ongoing_ids(), get_graduated_ids(), get_switched_out_ids(), get_never_declared_ids(), get_entry_pathways(), classify_origin(), classify_entry_method(), classify_entry_status(), build_demographic_population()

A student population is built in three stages: (1) identify candidates — any student who ever appeared in the focal major; (2) classify outcomes — determine what happened to each candidate relative to the major; (3) filter and label — include the desired outcome groups and assign labels. The result (a tibble with student_id, population_label, outcome, entry_pathway, origin, entry_method, entry_status, relevant_until) is passed to every downstream analysis.

Outcomes

  • ongoing — still declared in the focal major in the most recent data term.
  • graduated — received a degree in the focal major in their last focal term.
  • switched_out — left the focal major but remained at UNM. Detected two ways: (1) a formal declaration of another major after their last focal term in cedar_programs; (2) any enrollment record in cedar_students after their last focal term, even without a re-declaration.
  • stopped_out — all declared candidates not accounted for by ongoing, graduated, or switched_out. No UNM enrollment or major record after their last focal term.
  • chose_elsewhere — appeared only as a pre-major; never declared the focal major, but did declare a different major afterward.
  • left_undeclared — appeared only as a pre-major; never declared any major. Left without committing.

Entry pathway (<code>entry_pathway</code>)

How the student arrived at the focal major — computed by get_entry_pathways() :

  • direct — first major at UNM was the focal major (no prior declared major or pre-major).
  • switched_in — had a non-focal declared major before declaring the focal major.
  • pre_major — appeared as a focal pre-major before (or instead of) declaring.

Entry classification columns

  • entry_method (classify_entry_method()) — first_program: no prior major record of any kind before this unit; switched_in: had at least one prior major record; unclear: first unit record is at the earliest available term, so prior history is unobservable.
  • entry_status (classify_entry_status()) — whether the student’s first record in this unit was as a pre_major or a declared major.

Enrollment window (<code>relevant_until</code>)

Each non-ongoing population student carries a relevant_until term: their last_declared_term (last term with a declared, non-pre-major focal record). Course enrollments after that term are excluded from all analyses. A student who was History for 2 terms, then switched to Business for 8 terms, contributes only the 2 History terms to the analysis. Ongoing students have relevant_until = NA (no restriction).

Worked example — dept = HIST, default scope (declared majors)

student_id program_name program_type is_pre_major outcome result
S001 History Major FALSE ongoing ✓ included
S002 History Second Major FALSE ongoing ✓ included (Second Major counts)
S003 History Major TRUE chose_elsewhere / left_undeclared — excluded by default (pre-major only)
S004 English Major FALSE — excluded (different dept)
S005 History Minor FALSE — excluded (Minor)

What programs belong to a department? The lookup uses cedar_programs$dept_code, which is populated during transformation via a three-tier lookup: major_dept_map → subj_dept_map → major_code identity. If a program’s dept_code is missing or wrong, it won’t appear in the dropdown.

2. Bottlenecks — Unmet Enrollment Demand

File: R/cones/bottleneck.R
Functions: get_bottlenecks(), compute_waitlist_pressure()

Counts group students who are waitlisted for a course but hold no registered seat in it. These are the students who wanted in and didn’t get in.

Exact computation

  1. Waitlisted = registration_status_code == “WL”
  2. Registered = registration_status_code %in% c(“RE”, “RS”, “RR”)
  3. Pure waitlisters = waitlisted rows that do not also appear as registered in the same course. A student waitlisted for section 002 while registered in section 001 is a hedged waitlister and is excluded — they already have a seat.
  4. Count unique student IDs per course among pure waitlisters.

Worked example

student_id subject_course status counted?
S001 BIOL 2310 WL ✓ pure waitlister
S002 BIOL 2310 WL + RE (other section) ✗ hedged — already registered
S003 BIOL 2310 RE ✗ not waitlisted

Result: BIOL 2310 → n_waitlisted = 1 (S001 only)

⚠ Interpretation caution: Waitlist data in CEDAR reflects end-of-term snapshots. Students who wanted a course, couldn’t get in, and stopped trying do not appear — they simply have no waitlist record. High counts are a real signal; low counts do not confirm demand is met.

3. Roadblocks — DFW as a Predictor of Leaving

File: R/cones/stopout.R
Functions: get_stopout(), classify_outcomes(), compute_stopout_for_group()

For each course, compares the fraction of group students who did not return the following term among those who got a DFW grade versus those who passed. The gap between those rates is the key signal.

Step 1: Classify outcomes (per student per course per term)

registration_status_code final_grade classified as
DR (early drop) any dfw — non-completion regardless of grade
RE / RS / RR D, D+, D–, F, W, RD, RF dfw
RE / RS / RR A–C, CR, P, S, RA–RC, RCR pass
RE / RS / RR I, AUD, NR, or other excluded — ungraded, no signal
WL / other any excluded

Step 2: Determine whether each student returned the following term

For each student in each term, we check whether they appear in cedar_students in the next fall or spring. Summer is not counted — skipping summer is normal and not a stop-out.

Graduate correction

Students who earned a degree in term T are not counted as stopped out for that term, even though they don’t appear in term T+1. Without this correction, every graduate who finished their program would be misclassified as a stop-out. The correction uses cedar_degrees$term to identify graduation terms.

⚠ Partial coverage: Graduate correction only applies to degrees recorded in CEDAR. Students who transferred out or completed credentials not in cedar_degrees will still appear as stop-outs.

Step 3: Compute rates and gap

student_id BIOL 2310 outcome returned next term?
S001 pass (A) yes
S002 pass (B) no
S003 dfw (F) yes
S004 dfw (W) no
S005 dfw (W) no

pass_stopout_rate = 1/2 = 0.500 (S002 didn’t return)
dfw_stopout_rate = 2/3 = 0.667 (S004, S005 didn’t return)
stopout_gap = 0.667 − 0.500 = 0.167
p_value: chi-squared test on the 2×2 contingency table (outcome × returned). Skipped if either group has fewer than 5 students — result is NA.

⚠ Known anomalies to watch for:
  • The most recent term in the data has no visible ‘next term,’ so all students in that term appear as stopped out. This inflates stop-out rates for recently active courses.
  • Rows where pop_n_dfw is very small (1–4) produce unreliable rates. The Min group DFW students filter (default 5) removes these.
  • The baseline is ALL non-group students in the same courses.
  • Stop-out is measured as ‘returned to UNM,’ not ‘continued in the program.’

4. Course Timing — When Students Take Each Course

File: R/cones/pathway.R
Functions: get_course_timing(), plot_curriculum_map()

Computes the fraction of group students who took each course in their 1st, 2nd, 3rd… enrolled term. Uses relative terms so students who started in different calendar years are aligned on the same axis.

How “term 1” is defined

Relative term 1 is the first term in which the student has a registered course record in cedar_students — not their first semester at UNM, not their first semester in the program, and not any self-reported start date. It is row_number() over their distinct enrolled terms, sorted chronologically by UNM term code.

Skipped semesters

The counter only increments for terms with actual registered enrollment. Gaps are invisible. A student enrolled in Fall, absent in Spring, enrolled in Fall has relative terms 1 and 2 — not 1 and 3. There is no concept of “missed term 2” in this model.

Summer terms

By default, summer does not advance the counter. Summer courses are pinned to the relative term of the immediately preceding fall or spring. A student taking a summer course between their 2nd and 3rd fall/spring semesters has those summer courses recorded as relative term 2. If “Include summer” is enabled, summer gets its own slot in the sequence.

Denominator

For each relative term, the denominator is the number of group students who reached that term — i.e., students whose enrollment record extends to at least that relative term. Students with only 3 terms of data are excluded from relative terms 4–8. This prevents the percentage from being artificially deflated for later terms.

⚠ Left-truncation artifact — Freshman filter is applied automatically:

Students who were already enrolled when CEDAR data begins (Fall 2018) have relative term 1 set to Fall 2018, regardless of how long they had actually been at UNM. A senior in Fall 2018 looks like a first-semester student, which makes the chart meaningless. This is called left truncation.

To prevent this, the app automatically restricts the relative-term axis to first-time freshmen — students whose first enrollment record in CEDAR is classified as Freshman. These are the only students whose term 1 is genuinely their first semester. You can override this by selecting a different Starting Classification in the filters.

This filter does not apply to the Classification, Inst. Credits, or Overall Credits x-axis modes — those use actual Banner values recorded at the time of enrollment and are unaffected by when the data window starts.

5. Course Pairs — Common Sequences

File: R/cones/pathway.R
Function: get_course_pairs()

Finds ordered pairs (A → B) where group students took Course A in one relative term and Course B in a later term, within a configurable term gap.

Exact computation

  1. Self-join enrolled records on student_id where term_B > term_A and term_B − term_A ≤ max_term_gap and course_A ≠ course_B.
  2. Count distinct students per (course_A, course_B) pair.
  3. pct_a_to_b = students who took both ÷ students who took A.
⚠ This is correlation, not causation. A high pct_a_to_b means students who took A commonly went on to take B. It does not mean A is a prerequisite for B or that taking A causes students to take B.

6. Major Changes

Files: R/cones/major-changes.R (detection and summarization), R/branches/population.R (group building), R/modules/pathways.R (focal program derivation and display)
Key functions: detect_major_changes(), major_change_pathways()

Detects when a student’s primary declared major changed from one term to the next, then summarizes those transitions for the selected student group.

Step 1: Detect change events

Source: detect_major_changes() in R/cones/major-changes.R.

  1. Filter cedar_programs to program_type == “Major” rows for the population students only.
  2. Sort by student_id, term. Use lag() to get each student’s program in the prior term (prev_major) and their prior academic level (prev_level).
  3. Flag a change when program_name != prev_major AND (is.na(prev_level) | student_level == prev_level). The level check excludes transitions between undergraduate and graduate programs — a History BA student enrolling in Law School is not a “major change” in the undergraduate sense. is.na(prev_level) passes the first record per student through since there is no prior level to compare.
  4. Each flagged row becomes one change event with: student_id, change_term, from_major, to_major, credits_at_change (institutional credits attempted at the time).

Worked example — History student program history

student_id term program_name student_level prev_major result
S001 202310 Psychology Undergraduate (none) — first term, no change
S001 202380 Psychology Undergraduate Psychology — same major
S001 202410 History Undergraduate Psychology ✓ change event: Psych → History
S001 202480 History Undergraduate History — same major
S001 202710 Juris Doctor Graduate/GASM History — level changed (UG→GR), excluded

Step 2: Derive focal majors

Source: mc_data reactive in R/modules/pathways.R.

Focal majors are the majors that define the selected student group — not all majors ever held by group members. A History cohort student who also declared Political Science should not make PolSci a focal major.

  • Dept mode (e.g., HIST): all majors where dept_code == “HIST” and program_type %in% c(“Major”, “Second Major”) in cedar_programs.
  • Specific majors mode: exactly the majors the user selected in the sidebar.
  • Preset mode: the program_names list from the population opt.

Step 3: Filter to focal changes

From the full set of change events, keep only rows where from_major %in% focal_programs OR to_major %in% focal_programs. This means a History cohort sees:

  • Psychology → History (arriving to History) ✓
  • History → Political Science (leaving History) ✓
  • Political Science → Law (made by a History student, but neither side is History) ✗ excluded

Step 4: Build summary outputs

Source: major_change_pathways() in R/cones/major-changes.R.

  • Inflow / Outflow table: count distinct to_major (arrivals) and from_major (departures) in focal changes, then filter to rows where the major is in focal_programs. Net = arrivals − departures.
  • Common Pathways table: group focal changes by (from_major, to_major), count events, compute avg_credits = average inst_credits_attempted at the moment of the switch. Minimum threshold (default 3) removes rare pairs.
  • Avg credits is a proxy for timing: 30 credits ≈ freshman year, 60 ≈ sophomore, 90 ≈ junior. A History → Political Science pair at 75 credits means students are switching in their junior year on average.
  • Trend sparkline: per-term count of arrivals (to_major %in% focal, green) and departures (from_major %in% focal, red).
  • Donuts: “Leaving for” = top non-focal to_major values among departures. “Arriving from” = top non-focal from_major values among arrivals. Students cycling between focal majors are excluded from the donuts to avoid self-referential loops.

Worked example — Inflow / Outflow for a History dept cohort

major students arriving to students leaving for elsewhere net
History 47 31 +16
History / Pre-Law 5 12 −7

Only History-dept programs appear. The 47 arriving students came from other majors; the 31 departures went to other majors (shown in the “Leaving for” donut).

⚠ Known edge cases:
  • A student who switched History → PolSci → History generates two change events. Both appear in the tables. The net can mask churn.
  • Pre-major → declared transitions within the same program are not flagged as changes (same program_name, different is_pre_major flag).
  • The minimum event threshold (sidebar) removes pairs with fewer than N events. Rare pathways that may still be meaningful are hidden. Lower the threshold to see them.
Reading this with Claude or GitHub Copilot:

Each section above names the exact file and function that implements it. To go deeper, open the file in your editor, select the function body, and ask “explain this function” or “what does this do step by step?” All functions have parameter descriptions in the header comment.

For a fuller picture, paste the function into Claude along with a specific question — for example: “Why does get_switched_out_ids() use last_focal_term + 100 as an upper bound?” or “What edge cases does the enrollment-based switch detection handle that the program-record check misses?” The code is designed to be readable; the AI fills in the reasoning.

Methodology reflects: R/branches/population.R (group builder), R/cones/bottleneck.R, R/cones/stopout.R, R/cones/pathway.R, R/cones/major-changes.R, and R/modules/pathways.R (display logic). Update this panel when cone logic changes.

Open Seats

Shows courses with available seats for the specified search parameters. It also provides DFW rates for those courses that have been offered in before with the same filtering parameters. No DFW rate means that the course has not been offered before with those parameters. It also provides tabs to see courses that were offered a year previously, courses not offered a year previously, and courses common to both terms. Gen Ed Likely tab shows courses that are active but with no enrollment and likely capped at 0 for now (e.g., gen ed courses not yet opened for enrollment).

DFW rates reflect courses matching your selected filters (e.g., if you filter by 2H, DFW % is for 2H versions of those courses).

Course Waitlist Reporting

Waitlist by Count

This table shows the number of students on the waitlist for each course. The courses are sorted by the number of students on the waitlist.

Waitlist by Major

This table shows the distribution of students on waitlists by their major. This can help identify which programs are most affected by course availability issues.

Waitlist by Classification

This table shows the distribution of students on waitlists by their classification (freshman, sophomore, etc.). This can help identify which student levels are most affected by course availability.

Student Headcount

Undergraduate Headcount
Graduate Headcount

Course Dynamics

Enrollment patterns, student flows, and grade distributions for a specific course.


Enrollment Trends


Enrollment History


Student Flow Patterns

Shows where students come from and go to relative to this course.


Shows the composition of students taking this course by classification and major.

Filter by campus to see rollcall data for specific locations. Multiple campuses can be selected to report TOTALS.

By Student Classification
By Major
Classification Trends Over Time
Major Trends Over Time
Data Tables

Department Profile

Health Enrollment Views

Select a set of health programs and a projected enrollment increase. The matrix below shows which courses will see additional demand — how many extra students, how many additional sections, and when. Click any cell for a detailed breakdown.

% of avg enrolled headcount added as steady-state demand.

Same delta applied in each projected semester (flat, not compounding).

Re-run after changing programs or baseline terms.
meets threshold ≥ 1 section needed — = below threshold in this semester Export CSV

Rows = courses most impacted by the enrollment increase. Columns = projected semesters. Each cell: +N new = additional students from growth; 0.Xs = sections of additional demand; X now → Y total = existing baseline students → projected total. Click any cell for a detailed breakdown.

Re-run after changing programs or baseline terms.

Average students per term from each selected program enrolled in each course. Rows = courses (most enrollment at top). Columns = program × status, sorted by headcount (most students on left). Averages across all terms in the selected year range.

Re-run after changing programs or baseline terms.

Data Status & Usage Analytics

Data presented here is MyReports data — not official institutional data — and should not be used for required reporting purposes. CEDAR tables are updated nightly for the current semester and +/- 1-2 terms.


Last updated information for all loaded datasets. This data is computed at startup.




Usage Summary

High-level overview of CEDAR usage during the selected date range.

Most Used Features
Department Profile
Course Dynamics



Usage Event Log

Course Report Cache

CEDAR caches expensive lookup calculations (course flow analysis) to speed up repeated course report requests. The cache automatically invalidates when data changes.


Department Profile Cache

Department profile reports are cached to disk after first generation. The cache invalidates automatically when source data changes. Use this button after manually correcting data or when reports look stale.

CEDAR Changelog

Recent Updates
All Changes