Javascript 小型多折线图的独立比例尺

Javascript 小型多折线图的独立比例尺,javascript,d3.js,observablehq,Javascript,D3.js,Observablehq,我正在使用Observable上的d3.v5制作一个小型多折线图,数据集的结构如下: 对于可视化,y比例从域的值数组中获取num。有几行具有唯一的键值,我想用它们来生成小倍数。上图显示了第一个键 在可视化小倍数后,我注意到所有的折线图都使用相同的y刻度,这不是我想要做的。这就是我目前拥有的: const y_scale=d3 .scaleLinear() .domain([0,d3.max(series,d=>d3.max(d.values,m=>m.num))) .范围([width/2,w

我正在使用Observable上的d3.v5制作一个小型多折线图,数据集的结构如下:

对于可视化,y比例从域的
数组中获取
num
。有几行具有唯一的键值,我想用它们来生成小倍数。上图显示了第一个键

在可视化小倍数后,我注意到所有的折线图都使用相同的y刻度,这不是我想要做的。这就是我目前拥有的:

const y_scale=d3
.scaleLinear()
.domain([0,d3.max(series,d=>d3.max(d.values,m=>m.num)))
.范围([width/2,width/2-起始y-边距.bottom]);
是否有一种方法可以调整域,使每个图表根据其自己的
num
值具有自己的比例


编辑1:在顶部添加笔记本链接

这里惯用的D3解决方案将使用。然而,有几种不同的工作备选方案

对于使用局部变量,我们首先声明它们

const localScale = d3.local();
const localLine = d3.local();
然后,我们在“输入”选项中设置不同的比例:

var enter = my_group
    .enter()
    .append("g")
    .attr("class", "chart_group")
    .each(function(d) {
        const yScale = localScale.set(this, d3
            .scaleLinear()
            .domain([0, d3.max(d.values, d => d.num)])
            .range([panel_width / 2, panel_width / 2 - start_y - margin]));

        localLine.set(this, d3
            .line()
            .x(d => x_scale(d.date))
            .y(d => yScale(d.num)));
    });
最后,我们得到这些尺度:

sub_group
    .select(".chart_line")
    .attr("d", function(d) {
        return localLine.get(this)(d)
    })
这是整个单元格,将其复制/粘贴到笔记本中,替换单元格:

chart = {
    const panels_per_row = 4;
    const panel_width = (width - margin * 8) / panels_per_row;
    const height =
        margin + (panel_width + margin) * (parseInt(my_data.length / 2) + 1);

    const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
    const start_x = 2;
    const start_y = panel_width / 3 + margin;

    const x_scale = d3
        .scaleBand()
        .domain(d3.set(series[0].values, d => d.date).values())
        .range([0, panel_width]);
    const localScale = d3.local();
    const localLine = d3.local();

    //join
    var my_group = svg.selectAll('.chart_group').data(series, d => d.key);

    //exit and remove
    my_group.exit().remove();
    //enter new groups
    var enter = my_group
        .enter()
        .append("g")
        .attr("class", "chart_group")
        .each(function(d) {
            const yScale = localScale.set(this, d3
                .scaleLinear()
                .domain([0, d3.max(d.values, d => d.num)])
                .range([panel_width / 2, panel_width / 2 - start_y - margin]));

            localLine.set(this, d3
                .line()
                .x(d => x_scale(d.date))
                .y(d => yScale(d.num)));
        });

    //append elements to new group
    enter.append("rect").attr("class", "group_rect");
    enter.append("text").attr("class", "group_text");
    enter.append("g").attr("class", "sub_chart_group");

    //merge
    my_group = my_group.merge(enter);

    position_group_elements(my_group);

    //join
    var sub_group = my_group
        .select(".sub_chart_group")
        .selectAll('.sub_chart_elements_group')
        .data(d => [d.values]); // data is wrapped in an array because this is a line/area chart

    //exit and remove
    sub_group.exit().remove();
    //enter new groups
    var sub_enter = sub_group
        .enter()
        .append("g")
        .attr("class", "sub_chart_elements_group");

    //append elements to new group
    sub_enter.append("path").attr("class", "chart_line");

    //merge
    sub_group = sub_group.merge(sub_enter);

    sub_group
        .select(".chart_line")
        .attr("d", function(d) {
            return localLine.get(this)(d)
        })
        .attr("fill", "none")
        .attr("stroke", "black")
        .attr("stroke-width", 1)
        .attr("transform", "translate(" + start_x + "," + start_y + ")");

    function position_group_elements(my_group) {
        //position rectangle
        my_group
            .select(".group_rect")
            .attr("x", function(d, i) {
                //two groups per row so
                var position = i % panels_per_row;
                d.x_pos = position * (panel_width + margin) + margin;
                d.y_pos =
                    parseInt(i / panels_per_row) * (panel_width + margin) + margin;
                return d.x_pos;
            })
            .attr("y", d => d.y_pos)
            .attr("fill", "#eee")
            .attr("stroke", "#aaa")
            .attr("stroke-width", 1)
            .attr("width", panel_width)
            .attr("height", panel_width);

        //then position sub groups
        my_group
            .select(".sub_chart_group")
            .attr("id", d => d.key)
            .attr("transform", d => "translate(" + d.x_pos + "," + d.y_pos + ")");
    }

    return svg.node();
}

谢谢,成功了!有没有一种方法可以对圆进行同样的处理?我尝试使用相同的方法附加多个圆,但我不确定如何在
.set
函数中设置其属性。只需在
.attr(“cy”,函数(d){…})
中获取y刻度的局部变量即可。