From 943baa3cdae3664e5b563801075d49c20b9b9e86 Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 17:14:27 +0000 Subject: [PATCH 1/2] Setting up GitHub Classroom Feedback From acbbf2a2462cfe0e87851b436a44109e3dcb70de Mon Sep 17 00:00:00 2001 From: sammuhanguzi Date: Mon, 15 Jan 2024 16:31:53 -0500 Subject: [PATCH 2/2] deleted, modified, and created files --- ...311_boston_data.csv => 311_boston_data.csv | 0 index.html | 20 +++ pivot.py | 2 +- script.js | 119 ++++++++++++++++++ style.css | 37 ++++++ 5 files changed, 177 insertions(+), 1 deletion(-) rename 311-basic/311_boston_data.csv => 311_boston_data.csv (100%) create mode 100644 script.js create mode 100644 style.css diff --git a/311-basic/311_boston_data.csv b/311_boston_data.csv similarity index 100% rename from 311-basic/311_boston_data.csv rename to 311_boston_data.csv diff --git a/index.html b/index.html index d80e631..f18ff0f 100644 --- a/index.html +++ b/index.html @@ -1 +1,21 @@ + + + + + + + + D3 Bar Chart - 311 Calls in Boston + + +
+

311 Calls in Boston from 2023

+

Barchart for top 10 reasons

+
+
+ + + + + \ No newline at end of file diff --git a/pivot.py b/pivot.py index aaa15f5..6bdbc9f 100644 --- a/pivot.py +++ b/pivot.py @@ -3,7 +3,7 @@ import pandas as pd # Read the CSV file into a pandas DataFrame -data = pd.read_csv('boston_311_2023.csv') +data = pd.read_csv('311_boston_data.csv') # Group the data by the 'reason' column and count the occurrences of each reason reason_counts = data.groupby('reason').size().reset_index(name='Count') diff --git a/script.js b/script.js new file mode 100644 index 0000000..2cf5092 --- /dev/null +++ b/script.js @@ -0,0 +1,119 @@ +// Load CSV data +d3.csv('311_boston_data.csv').then(data => { + // Process the data + data.forEach(d => { + d.Count = +d.Count; // Convert Count to a number + }); + + // Sort the data by Count in descending order. first step to top 10 + data.sort((a, b) => b.Count - a.Count); + + // Take only the top 10 types + const top10Data = data.slice(0, 10); + + // Set up SVG container + const svgWidth = 800; + const svgHeight = 500; + const margin = { top: 40, right: 40, bottom: 80, left: 200 }; + const width = svgWidth - margin.left - margin.right; + const height = svgHeight - margin.top - margin.bottom; + + const svg = d3.select('#chart_311') + .append('svg') + .attr('width', svgWidth) + .attr('height', svgHeight) + .append('g') + .attr('transform', `translate(${margin.left},${margin.top})`); + + // Create scales + const yScale = d3.scaleBand() + .domain(top10Data.map(d => d.reason)) + .range([0, height]) + .padding(0.2); + + const xScale = d3.scaleLinear() + .domain([0, d3.max(top10Data, d => d.Count)]) + .range([0, width]); + + // Create bars + const bars = svg.selectAll('rect') + .data(top10Data) + .enter() + .append('rect') + .attr('x', 0) + .attr('y', d => yScale(d.reason)) + .attr('width', d => xScale(d.Count)) + .attr('height', yScale.bandwidth()) + .attr('fill', (d, i) => `rgb(${i * 25}, ${i * 10}, ${i * 5})`) // Use different colors for each bar + .on('mouseover', function (event, d) { + d3.select(this).attr('fill', 'orange'); // Change color on hover + }) + .on('mouseout', function () { + d3.select(this).attr('fill', (d, i) => `rgb(${i * 25}, ${i * 10}, ${i * 5})`); // Revert color on mouseout + }); + + // Add labels inside bars + svg.selectAll('text') + .data(top10Data) + .enter() + .append('text') + .text(d => d.reason) + .attr('x', 5) // Adjust the x-coordinate for proper placement + .attr('y', d => yScale(d.reason) + yScale.bandwidth() / 2) + .attr('dy', '0.35em') + .style('font-size', '12px') + .style('fill', 'white'); // Make text white for visibility + + // Add axes + svg.append('g') + .call(d3.axisLeft(yScale)) + .classed('axisLeft', true); + + svg.append('g') + .attr('transform', `translate(0,${height})`) + .call(d3.axisBottom(xScale)) + .classed('axisBottom', true); + + // Add attribution line at the bottom + svg.append('text') + .attr('x', width / 2) + .attr('y', height + margin.top + 20) // Adjust the y-coordinate for proper placement + .attr('text-anchor', 'left') + .style('font-size', '12px') + .text('Chart created by Sam Muhanguzi. source: boston.gov'); + + // Button to show extended bar chart + d3.select('body') + .append('button') + .text('Show Extended Chart') + .on('click', function () { + // Update data to include all counts + const extendedData = data.slice(0); + + // Update scales + yScale.domain(extendedData.map(d => d.reason)); + xScale.domain([0, d3.max(extendedData, d => d.Count)]); + + // Update bars + bars.data(extendedData) + .transition() + .duration(1000) + .attr('width', d => xScale(d.Count)); + + // Update labels inside bars + svg.selectAll('text') + .data(extendedData) + .text(d => d.reason); + + // Update axes + svg.select('.axisLeft') + .transition() + .duration(1000) + .call(d3.axisLeft(yScale)); + + svg.select('.axisBottom') + .transition() + .duration(1000) + .call(d3.axisBottom(xScale)); + }); +}); diff --git a/style.css b/style.css new file mode 100644 index 0000000..fc663b5 --- /dev/null +++ b/style.css @@ -0,0 +1,37 @@ +/* Add any CSS styles here */ +body { + font-family: 'Roboto', sans-serif; /* Use Roboto font */ + background-color: whitesmoke; + color: black; + margin: 20px; +} + +header { + text-align: left; + margin-bottom: 10px; /* Adjust margin as needed for the header */ +} + +svg { + margin-top: 10px; /* Adjust margin as needed for the chart */ +} + +h1 { + color: black; + font-size: 2em; /* Increase font size for the main header */ + margin-bottom: 0; /* No margin at the bottom of the main header */ + transition: color 0.3s; /* Smooth transition for color change on hover */ +} + +p { + line-height: 1.5; + font-size: 1.2em; /* Increase font size for the subheader */ + margin-top: 0; /* No margin at the top of the subheader */ + margin-bottom: 20px; /* Adjust margin as needed for the subheader */ + font-weight: bold; + transition: color 0.3s; /* Smooth transition for color change on hover */ +} + +/* Hover styles */ +h1:hover, +p +