Bir çizgiden ve değerden bir çizgi yayı oluşturma


9

Böyle bir Origin-Destination arsa yeniden yaratmaya çalışıyorum :

resim açıklamasını buraya girin

Ben bir MSOA LAD tabloya verileri munge başardı ve kökeni MSOA biri için böyle bir harita çizebilirsiniz.

resim açıklamasını buraya girin

Hangi bir zamanlar (şimdi gülünç) mesafelere izin verirseniz, Peak District'teki insanlar işe giderler.

Ama yazarın çizgileri "açığa çıkararak" başardığı etkiyi çok seviyorum. Açıkçası, 522 ve 371 akışları ile, banliyö başına tek bir çizgi için gidemem, ancak yolculuğu yapan insan sayısını göstermek için orantılı bir çizgi yayı üretmek iyi olurdu.

Geometri Jeneratörünü kullanabileceğimi düşündüm ama bir döngü yapısı olmadan ilerleyemiyorum.


Bu ESRI aracı ilginizi çekebilir veya en azından satırların "kama" oluşturulmasına ilişkin kod fikirleri için bir yay panosu olabilir.
Hornbydd

Ve bir çizgi sembolize ettiğinde, diyelim ki hat başına 50 (100, 200) taşıt? Bazı python kodu (veya geometri üreteci ile emin değilim) çizgileri (x / 50) farklı bir miktarda döndürebilirsiniz.
Stefan

Yanıtlar:


5

Harika bir meydan okuma!

Bu cevap öncelikle Geometri üretecini kullanır ve QGIS 3.2'de yazılmıştır. QGIS, çizgileri ilk oluşturduktan ve neredeyse vazgeçtikten hemen sonra (kaydetmeden benden!) Çöktü, ancak son kullanılan ifade listesi günü kurtardı - Geometri jeneratörünü kullanmanın başka bir bonusu

İki nokta seti ile başladım, bir kaynak ve üç hedef. Hedefler sayımlarla etiketlenmiştir:

Başlangıç ​​noktaları

Daha sonra, aşağıdaki kodu kullanarak sanal bir katman kullanarak tüm hedeflere kaynak noktasını bağlayan çizgiler oluşturdum:

SELECT d.Count_MF, Makeline( s.geometry, d.geometry) 'geometry' 
  FROM Source AS s JOIN Destinations AS d

Bağlı noktalar

Sonra satırları stilize etmek için aşağıdaki Geometri üreteci ifadesini kullandım:

 intersection(
   geom_from_wkt( 
     'MULTILINESTRING ((' ||  $x_at( 0)  || ' ' || $y_at( 0)  || ', ' || 
     array_to_string(
       array_remove_at( string_to_array( regexp_replace(
             geom_to_wkt(nodes_to_points( tapered_buffer(  $geometry ,0, "Count_MF" * 200, floor("Count_MF" / 10)),true)),
             '[\\(\\)]','')),0)
     , ') , ('  ||  $x_at( 0)  || ' ' || $y_at( 0)  || ', ' )
    || '))')
    ,buffer( point_n(  $geometry ,1), $length))

Bu, her satırı alır ve aşağıdaki adımları uygular:

  1. Kaynaktaki sıfır genişliğinden, hedef uçtaki hedef sayısı ile ölçeklendirilmiş bir genişliğe giden konik bir tampon oluşturur. Arabellek noktası yoğunluğu hedef sayım özniteliği tarafından da ölçeklendirilir.
  2. Tampon çokgenin köşeleri noktalara dönüştürülür (bu muhtemelen gereksizdir) ve daha sonra WKT'ye aktarılır ve parantezler bir diziye dönüştürülmeden önce bir normal ifade kullanılarak kaldırılır
  3. Daha sonra dizi, çoklu nokta için WKT dizesine geri genişletilir, kaynak noktasının koordinatlarına ve ilgili biçimlendirmeye eklenir - bu, kaynak noktasına bağlı çıkarılan her köşe için ayrı bir satır oluşturur
  4. WKT, bir geometri nesnesine geri dönüştürülür ve son olarak, hedef noktasının oturduğu daireye geri çekmek için kaynak noktasının tamponuyla kesişir (bunun tapered_bufferneden gerekli olduğunu anlamak için a'nın çıkışına bakın )

Fanlar

Adımları yazarken, bir diziye ve diziden dönüşümün gerekli olmadığını ve tüm WKT manipülasyonunun regexes ile yapılabileceğini anlıyorum. Bu ifade aşağıdadır ve tapered_arrayişlev farklı bir işlevle değiştirilebiliyorsa, bu QGIS 2.18'de de kullanılabilir.

intersection(
   geom_from_wkt(
    'MULTILINESTRING ((' ||  $x_at( 0)  || ' ' || $y_at( 0)  || ', ' ||
  replace(
    regexp_replace(
      regexp_replace(
        geom_to_wkt(tapered_buffer(  $geometry ,0, "Count_MF" * 200, floor("Count_MF" / 10))),
      '^[^,]*,',''),
    ',[^,]*$',''),
  ',',') , ('  ||  $x_at( 0)  || ' ' || $y_at( 0)  || ', ')
  || '))')
,buffer( point_n(  $geometry ,1), $length))

6

Sorunuz beni meraklandırdı.

Bu çözüm yalnızca Python Konsolu'ndaki QGIS 2.x için çalışır

Yorumumda belirtildiği gibi, burada Python ile çizgi yayı oluşturmak benim fikrim.

İki nokta katmanım var:

ben. Biri sermayeyi elinde tutar (id, sermaye)

ii. Kasabalardan biri (kimlik, kasaba, taşıt)

Taşıt miktarı "banknotlara ayrılmıştır" ve bunlar arkı oluşturan çizgiler olacaktır. 371 yolcular, 3x100, 1x50, 2x10 ve 1x1 ve toplam 7 banknottan oluşan bir kombinasyon. Daha sonra çizgiler kural tabanlı bir stil ile şekillendirilir.

İşte kod:

from qgis.gui import *
from qgis.utils import *
from qgis.core import *
from PyQt4 import QtGui, uic
from PyQt4.QtGui import *
from PyQt4.QtCore import *

for lyr in QgsMapLayerRegistry.instance().mapLayers().values():
    if lyr.name() == "capital":
        capital_layer = lyr

for lyr in QgsMapLayerRegistry.instance().mapLayers().values():
    if lyr.name() == "town":
        town_layer = lyr

    # creating the memory layer
d_lyr = QgsVectorLayer('LineString', 'distance', 'memory')
QgsMapLayerRegistry.instance().addMapLayer(d_lyr)
prov = d_lyr.dataProvider()
prov.addAttributes( [ QgsField("id", QVariant.Int), QgsField("banknote",QVariant.Int)])

    # function to create the banknotes
def banknoteOutput(number):
    number_list = []
    number_list.append(number)
    banknote_count = []
    temp_list = []
    banknote_list = []
    for n in number_list:
        total_sum = 0
        total = int(n/100)
        total_sum = total_sum + total
        if total > 0:
            banknote_count.append([total, 100])
        n = n-(total*100)
        total = int(n/50)
        total_sum = total_sum + total
        if total > 0:
            banknote_count.append([total, 50])
        n = n-(total*50)
        total = int(n/10)
        total_sum = total_sum + total
        if total > 0:
            banknote_count.append([total, 10])
        n = n-(total*10)
        total = int(n/5)
        total_sum = total_sum + total
        if total > 0:
            banknote_count.append([total, 5])
        n = n-(total*5)
        total = int(n/1)
        total_sum = total_sum + total
        if total > 0:
            banknote_count.append([total, 1])
        for i in banknote_count:
            temp_list.append(i*i[0])
        banknote_list = [item for sublist in temp_list for item in sublist][1::2]
        return banknote_list

        # creating lines with the amount of banknotes
for capital in capital_layer.getFeatures():
    for town in town_layer.getFeatures():
        commuter_splitting = banknoteOutput(town['commuters'])
        for i,banknote in enumerate(commuter_splitting):
            angle = 2
            distance = QgsDistanceArea()
            distance.measureLine(capital.geometry().asPoint(), town.geometry().asPoint())
            vect = QgsFeature()
            vect.setGeometry(QgsGeometry.fromPolyline([capital.geometry().asPoint(), town.geometry().asPoint()]))
            vect.geometry().rotate(0+(i*angle), capital.geometry().asPoint())
            vect.setAttributes([int(town["id"]), int(banknote)])
            prov.addFeatures([vect])

d_lyr.updateExtents()
d_lyr.triggerRepaint()
d_lyr.updateFields()

Sonuç şöyle görünebilir:

resim açıklamasını buraya girin

GÜNCELLEME: ayrım erkek / kadın

4 Bellek Katmanı ile sonuçlanır.

from qgis.gui import *
from qgis.utils import *
from qgis.core import *
from PyQt4 import QtGui, uic
from PyQt4.QtGui import *
from PyQt4.QtCore import *

for lyr in QgsMapLayerRegistry.instance().mapLayers().values():
    if lyr.name() == "capital":
        capital_layer = lyr

for lyr in QgsMapLayerRegistry.instance().mapLayers().values():
    if lyr.name() == "town":
        town_layer = lyr

    # function to create the banknotes
def banknoteOutput(number):
    number_list = []
    number_list.append(number)
    banknote_count = []
    temp_list = []
    banknote_list = []
    for n in number_list:
        total_sum = 0
        total = int(n/100)
        total_sum = total_sum + total
        if total > 0:
            banknote_count.append([total, 100])
        n = n-(total*100)
        total = int(n/50)
        total_sum = total_sum + total
        if total > 0:
            banknote_count.append([total, 50])
        n = n-(total*50)
        total = int(n/10)
        total_sum = total_sum + total
        if total > 0:
            banknote_count.append([total, 10])
        n = n-(total*10)
        total = int(n/5)
        total_sum = total_sum + total
        if total > 0:
            banknote_count.append([total, 5])
        n = n-(total*5)
        total = int(n/1)
        total_sum = total_sum + total
        if total > 0:
            banknote_count.append([total, 1])
        for i in banknote_count:
            temp_list.append(i*i[0])
        banknote_list = [item for sublist in temp_list for item in sublist][1::2]
        return banknote_list

    # creating the male memory layer
cmt_male = QgsVectorLayer('LineString', 'Commuters_Male', 'memory')
QgsMapLayerRegistry.instance().addMapLayer(cmt_male)
prov_male = cmt_male.dataProvider()
prov_male.addAttributes( [ QgsField("id", QVariant.Int), QgsField("banknote",QVariant.Int)])

    # creating the male polygon memory layer
cmt_male_polygon = QgsVectorLayer('Polygon', 'Commuters_Male_Poly', 'memory')
QgsMapLayerRegistry.instance().addMapLayer(cmt_male_polygon)
prov_cmt_male_polygon = cmt_male_polygon.dataProvider()
prov_cmt_male_polygon.addAttributes( [ QgsField("id", QVariant.Int), QgsField("banknote",QVariant.Int)])

    # creating lines with the amount of banknotes
for capital in capital_layer.getFeatures():
    for town in town_layer.getFeatures():
        commuter_splitting = banknoteOutput(town['cmt_male'])
        points = []
        for i,banknote in enumerate(reversed(commuter_splitting)):
            angle = 2
            distance = QgsDistanceArea()
            distance.measureLine(capital.geometry().asPoint(), town.geometry().asPoint())
            vect = QgsFeature()
            vect.setGeometry(QgsGeometry.fromPolyline([capital.geometry().asPoint(), town.geometry().asPoint()]))
            vect.geometry().rotate(0+(i*angle), capital.geometry().asPoint())
            vect.setAttributes([int(town["id"]), int(banknote)])
            points.append(vect.geometry().asPolyline()[1])
            prov_male.addFeatures([vect])
        polygon = QgsFeature()
        points.insert(0,capital.geometry().asPoint())
        points.insert(len(points),capital.geometry().asPoint())
        polygon.setGeometry(QgsGeometry.fromPolygon([points]))
        polygon.setAttributes([1, 2])
        prov_cmt_male_polygon.addFeatures([polygon])

cmt_male.updateExtents()
cmt_male.triggerRepaint()
cmt_male.updateFields()
cmt_male_polygon.updateExtents()
cmt_male_polygon.triggerRepaint()
cmt_male_polygon.updateFields()

    # creating the female memory layer
cmt_female = QgsVectorLayer('LineString', 'Commuters_Female', 'memory')
QgsMapLayerRegistry.instance().addMapLayer(cmt_female)
prov_female = cmt_female.dataProvider()
prov_female.addAttributes( [ QgsField("id", QVariant.Int), QgsField("banknote",QVariant.Int)])

    # creating the female polygon memory layer
cmt_female_polygon = QgsVectorLayer('Polygon', 'Commuters_Female_Poly', 'memory')
QgsMapLayerRegistry.instance().addMapLayer(cmt_female_polygon)
prov_cmt_female_polygon = cmt_female_polygon.dataProvider()
prov_cmt_female_polygon.addAttributes( [ QgsField("id", QVariant.Int), QgsField("banknote",QVariant.Int)])

    # creating lines with the amount of banknotes
for capital in capital_layer.getFeatures():
    for town in town_layer.getFeatures():
        commuter_splitting = banknoteOutput(town['cmt_female'])
        points = []
        for i,banknote in enumerate(commuter_splitting):
            angle = 2
            distance = QgsDistanceArea()
            distance.measureLine(capital.geometry().asPoint(), town.geometry().asPoint())
            vect = QgsFeature()
            vect.setGeometry(QgsGeometry.fromPolyline([capital.geometry().asPoint(), town.geometry().asPoint()]))
            vect.geometry().rotate(-angle-(i*angle), capital.geometry().asPoint())
            vect.setAttributes([int(town["id"]), int(banknote)])
            points.append(vect.geometry().asPolyline()[1])
            prov_female.addFeatures([vect])
        polygon = QgsFeature()
        points.insert(0,capital.geometry().asPoint())
        points.insert(len(points),capital.geometry().asPoint())
        polygon.setGeometry(QgsGeometry.fromPolygon([points]))
        polygon.setAttributes([1, 2])
        prov_cmt_female_polygon.addFeatures([polygon])

cmt_female.updateExtents()
cmt_female.triggerRepaint()
cmt_female.updateFields()
cmt_female_polygon.updateExtents()
cmt_female_polygon.triggerRepaint()
cmt_female_polygon.updateFields()

Sonuç şöyle görünebilir:resim açıklamasını buraya girin

Kartografik açıdan ideal olmayan bir şey:

Bir çizgi yayının boyutu, ilk bakışta daha büyük bir arkın daha fazla taşıt temsil edebileceği şekilde tahriş edici olabilir. Bir ark, daha az taşıtla (289 taşıt / 11 banknot) daha fazla taşıtla (311 taşıt / 5 banknot) diğerinden daha büyük olabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.