Scatter Plot
vizhub上实现的代码:
https://vizhub.com/Edward-Elric233/53807a1b35d94329b3689081cd2ea945
https://vizhub.com/Edward-Elric233/b9647d50899a4a0e8e917f913cd0a53a
https://vizhub.com/Edward-Elric233/8c6b50cd81a04f048f490f48e4fe6264
由前面的柱状图,我们对图形进行一定的修改就可以得到散点图:
只要将绑定数据以后enter进行添加矩形的操作换成圆形就可以了,不过需要注意的是不能够y坐标再使用
scaleBand
了,而应该使用scalePoint
,如果继续使用scaleBand
的话需要调整圆的坐标(y坐标是Categorical的)。注意圆形的属性是cx,cy,r
分别表示圆心的坐标和半径。
index.html
<!DOCTYPE html>
<html>
<head>
<title>Scatter Plot</title>
<link rel="stylesheet" href="./styles.css">
<script src="https://unpkg.com/d3@5.7.0/dist/d3.min.js"></script>
<!-- find D3 file on UNPKG d3.min.js-->
</head>
<body>
<svg width="960" height="500"></svg>
<script src="./index.js">
// console.log(d3); test whether you have imported d3.js or not
</script>
</body>
</html>
index.js
const svg = d3.select('svg');
// svg.style('background-color', 'red'); test
const width = +svg.attr('width');
const height = +svg.attr('height');
const render = data => {
const xValue = d => d.population;
const yValue = d => d.country;
const margin = { top: 60, right: 20, bottom: 80, left: 150 };
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
const xScale = d3.scaleLinear()
.domain([0, d3.max(data, xValue)])
.range([0, innerWidth])
.nice(); //作用是如果值域的最大值不够整齐可以变得整齐
// const yScale = scaleBand()
const yScale = d3.scalePoint()
.domain(data.map(yValue))
.range([0, innerHeight])
.padding(0.5);
const xAxisTickFormat = number => d3.format('.3s')(number).replace('G', 'B');
const yAxis = d3.axisLeft(yScale)
.tickSize(-innerWidth);;
const xAxis = d3.axisBottom(xScale)
.tickFormat(xAxisTickFormat)
.tickSize(-innerHeight); //设置tick-line的长度
const g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
//yAxis(g.append('g'));
const yAxisG = g.append('g').call(yAxis).selectAll('.domain').remove();
const xAxisG = g.append('g').call(xAxis)
.attr('transform', `translate(0,${innerHeight})`);
xAxisG.selectAll('.domain').remove();
xAxisG.append('text')
.attr('class', 'axis-label')
.attr('y', 60)
.attr('x', innerWidth / 2)
.attr('fill', 'black')
.text('populiation');
let colorSet = ['#eb2617', '#ffaa00', '#4dff00', '#00fbff', '#bb00ff', '#eeff00'];
const createGetColor = (idx) => {
var i = idx || -1;
return {
get: () => { i = (i + 1) % colorSet.length; return colorSet[i]; }
};
};
const getColor = createGetColor();
g.selectAll('circle').data(data)
.enter().append('circle')
.attr('cy', d => yScale(yValue(d)))
.attr('cx', d => xScale(xValue(d)))
.attr('r', 15)
.attr('fill', getColor.get);
g.append('text')
.attr('class', 'title')
.attr('y', -20)
.text('Top 10 Most Population Countries');
};
d3.csv("https://gist.githubusercontent.com/Edward-Elric233/23f3024c472ffd7e34e6a5ac04bad26c/raw/6ced2249ea6f5d12f72c1eb00b8c1278d2c86e95/every%2520countries'%2520population").then(data => {
data.forEach(d => {
d.population = +d.population * 1000;
});
render(data);
// console.log(data);
});
styles.css
body {
margin: 0px;
overflow: hidden;
font-family: manosapce;
}
text {
font-family: sans-serif;
}
.tick text {
font-size: 2em;
fill: #8E8883
}
.axis-label {
fill: #8E8883;
font-size: 2.5em
}
.title {
font-size: 3em;
fill: #8E8883
}
虽然大概实现了散点图,但是上面的数据不适合用散点图来进行表示。因此我们不妨更换数据,使用更适合的数据。
这里因为y坐标也是Quantitative的,所以应该使用
scaleLinear
。画的时候注意坐标的方向,如果方向不对应的画可以调整scaleLinear
的domain
或者range
(反向即可)。这里因为圆形比较密集就设置了一下圆形的透明度opacity
,看起来比较好看。
index.html
<!DOCTYPE html>
<html>
<head>
<title>Cars Scatter Plot</title>
<link rel="stylesheet" href="./styles.css">
<script src="https://unpkg.com/d3@5.7.0/dist/d3.min.js"></script>
<!-- find D3 file on UNPKG d3.min.js-->
</head>
<body>
<svg width="960" height="500"></svg>
<script src="./index.js">
// console.log(d3); test whether you have imported d3.js or not
</script>
</body>
</html>
index.js
const svg = d3.select('svg');
// svg.style('background-color', 'red'); test
const width = +svg.attr('width');
const height = +svg.attr('height');
//mpg cylinders displacement horsepower weight acceleration year origin name
const render = data => {
const title = 'Cars: Mpg vs. Horsepower';
const xValue = d => d.mpg;
const xAxisLabel = 'Mpg';
const yValue = d => d.horsepower;
const yAxisLabel = 'Horsepower';
const margin = { top: 60, right: 20, bottom: 80, left: 100 };
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
const circleRadius = 10;
const xScale = d3.scaleLinear()
//.domain([min(data, xValue), max(data, xValue)]) //和下面的写法等价
.domain(d3.extent(data, xValue))
.range([0, innerWidth])
.nice(); //作用是如果值域的最大值不够整齐可以变得整齐
// const yScale = scaleBand()
const yScale = d3.scaleLinear()
.domain([d3.max(data, yValue), d3.min(data, yValue)])
.range([0, innerHeight])
.nice();
//const xAxisTickFormat = number => format('.3s')(number).replace('G','B');
const yAxis = d3.axisLeft(yScale)
.tickSize(-innerWidth)
.tickPadding(15);
const xAxis = d3.axisBottom(xScale)
//.tickFormat(xAxisTickFormat)
.tickSize(-innerHeight) //设置tick-line的长度
.tickPadding(15); //通过设置Padding让x轴的数字离远一点
const g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
//yAxis(g.append('g'));
const yAxisG = g.append('g').call(yAxis);
yAxisG.selectAll('.domain').remove();
yAxisG.append('text')
.attr('class', 'axis-label')
.attr('y', -70)
.attr('x', -innerHeight / 2)
.attr('fill', 'black')
.attr('transform', `rotate(-90)`)
.attr('text-anchor', 'middle') //设置锚点在中心
.text(yAxisLabel);
const xAxisG = g.append('g').call(xAxis)
.attr('transform', `translate(0,${innerHeight})`);
xAxisG.selectAll('.domain').remove();
xAxisG.append('text')
.attr('class', 'axis-label')
.attr('y', 60)
.attr('x', innerWidth / 2)
.attr('fill', 'black')
.text(xAxisLabel);
let colorSet = ['#eb2617', '#ffaa00', '#4dff00', '#00fbff', '#bb00ff', '#eeff00'];
const createGetColor = (idx) => {
var i = idx || -1;
return {
get: () => { i = (i + 1) % colorSet.length; return colorSet[i]; }
};
};
const getColor = createGetColor();
g.selectAll('circle').data(data)
.enter().append('circle')
.attr('cy', d => yScale(yValue(d)))
.attr('cx', d => xScale(xValue(d)))
.attr('r', circleRadius)
.attr('fill', getColor.get);
g.append('text')
.attr('class', 'title')
.attr('y', -20)
.attr('x', innerWidth / 2)
.attr('text-anchor', 'middle')
.text(title);
};
d3.csv('https://vizhub.com/curran/datasets/auto-mpg.csv').then(data => {
data.forEach(d => {
//得到的数据默认每个属性的值都是字符串,因此需要进行转换
d.mpg = +d.mpg;
d.cylinders = +d.cylinders;
d.displacement = +d.displacement;
d.horsepower = +d.horsepower;
d.weight = +d.weight;
d.acceleration = +d.acceleration;
d.year = +d.year;
});
render(data);
// console.log(data);
});
styles.css
body {
margin: 0px;
overflow:hidden;
font-family: manosapce;
}
circle {
opacity : 0.5;
}
text {
font-family : sans-serif;
}
.tick text {
font-size : 2em;
fill : #8E8883
}
.tick line {
stroke : #E5E2E0
}
.axis-label {
fill : #8E8883;
font-size: 2.5em
}
.title {
font-size : 3em;
fill : #8E8883
}
对于时间轴的处理可以使用scaleTime
index.html
<!DOCTYPE html>
<html>
<head>
<title>Temperature in San Francisc Scatter Plot</title>
<link rel="stylesheet" href="./styles.css">
<script src="https://unpkg.com/d3@5.7.0/dist/d3.min.js"></script>
<!-- find D3 file on UNPKG d3.min.js-->
</head>
<body>
<svg width="960" height="500"></svg>
<script src="./index.js">
// console.log(d3); test whether you have imported d3.js or not
</script>
</body>
</html>
html.js
const svg = d3.select('svg');
// svg.style('background-color', 'red'); test
const width = +svg.attr('width');
const height = +svg.attr('height');
const render = data => {
const title = 'A week in San Francisco';
const xValue = d => d.timestamp;
const xAxisLabel = 'Time';
const yValue = d => d.temperature;
const yAxisLabel = 'Temperature';
const margin = { top: 60, right: 20, bottom: 80, left: 100 };
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
const circleRadius = 6;
const xScale = d3.scaleTime()
//.domain([min(data, xValue), max(data, xValue)]) //和下面的写法等价
.domain(d3.extent(data, xValue))
.range([0, innerWidth])
.nice(); //作用是如果值域的最大值不够整齐可以变得整齐
// const yScale = scaleBand()
const yScale = d3.scaleLinear()
.domain([d3.max(data, yValue), d3.min(data, yValue)])
.range([0, innerHeight])
.nice();
//const xAxisTickFormat = number => format('.3s')(number).replace('G','B');
const yAxis = d3.axisLeft(yScale)
.tickSize(-innerWidth)
.tickPadding(15);
const xAxis = d3.axisBottom(xScale)
//.tickFormat(xAxisTickFormat)
.tickSize(-innerHeight) //设置tick-line的长度
.tickPadding(15); //通过设置Padding让x轴的数字离远一点
const g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
//yAxis(g.append('g'));
const yAxisG = g.append('g').call(yAxis);
yAxisG.selectAll('.domain').remove();
yAxisG.append('text')
.attr('class', 'axis-label')
.attr('y', -70)
.attr('x', -innerHeight / 2)
.attr('fill', 'black')
.attr('transform', `rotate(-90)`)
.attr('text-anchor', 'middle') //设置锚点在中心
.text(yAxisLabel);
const xAxisG = g.append('g').call(xAxis)
.attr('transform', `translate(0,${innerHeight})`);
xAxisG.selectAll('.domain').remove();
xAxisG.append('text')
.attr('class', 'axis-label')
.attr('y', 60)
.attr('x', innerWidth / 2)
.attr('fill', 'black')
.text(xAxisLabel);
let colorSet = ['#eb2617', '#ffaa00', '#4dff00', '#00fbff', '#bb00ff', '#eeff00'];
const createGetColor = (idx) => {
var i = idx || -1;
return {
get: () => { i = (i + 1) % colorSet.length; return colorSet[i]; }
};
};
const getColor = createGetColor();
g.selectAll('circle').data(data)
.enter().append('circle')
.attr('cy', d => yScale(yValue(d)))
.attr('cx', d => xScale(xValue(d)))
.attr('r', circleRadius)
.attr('fill', 'red');
g.append('text')
.attr('class', 'title')
.attr('y', -20)
.attr('x', innerWidth / 2)
.attr('text-anchor', 'middle')
.text(title);
};
d3.csv('https://vizhub.com/curran/datasets/temperature-in-san-francisco.csv').then(data => {
// console.log(data);
data.forEach(d => {
//得到的数据默认每个属性的值都是字符串,因此需要进行转换
d.temperature = +d.temperature;
d.timestamp = new Date(d.timestamp);
});
render(data);
});
styles.css
body {
margin: 0px;
overflow: hidden;
font-family: manosapce;
}
circle {
opacity: 0.5;
}
text {
font-family: sans-serif;
}
.tick text {
font-size: 2em;
fill: #8E8883
}
.tick line {
stroke: #E5E2E0
}
.axis-label {
fill: #8E8883;
font-size: 2.5em
}
.title {
font-size: 3em;
fill: #8E8883
}