This is a scatter plot of number of complaints by product the CFPB recieved in 2016. The x-axis is month, the y-axis is the complaint count, and the color of the point is the product that the complaint was about. The user can zoom in on the points to see the overlapping points better.
This data is from part of the Data.gov: Consumer Complaint Database. The data shown in the plot is only 2016.
This scatter plot was forked from curran's block: Scatter Plot with Ordinal Axis and Responding to Resize
forked from emilyw15's block: 2017 MTA Average Ridership
xxxxxxxxxx
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.min.js"></script>
<title>2017 Average Commuter Ridership in Maryland</title>
<style>
body {
margin: 0px;
}
.domain {
display: none;
}
.tick line {
stroke: #C0C0BB;
}
.tick text, .legendCells text {
fill: #8E8883;
font-size: 12pt;
font-family: sans-serif;
}
.axis-label, .legend-label {
fill: #635F5D;
font-size: 15pt;
font-family: sans-serif;
}
#chart {
position: fixed;
left:0px;
right:0px;
top:0px;
bottom:0px;
}
</style>
</head>
<body>
<svg width="960" height="500"></svg>
<div id = "chart"></div>
<script>
const xValue = d => d.Month;
const xLabel = 'Month';
const yValue = d => d.Count;
const yLabel = 'Average Ridership';
const colorValue = d => d.product;
const colorLabel = 'Type';
const margin = { left: 100, right: 250, top: 20, bottom: 120 };
const row = d => {
d.Month = d['Month']
d.Count = +d.Count
return d;
};
var chartDiv = document.getElementById("chart")
var svg = d3.select(chartDiv).append("svg")
.attr("width","100%")
.attr("height","100%")
.call(d3.zoom().on("zoom",function() {
svg.attr("transform",d3.event.transform)
}));
const xScale = d3.scalePoint();
const yScale = d3.scaleLinear();
const colorScale = d3.scaleOrdinal()
.range(d3.schemeCategory20);
const colorLegend = d3.legendColor()
.scale(colorScale)
.shape('circle');
const g = svg.append('g');
const datag = g.append('g');
const xAxisG = g.append('g');
const xText = xAxisG.append('text')
.attr('class','axis-label')
const yAxisG = g.append('g');
const yText = yAxisG.append('text')
.attr('class','axis-label')
const colorLegendG = g.append('g')
function redraw() {
var width = chartDiv.clientWidth;
var height = chartDiv.clientHeight;
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
svg
.attr("width",width)
.attr("height",height);
g.attr('transform', `translate(${margin.left},${margin.top})`);
xAxisG
.attr('transform', `translate(0, ${innerHeight})`);
xText
.attr('x', innerWidth/2)
.attr('y',70)
.text(xLabel);
yText
.attr('x',-innerHeight/2)
.attr('y',-75)
.attr('transform',`rotate(-90)`)
.style('text-anchor','middle')
.text(yLabel)
colorLegendG.attr('transform', `translate(${innerWidth + 60}, 150)`);
const xAxis = d3.axisBottom()
.scale(xScale)
.tickPadding(15)
.tickSize(-innerHeight);
const yTicks = 5;
const yAxis = d3.axisLeft()
.scale(yScale)
.ticks(yTicks)
.tickPadding(15)
.tickSize(-innerWidth);
d3.csv('cfpb_2016.csv', row, data => {
xScale
.domain(data.map(xValue))
.range([0, innerWidth]);
yScale
.domain(d3.extent(data, yValue))
.range([innerHeight, 0])
.nice(yTicks);
var circles = datag.selectAll('circle').data(data)
circles
.enter()
.append('circle')
.attr('fill-opacity', 0.6)
.merge(circles)
.attr('cx', d => xScale(xValue(d)))
.attr('cy', d => yScale(yValue(d)))
.attr('fill', d => colorScale(colorValue(d)))
.attr('r', 8);
xAxisG.call(xAxis);
yAxisG.call(yAxis);
colorLegendG.call(colorLegend)
.selectAll('.cell text')
.attr('dy', '0.1em');
});
}
redraw();
window.addEventListener("resize",redraw);
</script>
</body>
</html>
https://d3js.org/d3.v4.min.js
https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.min.js