D3 для карт --- на якому етапі занести дані до гео?


12

Я хотів би скласти карту світу для показу з D3, а:

У мене є набір даних, який я хотів би відобразити, який націлений на клавіші ISO-альфа-3. Так...

danger.csv
iso,level
AFG,100
ALB,0
DZA,12

тощо.

Виконуючи вказівки щодо topojson, я знаю, що можу зробити ...

wget "http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/50m/cultural/ne_50m_admin_0_countries.zip"
unzip ne_50m_admin_0_countries.zip
ogr2ogr -f "GeoJSON" output_features.json ne_50m_admin_0_countries.shp -select iso_a3
topojson -o topo.json output_features.json --id-property iso_a3

для створення світової карти json, яка ідентифікується ISO3.

Моє запитання: в який момент робочого процесу я повинен об'єднати дані з nevar.csv на геодані? Раніше я працював з qGIS як графічний інтерфейс, але де / повинен / злитися? У .shp? Після ogr2ogr? Динамічно у браузері після зменшення топойсона (наприклад, http://bl.ocks.org/mbostock/4060606 http://bl.ocks.org/mbostock/3306362 )?

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

(У мене також є споріднене, але більш зацікавлене спостереження щодо Stackoverflow, яке, можливо, мені слід перенести сюди: /programming/18604877/how-to-do-time-data-in-d3-maps )


Я просто переглядав приклади @ mbostock і побачив, що є такий, який спеціально стосується GeoJoins , або "Простий скрипт для приєднання файлу GeoJSON із зовнішніми властивостями у файлі CSV або TSV; витягнутий з TopoJSON" .
RyanKDalton

Відповіді:


11

Задайте собі два питання:

  1. Чи збираєтесь ви повторно використовувати географію на кількох наборах даних?

    Якщо ви будете використовувати одну і ту ж географію з декількома наборами даних, то має сенс тримати географію та дані окремо та приєднувати їх до клієнта. Багато моїх прикладів мають окремі файли CSV (або TSV) з цієї причини. Таким чином, TopoJSON для американських штатів та повітів, а також інших країн світу, можна використовувати повторно, замість того, щоб створювати окремі TopoJSON для кожного прикладу.

    З іншого боку, якщо ви будете використовувати цю географію лише один раз , вам, ймовірно, слід "запекти" дані в географії як властивості, аби лише спростити код. Цей підхід простіший, оскільки вам потрібно завантажувати лише один файл (тому немає queue.js ), а оскільки дані зберігаються як властивості кожної функції, вам не потрібно приєднувати дані до клієнта (так що немає d3. карта ).

    Бічна примітка: TSV і CSV часто набагато ефективніші для зберігання властивостей, ніж GeoJSON і TopoJSON, просто тому, що останні повинні повторювати імена властивостей на кожному об'єкті. Розмір файлу може бути ще однією причиною зберігання ваших даних в окремому файлі та приєднання їх до клієнта.

  2. Чи ваші дані вже пов'язані з географією (наприклад, властивістю вашої форми даних)?

    Якщо припустити, що ви відповіли "ні" на перше запитання і хочете записати дані в географію (а не робити це у клієнта), як це зробити, залежить від формату даних.

    Якщо ваші дані вже є вашим topojson -pфайлом форм , використовуйте для керування, які властивості зберігаються в створеному файлі TopoJSON. Ви також можете використовувати це для перейменування властивостей і примушування їх до чисел. Приклади див. У розділі Давайте зробимо карту .

    Якщо ваші дані знаходяться в окремому файлі CSV або TSV, використовуйте topojson -e (крім -p), щоб вказати файл зовнішніх властивостей, який можна приєднати до ваших географічних особливостей. Наводимо приклад з wiki, якщо у вас був такий файл TSV:

    FIPS    rate
    1001    .097
    1003    .091
    1005    .134
    1007    .121
    1009    .099
    1011    .164
    1013    .167
    1015    .108
    1017    .186
    1019    .118
    1021    .099
    

    Використовуючи їх -e, можна зіставити їх у властивості числового виводу під назвою "безробіття":

    topojson \
      -o output.json \
      -e unemployment.tsv \
      --id-property=+FIPS \
      -p unemployment=+rate \
      -- input.shp
    

    Прикладом такого підходу є хороплет населення Кентуккі, bl.ocks.org/5144735 .


2
І тут я задавав свої жорсткі запитання щодо картографування D3 щодо stackoverflow замість gis.stackexchange, тому що я думав, що там більше досвіду --- і тоді сам майстер відповідає на моє запитання тут. =) Ну, це робить 2 речі, про які я сьогодні дізнався. Дякую!
Mittenchops

3

Хороше питання. Один із поданих вами прикладів, здається, робить трюк, хоча важко наслідувати.

Ви помітите , що приклад має два зовнішніх файлів даних, us.json і unemployment.tsv . Ви можете думати про безробіття.tsv як про вашу небезпеку.csv; us.json - це географічні особливості, з якими потрібно пов’язати параметри з nevar.csv. Останнє, безробіття.tsv, має idі rateполя, де idце те саме, що і idв us.json.

Саме у клієнта з D3 ви повинні об'єднати свої дані та функції , принаймні на цьому прикладі. Саме в клієнті рівень безробіття в цьому прикладі приєднується до функцій округу, використовуючи функцію d3.map () . Тут ініціалізується:

var rateById = d3.map();

І ось це rateвідображається на id:

queue()
    .defer(d3.json, "/mbostock/raw/4090846/us.json")
    .defer(d3.tsv, "unemployment.tsv", function(d) { rateById.set(d.id, +d.rate); })
    .await(ready);

Треба визнати, що не знаю, для чого queue()це, але це не важливо для цієї дискусії. Що важливо зазначити, це те, що idсфера у кожному окрузі є заміщеною безробіттям rate. rateтепер доступний за загальними ідентифікатором id( EDIT: Як @ blord-Castillo вказує, що це на самому справі покоління нового асоціативного масиву або хеш - ключ, де rateзіставляється зid ). Ось тут rateвикликається для символіки (тут для кожного квантиля доступні заздалегідь визначені класи CSS):

...
.enter().append("path")
  .attr("class", function(d) { return quantize(rateById.get(d.id)); })
  .attr("d", path);

Якщо quantize()функція повертає назву класу CSS, який слід використовувати для стилю цієї функції (округу), виходячи з рівня її безробіття, який зараз визначений у полі функції id.



черга дозволяє асинхронізувати паралельне завантаження джерел даних замість послідовного завантаження.
blord-castillo

1
У цьому прикладі відбувається те, що rateById є ключовим хешем. Зміни в особливостях країни ніколи не вносяться, а дані us.json не стосуються. Натомість безробіття.tsv перетворюється на ключовий хеш під назвою 'rateById'. rateById.set () перекидається на безробіття.tsv, так що для кожного id в безробіття.tsv (не в us.json) вставляється ключ, а значення цього ключа встановлюється у поле ставки для цього id у безробітті.tsv . Пізніше rateById.get () закликається використовувати хеш для пошуку рівня безробіття за id; це значення використовується для встановлення стилю для функцій us.json, а потім відкидається.
blord-castillo

Чому це / замінює / ідентифікатор швидкістю замість того, щоб приєднувати його як атрибут деінде? Це, мабуть, ускладнить зробити вибір пізніше.
Mittenchops

1
Він не замінює ідентифікатор на ставку. Це створює хеш пошуку для пошуку від id до курсу.
blord-castillo

2

По-перше, перший рядок вашого csv повинен бути розділеним комами списком імен стовпців, щоб використовувати цей метод. Якщо це не можливо, додати коментар про це , і я буду бачити , якщо я можу працювати, як використовувати d3.csv.parseRowsзамість d3.csv.parse. d3.csv.parseвикликається функцією оцінювача на .defer(function, url, assessor).

Я припускаю, що ваш файл зараз виглядає так:

danger.csv
iso,level
AFG,100
ALB,0
DZA,12
...

Використовуючи це, ви можете створити хеш-код пошуку від ISO3 до рівня небезпеки.

var dangerByISO3 = d3.map();
queue()
    .defer(d3.json, "url to topo.json")
    .defer(d3.csv, "url to danger.csv", function(d) {dangerByISO3.set(d.iso, +d.level);})
    .await(ready);
function ready(error, world) {
    //You now have world as your available topojson
    //And you have dangerByISO3 as your danger level hash
    //You can lookup a danger level by dangerByISO3.get(ISO3 code)
}

Посібник із кодом

var dangerByISO3 = d3.map();

Спочатку ви створюєте об'єкт d3.map (), який буде функціонувати як ваш хеш-ключ, і зберігаєте це у змінній небезпеціByISO3.

queue()

Використовуйте чергу для паралельного завантаження.

.defer(d3.json, "url to topo.json")

Завантажте свій topojson як перший аргумент, який буде передано функції очікування (після помилки). Зверніть увагу на стиль, у якому ця функція пов'язана ланцюжком queue(), але вказана в окремому рядку (на кінці немає крапки з комою queue()).

.defer(d3.csv, "url to danger.csv", function(d) {dangerByISO3.set(d.iso, +d.level);})

Тут відбуваються дві речі. По-перше, ви завантажуєте nevar.csv як ваш другий аргумент, який потрібно передати функції очікування. Як ви побачите нижче, цей аргумент насправді не використовується. Натомість аргумент оцінювача надається функції завантаження, d3.csv. Цей оцінювач буде обробляти кожен рядок csv. У цьому випадку ми називаємо функцію встановлення на nevarByISO3, так що для кожної комбінації isoключа ми встановлюємо значення levelяк значення, що йде з цим ключем. +d.levelПозначення використовують унарні +примушувати значення d.level до ряду.

.await(ready);

Після завантаження обох джерел даних вони передаються функції як два окремі аргументи ready(). Перший аргумент зворотного виклику - це завжди перша помилка, яка виникла. Якщо помилки не сталося, нуль буде передано як перший аргумент. Другий аргумент - це перше джерело даних (результат першого завдання), а третій аргумент - друге джерело даних (результат другого завдання).

function ready(error, world) {...}

Це функція зворотного дзвінка ready(). Спочатку ми беремо errorаргумент, який повинен бути недійсним, якщо два завдання з завантаження успішно виконані (ви насправді повинні додати мову для лову та обробки помилок). Далі ми беремо дані топойсона як об’єкт countries. Ці дані повинні бути оброблені в тілі функції з чимось подібним .data(topojson.feature(world,world.objects.countries).features). Оскільки ready()третій аргумент не бере, результат другого завдання, наш csv, просто відкидається. Ми використовували його лише для створення ключового хешу і не знадобився йому після цього.


Так, ти маєш рацію, мій csv насправді виглядає як добре сформований csv замість недбалого демо, яке я розмістив. =) Вибачте, я оновлю це.
Mittenchops
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.