Строка D3.js возвращает случайное число - PullRequest
0 голосов
/ 26 октября 2018

Это связано с тем фактом, что я новичок в D3, и это, вероятно, простая ошибка, которую я упускаю - я знаю, что так и должно быть.Что-то с тем, как я пытаюсь получить доступ к данным.

Пытаюсь немного разобраться с этим парнем.(возможно, я смотрел на это слишком долго)

Я играл с ним до тех пор, пока моя строка наконец не появилась вообще, но теперь она не отображает полную строку, только два очка -это цифры, в которых я не уверен.

Заранее спасибо!

РЕДАКТИРОВАТЬ: цель состоит в том, чтобы использовать lineData [0] для построения одной линии вдоль оси x lineData 1 (месяцы).В конце концов, lineData 2 будет использоваться для второй строки, но просто пытается заставить первую строку работать в данный момент.

EDIT: можно найти обновленный код (согласно предложениям Шашанка)здесь: https://codepen.io/anon/pen/RevxYG?editors=0010

Мой обновленный график выглядит лучше, но все еще видит значения NaN: enter image description here

Вот мой код:

 let lineData = [
    [4, 2, 0, 3, 3, 4, 52, 3, 0, 3, 3, 1], 
    [0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0], 
    ["Oct", "Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"]
  ]
            console.log("lineData", lineData)

        // set dimensions of the line chart
        let width = 393,
            height = 285;


        // set the scales
        let yScale = d3.scaleLinear()    
            .domain([0, 52])
            .range([height - 40 , 0]);

        let xScale = d3.scaleOrdinal()
            .range([0, width - 40]);

        // create the line
        let line = d3.line()
            .x(function(d, i) { return xScale(i); })
            .y(function(d) { return yScale(d[0]); });

        // create svg container
        let lineChart = d3.select(element)
            .append("svg")
            .attr("viewbox", "0 60 960 600")
            .attr("preserveAspectRatio", "xMinYMin meet")
            .attr("width", width)
            .attr("height", height)
            .attr("class", "line-chart")

        lineChart.append("path")
            .datum(lineData)
            .attr("d", line)
            .attr("fill", "none")
            .attr("stroke", "rebeccapurple")
            .attr("stroke-width", 2)

        lineChart.selectAll("dot")
            .data(lineData)
            .attr("d", line)
            .enter()
            .append("circle")
            .attr("r", 3.5)
            .attr("cx", function(d, i) { return xScale(i)})
            .attr("cy", function(d) { return yScale(d[0])})
            .attr("fill", "rebeccapurple")

        lineChart.append("g")
            .attr("transform", "translate(20, 245)")
            .call(d3.axisBottom(xScale))

        lineChart.append("g")
            .attr("transform", "translate(20, 0)")
            .call(d3.axisLeft(yScale))

Данные передаются через функцию.

данные: enter image description here

и мой график выглядит так: enter image description here

и мои генерируемые пути / точки выглядят так: enter image description here

1 Ответ

0 голосов
/ 26 октября 2018

Недостающие точки:

  1. Важно: в идеале вы должны использовать d3 шкалу времени , так как вы хотите построить линию на основе месяцев. Но порядковый масштаб тоже подойдет. Я предполагаю, что вы ищете d3.scaleBand здесь.

Шкала диапазонов подобна порядковым шкалам, за исключением того, что выходной диапазон является непрерывным и числовым.

Почему бы не использовать d3.scaleOrdinal? Вот пример:

let lineData = [
    [4, 2, 0, 3, 3, 4, 52, 3, 0, 3, 3, 1], 
    [0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0], 
    ["Oct", "Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"]
  ]

        let xScale = d3.scaleOrdinal().range(lineData[2])
            .domain(lineData[0]);
            
    console.log('domain is: ' + xScale.domain());
    console.log('range is: ' + xScale.range());
<script src="https://d3js.org/d3.v4.min.js"></script>

Вы видите, как повторяющиеся значения отображаются на месяцы, которые не помогут в вашем случае, и, таким образом, d3.scaleBand() (вы также можете поиграть с использованием d3.scalePoint. Подробнее об этом в этом ответе .

  1. Используя вышеуказанную шкалу частот, домен, который вы установите, будет lineData[2] следующим образом:

    xScale = d3.scaleBand().domain(lineData[2])
    
  2. Преобразования не применялись к line и circles. Поэтому я добавил контейнеры <g>, чтобы они содержали линии и круги соответственно, и преобразовал эти элементы группы. Например:

    var dots = lineChart.append('g')
        .attr("transform", "translate(20, 0)");
    

Приведенное ниже решение как раз отвечает на этот конкретный вопрос, добавляя первую строку в таблицу. Как вы упомянули в комментариях, что в конечном итоге вы добавите второй элемент в качестве другой строки, выбор path изменится

let lineData = [
    [4, 2, 0, 3, 3, 4, 52, 3, 0, 3, 3, 1], 
    [0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0], 
    ["Oct", "Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"]
  ]
        // set dimensions of the line chart
        let width = 393,
            height = 285;


        // set the scales
        let yScale = d3.scaleLinear()    
            .domain([0, 52])
            .range([height - 40 , 0]);

        let xScale = d3.scaleBand().domain(lineData[2])
            .rangeRound([0, width - 40]);

        // create the line
        let line = d3.line()
            .x(function(d, i) { 
            	return xScale(lineData[2][i]) + xScale.bandwidth()/2; 
            })
            .y(function(d) { return yScale(d); });

        // create svg container
        let lineChart = d3.select('body')
            .append("svg")
            .attr("viewbox", "0 60 960 600")
            .attr("preserveAspectRatio", "xMinYMin meet")
            .attr("width", width)
            .attr("height", height)
            .attr("class", "line-chart")

				var lineG = lineChart.append('g')
        	.attr("transform", "translate(20, 0)");
          
        lineG.append("path")
            .data(lineData)
            .attr("d", line)
            .attr("fill", "none")
            .attr("stroke", "rebeccapurple")
            .attr("stroke-width", 2)

			var dots = lineChart.append('g')
        	.attr("transform", "translate(20, 0)");
        dots.selectAll("dot")
            .data(lineData[0])
            .enter()
            .append("circle").classed('dot', true)
            .attr("r", 3.5)
            .attr("cx", function(d, i) { return xScale(lineData[2][i]) + xScale.bandwidth()/2})
            .attr("cy", function(d) { return yScale(d)})
            .attr("fill", "rebeccapurple")

        lineChart.append("g")
            .attr("transform", "translate(20, 245)")
            .call(d3.axisBottom(xScale))

        lineChart.append("g")
            .attr("transform", "translate(20, 0)")
            .call(d3.axisLeft(yScale))
<script src="https://d3js.org/d3.v4.min.js"></script>

Предложение. Не рекомендуется устанавливать статическое значение для домена, как для yScale [0,52]. Попробуйте использовать методы d3.extent или d3.min .

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

Редактировать: Когда вы пытаетесь использовать d3.scalePoint, вы делаете небольшую ошибку при выборе значения xScale в функции line и для кругов. Вам нужно будет выбрать categories[i] в строке fn следующим образом:

.x(function(d, i) { 
     return xScale(categories[i]); 
 })

Обновлен фрагмент с использованием d3.scalePoint

let data = {
    'New': [4, 2, 0, 3, 3, 4, 52, 3, 0, 3, 3, 1], 
    'Terminated': [0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0]
  };
  let categories = ["Oct", "Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"];
  
            let lineData = [data.New, data.Terminated, categories];

        
            // set dimensions of the line chart
            let width = 393,
                height = 285;

            // set the scales
            let yScale = d3.scaleLinear()    
                .domain([0, 60]).nice()
                .range([height - 40 , 0]);
        
            let xScale = d3.scalePoint()
                .domain(lineData[2].map(function(d, i) { return d; }))
                .range([0, width - 40]);
        
            // create the line
            let line = d3.line()
                .x(function(d, i) { 
                	return xScale(categories[i]); 
                })
                .y(function(d) { return yScale(d); });
        
            // create svg container
            let lineChart = d3.select('body')
                .append("svg")
                .attr("viewbox", "0 60 960 600")
                .attr("preserveAspectRatio", "xMinYMin meet")
                .attr("width", width)
                .attr("height", height)
                .attr("class", "line-chart")

				var lineG = lineChart.append('g')
        	.attr("transform", "translate(20, 0)");
            lineG.append("path")
                .datum(lineData)
                .attr("d", function(d) { return line(d[0]); })
                .attr("fill", "none")
                .attr("stroke", "rebeccapurple")
                .attr("stroke-width", 2)
          
            lineChart.selectAll("dot")
                .data(lineData[0])
                .enter()
                .append("circle")
                .attr("transform", "translate(20, 0)")
                .attr("r", 3.5)
                .attr("cx", function(d, i) { return xScale(categories[i])})
                .attr("cy", function(d) { return yScale(d)})
                .attr("fill", "rebeccapurple")
        
            lineChart.append("g")
                .attr("transform", "translate(20, 245)")
                .call(d3.axisBottom(xScale))

        
            lineChart.append("g")
                .attr("transform", "translate(20, 0)")
                .call(d3.axisLeft(yScale))
<script src="https://d3js.org/d3.v4.min.js"></script>

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

...