上周,我们首先看了开源图表库React-vis ,并使用纽约市流行的婴儿名字城市数据集构建了我们的第一个条形图。 本周,我们将扩展最初的示例,并说明如何开始合并基本的交互。 作为回顾,我们的数据集包含如下所示的数据行:
{
"Year of Birth": "2016",
"Gender": "FEMALE",
"Ethnicity": "ASIAN AND PACIFIC ISLANDER",
"Child's First Name": "Olivia",
"Count": "172",
"Rank": "1"
}
我们建立的第一个可视化图是条形图,显示了按年份在数据中所占的儿童名字的总数,如下所示:
![对fig03做出反应](https://i-blog.csdnimg.cn/blog_migrate/ce6e74e3e53c4f46fd2f4395fc55e07c.png)
对于下一个可视化,让我们看看是否可以映射名称的流行度。 首先,我们将使用LineMarkSeries
组件构建一个简单的折线图。 为了使名称Olivia随着时间的流逝而流行,如果我们提前添加过滤步骤,则可以使用与获取年度总数相同的过滤逻辑:
const oliviaData = data.filter(d => d.firstName === 'Olivia');
const oliviasByYear = Object.entries(oliviaData.reduce((acc, row) => {
if(row.yearOfBirth in acc) {
acc[row.yearOfBirth] = acc[row.yearOfBirth] + row.count
} else {
acc[row.yearOfBirth] = row.count
}
return acc;
}, {})).map(([k, v]) => ({x: +k, y: v}));
上面计算oliviasByYear
的逻辑与我们用于totalBabiesByYear
逻辑相同; 我们只是先过滤了数据。 当要在折线图中显示此数据时,我们要做的就是将LineMarkSeries
组件替换为VerticalBarSeries
组件。
![相对于折线图01](https://i-blog.csdnimg.cn/blog_migrate/1a0a003a4a14040449d6cd01d90b9dcf.png)
本身并没有那么有趣,所以让我们添加一些数据来使这种可视化更有意义。 通常,我们希望添加其他数据以提供相对比较,即与Olivia一起绘制其他名称的图表。 为此,我做了一些努力,以获取数据集中排名前10位的最受欢迎的名称,并提取了我们用来获得Olivia的流行度的代码:
const getPopularityByYearForName = (data, name) => {
const nameData = data.filter(d => d.firstName === name);
return Object.entries(nameData.reduce((acc, row) => {
if(row.yearOfBirth in acc) {
acc[row.yearOfBirth] = acc[row.yearOfBirth] + row.count
} else {
acc[row.yearOfBirth] = row.count
}
return acc;
}, {})).map(([k, v]) => ({x: +k, y: v}));
};
// Later in our processing code:
const popularNames = ["Liam", "Jacob", "Dylan", "Ethan", "David", "Aiden", "Noah", "Matthew", "Olivia", "Emma"];
const namesWithData = popularNames.map(name => ({name, data: getPopularityByYearForName(data, name)}));
上面的代码为我们提供了一个对象列表,其中包括名称和年度受欢迎程度数据:
{
"name": "Olivia",
"data": [
{
"x": 2013,
"y": 297
},
{
"x": 2014,
"y": 96
},
{
"x": 2015,
"y": 589
},
{
"x": 2016,
"y": 559
}
]
}
然后,我们可以在组件渲染中使用此列表。 相反,我们的硬编码的LineMarkSeries
与数据属性oliviasByYear
数据,我们可以简单地映射了我们创建的列表和动态添加LineMarkSeries
数组中的每个元素:
<XYPlot
width={1200}
height={600}
margin={{
left: 70
}}
xType="ordinal"
>
{namesWithData.map(({name, data}) => (<LineMarkSeries
key={name}
data={data}
/>))}
<XAxis />
<YAxis />
</XYPlot>
我还将可视化效果扩大了两倍,使其看起来更好:
![对折线图02做出反应](https://i-blog.csdnimg.cn/blog_migrate/2e947faa2e8b868080efd9d74c2e8a88.png)
现在,随着时间的推移,我们拥有十大最受欢迎的名字,但是我们怎么知道哪个是哪个呢? 我们将添加一些交互,以便当我们将鼠标悬停在特定的行上时,它将向我们显示名称。 React-vis库提供了一个处理工具Hint
组件,但是我们需要设置一些样板才能使用该组件。 首先,我们将在组件的状态中添加一个字段,以跟踪应该在提示文本中显示的数据点(如果有):
this.state = {
data: [],
hoverData: null,
};
接下来,如果设置了该字段,我们将有条件地呈现“ Hint
组件:
<XYPlot /* existing properties */>
/* existing components */
{hoverData && <Hint value={hoverData} />}
</XYPlot>
现在,我们要做的就是将元素悬停在元素上,并在停止悬停时将其清除:
<XYPlot
/* existing properties */
onMouseLeave={() => this.setState({hoverData: null})}
>
{namesWithData.map(({name, data}) => (<LineMarkSeries
onValueMouseOver={(d) => this.setState({hoverData: d})}
key={name}
data={data}
/>))}
/* existing components */
</XYPlot>
![相对于折线图03](https://i-blog.csdnimg.cn/blog_migrate/8a33b6c4c605c6aa57519b7533bbf923.png)
它不是最理想的图表,但是我们已经取得了很大进步。 下周,我们将研究如何将动画添加到可视化中,以创建更具吸引力的用户体验。 与往常一样,该代码在GitHub上可用 ,您可以在Twitter上继续对话: @freethejazz 。