diff --git a/boston_311_2023_by_reason.csv b/boston_311_2023_by_reason.csv new file mode 100644 index 0000000..076c2a2 --- /dev/null +++ b/boston_311_2023_by_reason.csv @@ -0,0 +1,45 @@ +reason,Count +Abandoned Bicycle,1318 +Administrative & General Requests,2025 +Air Pollution Control,35 +Alert Boston,3 +Animal Issues,4155 +Billing,6 +Boston Bikes,64 +Bridge Maintenance,8 +Building,5209 +Catchbasin,621 +Cemetery,29 +Code Enforcement,31812 +Employee & General Comments,2166 +Enforcement & Abandoned Vehicles,61541 +Environmental Services,4416 +Fire Hydrant,205 +General Request,196 +Generic Noise Disturbance,109 +Graffiti,1839 +Health,1349 +Highway Maintenance,25096 +Housing,7590 +MBTA,1 +Massport,8 +Needle Program,7413 +Neighborhood Services Issues,28 +Noise Disturbance,832 +Notification,607 +Office of The Parking Clerk,18 +Operations,283 +Park Maintenance & Safety,7932 +Parking Complaints,19 +Pothole,85 +Programs,6 +Recycling,9955 +Sanitation,59389 +Sidewalk Cover / Manhole,291 +Signs & Signals,11209 +Street Cleaning,45659 +Street Lights,8499 +Traffic Management & Engineering,751 +Trees,10390 +Valet,7 +Weights and Measures,52 diff --git a/index.html b/index.html index d80e631..83f3d4d 100644 --- a/index.html +++ b/index.html @@ -1 +1,18 @@ - \ No newline at end of file + + + + 311 Calls in Boston - Top 10 Reasons + + + + + +
+

Top 10 Reasons for 311 Calls in Boston (2023)

+

Enforcement leads the chart with the number of calls:

+
+ + +
+ + diff --git a/script.js b/script.js new file mode 100644 index 0000000..664ac5b --- /dev/null +++ b/script.js @@ -0,0 +1,98 @@ +// Load the data from the CSV file... +d3.csv("boston_311_2023_by_reason.csv") + .then(function(data) { + // Process the data to get the counts for each reason + var reasonsCount = {}; + + data.forEach(function(d) { + var reason = d.reason.trim(); + var count = +d.Count; + + if (!reasonsCount[reason]) { + reasonsCount[reason] = 0; + } + reasonsCount[reason] += count; + }); + + var reasonsArray = Object.keys(reasonsCount).map(function(reason) { + return { reason: reason, count: reasonsCount[reason] }; + }); + + reasonsArray.sort(function(a, b) { + return b.count - a.count; // Sort in descending order + }); + var top10Reasons = reasonsArray.slice(0, 10).reverse(); // Reverse the order + + // Set up the SVG dimensions and margins + var margin = { top: 20, right: 20, bottom: 70, left: 200 }; // Increased bottom margin + var width = 800 - margin.left - margin.right; + var height = 500 - margin.top - margin.bottom; + + // Create SVG element + var svg = d3.select("#chart") + .append("svg") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + .append("g") + .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); + + var x = d3.scaleLinear() + .domain([0, d3.max(top10Reasons, function(d) { return d.count; })]) + .nice() + .range([0, width]); + + var y = d3.scaleBand() + .domain(top10Reasons.map(function(d) { return d.reason; })) + .range([height, 0]) + .padding(0.2); + + svg.selectAll(".bar") + .data(top10Reasons) + .enter().append("rect") + .attr("class", "bar") + .attr("y", function(d) { return y(d.reason); }) + .attr("width", function(d) { return x(d.count); }) + .attr("height", y.bandwidth()); + + svg.selectAll(".label") + .data(top10Reasons) + .enter().append("text") + .attr("class", "label") + .attr("x", function(d) { return x(d.count) + 5; }) + .attr("y", function(d) { return y(d.reason) + y.bandwidth() / 2; }) + .text(function(d) { return d3.format(",")(d.count); }) // Add comma separator + .attr("dy", ".35em") + .style("font-size", "12px") + .style("fill", "#333") + .style("text-anchor", "start"); + + svg.selectAll(".axis-x text") + .style("display", "none"); + + svg.append("g") + .call(d3.axisLeft(y)) + .selectAll("text") + .style("font-size", "12px") + .style("fill", "#333"); + + // Append citation for data source + svg.append("text") + .attr("x", width - 10) + .attr("y", height + margin.bottom - 10) + .style("text-anchor", "end") + .style("font-size", "10px") + .text("Data Source: ") + .append("a") + .attr("xlink:href", "https://data.boston.gov/dataset/311-service-requests") + .text("Boston 311 Service Requests"); + + // Add chart authorship credit in the footnotes + svg.append("text") + .attr("x", 10) + .attr("y", height + margin.bottom - 10) + .style("font-size", "10px") + .text("By Anat Golan"); + }) + .catch(function(error) { + console.log(error); + }); diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..a8443a7 --- /dev/null +++ b/styles.css @@ -0,0 +1,55 @@ +/* styles.css */ + +/* Body font and background */ +body { + font-family: 'Arial', sans-serif; /* Change to a more sophisticated font if desired */ + background-color: #f7f7f7; /* Change to a preferred background color */ + color: #333; /* Adjust text color as needed */ + margin: 0; + padding: 0; +} + +/* Header styles */ +h1 { + font-size: 28px; + font-weight: bold; + margin: 20px 0; + text-align: center; +} + +h2 { + font-size: 24px; + font-weight: bold; + margin: 15px 0; + text-align: center; +} + +/* Chart container */ +.chart-container { + margin-left: 200px; + padding: 20px; + background-color: #fff; /* Container background color */ + border-radius: 8px; /* Rounded corners */ + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* Box shadow for a subtle depth effect */ +} + +/* Styles for bars */ +.bar { + fill: steelblue; +} + +.bar:hover { + fill: #ff9900; /* Change hover color if desired */ +} + +/* Styles for x-axis text */ +.axis-x text { + font-size: 12px; + fill: #666; /* Adjust color of axis text */ +} + +/* Y-axis label */ +.axis-y text { + font-size: 12px; + fill: #666; /* Adjust color of y-axis text */ +}