2016-04-14 3 views
1

Я пытаюсь создать очень простую стеклянную горизонтальную гистограмму из простого набора данных, содержащего 2 значения.D3 - Термоусадочная линейная шкала

  1. Я хочу отобразить значения набора данных слева и справа от баров соответственно. <svg> шириной 500 пикселей, и мне хотелось бы диаграмму для отображения от 100 до 400, чтобы я мог разместить <text> до и после баров. Для этого я пытаюсь сжать диапазон с [0, 500] до [100, 400], но результат не так, как ожидалось.

  2. Я также хотел бы обратить диаграмму без использования layout.stack(), так что я могу использовать простой набор данных, как [66852, 7550]

Вот это Fiddle

//Width and height 
var w = 500; 
var h = 60; 

//Original data 
//var dataset = [66852, 7550] 
//changed to below to support layout.stack() 
var dataset = [ [{y:66852}], [{y:7550}] ]; 

//Set up stack method 
var stack = d3.layout.stack(); 

//Data, stacked 
stack(dataset); 

//Set up scales 
var xScale = d3.scale.linear() 
    .domain([0, d3.max(dataset, function(d) { 
      return d3.max(d, function(d) { 
       return d.y0 + d.y; 
      }); 
     }) 
    ]) 
    .range([100, 400]); 

var yScale = d3.scale.ordinal() 
    .domain(d3.range(dataset[0].length)) 
    .rangeRoundBands([0, h], 0.05); 

//Easy colors accessible via a 10-step ordinal scale 
var colors = d3.scale.category10(); 

//Create SVG element 
var svg = d3.select(".chart") 
    .attr("width", w) 
    .attr("height", h); 

// Add a group for each row of data 
var groups = svg.selectAll("g") 
    .data(dataset) 
    .enter() 
    .append("g") 
    .style("fill", function(d, i) { 
     return colors(i); 
    }); 

// Add a rect for each data value 
var rects = groups.selectAll('rect') 
    .data(function(d) { return d; }) 
    .enter() 
    .append("rect") 
    .attr("x", function(d, i) {  
     return xScale(d.y0);   
    }) 
    .attr("y", function(d, i) { 
     console.log('y: '+yScale(i)); 
     return yScale(i); 
    }) 
    .attr("width", function(d) { 
     console.log('width: '+xScale(d.y)); 
     return xScale(d.y); 
    }) 
    .attr("height", 10); 

ответ

2

Проблема в том, что, несмотря на свое название, ваш линейный xScale не является линейным (изображение 0 равно 100). Поэтому, когда вы используете return xScale(d.y); для ширины, вы добавляете 100 к ширине каждого прямоугольника (в математических терминах используется функция xScale (z) = 0.00211 * z + 100: это аффинная, а не линейная).


Редактировать, примеры:

  • прямоугольник, начиная с d.y0 = 0 должен иметь х = 100
  • прямоугольник с Dy = 0 должен иметь ширину = 0
  • в прямоугольник с d.y0 = 71000 (около половины суммы) должно иметь x = 250 (середина чертежа)
  • прямоугольник с dy = 71000 должен иметь ширину = 150 (половина ширины чертежа)

=> Нельзя использовать один и тот же масштаб для ширины и положения x. Поэтому либо вы используете разные функции для вычисления ширины и x, либо обманываете с помощью дополнительного transform для x (см. Мое первоначальное решение ниже).


Самым простым решением является иметь range из [0,300] (вместо [100,400]), и поместить в области рисования в g с .attr("transform", "translate(100,0)") до центра участка.

Второй вариант (походит на тот, который вы предпочитаете): используйте xScale(d.y0+d.y) - xScale(d.y0) для ширины (вместо xScale(d.y)). Это непосредственно вычисляет расстояние между левым и правым оконечными точками, т. Е. Дает ширину. Он должен работать с любым масштабом (не обязательно линейным).

Что касается вашего второго вопроса, я не знаю другого общего способа сделать это (кроме написания собственной процедуры рисования, это будет не слишком сложно). Но вы можете легко перевести простой массив в удобное расположение:

var dataset = [66852, 7550] 
var layoutDataset = dataset.map(function(d){ return [{y:d}] }); 
+0

Спасибо за ваш ответ. Мне трудно понять, почему D3 не будет принимать 100 в качестве стартового значения диапазона при расчете ширины. В идеале он должен соответствовать или отображать от 0 до 100, но нет. Другими словами, как мне отображать домен, такой как [0, 500], как диапазон [100, 300] без использования преобразования? – AlwaysALearner

+0

Надеюсь, что теперь яснее :) – tarulen

+0

Много! Еще раз спасибо! :) – AlwaysALearner

Смежные вопросы