From ec4ad4934b6753a9fd8b5c946036bb846e0ba394 Mon Sep 17 00:00:00 2001 From: Matt Huntington Date: Thu, 28 Sep 2023 10:12:26 -0400 Subject: [PATCH 1/9] removing todo --- public/app.js | 1 - 1 file changed, 1 deletion(-) diff --git a/public/app.js b/public/app.js index fa806ce..527491d 100644 --- a/public/app.js +++ b/public/app.js @@ -1,4 +1,3 @@ -// TODO - styling const WIDTH = 800; const HEIGHT = 600; const parseTime = d3.timeParse("%B %e, %Y"); From d2540495fa6163050c1a0479ff650e4185f6a0ba Mon Sep 17 00:00:00 2001 From: Matt Huntington Date: Thu, 28 Sep 2023 19:15:25 -0400 Subject: [PATCH 2/9] moved zoom/pan to func --- public/app.js | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/public/app.js b/public/app.js index 527491d..649e33b 100644 --- a/public/app.js +++ b/public/app.js @@ -241,6 +241,26 @@ const createRadioButtonHanlders = ()=>{ }) } +const setUpZoomPan = ()=>{ + const zoomCallback = (event) => { + d3.select('#points').attr("transform", event.transform); + d3.select('#x-axis') + .call(bottomAxis.scale(event.transform.rescaleX(xScale))); + d3.select('#y-axis') + .call(leftAxis.scale(event.transform.rescaleY(yScale))); + + if(event.transform.k !== zoomScale){ + zoomScale = event.transform.k + d3.selectAll('circle') + .attr('r', datum => (datum.color ? 10 : 5) / zoomScale); + } + } + + const zoom = d3.zoom() + .on('zoom', zoomCallback); + d3.select('#container').call(zoom); +} + window.onload = async ()=>{ instances = await d3.json('/instances'); for(let instance of instances){ @@ -261,21 +281,5 @@ window.onload = async ()=>{ renderPoints(); createFormSubmissionHandler(); createRadioButtonHanlders(); - const zoomCallback = (event) => { - d3.select('#points').attr("transform", event.transform); - d3.select('#x-axis') - .call(bottomAxis.scale(event.transform.rescaleX(xScale))); - d3.select('#y-axis') - .call(leftAxis.scale(event.transform.rescaleY(yScale))); - - if(event.transform.k !== zoomScale){ - zoomScale = event.transform.k - d3.selectAll('circle') - .attr('r', datum => (datum.color ? 10 : 5) / zoomScale); - } - } - - const zoom = d3.zoom() - .on('zoom', zoomCallback); - d3.select('#container').call(zoom); + setUpZoomPan(); } From 64f5fa88bb27c2df56c39185374c5f6e3bc50a40 Mon Sep 17 00:00:00 2001 From: Matt Huntington Date: Thu, 28 Sep 2023 20:00:57 -0400 Subject: [PATCH 3/9] starting average work --- public/app.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/public/app.js b/public/app.js index 649e33b..732876c 100644 --- a/public/app.js +++ b/public/app.js @@ -11,6 +11,8 @@ let yAxis = 'outcomes' let bottomAxis; let leftAxis; let zoomScale = 1 +let averageOutcomes = [] +let sortedInstances; const randomColor = ()=>{ const red = Math.floor(Math.random()*128) + 64; @@ -261,6 +263,23 @@ const setUpZoomPan = ()=>{ d3.select('#container').call(zoom); } +const getAverage = (start, end) => { + let sum = 0 + for(let i = start; i < end; i++){ + sum += sortedInstances[i].ninety_day_outcomes/sortedInstances[i].graduates*100 + } + averageOutcomes.push({average:sum/(end-start), initialGraduationDate:sortedInstances[start].graduation_date}) +} + +const displayMeanStandardDeviation = () => { + sortedInstances = instances.sort((a,b) => Date.parse(a.graduation_date) - Date.parse(b.graduation_date)) + + for(let i = 0; i < sortedInstances.length-10; i += 10){ + getAverage(i,i+10) + } + console.log(averageOutcomes); +} + window.onload = async ()=>{ instances = await d3.json('/instances'); for(let instance of instances){ @@ -282,4 +301,6 @@ window.onload = async ()=>{ createFormSubmissionHandler(); createRadioButtonHanlders(); setUpZoomPan(); + + displayMeanStandardDeviation(); } From c5f759cda45c06db1bdfc53058b271b3bdcb7bde Mon Sep 17 00:00:00 2001 From: Matthew Huntington Date: Thu, 28 Sep 2023 21:17:43 -0400 Subject: [PATCH 4/9] created average line --- public/app.js | 46 ++++++++++++++++++++++++++++++++++++++++------ public/index.html | 5 +++++ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/public/app.js b/public/app.js index 732876c..4d86c97 100644 --- a/public/app.js +++ b/public/app.js @@ -11,8 +11,9 @@ let yAxis = 'outcomes' let bottomAxis; let leftAxis; let zoomScale = 1 -let averageOutcomes = [] +let averageOutcomes let sortedInstances; +let displayAverage = true; const randomColor = ()=>{ const red = Math.floor(Math.random()*128) + 64; @@ -240,6 +241,7 @@ const createRadioButtonHanlders = ()=>{ setupGraph() createAxes() renderPoints() + displayMeanStandardDeviation(); }) } @@ -264,20 +266,51 @@ const setUpZoomPan = ()=>{ } const getAverage = (start, end) => { - let sum = 0 + let sumOutcomes = 0 + let sumDropped = 0 for(let i = start; i < end; i++){ - sum += sortedInstances[i].ninety_day_outcomes/sortedInstances[i].graduates*100 + sumOutcomes += sortedInstances[i].ninety_day_outcomes/sortedInstances[i].graduates*100 + sumDropped += sortedInstances[i].dropped/sortedInstances[i].total_students*100 } - averageOutcomes.push({average:sum/(end-start), initialGraduationDate:sortedInstances[start].graduation_date}) + averageOutcomes.push({ + averageOutcomes:sumOutcomes/(end-start), + averageDropped:sumDropped/(end-start), + initialGraduationDate:sortedInstances[start].graduation_date + }) } const displayMeanStandardDeviation = () => { sortedInstances = instances.sort((a,b) => Date.parse(a.graduation_date) - Date.parse(b.graduation_date)) - + averageOutcomes = [] for(let i = 0; i < sortedInstances.length-10; i += 10){ getAverage(i,i+10) } - console.log(averageOutcomes); + + d3.selectAll('#points path').remove(); + + if(displayAverage){ + + d3.select('#points') + .append('path') + .datum(averageOutcomes) + .attr('fill', 'none') + .attr('stroke', 'steelblue') + .attr('stroke-width', 5) + .attr('opacity', 0.7) + .attr('d', d3.line() + .x(d => xScale(parseTime(d.initialGraduationDate))) + .y(d => (yAxis === 'outcomes') ? yScale(d.averageOutcomes) : yScale(d.averageDropped)) + ) + + } +} + +const setUpDisplayAverageHandler = ()=>{ + d3.select('#average input') + .on('click', (event)=>{ + displayAverage = event.target.checked + displayMeanStandardDeviation() + }) } window.onload = async ()=>{ @@ -303,4 +336,5 @@ window.onload = async ()=>{ setUpZoomPan(); displayMeanStandardDeviation(); + setUpDisplayAverageHandler() } diff --git a/public/index.html b/public/index.html index 81be8c0..143080c 100644 --- a/public/index.html +++ b/public/index.html @@ -23,6 +23,11 @@ 90 Day Outcomes % Dropped % +
+

Display Average?

+ + Display Average? +

Choose Metros To Display

From 5e52eeac50643418328956f27436da6598f6109f Mon Sep 17 00:00:00 2001 From: Matthew Huntington Date: Thu, 28 Sep 2023 21:44:11 -0400 Subject: [PATCH 5/9] filter by course and metro works on average --- public/app.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/public/app.js b/public/app.js index 4d86c97..5afc94b 100644 --- a/public/app.js +++ b/public/app.js @@ -178,6 +178,7 @@ const populateMetrosCoursesCheckboxes = ()=>{ .on('click', (event, datum)=>{ datum.checked = !datum.checked renderPoints() + displayMeanStandardDeviation() }) d3.select('#metros ul') @@ -194,6 +195,7 @@ const populateMetrosCoursesCheckboxes = ()=>{ .on('click', (event, datum)=>{ datum.checked = !datum.checked renderPoints() + displayMeanStandardDeviation() }) d3.select('#courses button:nth-child(2)') @@ -202,6 +204,7 @@ const populateMetrosCoursesCheckboxes = ()=>{ course.checked = true } renderPoints() + displayMeanStandardDeviation() populateMetrosCoursesCheckboxes() }) d3.select('#courses button:nth-child(3)') @@ -210,6 +213,7 @@ const populateMetrosCoursesCheckboxes = ()=>{ course.checked = false } renderPoints() + displayMeanStandardDeviation() populateMetrosCoursesCheckboxes() }) @@ -219,6 +223,7 @@ const populateMetrosCoursesCheckboxes = ()=>{ metro.checked = true } renderPoints() + displayMeanStandardDeviation() populateMetrosCoursesCheckboxes() }) d3.select('#metros button:nth-child(3)') @@ -227,6 +232,7 @@ const populateMetrosCoursesCheckboxes = ()=>{ metro.checked = false } renderPoints() + displayMeanStandardDeviation() populateMetrosCoursesCheckboxes() }) } @@ -281,6 +287,18 @@ const getAverage = (start, end) => { const displayMeanStandardDeviation = () => { sortedInstances = instances.sort((a,b) => Date.parse(a.graduation_date) - Date.parse(b.graduation_date)) + sortedInstances = sortedInstances.filter(datum=> { + const instanceMetro = datum.course.split('-')[0] + const instanceCourse = datum.course.split('-')[1] + const metro = metros.find(m => m.metro === instanceMetro) + const course = courses.find(c => c.course === instanceCourse) + if(metro.checked && course.checked){ + return true + } else { + return false + } + }) + averageOutcomes = [] for(let i = 0; i < sortedInstances.length-10; i += 10){ getAverage(i,i+10) From 6e941ff7dce7aaeb9b0e81783e994cf0380c8353 Mon Sep 17 00:00:00 2001 From: Matthew Huntington Date: Thu, 28 Sep 2023 22:06:08 -0400 Subject: [PATCH 6/9] standard deviation --- public/app.js | 51 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/public/app.js b/public/app.js index 5afc94b..8f3f890 100644 --- a/public/app.js +++ b/public/app.js @@ -11,7 +11,7 @@ let yAxis = 'outcomes' let bottomAxis; let leftAxis; let zoomScale = 1 -let averageOutcomes +let averageOutcomesArray let sortedInstances; let displayAverage = true; @@ -278,9 +278,23 @@ const getAverage = (start, end) => { sumOutcomes += sortedInstances[i].ninety_day_outcomes/sortedInstances[i].graduates*100 sumDropped += sortedInstances[i].dropped/sortedInstances[i].total_students*100 } - averageOutcomes.push({ - averageOutcomes:sumOutcomes/(end-start), - averageDropped:sumDropped/(end-start), + const averageOutcomes = sumOutcomes/(end-start) + const averageDropped = sumDropped/(end-start) + + let sumOutcomesDifferences = 0 + let sumDroppedDifferences = 0 + for(let i = start; i < end; i++){ + sumOutcomesDifferences += Math.pow(sortedInstances[i].ninety_day_outcomes/sortedInstances[i].graduates*100 - averageOutcomes,2) + sumDroppedDifferences += Math.pow(sortedInstances[i].dropped/sortedInstances[i].total_students*100 - averageDropped,2) + } + const stdDevOutcomes = Math.sqrt(sumOutcomesDifferences/(end-start)) + const stdDevDropped = Math.sqrt(sumDroppedDifferences/(end-start)) + + averageOutcomesArray.push({ + averageOutcomes, + averageDropped, + stdDevOutcomes, + stdDevDropped, initialGraduationDate:sortedInstances[start].graduation_date }) } @@ -299,7 +313,7 @@ const displayMeanStandardDeviation = () => { } }) - averageOutcomes = [] + averageOutcomesArray = [] for(let i = 0; i < sortedInstances.length-10; i += 10){ getAverage(i,i+10) } @@ -310,16 +324,39 @@ const displayMeanStandardDeviation = () => { d3.select('#points') .append('path') - .datum(averageOutcomes) + .datum(averageOutcomesArray) .attr('fill', 'none') .attr('stroke', 'steelblue') - .attr('stroke-width', 5) + .attr('stroke-width', 2) .attr('opacity', 0.7) .attr('d', d3.line() .x(d => xScale(parseTime(d.initialGraduationDate))) .y(d => (yAxis === 'outcomes') ? yScale(d.averageOutcomes) : yScale(d.averageDropped)) ) + d3.select('#points') + .append('path') + .datum(averageOutcomesArray) + .attr('fill', 'none') + .attr('stroke', 'red') + .attr('stroke-width', 2) + .attr('opacity', 0.7) + .attr('d', d3.line() + .x(d => xScale(parseTime(d.initialGraduationDate))) + .y(d => (yAxis === 'outcomes') ? yScale(d.averageOutcomes+d.stdDevOutcomes) : yScale(d.averageDropped+d.stdDevDropped)) + ) + + d3.select('#points') + .append('path') + .datum(averageOutcomesArray) + .attr('fill', 'none') + .attr('stroke', 'red') + .attr('stroke-width', 2) + .attr('opacity', 0.7) + .attr('d', d3.line() + .x(d => xScale(parseTime(d.initialGraduationDate))) + .y(d => (yAxis === 'outcomes') ? yScale(d.averageOutcomes-d.stdDevOutcomes) : yScale(d.averageDropped-d.stdDevDropped)) + ) } } From 2bb34512081cb8d1e425041bcc43f7b7d9ce449d Mon Sep 17 00:00:00 2001 From: Matthew Huntington Date: Thu, 28 Sep 2023 22:23:58 -0400 Subject: [PATCH 7/9] separate button to display standard deviation --- public/app.js | 13 ++++++++++--- public/index.html | 4 +++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/public/app.js b/public/app.js index 8f3f890..1d51799 100644 --- a/public/app.js +++ b/public/app.js @@ -13,7 +13,8 @@ let leftAxis; let zoomScale = 1 let averageOutcomesArray let sortedInstances; -let displayAverage = true; +let displayAverage = false; +let displayStandardDeviation = false; const randomColor = ()=>{ const red = Math.floor(Math.random()*128) + 64; @@ -333,7 +334,8 @@ const displayMeanStandardDeviation = () => { .x(d => xScale(parseTime(d.initialGraduationDate))) .y(d => (yAxis === 'outcomes') ? yScale(d.averageOutcomes) : yScale(d.averageDropped)) ) - + } + if(displayStandardDeviation){ d3.select('#points') .append('path') .datum(averageOutcomesArray) @@ -361,11 +363,16 @@ const displayMeanStandardDeviation = () => { } const setUpDisplayAverageHandler = ()=>{ - d3.select('#average input') + d3.select('#average input:nth-child(2)') .on('click', (event)=>{ displayAverage = event.target.checked displayMeanStandardDeviation() }) + d3.select('#average input:nth-child(3)') + .on('click', (event)=>{ + displayStandardDeviation = event.target.checked + displayMeanStandardDeviation() + }) } window.onload = async ()=>{ diff --git a/public/index.html b/public/index.html index 143080c..43da49c 100644 --- a/public/index.html +++ b/public/index.html @@ -25,8 +25,10 @@

Display Average?

- + Display Average? + + Display Standard Deviation?

Choose Metros To Display

From ec8786539e1bba3125f8c018914800dd42e9021a Mon Sep 17 00:00:00 2001 From: Matt Huntington Date: Fri, 29 Sep 2023 10:06:15 -0400 Subject: [PATCH 8/9] display instances checkbox --- public/app.js | 8 +++++++- public/index.html | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/public/app.js b/public/app.js index 1d51799..8ba4440 100644 --- a/public/app.js +++ b/public/app.js @@ -15,6 +15,7 @@ let averageOutcomesArray let sortedInstances; let displayAverage = false; let displayStandardDeviation = false; +let displayInstances = true; const randomColor = ()=>{ const red = Math.floor(Math.random()*128) + 64; @@ -87,7 +88,7 @@ const renderPoints = () => { const metro = metros.find(m => m.metro === instanceMetro) const course = courses.find(c => c.course === instanceCourse) - if(metro.checked && course.checked){ + if(displayInstances && metro.checked && course.checked){ return 'block' } else { return 'none' @@ -373,6 +374,11 @@ const setUpDisplayAverageHandler = ()=>{ displayStandardDeviation = event.target.checked displayMeanStandardDeviation() }) + d3.select('#average input:nth-child(4)') + .on('click', (event)=>{ + displayInstances = event.target.checked + renderPoints() + }) } window.onload = async ()=>{ diff --git a/public/index.html b/public/index.html index 43da49c..53427e0 100644 --- a/public/index.html +++ b/public/index.html @@ -29,6 +29,8 @@ Display Average? Display Standard Deviation? + + Display Instances?

Choose Metros To Display

From 4d77e2fc78da656f051085543014653345ae62c4 Mon Sep 17 00:00:00 2001 From: Matthew Huntington Date: Thu, 12 Oct 2023 11:27:08 -0400 Subject: [PATCH 9/9] fixing width/height in FF --- public/app.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/public/app.js b/public/app.js index 8ba4440..5fe9fd5 100644 --- a/public/app.js +++ b/public/app.js @@ -111,10 +111,9 @@ const renderPoints = () => { } const setupGraph = ()=>{ - d3.select('svg'); - d3.select('svg') - .style('width', WIDTH) - .style('height', HEIGHT); + d3.select('#container') + .attr('width', WIDTH) + .attr('height', HEIGHT); xScale = d3.scaleTime(); xScale.range([0,WIDTH]);