Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions data-stories/activity-patterns-memory/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Overview
Author: Kate Marine kate-marine

**Main question:** Can the temporal patterns in fitbit activity data predict memory-task performance beyond what is already captured by a participant's average activity level?

Link to video: https://youtu.be/tRfJIgmk0RA

Link to code: https://github.com/kate-marine/wearable-dynamics-data-model.git

## Approach

I built two models, one as a baseline using only mean activity, and another with added temporal/dynamic features. These included variability metrics (standard deviation, range, coefficient of variation) linear slope over the year, and autocorrelation at lags 1 and 7 days. For both models I standardized every feature so they were on a common scale and then fit a Ridge regression. I scored everything with shuffled k-fold cross-validation, and then looked at the R² to compare the two models' performance.

After I got pretty weak cross-validated $R^2$ for both Ridge models, I then starting looking into whether the result was due the kind of model I was using and so I tried out alternative models (Elastic Net and Random Forest) to see if they would perform better on the same features. Finally I looked to see if any individual features showed clear monotonic relationships with behavior outcomes (mainly as motivation for next steps) by computing Spearman correlations for every fitbit feature / behavior outcome pair from the 40 valid behavior outcomes from behavior.pkl.

## Findings

Adding temporal dynamics did not help predicting memory-task performance, and it actually did significantly worst then the baseline model using average activity level. The models are mostly likely overfitting as is common with having more predictors (163) than participants (113). The null result stayed the same even after three stress tests (expanding to 40 fine-grained outcomes, switching to Elastic Net and Random Forest models, and a univariate Spearman screen across 560 feature–target pairs where no dynamic feature appeared among the top correlates).


## Downloading the data

I used 113 participants' Fitbit data along with memory-task outcomes from the study _Manning, J. R., Notaro, G. M., Chen, E., & Fitzpatrick, P. C. (2022)_. Fitness tracking reveals task-specific associations between memory, mental health, and physical activity. *Scientific Reports*, 12, 13822. https://doi.org/10.1038/s41598-022-17781-0

I reshaped the raw Fitbit CSVs into a participant-by-date panel for the temporal modeling.


## Running the code

Set up:

```bash
git clone https://github.com/kate-marine/wearable-dynamics-data-model.git
cd wearable-dynamics-data-model
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate

# run
python -m src.phase1 # load CSVs, build panel, coverage diagnostics, means-only baseline
python -m src.phase2 # dynamic feature extraction and model comparison
python -m src.exploratory_full_behavior # rerun comparison across all behavior.pkl outcomes
python -m src.posthoc_analysis # Elastic Net, Random Forest, Spearman univariate screen

```

## Contributing to the code

### Challenges and potential next steps:
I was a little limited in what I could include in the models since things like sleep and heart-rate/HRV (probably pretty strong ties to cognitive performance) were too sparse in the data. So this could definitely be revisited/replicated if can get more data. As a next step I might look into a different target metric (rather than memory) such as one of the mental health measures like typical stress. From a Spearman screen I ran I might look into the mean__floors vs. vocab learning correlation as well.

The biggest problem with the apporach I've taken is that the sample size of 113 participants is too small for meaningful modeling and led to significant overfitting.

## Acknowledgements

_Manning, J. R., Notaro, G. M., Chen, E., & Fitzpatrick, P. C. (2022)_. Fitness tracking reveals task-specific associations between memory, mental health, and physical activity. *Scientific Reports*, 12, 13822. https://doi.org/10.1038/s41598-022-17781-0
25 changes: 12 additions & 13 deletions data-stories/coffee-consulting-story/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,38 @@ Username: kate-marine

# Overview

Main question: what it would look like to build something that lets a language model actually do data analysis, instead of just write code for someone else to run?

For this project I designed and built an MCP server that lets clients such as LLMs upload data, define visualizations, and retrieve resutlts as part of a contextual workflow. It was originally part of a project for the DALI lab, but I expanded it to explore more practical applications. When working with an LLM on a dataset, such as like I have been doing with earlier data stories projects, it can produce great code snippets, but I still have to run everything in a notebook and continuously communicate back and forth into the chat (before I started doing Claude code).
Instead of asking Claude to generate code, an MCP client can call a tool that actually does the thing, such as loading a dataset or rendering a chart and gets the result back inline. My server exposes a bunch tools organized into four categories: dataset operations (upload, describe, list), transforms (filter, aggregate, sort, select columns), visualization specifications (create, suggest, update chart definitions), and rendering (generate PNG or interactive HTML plots). I built it in Python using FastMCP for the protocol layer, pandas for data manipulation, matplotlib for static charts, and Plotly for interactive ones.
Instead of asking Claude to generate code, an MCP client can call a tool that actually does the thing, such as loading a dataset or rendering a chart and gets the result back inline.

## Approach

My server exposes a bunch tools organized into four categories: dataset operations (upload, describe, list), transforms (filter, aggregate, sort, select columns), visualization specifications (create, suggest, update chart definitions), and rendering (generate PNG or interactive HTML plots). I built it in Python using FastMCP for the protocol layer, pandas for data manipulation, matplotlib for static charts, and Plotly for interactive ones.

The most important design decision was making every object the server creates (such as datasets, chart specs, rendered plots) addressable by a unique ID, so that any follow-up call can reference earlier work without having to re-upload anything. For example when a user wants to now filter to just Boston store locations and regenerate the plot, the client doesn't need to send the dataset again it just passes the ID.

For the actually story part, I wanted to show how the server could actually be used in a somewhat real world scenario. The data is a simulated coffee sales dataset that I was using for testing. It includes twelve months of revenue, customers, ratings, and marketing spend across six cities. The main point of the story wasn't to actually emphasize the findings themselves (because it’s just simulated) but to show how the tool could be used in a real kind of iterative analysis workflow.

The biggest limitation I ran into was that suggest_vizspec (tool that is supposed to interpret plain English chart requests but didn’t end up finishing) can pick the right plot type but doesn't know to chain in a aggregate_dataset call when the request implies it. For example asking for "total revenue by city" is a single spoken phrase but implies two server-side operations, and means letting tools call other tools which I didn’t have time to implement.

See DESIGN.md for more in depth explanation of server itself and https://github.com/kate-marine/data-visualization-mcp-server.git for the full repo of for the mcp server
See DESIGN.md for more in depth explanation of approach and the server itself and https://github.com/kate-marine/data-visualization-mcp-server.git for the full repo of for the mcp server


**Video link:** https://youtu.be/ghtawmGFPXc


## Downloading the data

See csv. It's super small, used just to test the MCP tools which were the main focus of this project
See coffee_chain.csv. It's super small, used just to test the MCP tools which were the main focus of this project.

# Running the code

See https://github.com/kate-marine/data-visualization-mcp-server.git for full code repo.

Describe, in sufficient detail for a new person (moderately competent but unfamiliar with your work) to follow, how to run your code.

# Contributing to the code

Tell other people how they can contribute to the project you've started. Specifically:
- What are the most obvious next steps?
- What are some questions that your work raises?
- What challenges remain?
- Are there any known bugs or problems with your approach that someone continuing your project should be aware of?
The biggest limitation I ran into was that suggest_vizspec (tool that is supposed to interpret plain English chart requests but didn’t end up finishing) can pick the right plot type but doesn't know to chain in a aggregate_dataset call when the request implies it. For example asking for "total revenue by city" implies two server-side operations and means letting tools call other tools which I didn’t have time to implement. Future work could definitely work on building out this tool for non-LLM clients (as its redundant with a client like Claude desktop).

Also, the server currently only works with limited set of different plot types and very simple ones. Future work could expand to make visualizations more appealing or supportive for more complex data. Same with HTML piece for making more complex interactive visualizations.
Comment on lines +36 to +38


# Acknowledgements

Expand Down
73 changes: 73 additions & 0 deletions data-stories/coffee-consulting-story/coffee_chain.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
city,month,quarter,revenue,customers,avg_order,rating,marketing_spend
Seattle,Jan,Q1,44200,2180,20.3,4.1,3200
Seattle,Feb,Q1,43800,2160,20.3,4.2,3100
Seattle,Mar,Q1,45100,2220,20.3,4.2,3200
Seattle,Apr,Q2,45800,2250,20.4,4.3,3300
Seattle,May,Q2,47200,2310,20.4,4.2,3400
Seattle,Jun,Q2,48100,2350,20.5,4.3,3500
Seattle,Jul,Q3,49200,2390,20.6,4.3,3600
Seattle,Aug,Q3,50100,2420,20.7,4.2,3600
Seattle,Sep,Q3,49800,2400,20.8,4.3,3500
Seattle,Oct,Q4,51200,2460,20.8,4.3,3700
Seattle,Nov,Q4,52100,2490,20.9,4.4,3800
Seattle,Dec,Q4,54300,2550,21.3,4.4,4200
Austin,Jan,Q1,28400,1420,20.0,4.4,5800
Austin,Feb,Q1,30600,1520,20.1,4.5,6200
Austin,Mar,Q1,33100,1640,20.2,4.5,6500
Austin,Apr,Q2,35700,1760,20.3,4.6,6800
Austin,May,Q2,38500,1890,20.4,4.5,7200
Austin,Jun,Q2,41800,2030,20.6,4.6,7600
Austin,Jul,Q3,45100,2170,20.8,4.6,8000
Austin,Aug,Q3,48600,2310,21.0,4.7,8200
Austin,Sep,Q3,52200,2460,21.2,4.6,8400
Austin,Oct,Q4,56100,2620,21.4,4.7,8800
Austin,Nov,Q4,60200,2790,21.6,4.7,9200
Austin,Dec,Q4,64800,2980,21.7,4.8,9800
Chicago,Jan,Q1,37800,1890,20.0,3.9,4200
Chicago,Feb,Q1,36900,1850,19.9,4.0,4100
Chicago,Mar,Q1,38500,1930,19.9,4.0,4200
Chicago,Apr,Q2,39200,1960,20.0,4.1,4300
Chicago,May,Q2,40100,2000,20.1,4.0,4400
Chicago,Jun,Q2,41300,2060,20.0,4.0,4500
Chicago,Jul,Q3,40800,2040,20.0,4.1,4400
Chicago,Aug,Q3,41900,2090,20.0,4.0,4500
Chicago,Sep,Q3,42600,2130,20.0,4.1,4500
Chicago,Oct,Q4,43800,2190,20.0,4.1,4600
Chicago,Nov,Q4,44900,2240,20.0,4.2,4700
Chicago,Dec,Q4,47200,2360,20.0,4.1,5100
Portland,Jan,Q1,21800,880,24.8,4.7,1800
Portland,Feb,Q1,22100,890,24.8,4.8,1800
Portland,Mar,Q1,22600,910,24.8,4.7,1900
Portland,Apr,Q2,23200,930,24.9,4.8,1900
Portland,May,Q2,23800,955,24.9,4.8,2000
Portland,Jun,Q2,24500,980,25.0,4.8,2000
Portland,Jul,Q3,25200,1005,25.1,4.8,2100
Portland,Aug,Q3,25900,1030,25.1,4.9,2100
Portland,Sep,Q3,26100,1040,25.1,4.8,2100
Portland,Oct,Q4,26800,1065,25.2,4.9,2200
Portland,Nov,Q4,27500,1090,25.2,4.9,2200
Portland,Dec,Q4,29100,1145,25.4,4.9,2500
New York,Jan,Q1,14200,620,22.9,3.8,9500
New York,Feb,Q1,16800,730,23.0,3.9,9000
New York,Mar,Q1,19400,840,23.1,4.0,8500
New York,Apr,Q2,22600,970,23.3,4.1,8000
New York,May,Q2,26100,1110,23.5,4.1,7500
New York,Jun,Q2,30200,1280,23.6,4.2,7000
New York,Jul,Q3,34500,1450,23.8,4.2,6800
New York,Aug,Q3,38100,1590,24.0,4.3,6500
New York,Sep,Q3,40800,1690,24.1,4.3,6200
New York,Oct,Q4,43200,1780,24.3,4.4,6000
New York,Nov,Q4,45600,1870,24.4,4.4,6000
New York,Dec,Q4,49800,2020,24.7,4.5,7000
Boston,Jan,Q1,19200,870,22.1,3.6,4500
Boston,Feb,Q1,18600,845,22.0,3.7,4800
Boston,Mar,Q1,18900,860,22.0,3.7,5000
Boston,Apr,Q2,19400,880,22.0,3.8,5200
Boston,May,Q2,20100,910,22.1,3.8,5400
Boston,Jun,Q2,20600,930,22.2,3.9,5200
Boston,Jul,Q3,20200,915,22.1,3.8,4800
Boston,Aug,Q3,20800,940,22.1,3.9,4800
Boston,Sep,Q3,21200,960,22.1,3.9,5000
Boston,Oct,Q4,21800,985,22.1,4.0,5200
Boston,Nov,Q4,22300,1005,22.2,4.0,5400
Boston,Dec,Q4,24100,1080,22.3,4.1,5800
65 changes: 65 additions & 0 deletions data-stories/collaborative/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Project information

The Collaborative is one of Vermont's largest substance misuse prevention organizations, dedicated to empowering youth and families while fostering
healthy, supportive communities. One of their main initiatives is the Resilience Through Understanding (RTU) program which is a series of events
designed for middle and high school students and their families. The goal of this project was to track where the program maintains participation in these
events throughout the school year and where it starts to fall off.

Authors: Marissa Benz, Kate Marine, Andy Kim, Henry Ren, Natalia Schmitter-Emerson, SamMacuga

**Link to video:** https://youtu.be/Hd0XKR3HTLg

# Overview

## Research questions

Where does RTU's reach hold across the program year, and where does it break down?

Specifically:
- How many youth-adult pairs participate at each of the five events?
- Where in the program do the largest drops happen?
- Are those drops uniform across schools, or are they possibly driven by specific schools or specific event formats?
- What do the patterns suggest about program design and scalability?

## Data

We used data from a series of follow-up surveys that RTU asked partipants after each event. These surveys contain responses from both youth participants and their caring adults,
who attend events together as pairs (so for this project all participation counts refer to youth-adult pairs). The dataset for these surveys is an Excel workbook with one sheet
per event (Kickoff, Event 2, Event 3, Event 4, Event 5). Each row is one survey response from a youth-adult pair.

## Approach

We started by cleaning the data by removing blank rows (artifact from the Excel format) and standardizing school names so we didn't do any double-counting.
Then we counted youth-adult pairs (one row = one pair) at each of the five events. To analyze where the drops were happening, we built a matrix where rows were
schools and columns were events and observed the results.

## Findings

The first main point where we found participate to clearly start dropping off was Event 4. Response counts fell by 149 compared to Event 3, and it was consistent across all participating schools (BBA fell by 56, Long Trail by 22, Leland & Gray by 17, Flood Brook by 16, and Maple Street by 10).
Some of this could definitely be due to the fact that Event 4 was in January, where weather can disrupts scheduling and the ski pass incentive starts to lose its power as students have possibly already purchased ones for the season.
Comment on lines +38 to +39

The second major participation dropoff was at Event 5, especially when viewed at the school-level. There were 137 fewer responses in total.
Interestingly, participation came almost entirely from the schools Leland & Gray (23), BBA (20), and Long Trail (13). The other seven schools only had a handful of responses or none at all.


## Downloading the data

Survey dataset is stored an Excel workbook with one sheet per event (Kickoff, Event 2, Event 3, Event 4, Event 5).
Each row is one survey response from a youth-adult pair. See data-stories/collaborative/2025-2026 All RTU Data.xlsx

## Running the code

Link to colab notebook: https://colab.research.google.com/github/ContextLab/storytelling-with-data/blob/master/data-stories/collaborative/Assignment4.ipynb

## Contributing to the code

We want to acknowledge that the data is using survey responses and not actual attendance count. So if a pair attended an event but didn't fill out the follow-up survey then they get missed out
and this could definitely have contributed to misleading stats in our analysis. Also, we treat each row as one youth-adult pair and we don't have a consistent pair ID across events, so we can't track individual
pairs over time. Future surveys could implement this and allow for some interesting case studies of how participants perhaps change over time as they go through the events.
The Event 2 count exceeds Kickoff for several schools (e.g., Leland & Gray: 69 → 93). This likely reflects late joiners or makeup activity rather than a true increase in unique pairs. Our retention curves show this honestly rather than capping at 100%.
Finally, we can only really make guesses at the reasons behind some of the participation drops. Future work could possibly involve more interviews from Collaborative staff and participants.


## Acknowledgements

Thank you to https://thecollaborative.us/ for giving access to their survey data and allowing us to help support their work.
Loading