Выравнивание отметок на диаграмме области с помощью строковых значений X - PullRequest
0 голосов
/ 05 марта 2019

Я строю диаграмму области, используя библиотеку D3, и я использовал их пример диаграммы площади , чтобы помочь мне построить его.Однако я не использую даты по оси X, вместо этого я использую строки, поэтому я попытался использовать их пример гистограмма , чтобы помочь мне обработать xAxis и его значения.

Из-за этого, однако, мои отметки по оси X «центрированы» между двумя точками значения, а не выровнены по левому краю (см. Изображение ниже).

Sample Area Chart

Когда я пытался использовать пример диаграммы области для построения оси x, я не видел ни области, которая заполнялась, ни каких-либо точек данных вдоль оси x.

Как мне переместить метки, чтобы они были выровнены непосредственно на точке данных, а не центрированы между двумя разными точками данных?

Вот как выглядит мой код при построении графика ":

    sampleAreaData = [
        {"month": "Jun. 2018", "value": "2"},
        {"month": "Jul. 2018", "value": "12"},
        {"month": "Aug. 2018", "value": "33"},
        {"month": "Sept. 2018", "value": "100"},
        {"month": "Oct. 2018", "value": "150"},
        {"month": "Nov. 2018", "value": "368"},
        {"month": "Dec. 2018", "value": "404"},
        {"month": "Jan. 2019", "value": "482"},
        {"month": "Feb. 2019", "value": "559"},
    ]

    initializeSampleAreaGraph() {
        // Variables
        const svg = d3.select(this.template.querySelector('svg.sampleAreaGraph'));
        const width = this.svgSampleAreaWidth;
        const height = this.svgSampleAreaHeight;
        const margin = ({top: 20, right: 20, bottom: 30, left: 30});
        const x = d3.scaleBand()
            .domain(this.sampleAreaData.map(d => d.month))
            .range([margin.left, width - margin.right])
        const y = d3.scaleLinear()
            .domain([0, d3.max(this.sampleAreaData, d => d.value)]).nice()
            .range([height - margin.bottom, margin.top]);
        const xAxis = g => g
            .attr("transform", `translate(0,${height - margin.bottom})`)
            .call(d3.axisBottom(x).ticks(width / 80).tickSizeOuter(0));
        const yAxis = g => g
            .attr("transform", `translate(${margin.left},0)`)
            .call(d3.axisLeft(y))
            .call(g => g.select(".domain").remove())
            .call(g => g.select(".tick:last-of-type text").clone()
                .attr("x", 3)
                .attr("text-anchor", "start")
                .attr("font-weight", "bold")
                .text(this.sampleAreaData.month));
        const area = d3.area()
            .x(d => x(d.month))
            .y0(y(0))
            .y1(d => y(d.value));

        // SVG Construction
        svg.append("path")
            .attr("fill", "steelblue")
            .datum(this.sampleAreaData)
            .attr("d", area)
        svg.append("g")
            .call(xAxis);
        svg.append("g")
            .call(yAxis);
        return svg.node();
    }

1 Ответ

0 голосов
/ 05 марта 2019

Ну, есть несколько вещей, которые вы могли бы улучшить. TL; DR; код ниже.

d3.scaleBand вернет тики в середине полосы, как следует из названия. Следующее изображение было беззастенчиво скопировано из d3 docs : enter image description here

Как видите, цель scaleBand - разделить ось на четные полосы.

Поскольку у вас уже есть какая-то временная информация, вы можете попытаться проанализировать ее с помощью Date.parse(d.month) и передать эту информацию для создания вашего домена.

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

var sampleAreaData = [
        {"month": "Jun. 2018", "value": "2"},
        {"month": "Jul. 2018", "value": "12"},
        {"month": "Aug. 2018", "value": "33"},
        {"month": "Sept. 2018", "value": "100"},
        {"month": "Oct. 2018", "value": "150"},
        {"month": "Nov. 2018", "value": "368"},
        {"month": "Dec. 2018", "value": "404"},
        {"month": "Jan. 2019", "value": "482"},
        {"month": "Feb. 2019", "value": "559"},
    ];

    function initializeSampleAreaGraph() {
        // Variables
        // const svg = d3.select(this.template.querySelector('svg.sampleAreaGraph')); // no need to select a selection. d3.select is the same as a querySelector.
        const svg = d3.select('svg.sampleAreaGraph');
        const width = 500;
        const height = 500;
        const margin = ({top: 20, right: 20, bottom: 30, left: 30});
        const xScale = d3.scaleTime() // changed this to scaleBand
            .domain(d3.extent(sampleAreaData, function(d) { return Date.parse(d.month) })) // d3.extent return an array with min and max values
            .range([margin.left, width - margin.right]);
        const yScale = d3.scaleLinear()
            .domain([0, d3.max(sampleAreaData, d => d.value)])
            .nice()
            .range([height - margin.bottom, margin.top]);
        const xAxis = g => g
            .attr("transform", `translate(0, ${height - margin.bottom})`)
            .call(d3.axisBottom(xScale).ticks(width / 80).tickSizeOuter(0));
        const yAxis = g => g
            .attr("transform", `translate(${margin.left},0)`)
            .call(d3.axisLeft(yScale))
            .call(g => g.select(".domain").remove())
            .call(g => g.select(".tick:last-of-type text").clone()
                .attr("x", 3)
                .attr("text-anchor", "start")
                .attr("font-weight", "bold")
                .text(sampleAreaData.month));
        
      const area = d3.area(sampleAreaData)
            .x(d => xScale(Date.parse(d.month))) // pass a valid date number
            .y0(yScale(0))
            .y1(d => yScale(d.value));

        // SVG Construction
        svg.append("path")
            .attr("fill", "steelblue")
            .datum(this.sampleAreaData)
            .attr("d", area)
        svg.append("g")
            .call(xAxis);
        svg.append("g")
            .call(yAxis);
        return svg.node();
    }

initializeSampleAreaGraph();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="900" height="500" class="sampleAreaGraph"></svg>

Надеюсь, это поможет.

...