D3 v5 - фрагментированная гистограмма - PullRequest
0 голосов
/ 27 февраля 2020

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

enter image description here

До сих пор мне удавалось добиться тривиального прогресса только путем зацикливания массивов, которые я расширены из подкатегории пропорции:

var margins = {top:20, bottom:300, left:30, right:100};

var height = 600;
var width = 900;

var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;

var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);

var graphGroup = svg.append('g')
.attr('transform', "translate("+margins.left+","+margins.top+")");

var protoData = [

  {'type':'Financial bonds', 'number':1990, 'volume':326.3, 'type1':68.8, 'type2':6.9, 'type3':13.6, 'type4':1.2, 'type5':6, 'type6':1, 'type7':2},
  {'type':'Enterprise bonds', 'number':850, 'volume':34.5, 'type1':10, 'type2':20, 'type3':10, 'type4':20, 'type5':40},
  {'type':'Corporate bonds', 'number':300, 'volume':34.5, 'type1':10, 'type2':20, 'type3':10, 'type4':20, 'type5':40},
  {'type':'Commercial paper', 'number':200, 'volume':34.5, 'type1':10, 'type2':20, 'type3':10, 'type4':20, 'type5':40}
];

var maxRows = 4;
var data = [];

var yScale = d3.scaleLinear()
.domain([0,500])
.range([height,0]);

protoData.forEach(obj => {
  data.push(Object.keys(obj).reduce((acc, _, i) =>
acc.concat(d3.range(Math.round(obj["type" + (i + 1)])).map(() => i)), []))
});

//console.log(data)

var colorScale = d3.scaleOrdinal(["#003366","#366092","#4f81b9","#95b3d7","#b8cce4","#e7eef8","#a6a6a6","#d9d9d9"]);

for (var j=0; j<data.length; j++) {



    graphGroup.selectAll('rect')
        .data(data[j])
        .enter()
        .append('rect')
        .attr('x', function(d, i) {
            return ((i / maxRows) % maxRows) * 25 + (j*150)
        })
        .attr('y', function(d, i) {
            return ~~(i/maxRows) * 25;
        })
        .attr('width', 20)
        .attr('height', 20)
        .attr('transform', "translate("+0+","+0+")")
        .style('fill', function(d) {
          return colorScale(d);
        });

}
<script src="https://d3js.org/d3.v5.min.js"></script>

Похоже, мои maxRow logi c отключены ... очень. Этот недостаток помешал мне предпринять дальнейшие шаги. Например, я подозреваю, что в какой-то момент нам нужно ввести лог c для установки maxRows, равную значению y для этой категории. (yScale предназначен для использования с d.volume в данных.)

В настоящее время все массивы имеют длину 100, но в зависимости от значения y может потребоваться изменить размер самого массива. Например, если категория 1 имеет значение y, вдвое большее, чем категория 2, то имеет смысл разделить категорию 1 на 100 квадратов и разделить категорию 2 на 50 квадратов. Это означает, что каждый квадрат в категории 1 стоит 1%, но каждый квадрат в категории 2 будет стоить 2%. И так далее для каждой категории.

Вопрос

Если мы сохраним ширину и высоту каждого квадрата на фрагментированной гистограмме на 20, то как мы можем построить оставшуюся координату x, y? logi c добавить ректы в соответствии с yScale и цветовое кодирование colorScale?

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

Примечание: Я понимаю, что этот форм-фактор отнимает от точности d3.scaleLinear(), используемой yScale, поэтому я готов признать, что высоты могут быть не точно пикселей идеальными.

...