Skip to main content

Cortex Visualizations

Cortex includes three visualization modules in cortex.visualizations. The participant and data quality modules produce Altair/Vega-Lite chart specifications that can be uploaded directly to the LAMP portal dashboard. The correlation module produces Matplotlib figures for offline analysis.

Participant Visualizationsโ€‹

cortex.visualizations.participant โ€” generates participant-level charts for the LAMP portal.

All functions in this module accept LAMP IDs at any level (participant, study, or researcher). When a study or researcher ID is provided, the function iterates over all participants below it.

passive()โ€‹

Passive sensor data quality visualization showing when data was received and collection density.

from cortex.visualizations.participant import passive

result = passive(
id_list="U1234567890",
sensor_info=[
{"sensor": "lamp.gps", "target_hz": 0.1, "display_name": "GPS_Quality"},
{"sensor": "lamp.accelerometer", "target_hz": 3, "display_name": "Accel_Quality"}
],
show_graphs=True,
attach_graphs='all',
display_graphs=True,
days_ago=0,
sample_length=7,
set_to_utc_midnight=True,
return_dict=False,
reset=False
)
ParameterTypeDefaultDescription
id_liststr or listrequiredLAMP ID(s) โ€” participant, study, or researcher
sensor_infolistGPS + accelerometerSensors to visualize, each a dict with sensor (LAMP sensor name), target_hz (expected delivered sampling rate), and display_name (label for graphs and attachments)
Why target_hz for GPS defaults to 0.1, not 1

The app requests GPS at 1 Hz (once per second), but mobile operating systems aggressively throttle background location delivery. In practice, GPS data points arrive at roughly 0.1 Hz (once per 10 seconds) or less when the app is in the background. Cortex's target_hz reflects this real-world delivered rate โ€” it is used to draw the reference line on scatter plots and to evaluate data quality against realistic expectations, not the configured request rate. Similarly, Cortex's data_quality feature uses 10-minute bins for GPS (not 1-second bins) because this aligns with achievable coverage in background collection.

| show_graphs | bool | True | Display graphs in output | | attach_graphs | bool or str | 'all' | Attach graphs to participant. Options: True/'all' (both), 'scatter', 'heatmap', or False | | display_graphs | bool | True | Display graphs on study/researcher portal | | days_ago | int | 0 | Days ago the analysis window ends (0 = today) | | sample_length | int | 7 | Window length in days | | set_to_utc_midnight | bool | True | Align window boundaries to UTC midnight | | reporter_func | callable | print | Function for logging output (e.g., Slack webhook) | | return_dict | bool | False | If True, return summary dictionary; else return None | | reset | bool | False | Delete cached data from previous runs |

Returns: Summary dictionary (if return_dict=True) containing raw data and chart specs per participant and sensor, or None.

Each sensor produces two chart components:

  • Scatter plot โ€” data entries received over time, with a target sample rate reference line
  • Heatmap โ€” hourly data density by day
Scatter plotHeatmap
Passive scatter plotPassive heatmap

Results are cached as LAMP attachments (under lamp.analysis.<display_name>_stored) to speed up subsequent runs. Use reset=True to clear cached data.

active()โ€‹

Activity completion visualization showing engagement over time.

from cortex.visualizations.participant import active

result = active(
id_list="U1234567890",
target_array=[''],
exclude_array=None,
exclude_groups=True,
show_graphs=True,
attach_graphs=True,
display_graphs=True,
graph_name='lamp.dashboard.experimental.activity_counts',
days_ago=0,
sample_length=30,
reporter_func=print,
return_dict=False
)
ParameterTypeDefaultDescription
id_liststr or listrequiredLAMP ID(s) โ€” participant, study, or researcher
target_arraylist['']Filter by activity specs, names, or IDs. Include '' to show all activities
exclude_arraylistNoneActivity names to exclude
exclude_groupsboolTrueExclude group activity completions
show_graphsboolTrueDisplay graphs in output
attach_graphsboolTrueAttach graphs to participant
display_graphsboolTrueDisplay graphs on study/researcher portal
graph_namestr'lamp.dashboard.experimental.activity_counts'LAMP attachment key for the graph
days_agoint0Days ago the analysis window ends (0 = today)
sample_lengthint30Window length in days
reporter_funccallableprintFunction for logging output
return_dictboolFalseIf True, return data dictionary; else return None

Returns: Dictionary of DataFrames per participant (if return_dict=True), or None. Generates a stacked bar chart of activity counts by type over time with interactive tooltips.

Active visualization โ€” activity completion over time

cortex_tertiles()โ€‹

Tertile analysis of Cortex features, categorizing values into high/medium/low bands with color-coded temporal trends.

from cortex.visualizations.participant import cortex_tertiles

result = cortex_tertiles(
target_id="U1234567890",
cortex_measures=['acc_energy', 'entropy', 'hometime', 'screen_duration'],
measure_params={},
use_cache=False,
show_graphs=True,
attach_graphs=True,
display_graphs=True,
days_ago=0,
sample_length=7,
set_to_utc_midnight=True,
reporter_func=print,
return_dict=False
)
ParameterTypeDefaultDescription
target_idstr or listrequiredLAMP ID(s) โ€” participant, study, or researcher
cortex_measuresstr, list, or dict['acc_energy', 'entropy', 'hometime', 'screen_duration']Cortex features to analyze. If a dict, keys are feature names and values are display labels (e.g., {'sleep_periods': 'Sleep'})
measure_paramsdict{}Parameters to pass to cortex.run()
use_cacheboolFalseUse cached Cortex data
show_graphsboolTrueDisplay graphs in output
attach_graphsboolTrueAttach graphs to participant
display_graphsboolTrueDisplay graphs on study/researcher portal
days_agoint0Days ago the analysis window ends (0 = today)
sample_lengthint7Window length in days
set_to_utc_midnightboolTrueAlign window boundaries to UTC midnight
reporter_funccallableprintFunction for logging output
return_dictboolFalseIf True, return results dictionary; else return None

Returns: Dictionary containing raw Cortex output and Vega-Lite chart specs per participant (if return_dict=True), or None.

Tertile boundaries are computed from the data range: values above the upper third are "High" (blue), between upper and lower third are "Medium" (salmon), below the lower third are "Low" (goldenrod), and exactly zero are "Zero" (black).

Screen durationHometimeEntropy
Screen duration tertilesHometime tertilesEntropy tertiles

create_sample_window()โ€‹

Helper to define a time window for analysis.

from cortex.visualizations.participant import create_sample_window

start, end = create_sample_window(
end_of_window=7,
sample_length=7,
set_to_utc_midnight=True
)
# Returns (start_ms, end_ms) for the window 14โ€“7 days ago
ParameterTypeDefaultDescription
end_of_windowintrequiredNumber of days ago the window ends
sample_lengthintrequiredWindow length in days (goes backward from end_of_window)
set_to_utc_midnightboolrequiredAlign boundaries to UTC midnight

Returns: Tuple of (start_timestamp_ms, end_timestamp_ms).


Data Quality Dashboardโ€‹

cortex.visualizations.data_quality โ€” researcher-level data quality monitoring. These functions generate visualizations and upload them directly to the LAMP portal.

Data quality visualizations in the LAMP Data Portal

data_quality()โ€‹

Generates a comprehensive quality report for all participants under a researcher. Orchestrates all helper functions below.

import cortex.visualizations.data_quality as dq

dq.data_quality(researcher_id="R1234567890")
ParameterTypeDefaultDescription
researcher_idstrrequiredResearcher LAMP ID

Returns: None โ€” uploads graphs directly to the LAMP portal. The analysis window is the most recent 7 days (hardcoded).

Generated visualizations:

  1. Activity type breakdown across participants (make_activity_count_graph)
  2. Data quality status tags (make_data_qual_tags)
  3. Passive feature summaries โ€” steps, screen duration, hometime (make_passive_data_graphs)

Activity type breakdown

Quality tagsLegend
Data quality tags heatmapQuality legend
StepsScreen durationHometime
Average stepsAverage screen durationAverage hometime

Quality thresholds:

SensorGoodOkayBad
GPS>0.80.5โ€“0.8<0.5
Accelerometer>0.80.5โ€“0.8<0.5
Screen StateData every day in windowโ€”Missing days

Quality tags append _missing (e.g., good_missing) when a sensor has overall good quality but is missing data on specific days. A sensor with no data at all is tagged missing.

Helper functionsโ€‹

These are called internally by data_quality() but can also be used individually. Note that most require pre-computed data from other helpers โ€” they do not accept simple (researcher_id, days) signatures.

FunctionSignatureDescription
get_parts(researcher_id)(researcher_id)Returns list of dicts with participant_id and study_name for all participants under a researcher
get_data_tags_df(participants)(participants)Assess data quality per participant. Takes output from get_parts(). Returns (qual_df1, qual_df2) โ€” raw quality DataFrame and plotting-ready DataFrame
make_activity_count_graph(participants, researcher_id)(participants, researcher_id)Activity type breakdown chart (Survey, Tips, Breathe, Group, Games, Other)
make_data_qual_tags(researcher_id, qual_df2)(researcher_id, qual_df2)Quality status heatmap. Takes qual_df2 from get_data_tags_df()
make_passive_data_graphs(participants, researcher_id, qual_df1)(participants, researcher_id, qual_df1)Feature summary charts for steps, screen duration, and hometime. Takes qual_df1 from get_data_tags_df(). Features are hardcoded
make_survey_count_graph_by_name(participants, researcher_id, name)(participants, researcher_id, name)Survey completion counts for a specific survey (exact name match)
make_percent_completion_graph(spec, researcher_id, name)(spec, researcher_id, name)Activity compliance rates. spec is a dict mapping IDs to expected activity counts (see below)
clear_chart(researcher_id, name)(researcher_id, name)Remove a specific chart from the LAMP portal by name

Typical workflow using helpers individually:

import cortex.visualizations.data_quality as dq

# Step 1: Get participants
participants = dq.get_parts("R1234567890")

# Step 2: Compute quality tags
qual_df1, qual_df2 = dq.get_data_tags_df(participants)

# Step 3: Generate individual charts
dq.make_activity_count_graph(participants, "R1234567890")
dq.make_data_qual_tags("R1234567890", qual_df2)
dq.make_passive_data_graphs(participants, "R1234567890", qual_df1)
dq.make_survey_count_graph_by_name(participants, "R1234567890", "Daily Survey")

make_percent_completion_graph spec format:

spec = {
"U1234567890": [
{"activity_name": "Daily Survey", "count": 7, "time_interval": 7 * 86400000},
{"activity_name": "Weekly Check-in", "count": 1, "time_interval": 7 * 86400000}
]
}
dq.make_percent_completion_graph(spec, "R1234567890", "compliance")

Each entry specifies an activity name, the expected completion count, and the time interval (in ms) to check. Participants can be grouped under any LAMP ID level.

# Clear a specific chart
dq.clear_chart("R1234567890", "compliance")

Correlation Analysisโ€‹

cortex.visualizations.correlation_functions โ€” statistical analysis and correlation plotting for research. Unlike the other modules, these produce local Matplotlib figures rather than LAMP portal uploads.

get_corr()โ€‹

Compute Pearson correlations with Benjamini-Hochberg FDR correction for multiple testing.

from cortex.visualizations.correlation_functions import get_corr

mat, pvals, corr_df = get_corr(
combined_df0,
survey_list=["PHQ-9", "GAD-7"],
feat_list=["screen_duration", "step_count", "hometime"],
req_list=[],
alpha=0.05,
show_num=1
)
ParameterTypeDefaultDescription
combined_df0DataFramerequiredCombined feature data with columns for all surveys and features
survey_listlistrequiredSurvey/outcome variable names (row labels in the matrix)
feat_listlistrequiredFeature/predictor variable names (column labels in the matrix)
req_listlist[]Filter criteria โ€” list of dicts with col_name, val, greater_than (1 for >, 0 for <)
alphafloat0.05Significance level for FDR correction
show_numint1Include correlation coefficient values in output strings

Returns:

  • mat โ€” correlation matrix (numpy array, shape: surveys x features)
  • pvals โ€” list of string arrays with coefficients and * for significant correlations after FDR correction
  • corr_df โ€” DataFrame with columns key, corr, p-val, and N

make_corr_plot()โ€‹

Create a correlation heatmap from get_corr() output.

from cortex.visualizations.correlation_functions import make_corr_plot

fig = make_corr_plot(mat, pvals, survey_list, feat_list, title="Feature Correlations")
ParameterTypeDefaultDescription
matnumpy arrayrequiredCorrelation matrix from get_corr()
pvalslistrequiredSignificance strings from get_corr()
survey_listlistrequiredRow labels
feat_listlistrequiredColumn labels
titlestr""Plot title

Returns: Matplotlib figure โ€” seaborn heatmap (color scale -0.5 to 0.5) with significance asterisks after FDR correction. Axis labels are shown when there are fewer than 10 items.

Correlation heatmapFeature key
Correlation heatmap exampleFeature key

get_avg_var_data()โ€‹

Compute average or variance for features across participants. Reads pre-saved survey CSVs and passive data pickle files from disk.

from cortex.visualizations.correlation_functions import get_avg_var_data

avg_df = get_avg_var_data(
parts=participant_ids,
scoring_guide=scoring_dict,
other_global_feats=["step_count"],
other_local_feats=["screen_duration"],
other_local_subfeats={"screen_duration": ["col1", "col2"]},
passive_feats=["hometime"],
survey_dir="/path/to/surveys/",
passive_dir="/path/to/passive/",
avg=1,
time_to_include=[-1, -1]
)
ParameterTypeDefaultDescription
partslistrequiredParticipant IDs
scoring_guidedictrequiredSurvey scoring dictionary with category_list and questions keys
other_global_featslistrequiredGlobal features (read from <id>_other_global_feats.csv)
other_local_featslistrequiredLocal features (read from <id>_<feat>.csv)
other_local_subfeatsdictrequiredSub-columns to extract per local feature
passive_featslistrequiredPassive features (read from <id>_<feat>.pkl)
survey_dirstrrequiredDirectory containing survey and feature CSVs
passive_dirstrrequiredDirectory containing passive data pickle files
avgint11 for average, 0 for variance
time_to_includelist[-1, -1][start_offset_ms, end_offset_ms] relative to first SensorEvent. [-1, -1] includes all time

Returns: DataFrame with part_id and one column per feature containing averages or variances.

produce_improvement_df0()โ€‹

Track feature changes over time relative to baseline โ€” for treatment response and longitudinal outcome analysis.

from cortex.visualizations.correlation_functions import produce_improvement_df0

improvement_df = produce_improvement_df0(
parts=participant_ids,
feature_name="PHQ-9",
amount_change=5.0,
feat_dir_0="/path/to/features/",
fn_0="phq9.csv",
min_num_records=2,
min_starting_score=0,
min_time_diff=0
)
ParameterTypeDefaultDescription
partslistrequiredParticipant IDs
feature_namestrrequiredColumn name in the feature file to compare
amount_changefloatrequiredMinimum change threshold (start - end). If between 0 and 1, treated as a proportion
feat_dir_0strrequiredDirectory containing feature files
fn_0strrequiredFeature filename (e.g., phq9.csv). Full path: <feat_dir_0><participant_id>_<fn_0>
min_num_recordsint2Minimum records required (must be at least 2)
min_starting_scorefloat0Only include participants with at least this starting score
min_time_difffloat0Minimum time difference (ms) between first and last records

Returns: DataFrame with columns part_id, improved (bool or None if criteria not met), and change (last value - first value).

Improvement across surveys and features

save_surveys_to_file()โ€‹

Export survey scores to CSV files, one per scoring category.

from cortex.visualizations.correlation_functions import save_surveys_to_file

save_surveys_to_file(
part_id="U1234567890",
survey_path="/path/to/output/",
scoring_dict=scoring_dict
)
# Creates files like U1234567890_anxiety.csv, U1234567890_depression.csv
ParameterTypeDefaultDescription
part_idstrrequiredParticipant ID
survey_pathstrrequiredOutput directory path
scoring_dictdictrequiredSurvey scoring dictionary with category_list and questions keys

Returns: None โ€” writes CSV files to disk. Each file is named <part_id>_<category>.csv with columns for each question in that category plus a timestamp column. Calls cortex.primary.survey_scores internally with return_ind_ques=True.