也许您只是想到,自编码旅程开始以前,您以前还没有看到任何数据,或者也许您还没有找到一个很好的博客来解释如何可视化数据。
不再说。
在这篇博客文章中,我们正在使用我的freecodecamp数据可视化项目作为现实生活中的demo。
我们还将使用一个名为d3.js的JavaScript库,对于那些不熟悉D3的人,它是一个JavaScript库,用于在Web浏览器中生成动态的交互式数据可视化。
第一步是在html
的头部添加D3脚本标签。
<script src="https://d3js.org/d3.v7.min.js"></script>
添加了此信息,恭喜我们现在可以可视化数据。
我牢记D3可能是一见钟情的非常令人困惑的事情,这就是为什么我要将其分解成小得多的原因,以便您了解我们为什么要做的事情。
HTML
1.在您的HTML中添加一个SVG元素:
这可以通过添加以下代码
来手动完成
<svg id="chart"></svg>
您的svg id
是您喜欢的任何东西,只要它与正在做的事情有关。
现在,添加SVG无需做任何事情,而是将其余的元素放在我们稍后将要放置的元素。在进入JavaScript方面之前,我们的条形图需要标题。
2.添加文本元素:
我们可以再次将其直接在我们的svg
中加入text
标签,在svg
标签中添加下面的行。
<text id="title" x="280" y="40">United States GDP</text>
不是数学的粉丝吗?不要混淆上面的x
和y
仅有助于定位,因为它的行为不像正常的html元素,x是左侧,y是最高的,将其视为左边的余量和保证金的顶部。
总而言之,我们的html文件应该看起来与此相似
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>bar chart</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<svg id="canvas">
<text id="title" x="280" y="40">United States GDP</text>
</svg>
</body>
</html>
一些CSS
如果您不准备给您的条形图一些样式,我建议给svg
至少一个background-color
,以便您可以看到将要进行的更改,对于此项目,我添加了一些样式,您可以自定义这适合您的口味。
body {
width: 100%;
height: 100vh;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #4a4e69;
font-family: Arial, Helvetica, sans-serif;
}
svg {
background-color: white;
border-radius: 10px;
padding: 10px;
}
#title {
font-size: 20px;
}
#tooltip {
margin-top: 20px;
font-size: 18px;
color: white;
}
rect {
fill: #4a4e69;
}
rect:hover {
fill: #f2e9e4
}
使用html
和css
,让我们了解你在这里的原因。
JavaScript
1.定义一些变量:
在您的script
中,我们将定义将在我们的条形图创建中将使用的变量,在您的script
中添加下面的代码
let values = [];
let heightScale;
let xScale;
let xAxisScale;
let yAxisScale;
let width = 800;
let height = 600;
let padding = 40;
values
数组是空的,因为稍后它将包含我们将要从API获得的数据。
heightScale
将决定每个条的高度,因为它不能说这样的恒定值像50或60一样,如果是这样的话,那么所有条形都将具有相同的高度,而不论其代表的值如何。
xScale
将确定棒在图表中的水平放置位置。
xAxisScale
将用于在底部创建xAxis
,而yAxisScale
将用于创建左侧的yAxis
,您可以将其视为图形上的x和y轴。
width
,height
和padding
是将添加到svg
的属性。
2.选择svg
:
要在普通JavaScript中选择一个元素,我们通常会经过document.getElementById()
或document.querySelector()
或Whate的路线
let svg = d3.select('svg')
就是这样,您已经选择了html中的svg
元素,并将其保存在称为svg
的变量中,如果文档中有多个svg
,则它将返回第一个元素,您也可以通过id
选择。或元素的class
,例如
let svg = d3.select('#chart')
两者都是在D3中选择元素的有效方法。
3.创建功能:
既然我们已经设置了变量,我们需要创建一些将要求做一件事或另一件事以创建我们的条形图的功能。
I.让我们drawChart()
:
svg
是所有其他元素都将坐在xAxis
,yAxis
和bars
的地方。为此,我们需要使用函数来定义IT的width
和height
。
选择svg
之后添加下面的代码
let drawChart = () => {
svg.attr('width', width)
.attr('height', height)
}
上面的代码是一个简单的箭头函数,可将svg
变量添加为svg
变量。 d3 .attr()
首先采用两个参数是我们要添加的属性,在这种情况下是width
和height
,第二个是值。
ii。让我们fetch()
一些数据:
在进行创建条形图之前,我们需要获取将使用条形图创建条形图的data
,现在FreeCodeCamp为我们提供了一个API。
https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json
您可以在新选项卡中打开它,以查看数据的结构。
要获取此数据,我要使用JavaScript自己的fetch
方法,在drawChart()
之后添加以下代码
fetch('https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json') //get the data
.then(res => res.json()) //convert the data to json
.then(data => {
values = data.data //save the data in the values array
console.log(values) //just so you can see that values now contains the data
});
上面的代码只需获取数据并将它们存储在values
数组中,如果您检查控制台,则应该看到此
最后在fetch
方法中,我们要调用稍后将要创建的函数,以下面的代码添加到您的fetch
drawChart()
generateScales()
drawBars()
generateAxes()
你应该有这样的东西
fetch('https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json')
.then(res => res.json())
.then(data => {
values = data.data;
console.log(values)
drawChart()
generateScales()
drawBars()
generateAxes()
});
iii。让我们generateScales()
:
我们需要创建轴将要使用的量表,在您的drawChart()
之后添加以下代码
let generateScales = () => {
heightScale = d3.scaleLinear()
.domain([0, d3.max(values, (item) => {
return item[1]
})])
.range([0, height - (2 * padding)])
xScale = d3.scaleLinear()
.domain([0, values.length - 1])
.range([padding, width - padding])
}
首先,我们通过调用d3.scaleLinear()
函数来定义heightScale
,之后我们不得不致电domain
,domain
只是告诉它,我们期望在这里有最大值和最小值的values
,以下面的代码为示例< br>
const arr = [100, 200, 300, 400, 500, 600];
在上面的最小数字上方的数组中,最大值为100,最大值为600。这本质上是域的作用,它获得了数据的最小值和最大数据。
但是域不能神奇地知道数据的最小值和最大,我们必须通过在其中打开一个数组并将最低值指定为第一个项目,而最高值则是第二个。
.domain([0, ])
由于我们正在使用GDP数据,因此我们确定最低的只能是0,否则我们已经与d3.min()
一起工作以找到数组中的最低值。
现在设置了域的最小值,我们必须找到最大值作为域数组中的第二个项目,现在在现实生活中,人们不一定总是知道确切的数字,它可能会在将来发生变化,这就是为什么以下代码是数组中的第二个项目,它在返回第二个索引的最高值之前将值数组和映射添加到每个项目上。
d3.max(values, (item) => {
return item[1]
})
这就是我们拥有这个的方式
.domain([0, d3.max(values, (item) => {
return item[1]
})])
现在到range
,它也采用了一个具有两个值的数组,第一个是最小值,然后将最大值以下面的代码示例
// our data
const arr = [100, 200, 300, 400, 500, 600];
如果您考虑一下,如何代表像600这样的巨大价值,那么身高应该是600px?那么,当我们以数千或数百万的方式工作时,会发生什么?这就是range
做的
const arr = [100, 200, 300, 400, 500, 600];
// we can say, to represent this data the range can be;
.range([10, 100])
这样做的是,100的值将在10高的高度表示,因为它是最小的,而600将在100的高度表示,因为它是最大值,同样,该值的其余高度将是在我们为其设置的范围内计算。
我希望现在的代码对您来说更有意义
.range([0, height - (2 * padding)])
它将最小范围设置为0,将最大值设置为SVG的高度,将两侧的填充物带走,因此有一些空间。
然后,我们类似地定义了XScale
xScale = d3.scaleLinear()
.domain([0, values.length - 1])
.range([padding, width - padding])
此量表用于定位xAxis
,它将水平位于底部。
在xScale
添加以下代码之后,在generateScale()
中继续前进。
let datesArr = values.map(item => {
return new Date(item[0]);
})
console.log(datesArr) // so you can see
xAxisScale = d3.scaleTime()
.domain([d3.min(datesArr), d3.max(datesArr)])
.range([padding, width - padding])
yAxisScale = d3.scaleLinear()
.domain([0, d3.max(values, (item) => {
return item[1]
})])
.range([height - padding, padding])
现在,要将此底轴与下面的日期配对
我们需要将字符串日期从数据转换为实际日期,如果您研究了数据,则会看到每个值的日期位于0
的索引。为了进行这种转换,我们创建了一个datesArr
来保持新转换的日期
let datesArr = values.map(item => {
return new Date(item[0]);
})
如果您console.log(datesArr)
,您会发现我们的数组包含新转换的日期
之后,我们通过调用d3.scaleTime()
来定义xAxisScale
,因为我们正在使用的值是日期,然后我们称为domain
和range
,同样适用于yAxisScale
。
iv。让我们generateAxes()
:
现在,generateScales()
的困难部分已经不在我们的两个轴开始了,请在generateScales()
函数下方添加此代码。
let generateAxes = () => {
let xAxis = d3.axisBottom(xAxisScale)
svg.append('g')
.call(xAxis)
.attr('id', 'x-axis')
.attr('transform', `translate(0, ${height - padding})`);
let yAxis = d3.axisLeft(yAxisScale);
svg.append('g')
.call(yAxis)
.attr('id', 'y-axis')
.attr('transform', `translate(${padding}, 0)`)
}
在上面的函数中,我们定义了代表图形的x
的xAxis
,然后使用d3.axisBottom(xAxisScale)
方法调用并给予xAxisScale
现在要在屏幕上显示此信息,将g
元素附加了已选择的svg
,然后我们称为xAxis
,该元素实际上告诉它在g
中绘制xAxis
let xAxis = d3.axisBottom(xAxisScale)
svg.append('g')
.call(xAxis)
.attr('id', 'x-axis')
.attr('transform', `translate(0, ${height - padding})`);
将id
属性添加到g
和一个transform
属性中,如果未添加的属性自然会坐在SVG的顶部,请尝试取出transform
属性,您将拥有类似的东西
之后,yScale
被定义并使用d3.axisLeft()
来调用,就像我们为xAxis
所做的那样,另一个g
附加到svg
,然后我们告诉它绘制其中的yAxis
,然后给出了id
属性transform
属性可以更好地将其定位在svg
中,尝试将transform
拿出来查看其自然位置。
let yAxis = d3.axisLeft(yAxisScale);
svg.append('g')
.call(yAxis)
.attr('id', 'y-axis')
.attr('transform', `translate(${padding}, 0)`)
所以我们总共有类似的东西
V.让我们kude97:
最后,我们将用代表其数据的条填充图形,在generateScales()
之后添加下面的代码
let drawBars = () => {
svg.selectAll('rect')
.data(values)
.enter()
.append('rect')
.attr('class', 'bar')
.attr('width', (width - (2 * padding)) / values.length)
.attr('data-date', (item) => {
return item[0];
})
.attr('data-gdp', (item) => {
return item[1];
})
.attr('height', (item) => {
return heightScale(item[1])
})
.attr('x', (item, index) => {
return xScale(index)
})
.attr('y', (item) => {
return (height - padding) - heightScale(item[1])
})
分解
svg.selectAll('rect')
.data(values)
.enter()
.append('rect')
首先,我们在SVG中选择了所有rect
或矩形,无论它们是否存在,我们都将rect
与values
与.data(values)
绑定在一起,将每个rect
与每个value
与每个value
相关在此之后发现并在此之后称呼为每个值,该.append(rect)
将创建新的矩形。
然后,我们添加了一些属性,例如width
,height
,class
,'X'和Y',以适当地显示和定位每个条,其他属性(例如data-date
和data-gdp
)是为了实现FreeCodeCamp的测试他们也是。
再次尝试拿走x
或y
属性,以查看如何将它们定位为默认位置。
.attr('class', 'bar')
.attr('width', (width - (2 * padding)) / values.length)
.attr('data-date', (item) => {
return item[0];
})
.attr('data-gdp', (item) => {
return item[1];
})
.attr('height', (item) => {
return heightScale(item[1])
})
.attr('x', (item, index) => {
return xScale(index)
})
.attr('y', (item) => {
return (height - padding) - heightScale(item[1])
}
您现在应该有类似的东西
vi。工具提示:
现在,我们已经显示了条形图的最后一件事是添加一个工具提示以显示有关徘徊的特定条形的一些信息,现在为此,我创建了一个非常简单的工具提示,请在下面的下面添加代码drawBars()
在rect
选择之前
let tooltip = d3.select('body')
.append('div')
.attr('id', 'tooltip')
.style('visibility', 'hidden')
.style('width', 'auto')
.style('height', 'auto')
这样做的是选择body
向其添加div
,并给它一个id
的属性,该属性设置为tooltip
,此后,我们给它提供了一些样式,例如将visibility
设置为“将visibility
”设置为默认情况width
和height
至auto
。
现在我们拥有tooltip
,下一件事是在徘徊时显示必要的信息,为此,D3对我们有一种方法,即.on()
,在svg
的y
属性后立即添加代码,请想想它是将事件听众添加到酒吧的。
.on('mouseover', (item, index) => {
tooltip.style('visibility', 'visible')
.html(`Date: ${index[0]} Data: <b>${index[1]}</b>`)
.attr('data-date', index[0])
})
.on('mouseout', (item) => {
tooltip.style('visibility', 'hidden')
})
使用.on()
方法,第一个参数以事件的名称命名,而第二个参数是事件发生时应运行的函数,此函数为item
和item
的index
。在函数内部,工具提示visibility
样式将鼠标效率设置为visible
,并给出一些html
,其中包括徘徊的特定栏的日期和值。还将data-date
属性给出了该工具提示的值,该工具提示的值是悬停在栏上的栏的日期。
.on('mouseover', (item, index) => {
tooltip.style('visibility', 'visible')
.html(`Date: ${index[0]} Data: <b>${index[1]}</b>`)
.attr('data-date', index[0])
})
现在,当鼠标离开时,我们在下面有此代码行,该行将工具提示的visibility
设置为hidden
,以便根据事件发生的事件打开和关闭。
.on('mouseout', (item) => {
tooltip.style('visibility', 'hidden')
})
完整的代码
let values = [];
let heightScale;
let xScale;
let xAxisScale;
let yAxisScale;
let width = 800;
let height = 600;
let padding = 40;
let svg = d3.select('#canvas');
// the drawChart function
let drawChart = () => {
svg.attr('width', width)
.attr('height', height)
}
// the generateScales function
let generateScales = () => {
heightScale = d3.scaleLinear()
.domain([0, d3.max(values, (item) => {
return item[1]
})])
.range([0, height - (2 * padding)])
xScale = d3.scaleLinear()
.domain([0, values.length - 1])
.range([padding, width - padding])
let datesArr = values.map(item => {
return new Date(item[0]);
})
console.log(datesArr)
xAxisScale = d3.scaleTime()
.domain([d3.min(datesArr), d3.max(datesArr)])
.range([padding, width - padding])
yAxisScale = d3.scaleLinear()
.domain([0, d3.max(values, (item) => {
return item[1]
})])
.range([height - padding, padding])
}
// the drawBars function
let drawBars = () => {
let tooltip = d3.select('body')
.append('div')
.attr('id', 'tooltip')
.style('visibility', 'hidden')
.style('width', 'auto')
.style('height', 'auto')
svg.selectAll('rect')
.data(values)
.enter()
.append('rect')
.attr('class', 'bar')
.attr('width', (width - (2 * padding)) / values.length)
.attr('data-date', (item) => {
return item[0];
})
.attr('data-gdp', (item) => {
return item[1];
})
.attr('height', (item) => {
return heightScale(item[1])
})
.attr('x', (item, index) => {
return xScale(index)
})
.attr('y', (item) => {
return (height - padding) - heightScale(item[1])
})
.on('mouseover', (item, index) => {
tooltip.style('visibility', 'visible')
.html(`Date: ${index[0]} Data: <b>${index[1]}</b>`)
.attr('data-date', index[0])
})
.on('mouseout', (item) => {
tooltip.style('visibility', 'hidden')
})
}
// the generateAxes function
let generateAxes = () => {
let xAxis = d3.axisBottom(xAxisScale)
svg.append('g')
.call(xAxis)
.attr('id', 'x-axis')
.attr('transform', `translate(0, ${height - padding})`);
let yAxis = d3.axisLeft(yAxisScale);
svg.append('g')
.call(yAxis)
.attr('id', 'y-axis')
.attr('transform', `translate(${padding}, 0)`)
}
// fetching the data
fetch('https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json')
.then(res => res.json())
.then(data => {
values = data.data
console.log(values)
drawChart()
generateScales()
drawBars()
generateAxes()
});
结论
恭喜!您刚刚创建了一个条形图。上面的代码显示了HTML,SVG,CSS和JavaScript如何一起创建令人惊叹的数据图。了解每个不同元素的工作方式及其功能对于开发更复杂的数据图至关重要,如果您想了解更多有关D3的信息,那么有许多教程和在线资源可以使您更好地了解它。
这可能是很多要掌握的,但不要太灰心,如果您想让我对D3进行详细的教程,您需要做的就是在下面发表评论。
感谢您的阅读!