Apakah mungkin untuk mengubah simbol legenda dalam legenda komposer cetak QGIS?

9

Saya memiliki beberapa lapisan dengan simbol yang didefinisikan data yang sangat kompleks. Jika saya menggunakan legenda di komposer cetak, simbol-simbol ini tidak digambar dengan benar.

Apakah ada cara untuk mengubah simbol legenda dengan pyqgis, jadi saya dapat menggunakan gambar PNG atau SVG khusus sebagai ganti simbol legenda default untuk lapisan ini?

Saya tahu cara menambahkan Tombol ke komposer Cetak dan bagaimana menghubungkannya dengan suatu fungsi. Saya ingin menambahkan tombol ke Legenda-Pengaturan untuk memungkinkan saya mengganti ikon legenda yang dibuat secara otomatis dengan gambar khusus. Jadi yang masih saya butuhkan adalah informasi tentang bagaimana saya dapat mengakses legenda-simbol dengan pyqgis / pyqt, dan bagaimana cara menggantinya dengan QImage pada QLabel atau sesuatu seperti itu?

Maket tombol yang sangat mendasar yang digunakan untuk mengubah simbol:

masukkan deskripsi gambar di sini

Legenda yang dihasilkan secara otomatis:

masukkan deskripsi gambar di sini

Legenda dengan simbol legenda kustom:

masukkan deskripsi gambar di sini

Saya sudah menemukan cara mengakses item legenda di komposer cetak tetapi belum cara mengakses simbol itu sendiri:

import qgis
from PyQt4.QtCore import *
from PyQt4.QtGui import *

activeComposer = iface.activeComposers()

for item in activeComposer:
    if item.composerWindow().windowTitle()=='test':
        for i in item.items():
            if isinstance(i,QgsComposerLegend):
                #print i
                #print i.model()
                legend = i
                for i in xrange(legend.modelV2().rowCount()):
                    posteleg=legend.modelV2().index(i, 0)
                    print posteleg.data()

Edit 1:

Saya juga menemukan cara Mengakses QIcon-Objects dari pohon-legenda tetapi belum dapat menukarnya:

def run(self):

        activeComposer = self.iface.activeComposers()
        #print(self.resolve('icon.png'))
        for item in activeComposer:
            if item.composerWindow().windowTitle()=='test':
                for i in item.items():
                    if isinstance(i,QgsComposerLegend):
                        legend = i

                        layerIcon = QIcon(os.path.join(os.path.dirname(__file__), "icon.png"))

                        for i in xrange(legend.modelV2().rowCount()):
                            posteleg=legend.modelV2().index(i, 0)
                            posteleg.model().iconGroup().swap(layerIcon)
                            print posteleg.data()

Berikut adalah satu contoh kehidupan nyata di mana Anda dapat melihat simbologi yang dikombinasikan dari banyak lapisan simbol: masukkan deskripsi gambar di sini Ini akan berakhir dalam legenda seperti ini: masukkan deskripsi gambar di sini

Karena saya membutuhkan simbol yang tepat dalam legenda, saya ingin membuat tangkapan layar simbol saya, memotongnya dan menggunakannya sebagai gambar dalam legenda saya.

Saya tahu saya hanya bisa overlay gambar terpisah di atas legenda saya yang mencakup simbol yang dibuat secara otomatis tetapi saya ingin memiliki solusi "bersih" yang memungkinkan saya untuk mengganti simbol dalam legenda dengan gambar khusus.

Edit 2:

Sementara itu saya telah menemukan cara lain untuk mendapatkan akses ke entri legenda:

from qgis.core import QgsLegendRenderer, QgsComposerLegendStyle

compDict = {}
for comp in iface.activeComposers():
    # workaround to get name: read it from window title
    compDict[comp.composerWindow().windowTitle()] = comp.composition()
if "mycomposername" in compDict:
    itemLlegend = compDict["mycomposername"].getComposerItemById("mylegend_id")
    if itemLlegend:
        print itemLlegend

tree_layer_layer =  itemLlegend.modelV2().rootGroup().children()
for item in tree_layer_layer:
        if item.layerName()=="MyLayername":
            print "match"
            QgsLegendRenderer.setNodeLegendStyle(item, QgsComposerLegendStyle.Group)

Ini memungkinkan saya untuk mengakses objek QgsLayerTreeLayer dan saya bisa mengganti Style legenda (Grup, Subkelompok, Tersembunyi). Tapi saya masih belum tahu bagaimana mengakses simbol-legenda. Ada ide?

markgraeflerland
sumber
1
Ketika saya mengalami ini dengan QGIS, saya biasanya akan membuat lapisan tambahan yang memiliki simbologi yang ingin saya perlihatkan dalam legenda (biasanya duplikat sederhana dari lapisan yang ada - bukan sumber data baru). Kemudian, di komposer saya mengatur jendela peta dan mengunci lapisan. Setelah lapisan terkunci, saya menyalakan lapisan "palsu" dan dapat menambahkannya ke legenda. Ini murni solusi, dan bukan di PyQGIS, tapi mungkin ada beberapa cara untuk meniru lapisan "palsu" untuk apa yang Anda butuhkan?
Nate Wanner

Jawaban:

10

Karena topik ini mencakup banyak argumen, saya hanya akan fokus pada layer simbol SVG, berharap bahwa saya telah memahami dengan baik apa yang Anda cari (saya tidak menyadari panjangnya jawaban saat menulis, jadi saya minta maaf untuk tapi saya harap ini akan menambah kejelasan).


Konteks

1) Kelas lapisan simbol

Kelas lapisan simbol berikut tersedia untuk format SVG:

  • QgsSvgMarkerSymbolLayerV2 , yang menampilkan geometri titik menggunakan gambar SVG yang ditentukan (ini berfungsi untuk layer titik );
  • QgsSVGFillSymbolLayer , yang menggambar interior geometri poligon menggunakan gambar SVG berulang (ini berfungsi untuk lapisan poligon ).

Pendekatan umum untuk membuat layer simbol menginisialisasi dengan kamus properti.

Anda dapat menginisialisasi lapisan simbol baru dan melihat properti default dengan cara ini:

symbol_layer = QgsSvgMarkerSymbolLayerV2()
for k,v in symbol_layer.properties().iteritems():
    print k, ':', v

Anda akan mendapatkan semua properti yang disimpan di dalamnya:

outline_width : 0.2
outline_color : 0,0,0,255
angle : 0
name : crosses/Star1.svg
scale_method : diameter
color : 0,0,0,255
size_unit : MM
horizontal_anchor_point : 1
size_map_unit_scale : 0,0,0,0,0,0
outline_width_unit : MM
offset : 0,0
offset_map_unit_scale : 0,0,0,0,0,0
outline_width_map_unit_scale : 0,0,0,0,0,0
size : 4
vertical_anchor_point : 1
offset_unit : MM

Jika Anda ingin mengedit properti, Anda dapat menggunakan metode, yang dapat dipanggil dari bantuan kelas (misalnya dijalankan help(QgsSvgMarkerSymbolLayerV2)di Konsol Python). Anda akan melihat nanti contoh cara menggunakan metode.

Demi kelengkapan, Anda juga dapat menginisialisasi lapisan simbol dengan kamus properti (misalnya, lihat di sini ), tetapi saya dengan tulus lebih memilih pendekatan pertama dan saya akan menggunakannya.

2) Membuat renderer

Untuk menggunakan layer simbol setelah Anda membuatnya (dan akhirnya diedit), Anda perlu membuat renderer yang sesuai dan kemudian menetapkan renderer itu ke layer peta Anda.

Untuk mengakses renderer layer yang ada:

renderer = layer.rendererV2()

Untuk mendapatkan daftar jenis renderer yang tersedia, gunakan:

renderer_types = QgsRendererV2Registry().renderersList()

Untuk kasus Anda, kami harus berurusan dengan renderer simbol Categorized . Seperti yang saya katakan sebelumnya, Anda perlu membuat renderer dan kemudian menetapkannya ke layer:

# define the lookup: value -> (color, label)
landuses = {'Agriculture': ('#d3a151', 'Agriculture'), 'Natural': ('#175dcd', 'Natural'),}

# create a category for each item in landuses
categories = []
for landuse_name, (color, label) in landuses.items():
    symbol = QgsSymbolV2.defaultSymbol(layer.geometryType())
    symbol.setColor(QColor(color))
    category = QgsRendererCategoryV2(landuse_name, symbol, label)
    categories.append(category)

# create the renderer and assign it to the layer
expression = 'landuse' # field name
renderer = QgsCategorizedSymbolRendererV2(expression, categories) # categorized symbol renderer
layer.setRendererV2(renderer) # assign the renderer to the layer

3) Mengubah layer simbol

Beberapa simbol renderer simbol Categorized dapat dipanggil melalui symbols()(mengembalikan daftar):

for symb in renderer.symbols():
    print symb

<qgis._core.QgsMarkerSymbolV2 object at 0x0E1FF760>
<qgis._core.QgsMarkerSymbolV2 object at 0x0E1FF7B0>

Jika Anda ingin mengganti layer simbol yang diberikan dalam yang symbolditentukan sebelumnya, Anda hanya perlu mengetahui indeksnya dan kemudian kirim ke renderer dengan cara ini:

renderer.symbols()[0].changeSymbolLayer(0, new_symbol)

di mana [0]menunjukkan item pertama dari grup yang dikategorikan.

Larutan

Akhirnya, mari kita terapkan apa yang baru saja kita pelajari!

Dengan asumsi bekerja pada lapisan poligon ini, yang menyimpan penggunaan lahan yang telah kita tentukan sebelumnya:

masukkan deskripsi gambar di sini

Jika Anda ingin mengubah pola default untuk penggunaan lahan pertanian (mereka memiliki posisi No. 1 di grup 'landuse') dengan gambar SVG tertentu, Anda dapat menjalankan kode ini (baca di sini untuk mengetahui cara menambahkan SVG khusus jalan):

import qgis
from PyQt4.QtCore import *
from PyQt4.QtGui import *

# define the lookup: value : (color, label)
landuses = {'Agriculture': ('#d3a151', 'Agriculture'), 'Natural': ('#175dcd', 'Natural'),}

# create a category for each item in landuses
categories = []
for landuse_name, (color, label) in landuses.items():
    symbol = QgsSymbolV2.defaultSymbol(layer.geometryType())
    symbol.setColor(QColor(color))
    category = QgsRendererCategoryV2(landuse_name, symbol, label)
    categories.append(category)

# create the renderer and assign it to the layer
expression = 'landuse' # field name
renderer = QgsCategorizedSymbolRendererV2(expression, categories)

activeComposer = iface.activeComposers()
for item in activeComposer:
    if item.composerWindow().windowTitle()=='test':
        for i in item.items():
            if isinstance(i,QgsComposerLegend):
                legend = i
                for k in xrange(legend.modelV2().rowCount()):
                    posteleg=legend.modelV2().index(k, 0)
                    layer = QgsMapLayerRegistry.instance().mapLayersByName( posteleg.data() )[0]
                    if k == 0: # k is the position of the layer of interest in Legend (NOT in the Layers Panel)
                        svg_location = 'C:/path_to_svg/smile.svg'
                        new_symbol = QgsSVGFillSymbolLayer()
                        new_symbol.setSvgFilePath(svg_location)
                        new_symbol.setPatternWidth(7.0)
                        #... If you want to set additional parameters, type help(QgsSVGFillSymbolLayer) in the Python Console
                        renderer.symbols()[1].changeSymbolLayer(0, new_symbol)
                    layer.setRendererV2(renderer)
                    layer.triggerRepaint()

Ini akan menjadi hasilnya:

masukkan deskripsi gambar di sini

Kode di atas sangat kasar tetapi, karena saya tidak tahu apakah Anda menginginkan solusi spesifik untuk contoh Anda atau penjelasan yang lebih umum, saya lebih suka memusatkan perhatian pada alat yang tersedia daripada memperbaiki kode itu sendiri (saya yakin Anda dapat sedikit mengeditnya sesuai dengan kebutuhan spesifik Anda!).

mgri
sumber
Terima kasih atas jawaban Anda yang luas tetapi saya mencari solusi untuk mengubah simbol (hanya) dalam legenda komposer bukan untuk layer itu sendiri. Saya akan memperbarui pertanyaan saya di atas dalam sedetik dengan satu contoh lagi
markgraeflerland
@markgraeflerland Saya yakin tidak ada yang memikirkan masalah yang dijelaskan dalam pertanyaan Anda yang telah diedit (baru). Anda tidak pernah menentukan bahwa gambar dalam legenda tidak akan mereproduksi apa yang Anda lihat di layer (sepertinya Anda ingin mengganti item dari legenda dengan gambar, seperti yang telah saya lakukan). Hormat saya, pertanyaan awal Anda sangat menyesatkan dan pos saya benar-benar mencoba memberikan jawaban. Saya minta maaf atas waktu yang terbuang, tetapi saya tidak akan menghapus jawaban karena itu bisa menarik bagi orang lain ketika googling. Semoga berhasil dengan riset Anda!
mgri
2
Dalam kalimat pertama dari pertanyaan saya, saya menulis "Jika saya menggunakan legenda di komposer cetak, simbol-simbol ini tidak digambar dengan benar" jadi saya tidak berpikir bahwa saya tidak menentukan bahwa gambar dalam legenda tidak akan mereproduksi apa yang saya lihat di layer.
markgraeflerland
5

Atau, dan tanpa pengkodean Python, saya menyelesaikan ini dengan membuat grup layer baru yang didedikasikan untuk pembuatan legenda, di mana saya dapat meletakkan apa pun yang saya suka, dengan ukuran dan warna yang saya inginkan. Seperti ini di komposer cetak saya baru saja menghapus dari item legenda layer data aktual dan hanya menyimpan grup layer legenda.

Secara khusus praktis ketika membutuhkan untuk membuat legenda yang dapat mewakili kasus tidak terjadi di peta cetak yang sebenarnya.

Sunting: dan tentang suntingan kedua Anda, dengan simbol yang dikomposisikan tidak ditampilkan dengan benar, apakah Anda memiliki beberapa variabel yang mendefinisikan simbol Anda, seperti "C" ou "G" sebenarnya relatif terhadap bidang, atau orientasinya? Jika ini masalahnya, QGIS tidak dapat menebak apa yang ingin Anda tampilkan, maka semuanya ditampilkan dengan menampilkan segala sesuatu tanpa nilai untuk parameter ini. Solusinya adalah simpply menyimpan simbol dengan beberapa nilai tetap di tempat variabel. Dengan cara ini saya dapat mengganti item legenda tampilan default ini: masukkan deskripsi gambar di sinidengan yang ini sesuai dengan kebutuhan sayamasukkan deskripsi gambar di sini

GuiOm Clair
sumber