Javascript 如何创建';平面图';在d3.js中?

Javascript 如何创建';平面图';在d3.js中?,javascript,d3.js,data-visualization,Javascript,D3.js,Data Visualization,假设我有一个不同运动员的数据集,他们在不同的日子里进行相同的测试。每天,他们将进行几次试验/跑步。我想用d3.js来可视化每一位运动员这几天的发展情况,但我很难理解我是如何完成这项任务的 使用Python中的seaborn或R中的ggplot2,我会使用一个FacePlot,其中每天都是一个方面。在这些方面,我将在x轴上进行试验,在I轴上进行性能测试。但是我如何在d3.js中做到这一点呢 允许我按运动员对数据集进行分组,我了解如何迭代每个运动员的值。但我不明白如何在d3.js中创建FacePlo

假设我有一个不同运动员的数据集,他们在不同的日子里进行相同的测试。每天,他们将进行几次试验/跑步。我想用d3.js来可视化每一位运动员这几天的发展情况,但我很难理解我是如何完成这项任务的

使用Python中的seaborn或R中的ggplot2,我会使用一个FacePlot,其中每天都是一个方面。在这些方面,我将在x轴上进行试验,在I轴上进行性能测试。但是我如何在d3.js中做到这一点呢

允许我按运动员对数据集进行分组,我了解如何迭代每个运动员的值。但我不明白如何在d3.js中创建FacePlot

我试图搜索有关observable的教程,但运气不好。一个有趣且相关的可视化是[Trumps Golfs bt Bostock]。另一个

有人能帮我找到正确的方向吗?我创建了一个简单的数据集和散点图,可以作为起点

const data=d3.range(10.map)(i=>({
围嘴:数学楼层(i/5)+1,
比率:-1+数学随机数()*5,
运行:[1,2,3,4,5][i%5],
运行:[1,2,3,4,5][i%5],
名称:['GIRL1'、'GIRL2'、'GIRL3'、'GIRL4'][数学楼层(i/5)]
}));
常数宽度=250;
常数高度=150;
const svg=d3.select('svg')
.attr('width',width)
.attr('height',height)
常量边距={
前20名,
右:20,,
底数:20,
左:50
}
const innerWidth=width-margin.left-margin.right;
const innerHeight=高度-margin.top-margin.bottom;
常量xScale=d3.scaleLinear()
.domain(d3.extent(数据,d=>d.run))
.range([0,innerWidth])
常量yScale=d3.scaleLinear()
.域(d3.范围(数据,d=>d.比率))
.范围([0,内部高度])
常量g=svg.append('g')
.attr('transform','translate(${margin.left},${margin.top})`)
g、 选择全部('圆圈')
.数据(数据)
.join('圆')
.attr('r',3)
.attr('cx',d=>xScale(d.run))
.attr('cy',d=>yScale(d.ratio))
g、 附加(“g”)
.call(d3.axisBottom(xScale))
.attr('transform','translate(0,${innerHeight})`);;
g、 附加(“g”)
.call(d3.axisLeft(yScale))

设置SVG

首先,让我们建立一个关于如何分配空间和构造页面的约定。由于只有一行图表,这就容易多了

我们需要定义上图中的变量。然后我们可以得出每个图的宽度和高度:

const height = 500;
const width = 500;
const margin = {
   top: 50,
   left: 50,
   right: 50,
   bottom: 50
}
const padding = 10; // labelled `pad` in image due to space constraints

const plotWidth = (width-padding)/numberOfPlots - padding;
const plotHeight = height-padding*2;
当然,你可以随意安排,我加入这一部分只是为了让剩下的答案更容易理解

下面我使用一个
g
来保持由边距限定的区域,以便于以后的定位

现在我们还有两种不同的比例,您已经在代码中这样做了,但是我们现在可以使用上述间距约定使用
plotWidth
plotHeight
定义范围

绘制数据

现在我们准备好创建图了。为此,我们将创建一个嵌套数据集:我们希望按绘图对数据进行分组,如您所述,我们可以使用d3.group:

 const grouped = d3.group(data,d=>d.bib);
对于每个分组,我们将使用基于上述结构的翻译创建一个
g
和位置:

 const plots = g.selectAll(".plot")
  .data(grouped)
  .enter()
  .append("g")
  .attr("transform", function(d,i) {
     return "translate("+[i*(padding+plotWidth)+padding,padding]+")";
   })
  
我们已经准备好使用嵌套数据进行绘图:

   plots.selectAll(null)
     .data(d=>d[1])
     .enter()
     .append("circle")
     ... // and so forth.
下面的代码段使用
d=>d[1]
,因为这是属于该组的项数组所在的位置
d[0]
是组的标识符。如果我的数据数组是数组的数组,我只需要使用
d=>d

现在我们可以在每个绘图上附加x轴:

 plots.append("g")
   .attr("transform","translate("+[0,plotHeight]+")")
   .call(d3.axisBottom(x));
和y轴:

 g.append("g")
   .attr("transform","translate("+[0,padding]+")");
   .call(d3.axisLeft(y));
我还没有添加父x轴,根据您的使用情况,您可能希望为其添加标签,也可能不添加。我还注意到,我按bib对数据分组,而不是按运行,但原则保持不变:对数据分组,输入并定位父图,然后将数据点添加到父图

示例

//数据和管理:
常量数据=d3.range(15.map)(i=>({
围嘴:数学楼层(i/5)+1,
比率:-1+数学随机数()*5,
运行:[1,2,3,4,5][i%5],
运行:[1,2,3,4,5][i%5],
名称:['GIRL1'、'GIRL2'、'GIRL3'、'GIRL4'][数学楼层(i/5)]
}));
const group=d3.group(数据,d=>d.bib);
//尺寸:
常数高度=500;
常数宽度=500;
常量边距={
前10名,
左:50,,
右:50,,
底数:50
}
常数填充=30;//由于空间限制,在图像中标记为“pad”
const plotWidth=(宽度填充)/grouped.size-填充;
const plotHeight=高度填充*2;
const svg=d3.选择(“主体”)
.append(“svg”)
.attr(“宽度”,边距.左+宽度+边距.右)
.attr(“高度”,页边距。顶部+高度+页边距。底部);
常量g=svg.append(“g”)
.attr(“转换”、“平移”(+[margin.left,margin.top]+));
//比例:
常量xScale=d3.scaleLinear()
.domain(d3.extent(数据,d=>d.run))
.范围([0,绘图宽度]);
常量yScale=d3.scaleLinear()
.域(d3.范围(数据,d=>d.比率))
.范围([plotHeight,0]);
//放置绘图:
const plots=g.selectAll(空)
.数据(分组)
.输入()
.附加(“g”)
.attr(“转换”,函数(d,i){
返回“translate(“+[i*(padding+plotWidth)+padding,padding]+”);
})
//可选绘图背景:
plots.append(“rect”)
.attr(“宽度”,绘图宽度)
.attr(“高度”,绘图高度)
.attr(“填充”、“ddd”);
//绘制实际数据
plots.selectAll(空)
.数据(d=>d[1])
.输入()
.附加(“圆圈”)
.attr(“r”,4)
.attr(“cy”,d=>yS