D3 สำหรับแผนที่ --- ในขั้นตอนใดที่จะนำข้อมูลเข้าสู่พื้นที่ทางภูมิศาสตร์?


12

ฉันต้องการทำแผนที่โลกร่วมแสดงกับ D3, a la:

ฉันมีชุดข้อมูลที่ฉันต้องการแสดงซึ่งมีการระบุคีย์ ISO-alpha-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

เพื่อสร้าง worldmap json ที่ ID'd โดย ISO3

คำถามของฉันคือ: ณ จุดใดในเวิร์กโฟลว์ที่ฉันควรรวมข้อมูลจาก danger.csv เข้ากับข้อมูลทางภูมิศาสตร์? ก่อนหน้านี้ฉันเคยทำงานกับ qGIS ในฐานะ GUI แต่ที่ไหน / ควร / การผสานเกิดขึ้นที่ไหน ใน. shp หลังจาก ogr2ogr แบบไดนามิกในเบราว์เซอร์หลังจากที่ topojson ย่อ (เช่นที่นี่http://bl.ocks.org/mbostock/4060606 http://bl.ocks.org/mbostock/3306362 )?

ฉันค่อนข้างดีกับงูหลาม แต่ค่อนข้างใหม่สำหรับ javascript และพบว่าตัวเองกำลังคัดลอกและวางตัวอย่างของ Bostock มากกว่าที่จะเป็น coder ทั่วไป

(ฉันมีหน่วยงานที่เกี่ยวข้อง แต่มีส่วนร่วมมากขึ้นในการติดตาม Stackoverflow ที่ฉันควรย้ายที่นี่: /programming/18604877/how-to-do-time-data-in-d3-maps )


ผมก็แค่มองไปที่ตัวอย่าง @ mbostock และเห็นว่ามีสิ่งหนึ่งที่เฉพาะที่อยู่GeoJoinsหรือ"สคริปต์ง่ายสำหรับการเข้าร่วมไฟล์ GeoJSON มีคุณสมบัติภายนอกในไฟล์ CSV หรือ TSV; สกัดจาก TopoJSON"
RyanKDalton

คำตอบ:


11

ถามตัวเองด้วยคำถามสองข้อ:

  1. คุณจะใช้ภูมิศาสตร์ซ้ำในชุดข้อมูลหลายชุดหรือไม่

    หากคุณใช้ภูมิศาสตร์เดียวกันกับชุดข้อมูลหลายชุดคุณควรแยกข้อมูลภูมิศาสตร์และข้อมูลออกจากกันและเข้าร่วมกับลูกค้า ตัวอย่างของฉันจำนวนมากมีไฟล์ CSV (หรือ TSV) แยกกันด้วยเหตุนี้ ด้วยวิธีนี้ TopoJSON สำหรับรัฐในสหรัฐอเมริกาและมณฑลหรือประเทศในโลกเดียวกันสามารถนำกลับมาใช้ใหม่ได้แทนที่จะสร้าง TopoJSON แยกต่างหากสำหรับทุกตัวอย่าง

    ในทางกลับกันหากคุณใช้ภูมิศาสตร์นี้เพียงครั้งเดียวคุณควร "อบ" ข้อมูลลงในภูมิศาสตร์เป็นคุณสมบัติหากเพียงเพื่อทำให้โค้ดง่ายขึ้น วิธีการนี้ง่ายกว่าเพราะคุณต้องโหลดไฟล์เดียว (ดังนั้นจึงไม่มีคิว. js ) และเนื่องจากข้อมูลถูกเก็บไว้เป็นคุณสมบัติของแต่ละคุณสมบัติคุณไม่จำเป็นต้องเข้าร่วมข้อมูลในไคลเอนต์ (ดังนั้นจึงไม่มีd3 แผนที่ )

    หมายเหตุด้านข้าง: TSV และ CSV มักจะมีประสิทธิภาพมากขึ้นในการจัดเก็บคุณสมบัติกว่า GeoJSON และ TopoJSON เพียงเพราะหลังต้องทำซ้ำชื่อคุณสมบัติในทุกวัตถุ ขนาดไฟล์อาจเป็นอีกเหตุผลหนึ่งในการจัดเก็บข้อมูลของคุณในไฟล์แยกและเข้าร่วมในไคลเอนต์

  2. ข้อมูลของคุณถูกผูกไว้กับภูมิศาสตร์แล้ว (เช่นคุณสมบัติของรูปร่างไฟล์) หรือไม่?

    สมมติว่าคุณตอบ“ ไม่” สำหรับคำถามแรกและต้องการอบข้อมูลลงในภูมิศาสตร์ (แทนที่จะทำในไคลเอนต์) วิธีการทำเช่นนี้ขึ้นอยู่กับรูปแบบของข้อมูล

    หากข้อมูลของคุณเป็นคุณสมบัติของtopojson -pรูปร่างไฟล์ของคุณอยู่แล้วให้ใช้เพื่อควบคุมคุณสมบัติที่จะบันทึกลงในไฟล์ TopoJSON ที่สร้างขึ้น นอกจากนี้คุณยังสามารถใช้สิ่งนี้เพื่อเปลี่ยนชื่อคุณสมบัติและบีบบังคับให้เป็นตัวเลขได้เช่นกัน ดูขอให้แผนที่สำหรับตัวอย่าง

    หากข้อมูลของคุณอยู่ในไฟล์ CSV หรือ TSV แยกต่างหากให้ใช้topojson -e (เพิ่มเติมจาก-p) เพื่อระบุไฟล์คุณสมบัติภายนอกที่สามารถเข้าร่วมกับคุณสมบัติทางภูมิศาสตร์ของคุณ ตัดตัวอย่างจากวิกิถ้าคุณมีไฟล์ 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

    ตัวอย่างของวิธีนี้คือเคนตั๊กกี้ประชากร choropleth, bl.ocks.org/5144735


2
และที่นี่ฉันถามคำถามการแมป D3 อย่างหนักของฉันใน stackoverflow แทน gis.stackexchange เพราะฉันคิดว่ามีความเชี่ยวชาญมากขึ้นที่นั่น --- แล้วอาจารย์ก็ตอบคำถามของฉันที่นี่ =) นั่นทำให้ 2 สิ่งที่ฉันเรียนรู้วันนี้ ขอบคุณ!
Mittenchops

3

คำถามที่ดี. หนึ่งในตัวอย่างที่คุณให้มาดูเหมือนจะเป็นการหลอกลวงแม้ว่าจะยากที่จะติดตาม

คุณจะได้ทราบว่าตัวอย่างมีสองไฟล์ข้อมูลภายนอกus.jsonและunemployment.tsv คุณสามารถคิดถึงการว่างงานได้เช่นเดียวกับอันตรายของคุณ us.json เป็นคุณสมบัติทางภูมิศาสตร์ที่คุณต้องการเชื่อมโยงพารามิเตอร์จาก danger.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()มีไว้เพื่ออะไรแต่มันไม่สำคัญสำหรับการสนทนานี้ อะไรคือสิ่งที่สำคัญที่ควรทราบก็คือว่าข้อมูลในลักษณะเขตแต่ละจะถูกแทนที่ด้วยการว่างงาน อยู่ในขณะนี้สามารถเข้าถึงได้โดยระบุที่ใช้ร่วมกัน( แก้ไข: ในฐานะที่เป็น @ blord-Castillo ชี้ให้เห็นนี้เป็นจริงรุ่นของอาเรย์ใหม่หรือกัญชาที่สำคัญที่ถูกแมปไป ) นี่คือตำแหน่งที่เรียกใช้สำหรับวัตถุประสงค์ของ symbology (ที่นี่คลาส CSS ที่กำหนดไว้ล่วงหน้ามีให้สำหรับแต่ละ quantile):idraterateidrateidrate

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

โดยที่quantize()ฟังก์ชันส่งคืนชื่อของคลาส CSS ที่ควรใช้เพื่อจัดรูปแบบคุณลักษณะนั้น (เคาน์ตี) ตามอัตราการว่างงานซึ่งตอนนี้กำหนดไว้ในidฟิลด์ของคุณสมบัติ



คิวช่วยให้การโหลด async แบบขนานของแหล่งข้อมูลแทนการโหลดแบบอนุกรม
blord-castillo

1
สิ่งที่เกิดขึ้นในตัวอย่างนั้นคือ rateById คือแฮชคีย์ ไม่มีการเปลี่ยนแปลงใด ๆ กับคุณลักษณะของประเทศและข้อมูล us.json ไม่ถูกแตะต้อง การว่างงานจะถูกแปลงเป็นแฮชคีย์ที่เรียกว่า 'rateById' แทน rateById.set () วนลูปมากกว่าการว่างงานเพื่อให้คีย์ถูกแทรกสำหรับแต่ละ id ในว่างงานment.tsv (ไม่ใช่ใน us.json) และค่าของคีย์นั้นถูกตั้งค่าเป็นฟิลด์อัตราสำหรับ id นั้นในการว่างงาน . ต่อมา rateById.get () ถูกเรียกให้ใช้แฮชเพื่อค้นหาอัตราการว่างงานตาม id ค่านั้นจะใช้ในการตั้งค่าสไตล์บนคุณสมบัติ us.json จากนั้นยกเลิก
blord-castillo

ทำไม / แทนที่ / ID ที่มีอัตราแทนที่จะแนบเป็นแอตทริบิวต์อื่น? ดูเหมือนว่าจะทำให้เลือกได้ยากขึ้นในภายหลัง
Mittenchops

1
มันไม่ได้แทนที่ ID ด้วยอัตรา มันสร้างแฮชการค้นหาจาก id เป็นอัตรา
blord-castillo

2

ก่อนอื่นแถวแรกของ csv ของคุณต้องเป็นรายการชื่อคอลัมน์ที่คั่นด้วยเครื่องหมายจุลภาคเพื่อใช้วิธีนี้ ถ้าเรื่องนี้เป็นไปไม่ได้เพิ่มความคิดเห็นเกี่ยวกับเรื่องนี้และเราจะดูว่าฉันสามารถทำงานออกวิธีการใช้งานแทนd3.csv.parseRows ถูกเรียกโดยฟังก์ชั่นในการประเมินd3.csv.parsed3.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 () ซึ่งจะทำหน้าที่เป็นแฮชคีย์ของคุณและเก็บสิ่งนี้ไว้ในตัวแปร dangerByISO3

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);})

มีสองสิ่งเกิดขึ้นที่นี่ ก่อนอื่นคุณกำลังโหลด danger.csv เป็นอาร์กิวเมนต์ที่สองของคุณที่จะถูกส่งผ่านไปยังฟังก์ชันรอ ดังที่คุณจะเห็นด้านล่างอาร์กิวเมนต์นี้ไม่ได้ใช้จริง อาร์กิวเมนต์ตัวประเมินจะถูกกำหนดให้กับฟังก์ชันการโหลด d3.csv ผู้ประเมินนี้จะประมวลผลแต่ละแถวของ csv ในกรณีนี้เราเรียกใช้ฟังก์ชั่นการตั้งค่าเกี่ยวกับ dangerByISO3 เพื่อให้การรวมกันของisoคีย์แต่ละครั้งเราตั้งค่าlevelเป็นค่าที่จะไปกับคีย์นั้น +d.levelสัญกรณ์ใช้เอก+บีบบังคับค่าของ d.level ไปจำนวน

.await(ready);

ready()เมื่อทั้งสองแหล่งข้อมูลจะถูกโหลดพวกเขาจะส่งเป็นสองอาร์กิวเมนต์ที่แยกต่างหากเพื่อฟังก์ชั่น อาร์กิวเมนต์แรกของการติดต่อกลับเป็นข้อผิดพลาดแรกที่เกิดขึ้นเสมอ หากไม่มีข้อผิดพลาดเกิดขึ้น null จะถูกส่งผ่านเป็นอาร์กิวเมนต์แรก อาร์กิวเมนต์ที่สองคือแหล่งข้อมูลแรก (ผลลัพธ์ของงานแรก) และอาร์กิวเมนต์ที่สามคือแหล่งข้อมูลที่สอง (ผลลัพธ์ของงานที่สอง)

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

ready()นี่คือฟังก์ชันการเรียกกลับ อันดับแรกเรารับerrorอาร์กิวเมนต์ที่ควรเป็นโมฆะหากงานการโหลดสองรายการเสร็จสมบูรณ์ (คุณควรเพิ่มภาษาเพื่อตรวจจับและจัดการข้อผิดพลาด) ต่อไปเราจะนำข้อมูล topojson countriesเป็นวัตถุ .data(topojson.feature(world,world.objects.countries).features)ข้อมูลนี้ควรจะดำเนินการในร่างกายของฟังก์ชั่นที่มีบางสิ่งบางอย่างเช่น เนื่องจากready()ไม่ใช้อาร์กิวเมนต์ที่สามผลลัพธ์ของภารกิจที่สองคือ csv ของเราจะถูกยกเลิก เราใช้มันเพื่อสร้างแฮชคีย์และไม่ต้องการมันหลังจากนั้น


ใช่คุณพูดถูก csv ของฉันดูเหมือนจะเป็น csv ที่มีรูปแบบที่ดีแทนที่จะเป็นแบบไม่ใส่ใจที่ฉันโพสต์ =) ขออภัยฉันจะอัปเดต
Mittenchops
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.