Картограмма D3 с легендой

У меня есть картограмма Соединенных Штатов, показывающая общую численность населения. Я хотел бы добавить на карту легенду, показывающую значения диапазона квантилей. Я видел другие подобные вопросы по этой теме, но, похоже, не могу заставить ее работать для моего конкретного случая. Я знаю, что мне нужно включить цветовой диапазон или цветовую область, но просто не уверен, что это правильный способ. На данный момент в легенде отображается только одна функция, возможно ли, что все функции легенды наложены друг на друга. Как я могу знать наверняка и как я могу это исправить.

//Define default colorbrewer scheme
var colorSchemeSelect = "Greens";
var colorScheme = colorbrewer[colorSchemeSelect]; 

//define default number of quantiles
var quantiles = 5;

//Define quantile scale to sort data values into buckets of color
var color = d3.scale.quantile()
   .range(colorScheme[quantiles]);

d3.csv(data, function (data) {
    color.domain([
         d3.min(data, function (d) {
           return d.value;
         }),
         d3.max(data, function (d
           return d.value
         }) 
    ]);

//legend                            
var legend = svg.selectAll('rect')
    .data(color.domain().reverse())
    .enter()
    .append('rect')
    .attr("x", width - 780)
    .attr("y", function(d, i) {
       return i * 20;
    })
   .attr("width", 10)
   .attr("height", 10)
   .style("fill", color);

person bailey    schedule 17.02.2014    source источник
comment
Что-то вроде этого? Вам просто нужно установить диапазон выходных цветов как квантили (т.е. 5 цветов).   -  person Lars Kotthoff    schedule 18.02.2014
comment
Да, я хотел бы, чтобы это было похоже на этот пример. Я не хочу иметь переменную с жестко закодированными значениями для легенды, как в примере. Я хочу, чтобы он использовал переменную color.domain и colorScheme для заполнения значений легенды.   -  person bailey    schedule 18.02.2014


Ответы (1)


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

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

Имея это в виду, чтобы получить одну запись легенды для каждого цвета, вам нужно будет использовать диапазон вашей цветовой шкалы, а не домен, в качестве данных для вашей легенды. Затем вы можете использовать метод quantileScale.invertExtent(), чтобы найти минимум и максимум входные значения, которые рисуются этим цветом.

Пример кода, в котором каждая запись легенды представляет собой <g>, содержащую как цветной прямоугольник, так и текстовую метку, показывающую соответствующие значения.

var legend = svg.selectAll('g.legendEntry')
    .data(color.range().reverse())
    .enter()
    .append('g').attr('class', 'legendEntry');

legend
    .append('rect')
    .attr("x", width - 780)
    .attr("y", function(d, i) {
       return i * 20;
    })
   .attr("width", 10)
   .attr("height", 10)
   .style("stroke", "black")
   .style("stroke-width", 1)
   .style("fill", function(d){return d;}); 
       //the data objects are the fill colors

legend
    .append('text')
    .attr("x", width - 765) //leave 5 pixel space after the <rect>
    .attr("y", function(d, i) {
       return i * 20;
    })
    .attr("dy", "0.8em") //place text one line *below* the x,y point
    .text(function(d,i) {
        var extent = color.invertExtent(d);
        //extent will be a two-element array, format it however you want:
        var format = d3.format("0.2f");
        return format(+extent[0]) + " - " + format(+extent[1]);
    });
person AmeliaBR    schedule 18.02.2014
comment
Кстати, глядя на остальную часть вашего кода, похоже, что вы действительно хотите использовать d3 квантовать шкалу (не квантиль), для которой домен представляет собой диапазон [min,max], а шкала делит его на группы, представляющие равные размер переменной домена (а не равное количество наблюдений). Приведенный выше код легенды работает одинаково для любого типа шкалы, поскольку в обоих случаях количество групп определяется массивом диапазонов, а доступ к соответствующим значениям домена можно получить с помощью invertExtent. - person AmeliaBR; 18.02.2014
comment
Большое спасибо за ваш содержательный ответ! Я хотел бы проголосовать за ваш ответ, но у меня пока недостаточно репутации для этого. У меня просто проблемы с методом .invertExtent() из примера кода. Это дает мне ошибку в консоли и не отображает текст, связанный с легендой. - person bailey; 18.02.2014
comment
Вы используете последнюю версию d3? похоже, что метод invertExtent был добавлен только для квантования и пороговых шкал в версии 3.2. В последней версии: вот живая версия со шкалой квантования; и вот оно с квантильной шкалой. Мне пришлось внести пару корректировок (в функцию форматирования и выравнивание текста, я обновлю приведенный выше пример кода), но ни одна из этих проблем не вызывала ошибок. - person AmeliaBR; 18.02.2014
comment
(Метод invertExtent был добавлен для квантильных шкал в версии 3.2.4, последняя версия с сайта d3js.org — 3.4.2.) - person AmeliaBR; 18.02.2014
comment
Я не использовал последнюю версию, так что это решило мою проблему! Благодарю вас! Слышали ли вы о последней версии D3, вызывающей проблемы с картографической проекцией? - person bailey; 18.02.2014