d3.js - d3 来自分组数据数组的每个刻度的多个圆圈
问题描述
我正在尝试非常快速地学习 d3,但我在选择和加入方面陷入了困境。
我希望能够为数组的每个成员绘制一个带有点的轴。一些数组成员具有相同的 x 值,但我仍然希望看到与该值一样多的点。我的数组(在带有 useState 的 React 中)看起来像这样:
const [data, setData] = useState(
[
{x: 2020, colour: "purple", y1: 0.001, y2: 0.63},
{x: 2027, colour: "red", y1: 0.003, y2: 0.84},
{x: 2031, colour: "yellow", y1: 0.024, y2: 0.56},
{x: 2031, colour: "green", y1: 0.054, y2: 0.22},
{x: 2040, colour: "blue", y1: 0.062, y2: 0.15},
{x: 2050, colour: "orange", y1: 0.062, y2: 0.15}
]
);
您可以看到 2031 有两个值,我想在标记为“2031”的 x 轴刻度处画一个黄点,然后在下方画一个紫点。
所以我用这个 reduce 函数(从 SO 中窃取)对我的数据进行分组:
const dot = data.reduce(
(r, v, _, __, k = v.x) => ((r[k] || (r[k] = [])).push(v), r),
{}
);
...产生这个:
{ 2020: [{x: 2020, colour: "purple", y1: 0.001, y2: 0.63}],
2027: [...] }
我启动我的 x 轴并为其创建一个占位符:
const g = d3.axisBottom( scX ).tickValues(
data.map(d => {
return d.x
})
)
svg.append( "g" )
.attr( "transform", "translate(" + 25 + "," + pxY/2 + ")")
.call( g )
.selectAll(".tick")
然后我想调用我的 dot 变量并遍历嵌套数组:
svg
.selectAll(".tick")
.call( dot )
.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 5)
.attr("fill", dot.colour)
我想做的是为每个嵌套数组绘制一个圆圈,并填充该数组中命名的颜色 - 这不起作用?
谁能解释一下?
解决方案
无需对数据进行分组。您可以将data
其视为一个数组,其中每个元素都对应一个圆圈。多个圆圈可以以相同的x
值存在,没有什么强制它们不能。
也不需要像那样设置轴刻度,d3 很可能会为您做所有事情。d3-axis
绝对方便 - 您需要调整默认值,而不是在这里从头开始构建所有内容。
您需要了解数据连接,因为您显然也不知道可以使用function(d, i) { ... }
或(d, i) => ...
以这种方式设置颜色来访问元素的数据。
const data = [{
x: 2020,
colour: "purple",
y1: 0.001,
y2: 0.63
},
{
x: 2027,
colour: "red",
y1: 0.003,
y2: 0.84
},
{
x: 2031,
colour: "yellow",
y1: 0.024,
y2: 0.56
},
{
x: 2031,
colour: "green",
y1: 0.054,
y2: 0.22
},
{
x: 2040,
colour: "blue",
y1: 0.062,
y2: 0.15
},
{
x: 2050,
colour: "orange",
y1: 0.062,
y2: 0.15
}
];
const width = 600,
height = 300;
var svg = d3.select("svg")
.attr("width", width)
.attr("height", height);
const x = d3.scaleLinear()
.domain(d3.extent(data, d => d.x))
.range([50, 550]);
const y1 = d3.scaleLinear()
.domain(d3.extent(data, d => d.y1))
.range([275, 25]);
const y2 = d3.scaleLinear()
.domain(d3.extent(data, d => d.y2))
.range([3, 10]);
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("fill", d => d.colour)
.attr("cx", d => x(d.x))
.attr("cy", d => y1(d.y1))
.attr("r", d => y2(d.y2));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>
推荐阅读
- node.js - Chromium 浏览器实例即服务
- android - 将 proguard 与 Hyperledger Iroha 一起使用时,我的应用程序崩溃了
- nativescript - 删除 TabView 的上边框?
- html - 当围绕它进行排序时,Div 始终保持在父 div 的中心
- java - Java - 我需要一个自定义的 spring 过滤器,应该在 http 响应之后调用
- reactjs - 使用 Laravel 和 MySQL 作为后端在 reactjs 和颤振中保存和显示博客内容的最佳方法
- .net - 错误 <%@ Application Codebehind="Global.asax.cs" Inherits="Erpeo.MvcApplication" Language="C#" %>
- algorithm - 为什么在 Djkstra 算法中使用堆?
- flutter - 如何在 Flutter 中制作具有淡入淡出效果的轮播/滑块/图像切换器
- php - 使用路由 laravel 5.8 传递参数