Line Chart
vizhub代碼:
https://vizhub.com/Edward-Elric233/094396fc7a164c828a4a8c2e13045308
實現效果:
這里先使用d3.line()
設置每個點的x
坐標和y
坐標,然后再用這個東西設置path
的'd'
屬性,就可以得到曲線。
const lineGenerator = d3.line().x(d => xScale(xValue(d))).y(d => yScale(yValue(d))).curve(d3.curveBasis); //使得曲線比較光滑g.append('path').attr('class', 'line-path').attr('d', lineGenerator(data));
index.html
<!DOCTYPE html>
<html><head><title>Temperature in San Francisc Line Chart</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();const lineGenerator = d3.line().x(d => xScale(xValue(d))).y(d => yScale(yValue(d))).curve(d3.curveBasis); //使得曲線比較光滑g.append('path').attr('class', 'line-path').attr('d', lineGenerator(data));/*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
}.line-path {fill: none;stroke: steelblue;stroke-width: 5;stroke-linejoin: round /*使得曲線比較光滑*/
}
其實也可以在折現圖上加上點,只需要去掉原本散點圖的注釋就可以了。但是我覺得這樣不好看就沒有加上。
Area Chart
vizhub代碼:
https://vizhub.com/Edward-Elric233/9fa9b8c649cf41a3afcde6e185a72cca
https://vizhub.com/Edward-Elric233/39790021eded4d398be6f97726e73dd2
area
圖只需要把使用line
的地方換成area
即可。不同的地方在于area
需要設置y0,y1,y
用來劃分區域,而且需要設置path
的fill
屬性,用來表示區域的顏色。一般來講應該不需要設置線的stroke
和stroke-width
屬性。
例如把上面的圖變成Area Chart
需要修改的js代碼如下:
const areaGenerator = area().x(d => xScale(xValue(d))).y1(d=>yScale(yValue(d))).y0(innerHeight).curve(curveBasis); //使得曲線比較光滑g.append('path').attr('class', 'line-path').attr('d', areaGenerator(data));
這里還畫了一個圖,把網格提到了圖形的前面。
雖然有些丑,但是如果需要使用的話還是可以的。技巧就是先生成Area圖,然后再生成坐標軸就可以了。這樣坐標線就會顯示在圖形的上面。
index.html
<!DOCTYPE html>
<html><head><title>World Population Area Chart</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 title = 'World Population';const xValue = d => d.year;const xAxisLabel = 'Year';const yValue = d => d.population;const yAxisLabel = 'Population';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), 0]).range([0, innerHeight]).nice();const yAxisTickFormat = number => d3.format('.1s')(number).replace('G', 'B');const yAxis = d3.axisLeft(yScale).tickFormat(yAxisTickFormat).tickSize(-innerWidth).tickPadding(15);const xAxis = d3.axisBottom(xScale)//.tickFormat(xAxisTickFormat).ticks(10) //設置標簽的多少,不知道為什么如果設置為10就會很亂,可能是因為這是一周的時間,如果劃分成10個以上就需要顯示小時吧.tickSize(-innerHeight) //設置tick-line的長度.tickPadding(15); //通過設置Padding讓x軸的數字離遠一點const g = svg.append('g').attr('transform', `translate(${margin.left},${margin.top})`);const areaGenerator = d3.area().x(d => xScale(xValue(d))).y1(d => yScale(yValue(d))).y0(innerHeight).curve(d3.curveBasis); //使得曲線比較光滑g.append('path').attr('class', 'line-path').attr('d', areaGenerator(data));//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/world-population-by-year-2015.csv').then(data => {console.log(data);data.forEach(d => {//得到的數據默認每個屬性的值都是字符串,因此需要進行轉換d.population = +d.population;d.year = new Date(d.year);});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
}.line-path {fill: #42A5B3;/* stroke : blue;stroke-width : 5; */
}