Unlisted
Edited
Dec 18, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
followupsHistoHorizontal = {
const col = "followup_queue.sum";
const ppt_data = user_stats.filter(d => selected_ppt_id == d.ppt_id);
return Plot.plot({
title: `Followups Required`,
marginRight: 80,
height: 400,
x: {
label: 'Number of Participants',
grid: true,
},
y: {
label: 'Number of Followups Required',
type: 'linear',
tickFormat: d => Math.floor(d),
// reverse: true, // NOTE: works for `type: 'band'`
},
color: {
// type: 'ordinal',
legend: true,
},
marks: [
Plot.rectX(
user_stats,
Plot.binY(
{
x: "count",
},
{
y: col,
fill: lighter_color,
tip: true,
},
)
),
Plot.ruleY(
ppt_data,
{
y: col,
stroke: darker_color,
strokeWidth: 3,
}
),
Plot.textY(
ppt_data,
{
y: col,
text: col,
textAnchor: 'start',
dx: 5,
dy: -10,
frameAnchor: 'right',
}
),
]
});
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
smallHistoFunction = ({overrideWidth=null, overrideHeight=null}) => {
// TODO: Get rid of all this extra stuff (doesn't actually improve resize behavior).

// TODO: Revise this histo and corresponding plot above as a single coordinated D3 plot,
// where the bars of the histo line up with the corresponding categories (or bins
// for continuous data).
const conf = {
width: width, // default width
x: {
label: null,
ticks: [],
},
y: {
label: null,
reverse: true,
},
marks: [
Plot.barX(
study_data.filter(d => d[selectedField] || d[selectedField] == 0),
Plot.binY(
{
x: 'count',
},
{
y: selectedField,
fill: lighter_color,
thresholds: 11,
tip: true,
}
)
),
]
}

// override width/height
if (overrideWidth || overrideWidth == 0) {
conf.width = overrideWidth;
}
if (overrideHeight || overrideHeight == 0) {
conf.height = overrideHeight;
}
return Plot.plot(conf);
}
Insert cell
responsivePlotFactory = plot_func => (container) => {
const updatePlot = () => {
const plot = plot_func({
overrideWidth: container.clientWidth || 200,
overrideHeight: container.clientHeight || 200,
});

// Replace or update the existing plot in the container
container.innerHTML = '';
container.appendChild(plot);
};

// Initial plot creation
updatePlot();

// Add event listener to update plot on container resize
window.addEventListener('resize', updatePlot);

// Return the container element
return container;
}
Insert cell
testSmallHisto = responsivePlotFactory(smallHistoFunction)(DOM.element('div'))
Insert cell
// NOTE: this will feedback forever without a height limit (in the notebook, at least)
testResponsive = responsivePlotFactory(
({overrideWidth=null, overrideHeight=null}) => Plot.plot({
width: overrideWidth,
height: Math.min(200, overrideHeight),
title: `Distribution of Significant Gaps`,
x: {
label: 'Number of Participants',
grid: true,
},
y: {
label: 'Number of Followups Required',
type: 'band',
tickFormat: d => Math.floor(d),
reverse: true,
},
color: {
// type: 'ordinal',
legend: true,
},
marks: [
Plot.barX(
user_stats,
Plot.binY(
{
x: "count",
},
{
y: {
value: "followup_queue.sum",
},
fill: lighter_color,
tip: true,
},
)
),
]
})
)(DOM.element('div'));
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
egStory = histoTen(
user_stats.filter(d => d['now_context_social.0.count'] > 150),
'now_affect_lonely',
'mean',
'More than 150 surveys answered alone'
)
Insert cell
findingsDesc1 = md`Perhaps unsurprisingly, we found that individuals who answered more than 150 surveys alone, were also far more likely to have higher mean scores for lonely affect. You completed ${user_stats.find(d => selected_ppt_id == d.ppt_id)['now_context_social.0.count']} surveys alone. As you continue in your journey of positive psychology, we encourage you to continue pursuing social connection.`
Insert cell
egRef = histoTen(
user_stats.filter(d => d['now_context_social.0.count'] <= 150),
'now_affect_lonely',
'mean',
'Fewer than 150 surveys answered alone'
)
Insert cell
histoTen(
user_stats,
'now_affect_sad',
'mean',
)
Insert cell
histoTen = (data, selected_feat, selected_agg, title) => {
const col = `${selected_feat}.${selected_agg}`;
const desc = colDescMap.has(selected_feat)
? `${selected_agg} ${colDescMap.get(selected_feat)}`
: col;
const marks = [
Plot.barY(
data,
Plot.groupX(
{
y: "proportion",
},
{
x: d => Math.round(d[col]),
// fill: lighter_color,
fill: d => selected_ppt_id == d.ppt_id ? 'You' : 'Population',
tip: true,
// thresholds: null,
},
),
),
];
const ppt_data = data.find(d => selected_ppt_id == d.ppt_id);
// if (ppt_data) {
// marks.push(
// Plot.ruleX(
// [ppt_data],
// {
// x: col,
// },
// )
// );
// };
return Plot.plot({
height: 400,
width: 600,
title: title,
// title: `Distribution of user ${selected_agg} for "${selected_feat}""`,
x: {
label: desc,
type: 'band',
domain: d3.range(11),
},
y: {
grid: true,
domain: [0, 1],
},
color: {
domain: ppt_data ? ['You', 'Population'] : ['Population'],
range: ppt_data ? [darker_color, lighter_color] : [lighter_color],
legend: true,
},
marks: marks,
});
}
Insert cell
d3.min(user_stats, d => d['now_sitb_si_intent.min'])
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
angrySadHeatMap = heatMap(study_data, 'now_affect_angry', 'now_affect_sad', scaling, {})
Insert cell
sadHopelessHeatMap = heatMap(study_data, 'now_affect_sad', 'now_affect_hopeless', scaling, {})
Insert cell
hopelessAngryHeatMap = heatMap(study_data, 'now_affect_hopeless', 'now_affect_angry', scaling, {})
Insert cell
heatMap = (
study_data,
heatX,
heatY,
scaling,
{
title=null,
height=null,
width=null,
}
) => {
const xDesc = colDescMap.has(heatX) ? colDescMap.get(heatX) : heatX;
const yDesc = colDescMap.has(heatY) ? colDescMap.get(heatY) : heatY;
const x = {
label: xDesc,
};
const y = {
label: yDesc,
reverse: true,
};

// Function to calculate Pearson correlation coefficient
const pearsonCorrelation = (data, x, y) => {
let n = 0;
let xSum = 0;
let ySum = 0;
let xySum = 0;
let x2Sum = 0;
let y2Sum = 0;

data.forEach(d => {
const xVal = +d[x];
const yVal = +d[y];
if (!isNaN(xVal) && !isNaN(yVal)) {
n++;
xSum += xVal;
ySum += yVal;
xySum += xVal * yVal;
x2Sum += xVal * xVal;
y2Sum += yVal * yVal;
}
});

if (n === 0) return NaN;

const numerator = (n * xySum) - (xSum * ySum);
const denominator = Math.sqrt((n * x2Sum - xSum * xSum) * (n * y2Sum - ySum * ySum));

return numerator / denominator;
};

// Calculate correlation coefficient
const correlationCoefficient = pearsonCorrelation(study_data, heatX, heatY);

return Plot.plot({
grid: true,
height: height || 400,
width: width || 600,
padding: 0,
marginLeft: 50,
x: x,
y: y,
color: {type: scaling, scheme: "Warm", legend: true},
title: title || `Correlation (${xDesc}, ${yDesc}): ${correlationCoefficient.toFixed(2)}`,
marks: [
Plot.cell(
study_data,
Plot.bin(
{fill: "count"},
{x: heatX, y: heatY}
)
),
]
});
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more