Независимые шкалы для небольших многолинейных диаграмм - PullRequest
1 голос
/ 19 июня 2020

Ссылка на записную книжку .

Я работаю над небольшой многолинейной диаграммой, используя d3.v5 в Observable, с набором данных, структурированным следующим образом:

enter image description here

Для визуализации масштаб y принимает num из массива values для домена. Есть несколько строк с уникальными значениями ключей, которые я хотел использовать для создания небольших кратных. На изображении выше показан первый ключ.

После визуализации небольшого кратного я заметил, что на всех линейных диаграммах используется один и тот же масштаб по оси Y, что я не собирался делать. Это то, что у меня сейчас есть:

  const y_scale = d3
    .scaleLinear()
    .domain([0, d3.max(series, d => d3.max(d.values, m => m.num))])
    .range([width/2, width/2 - start_y - margin.bottom]);

Есть ли способ настроить домен так, чтобы каждая диаграмма имела свой собственный масштаб на основе собственных num значений?

Редактировать 1: Ссылка на блокнот добавлена ​​вверху

1 Ответ

2 голосов
/ 19 июня 2020

Решение idiomati c 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();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...