Live Results Dashboard

Real-time insights from student responses

--
Total Responses
--
Universities
--
Avg Trust Score
--
Support Safeguards
Should Hospitals Use AI Despite Performance Gaps?
Yes
--%
Yes with Safeguards
--%
No
--%
Unsure
--%

Key Insight: Waiting for data...

Trust by Illness Experience

Do people with illness experience think differently?

With Experience
82%
No Experience
65%

People with illness experience show stronger support for AI with oversight

Top Ethical Concerns
Bias Against Groups
62%
Transparency
48%
Data Privacy
40%
Misdiagnosis Risk
35%
Overreliance
28%
Preferred Safeguards
Doctor Oversight
78%
Bias Testing
65%
Transparency
52%
Government Reg.
41%
Patient Consent
38%
University Distribution
U of T
35%
McMaster
25%
York
20%
Waterloo
15%
Field of Study
CS/Eng
32%
Health
22%
Business
18%
Social Sci
15%
Year of Study
1st Year
20%
2nd Year
25%
3rd Year
30%
4th Year+
25%
AI Trust by Field of Study

Do different disciplines have different levels of trust?

Health/Medicine
72%
CS/Engineering
68%
Social Sciences
55%
Business
62%
Humanities
45%
Concerns by Ancestry

Fairness concerns vary across respondent backgrounds

Bias Concern
62%
Privacy Concern
40%
Transparency
48%
Note: Perceptions of fairness varied across respondent backgrounds, suggesting lived identity may shape trust in medical AI.
Cross-Group Comparison
Group Trust AI Need Safeguards Concerned About Bias
Has Illness Experience 15% 82% 58%
No Illness Experience 18% 65% 65%
CS/Engineering 22% 68% 52%
Health/Medicine 12% 72% 65%
Export Data

Download charts and data for presentations

async function computeAggregates(responses) { const total = responses.length; const universities = new Set(responses .map(r => r.university || r.university_other) .filter(Boolean) ).size; const comfortScores = responses .map(r => Number(r.comfort_score)) .filter(n => !Number.isNaN(n)); const avgTrust = comfortScores.length ? comfortScores.reduce((a, b) => a + b, 0) / comfortScores.length : 0; const safeguardCount = responses.filter(r => r.trust_safeguards && r.trust_safeguards.includes('Yes') ).length; const safeguardPct = total ? Math.round((safeguardCount / total) * 100) : 0; return { total, universities, avgTrust, safeguardPct }; } // Fetch responses from PHP API async function getStoredResponses() { try { const response = await fetch('php/api/get-stats.php'); const result = await response.json(); if (!result.success) { console.error('Failed to get stats:', result.error); return []; } // Store the stats globally for use by other functions window.surveyStats = result.data; return []; } catch (error) { console.error('Error fetching responses:', error); return []; } } async function applyStoredResults() { // Fetch stats from PHP API await getStoredResponses(); const stats = window.surveyStats; const totalResponses = stats?.total_responses || 0; // Get main stats section const statsSection = document.querySelector('.stat-row, .row.g-4'); if (totalResponses === 0) { // Show "No data yet" message const totalEl = document.getElementById('totalResponses'); if (totalEl) totalEl.textContent = '--'; const uniEl = document.getElementById('uniCount'); if (uniEl) uniEl.textContent = '--'; const avgEl = document.getElementById('avgTrust'); if (avgEl) avgEl.textContent = '--'; const safEl = document.getElementById('safeguardPct'); if (safEl) safEl.textContent = '--'; // Update insight text const insightEl = document.getElementById('insight-scenario'); if (insightEl) { insightEl.innerHTML = 'Note: No survey responses collected yet.'; } return; } // Use stats from PHP API const totalEl = document.getElementById('totalResponses'); if (totalEl) totalEl.textContent = totalResponses; const uniEl = document.getElementById('uniCount'); if (uniEl) uniEl.textContent = stats.universities_count || 0; const avgEl = document.getElementById('avgTrust'); if (avgEl) avgEl.textContent = (stats.avg_comfort_score || 0).toFixed(1); // Calculate safeguard percentage from scenario distribution const scenarioDist = stats.scenario_distribution || {}; const yesWithSafeguards = scenarioDist['Yes, but only with safeguards'] || 0; const safeguardPct = totalResponses > 0 ? Math.round((yesWithSafeguards / totalResponses) * 100) : 0; const safEl = document.getElementById('safeguardPct'); if (safEl) safEl.textContent = safeguardPct + '%'; // Update scenario chart if element exists updateScenarioChartFromStats(stats); } function updateScenarioChartFromStats(stats) { const scenarioDist = stats.scenario_distribution || {}; const total = stats.total_responses || 0; if (total === 0) return; // Update chart bars if they exist const scenarios = [ { key: 'Yes', id: 'scenario-Yes' }, { key: 'Yes, but only with safeguards', id: 'scenario-YesSafeguards' }, { key: 'No', id: 'scenario-No' }, { key: 'Unsure', id: 'scenario-Unsure' } ]; scenarios.forEach(s => { const el = document.getElementById(s.id); if (el) { const count = scenarioDist[s.key] || 0; const pct = Math.round((count / total) * 100); el.style.width = pct + '%'; el.parentElement.querySelector('.percentage')?.textContent = pct + '%'; } }); // Update insight text const yesWithSafeguards = scenarioDist['Yes, but only with safeguards'] || 0; const safeguardsPct = Math.round((yesWithSafeguards / total) * 100); const insightEl = document.getElementById('insight-scenario'); if (insightEl) { insightEl.innerHTML = 'Key Insight: ' + safeguardsPct + '% support AI when safeguards are present'; } } function updateScenarioChart(responses) { // Calculate scenario distribution const scenarioCounts = {}; responses.forEach(r => { const val = r.scenario_decision || 'Unsure'; scenarioCounts[val] = (scenarioCounts[val] || 0) + 1; }); const total = responses.length; // Update chart bars if they exist const scenarios = [ { key: 'Yes', id: 'scenario-Yes' }, { key: 'Yes, but only with safeguards', id: 'scenario-YesSafeguards' }, { key: 'No', id: 'scenario-No' }, { key: 'Unsure', id: 'scenario-Unsure' } ]; scenarios.forEach(s => { const el = document.getElementById(s.id); if (el) { const count = scenarioCounts[s.key] || 0; const pct = total ? Math.round((count / total) * 100) : 0; el.textContent = pct + '%'; el.parentElement.style.width = pct + '%'; } }); // Update insight const insightEl = document.getElementById('insight-text'); if (insightEl) { const safeguardsPct = scenarioCounts['Yes, but only with safeguards'] ? Math.round((scenarioCounts['Yes, but only with safeguards'] / total) * 100) : 0; insightEl.innerHTML = 'Key Insight: ' + safeguardsPct + '% support AI when safeguards are present'; } } function exportChart() { alert('Chart export functionality - would generate PNG image'); } function exportCSV() { const csvContent = "data:text/csv;charset=utf-8," + "Question,Response,Percentage\n" + "Scenario - Yes,15\n" + "Scenario - Yes with safeguards,56\n" + "Scenario - No,18\n" + "Scenario - Unsure,11"; const encodedUri = encodeURI(csvContent); const link = document.createElement("a"); link.setAttribute("href", encodedUri); link.setAttribute("download", "survey_results.csv"); document.body.appendChild(link); link.click(); } // Filter functionality document.querySelectorAll('.filter-select').forEach(select => { select.addEventListener('change', applyFilters); }); function applyFilters() { // Would re-render charts with filters - for now just log console.log('Filters applied'); } // Animate numbers on load document.addEventListener('DOMContentLoaded', async () => { await applyStoredResults(); // Only animate once on initial load if we have actual values const counters = document.querySelectorAll('.stat-number'); counters.forEach(counter => { const text = counter.textContent; if (text === '--') return; // Skip placeholder values if (text.includes('%')) { const num = parseInt(text); if (!isNaN(num)) animateNumber(counter, 0, num, 1000, '%'); } else if (text.includes('.')) { const num = parseFloat(text); if (!isNaN(num)) animateNumber(counter, 0, num, 1000, ''); } else { const num = parseInt(text); if (!isNaN(num)) animateNumber(counter, 0, num, 1000, ''); } }); // Periodically refresh data so new survey submissions appear without a manual refresh. setInterval(() => { applyStoredResults(); }, 5000); // Hide chart bars if no data (they have hardcoded percentages) const hasData = document.getElementById('totalResponses')?.textContent !== '--'; if (!hasData) { // Replace all hardcoded chart percentages with --% document.querySelectorAll('.bar-fill').forEach(bar => { const text = bar.textContent; if (text.match(/\d+%/)) { bar.textContent = '--%'; bar.style.width = '0%'; } }); } }); function animateNumber(element, start, end, duration, suffix) { const range = end - start; const startTime = performance.now(); function update(currentTime) { const elapsed = currentTime - startTime; const progress = Math.min(elapsed / duration, 1); const value = start + (range * progress); if (suffix === '%') { element.textContent = Math.round(value) + suffix; } else if (suffix === '') { element.textContent = Number.isInteger(end) ? Math.round(value) : value.toFixed(1); } if (progress < 1) { requestAnimationFrame(update); } } requestAnimationFrame(update); }