From 78bad9aaa7a58d8e4aafb08bbaa1958d4005499b Mon Sep 17 00:00:00 2001 From: david-spacil Date: Mon, 9 Mar 2026 16:49:30 +0100 Subject: [PATCH 1/3] =?UTF-8?q?k=C3=B3d=20pro=20filtrov=C3=A1n=C3=AD=20a?= =?UTF-8?q?=20stahov=C3=A1n=C3=AD=20lokalit=20+=20doprovodn=C3=A9=20zm?= =?UTF-8?q?=C4=9Bny?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- amcr_viewer/akce.png | Bin 0 -> 869 bytes amcr_viewer/amcr_codelists.py | 9 ++- amcr_viewer/amcr_dialog.py | 107 ++++++++++++++++++++++--------- amcr_viewer/amcr_tools.py | 7 +- amcr_viewer/amcr_viewer.py | 55 ++++++++++++---- amcr_viewer/codelists/heslar.csv | 29 ++++++++- amcr_viewer/download.png | Bin 993 -> 0 bytes amcr_viewer/info.png | Bin 967 -> 0 bytes amcr_viewer/lokality.png | Bin 0 -> 877 bytes src/icon.svg | 99 ++++++++++++++++++++++++++++ 10 files changed, 257 insertions(+), 49 deletions(-) create mode 100644 amcr_viewer/akce.png delete mode 100644 amcr_viewer/download.png delete mode 100644 amcr_viewer/info.png create mode 100644 amcr_viewer/lokality.png create mode 100644 src/icon.svg diff --git a/amcr_viewer/akce.png b/amcr_viewer/akce.png new file mode 100644 index 0000000000000000000000000000000000000000..27b0910bf9afe8b3af44e82f99b34fc2f0df845d GIT binary patch literal 869 zcmV-r1DgDaP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10`f^j zK~zYIwUkY0R96(of9Jk8eo|^HmRc;BI%9|;f+BV!RY9xcOe}&?iwhT$g-`{HpDB4h ziK2^c{95QHN+2ceLd{H+?i5^zMg>1YGKo;DZh}xs#2WMN>7p@t^L#HIZ9Q-||MS29 z|2dp{kEkl|Gu(e8Wc=(5Fbhgv;bPj)E|vyQa~6j=l? zWKtiw!KWrFBvbNugDy|h!WwrK z;0)s~Xmgdn=F>3^q^{0EI2t9W&}^;DF8PJ=gM&=%@rrj8T^FH!>{{6!XD~8@jFbewU7D^674M_`F`Ci)P83AYX8|^FW z0HAcR<2JAZK;XDBb~}JkyBj{c1*|}+9i!l_K-Ft;NZ6*cy*0bkXe-wA0po@Z8%qm| ztr%{ie3;Nd4=EPuYW;Ie1Aw%bYY=D(L4g{(vTxy~$tV|y{7T?CuvqhYKMcOHO-JS2 zb3kthal|^U)t$ASz>jb6g>6ysF%5c~&i`%#S*l3)D5{?f+2AxEun)KzqMy>7o{Q5- z?f~d+YJXyf%vV6yFf^dX9MPpZgi;4Q1#aN7Gf5+H2H{BiYtv$b8$f-@FZ?`mxhP8z v9%)v8OT4VA6`krI@>P{`!>6JS{!9D~(-vfQR{-3V00000NkvXXu0mjfC-RP= literal 0 HcmV?d00001 diff --git a/amcr_viewer/amcr_codelists.py b/amcr_viewer/amcr_codelists.py index 17ec670..268d0fd 100644 --- a/amcr_viewer/amcr_codelists.py +++ b/amcr_viewer/amcr_codelists.py @@ -62,7 +62,8 @@ def load_all_data(): categorized_data = { 'obdobi': {}, 'typ_akce': {}, 'areal': {}, 'kraj': {}, 'organizace': {}, 'okres': {}, 'katastr': {}, - 'vedouci': {}, 'pian_presnost': {} + 'vedouci': {}, 'pian_presnost': {}, 'typ_lokality': {}, 'druh_lokality': {}, + 'jistota': {}, 'lokalita_zachovalost': {} } # Funkce pro roztřídění načteného slovníku (tohle je trochu redundance, ale pro zachování logiky) @@ -156,8 +157,12 @@ KRAJE = _DATA['kraj'] ORGANIZACE = _DATA['organizace'] OKRESY = _DATA['okres'] KATASTRY = _DATA['katastr'] -VEDOUCI = _DATA['vedouci'] # Tady to bude zpočátku prázdné, pokud soubor neexistuje +VEDOUCI = _DATA['vedouci'] PIAN_PRESNOST = _DATA['pian_presnost'] +TYP_LOKALITY = _DATA['typ_lokality'] +DRUH_LOKALITY = _DATA['druh_lokality'] +JISTOTA = _DATA['jistota'] +LOKALITA_ZACHOVALOST = _DATA['lokalita_zachovalost'] def refresh_vedouci_cache(): """ diff --git a/amcr_viewer/amcr_dialog.py b/amcr_viewer/amcr_dialog.py index 26de3fe..e410126 100644 --- a/amcr_viewer/amcr_dialog.py +++ b/amcr_viewer/amcr_dialog.py @@ -6,7 +6,8 @@ from qgis.PyQt.QtWidgets import (QDialog, QVBoxLayout, QFormLayout, QLabel, QMessageBox, QApplication, QWidget) from qgis.PyQt.QtCore import Qt from .amcr_codelists import (OBDOBI, TYP_AKCE, KRAJE, AREAL, ORGANIZACE, - OKRESY, KATASTRY, VEDOUCI, PIAN_PRESNOST, + OKRESY, KATASTRY, VEDOUCI, PIAN_PRESNOST, TYP_LOKALITY, + DRUH_LOKALITY, JISTOTA, LOKALITA_ZACHOVALOST, download_vedouci, refresh_vedouci_cache) class FilterableSelectionDialog(QDialog): @@ -65,15 +66,19 @@ class FilterableSelectionDialog(QDialog): # --- Main window --- class AmcrFilterDialog(QDialog): - def __init__(self, parent=None): - super().__init__(parent) + def __init__(self, typ_dat, parent=None): + super(AmcrFilterDialog, self).__init__(parent) self.setWindowTitle("Filtr AMČR") self.resize(500, 750) + self.typ_dat = typ_dat + + # Cache for filtering self.selection_cache = { 'organizace': [], 'kraj': [], 'obdobi': [], 'areal': [], - 'typ_akce': [], 'okres': [], 'katastr': [], 'vedouci': [], 'pian_presnost': [] + 'typ_akce': [], 'okres': [], 'katastr': [], 'vedouci': [], 'pian_presnost': [], + 'typ_lokality': [], 'druh_lokality': [], 'jistota': [], 'lokalita_zachovalost': [] } layout = QVBoxLayout() @@ -82,8 +87,11 @@ class AmcrFilterDialog(QDialog): self.chk_bbox.setChecked(True) layout.addWidget(self.chk_bbox) - self.chk_posevidence = QCheckBox("Pouze pozitivní zjištění") - layout.addWidget(self.chk_posevidence) + # Positive/negative evidence – valid for Akce + + if self.typ_dat == "akce": + self.chk_posevidence = QCheckBox("Pouze pozitivní zjištění") + layout.addWidget(self.chk_posevidence) layout.addSpacing(10) @@ -127,6 +135,8 @@ class AmcrFilterDialog(QDialog): row_widget.setLayout(row_layout) return row_widget + # Spatial information – valid for all + self.picker_kraj = setup_picker("Kraj", 'kraj', KRAJE) layout.addWidget(self.picker_kraj) @@ -136,28 +146,52 @@ class AmcrFilterDialog(QDialog): self.picker_katastr = setup_picker("Katastr", 'katastr', KATASTRY) layout.addWidget(self.picker_katastr) - self.picker_org = setup_picker("Organizace", 'organizace', ORGANIZACE) - layout.addWidget(self.picker_org) + self.picker_presnost = setup_picker("PIAN – přesnost", 'pian_presnost', PIAN_PRESNOST) + layout.addWidget(self.picker_presnost) - self.btn_update_vedouci = QPushButton("🔄") - self.btn_update_vedouci.setToolTip("Aktualizovat seznam vedoucích z API") - self.btn_update_vedouci.setFixedWidth(30) - self.btn_update_vedouci.clicked.connect(self.action_update_vedouci) + # Filters valid for Akce + + if self.typ_dat == "akce": + self.picker_org = setup_picker("Organizace", 'organizace', ORGANIZACE) + layout.addWidget(self.picker_org) + + self.btn_update_vedouci = QPushButton("🔄") + self.btn_update_vedouci.setToolTip("Aktualizovat seznam vedoucích z API") + self.btn_update_vedouci.setFixedWidth(30) + self.btn_update_vedouci.clicked.connect(self.action_update_vedouci) - self.picker_vedouci = setup_picker("Vedoucí výzkumu", 'vedouci', VEDOUCI, extra_btn=self.btn_update_vedouci) - layout.addWidget(self.picker_vedouci) + self.picker_vedouci = setup_picker("Vedoucí výzkumu", 'vedouci', VEDOUCI, extra_btn=self.btn_update_vedouci) + layout.addWidget(self.picker_vedouci) + + # Type of event + + self.picker_typ = setup_picker("Typ výzkumu", 'typ_akce', TYP_AKCE) + layout.addWidget(self.picker_typ) + + # Filters valid for Lokality + + if self.typ_dat == "lokalita": + self.picker_typ_lokality = setup_picker("Lokalita – typ", 'typ_lokality', TYP_LOKALITY) + layout.addWidget(self.picker_typ_lokality) + + self.picker_druh_lokality = setup_picker("Lokalita – druh", 'druh_lokality', DRUH_LOKALITY) + layout.addWidget(self.picker_druh_lokality) + + self.picker_jistota = setup_picker("Lokalita – jistota určení", 'jistota', JISTOTA) + layout.addWidget(self.picker_jistota) + + self.picker_lokalita_zachovalost = setup_picker("Lokalita - stav dochování", 'lokalita_zachovalost', LOKALITA_ZACHOVALOST) + layout.addWidget(self.picker_lokalita_zachovalost) + + # Contextual information self.picker_obdobi = setup_picker("Období", 'obdobi', OBDOBI) layout.addWidget(self.picker_obdobi) - self.picker_areal = setup_picker("Areál / Druh", 'areal', AREAL) + self.picker_areal = setup_picker("Areál", 'areal', AREAL) layout.addWidget(self.picker_areal) - self.picker_typ = setup_picker("Typ výzkumu", 'typ_akce', TYP_AKCE) - layout.addWidget(self.picker_typ) - - self.picker_presnost = setup_picker("PIAN – přesnost", 'pian_presnost', PIAN_PRESNOST) - layout.addWidget(self.picker_presnost) + layout.addStretch(1) @@ -188,12 +222,7 @@ class AmcrFilterDialog(QDialog): def get_filters(self): filters = {} - if self.chk_posevidence.isChecked(): - filters['posevidence'] = 'true' - - # Loading from cache - if self.selection_cache['organizace']: - filters['f_organizace'] = self.selection_cache['organizace'] + if self.selection_cache['kraj']: filters['f_kraj'] = self.selection_cache['kraj'] if self.selection_cache['okres']: @@ -204,11 +233,27 @@ class AmcrFilterDialog(QDialog): filters['f_obdobi'] = self.selection_cache['obdobi'] if self.selection_cache['areal']: filters['f_areal'] = self.selection_cache['areal'] - if self.selection_cache['typ_akce']: - filters['f_typ_vyzkumu'] = self.selection_cache['typ_akce'] - if self.selection_cache['vedouci']: - filters['f_vedouci'] = self.selection_cache['vedouci'] if self.selection_cache['pian_presnost']: - filters['f_pian_presnost'] = self.selection_cache['pian_presnost'] + filters['f_pian_presnost'] = self.selection_cache['pian_presnost'] + if self.typ_dat == "akce": + if self.chk_posevidence.isChecked(): + filters['posevidence'] = 'true' + if self.selection_cache['organizace']: + filters['f_organizace'] = self.selection_cache['organizace'] + if self.selection_cache['typ_akce']: + filters['f_typ_vyzkumu'] = self.selection_cache['typ_akce'] + if self.selection_cache['vedouci']: + filters['f_vedouci'] = self.selection_cache['vedouci'] + + if self.typ_dat == "lokalita": + if self.selection_cache['typ_lokality']: + filters['f_typ_lokality'] = self.selection_cache['typ_lokality'] + if self.selection_cache['druh_lokality']: + filters['f_druh_lokality'] = self.selection_cache['druh_lokality'] + if self.selection_cache['jistota']: + filters['f_jistota'] = self.selection_cache['jistota'] + if self.selection_cache['lokalita_zachovalost']: + filters['f_lokalita_zachovalost'] = self.selection_cache['lokalita_zachovalost'] + return filters \ No newline at end of file diff --git a/amcr_viewer/amcr_tools.py b/amcr_viewer/amcr_tools.py index 0692a08..266b107 100644 --- a/amcr_viewer/amcr_tools.py +++ b/amcr_viewer/amcr_tools.py @@ -33,7 +33,7 @@ def tr_code(code): return "" return TRANSLATIONS.get(code, code) -def load_amcr_data(canvas, bb, filters=None): +def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): load_translations() # 1. Bounding box @@ -51,15 +51,16 @@ def load_amcr_data(canvas, bb, filters=None): try: # =================== - # A) METADATA (Fieldwork event) + # A) METADATA (Fieldwork event/Site) # =================== base_params = { "mapa": "true", - "entity": "akce", "sort": "ident_cely asc" } + base_params["entity"] = typ_dat + if bb == "true": base_params["loc_rpt"] = bbox_str diff --git a/amcr_viewer/amcr_viewer.py b/amcr_viewer/amcr_viewer.py index bcc8a15..78474a4 100644 --- a/amcr_viewer/amcr_viewer.py +++ b/amcr_viewer/amcr_viewer.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication from qgis.PyQt.QtGui import QIcon -from qgis.PyQt.QtWidgets import QAction +from qgis.PyQt.QtWidgets import QMenu, QAction, QToolButton from .amcr_tools import load_amcr_data from .amcr_dialog import AmcrFilterDialog @@ -58,16 +58,47 @@ class AmcrViewer: import os plugin_dir = os.path.dirname(__file__) + icon_akce_path = os.path.join(plugin_dir, 'akce.png') + icon_lokality_path = os.path.join(plugin_dir, 'lokality.png') - icon = QIcon(os.path.join(plugin_dir, 'download.png')) + # 1. Vytvoření společného menu + self.plugin_menu = QMenu() + + # 2. Vytvoření akcí (bez automatického přidání do lišty a menu) + self.action_download_akce = self.add_action( + icon_path=icon_akce_path, + text=self.tr(u'Stáhnout data akcí | AMČR Viewer'), + callback=lambda checked=False: self.run_download('akce'), + parent=self.iface.mainWindow(), + add_to_menu=False, + add_to_toolbar=False + ) + self.plugin_menu.addAction(self.action_download_akce) + + self.action_download_lokality = self.add_action( + icon_path=icon_lokality_path, + text=self.tr(u'Stáhnout data lokalit | AMČR Viewer'), + callback=lambda checked=False: self.run_download('lokalita'), + parent=self.iface.mainWindow(), + add_to_menu=False, + add_to_toolbar=False + ) + self.plugin_menu.addAction(self.action_download_lokality) + + # 3. Přidání rozbalovacího menu do hlavního menu QGIS + main_icon = QIcon(icon_akce_path) + self.main_action = QAction(main_icon, 'AMČR Viewer', self.iface.mainWindow()) + self.main_action.setMenu(self.plugin_menu) + self.iface.addPluginToMenu(self.menu, self.main_action) + + # 4. Přidání rozevíracího tlačítka do nástrojové lišty (Toolbar) + self.tool_button = QToolButton() + self.tool_button.setMenu(self.plugin_menu) + self.tool_button.setDefaultAction(self.action_download_akce) + self.tool_button.setPopupMode(QToolButton.MenuButtonPopup) - - # Download data button - self.action_download = self.add_action( - icon, - text=self.tr(u'Načíst data z AMČR'), - callback=self.run_download, - parent=self.iface.mainWindow()) + # Vložení vytvořeného tlačítka do QGIS rozhraní + self.iface.addToolBarWidget(self.tool_button) self.first_start = True @@ -80,9 +111,9 @@ class AmcrViewer: self.iface.mapCanvas().unsetMapTool(self.tool) # --- Data downloading --- - def run_download(self): + def run_download(self, typ_dat): - dlg = AmcrFilterDialog() + dlg = AmcrFilterDialog(typ_dat) result = dlg.exec_() if result == 1: @@ -90,4 +121,4 @@ class AmcrViewer: bbox = dlg.get_bbox() canvas = self.iface.mapCanvas() - load_amcr_data(canvas, bbox, filters) + load_amcr_data(canvas, bbox, filters, typ_dat) diff --git a/amcr_viewer/codelists/heslar.csv b/amcr_viewer/codelists/heslar.csv index 4da02d1..e42c1b0 100644 --- a/amcr_viewer/codelists/heslar.csv +++ b/amcr_viewer/codelists/heslar.csv @@ -13617,4 +13617,31 @@ Zvotoky;Zvotoky;katastr odchylka jednotky metrů;HES-000861;pian_presnost odchylka desítky metrů;HES-000862;pian_presnost odchylka stovky metrů;HES-000863;pian_presnost -poloha podle katastru;HES-000864;pian_presnost \ No newline at end of file +poloha podle katastru;HES-000864;pian_presnost +nemovitá památka;HES-001122;typ_lokality +polygon průzkumu;HES-001123;typ_lokality +krajina;HES-001124;typ_lokality +polygon leteckého průzkumu;HES-000111;druh_lokality +osídlený skalní prostor;HES-000112;druh_lokality +krajina;HES-000117;druh_lokality +pomník/památník;HES-000128;druh_lokality +muzeum/skanzen;HES-000129;druh_lokality +pozůstatek mohylníku;HES-001430;druh_lokality +pozůstatek ohrazení;HES-001431;druh_lokality +pozůstatek represe;HES-001432;druh_lokality +pozůstatek kultu;HES-001433;druh_lokality +pozůstatek sídla elity;HES-001434;druh_lokality +pozůstatek sídliště;HES-001435;druh_lokality +pozůstatek těžby;HES-001436;druh_lokality +pozůstatek vojenství;HES-001437;druh_lokality +pozůstatek výroby;HES-001438;druh_lokality +pozůstatek komunikace;HES-001429;druh_lokality +jisté (> 95 %);HES-001449;jistota +nejisté (50–95 %);HES-001450;jistota +domnělé (5–50 %);HES-001451;jistota +pseudolokalita (< 5 %);HES-001452;jistota +zaniklá lokalita;HES-001453;lokalita_zachovalost +lokalita pod zástavbou;HES-001454;lokalita_zachovalost +nadzemní relikty;HES-001455;lokalita_zachovalost +ruina;HES-001456;lokalita_zachovalost +historická budova/komplex;HES-001457;lokalita_zachovalost diff --git a/amcr_viewer/download.png b/amcr_viewer/download.png deleted file mode 100644 index 548e37cbfa841653ea9f87ffe9fb97c64b99ad2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 993 zcmV<710MW|P)(X|oY)X8S zlbrLM=X-wN`Of!!=ZLEEf0ko8rY;dD5C@D-)%d>wNVX^Vs6x!>4bOHJeFLRdR5w_L zw2RV!>Ukt5^xn0pf&T>PDfVr|N*o5(CN&j#RaC-YeGIGv5cHHotk>GY(W}b_^b~ok zQR^olKf^nRN}piuQ;|);p}Pz&}f*^LGK|8J;mjUNM9Uv8>9DiO4r1x+C494ZQ`f7wiBTvq;`dzmz{>iJT`p zCns;F%9hvLVmPc{6p9uQVzdB9vjTeE?gC7CG`(Zmo)PW?$~&f}`1+k)pI!TN^j*U+ zW=xNJXw{mBhkzPj6qsEEkd-<48n@EMG3L~vj1D!8-yZMl5BEb`HBb$(@(wgcpfMVc z?r}L>mB82{fL)mh!wpQNY9rGl?EGz~t-qz;Uq2bauT2jtD4 zk1k%xg`O{f*9F3s<#^obGB0fJKWY9QOmO=8X-0025V{nyP40cH7hkTA=Hg}o4+Opf zUR(s|3I?kPJcZx3>jNRvN|SiUCznH z2NWl@zrH=r^r0U(Sar}g+%!x*QhNly)BkodJSza8Jv=pxvI9sYwShgI)Q^|2yL|T| ze`rHUYCJWc0H3GoSwA?*>M2_FGOB&d&p1!8f6qBdleTF-G+An`9SpY{hoFOkI1z;*TIQV$2lERyZ|p>Hg?5H+ z%BuT72J^;&H&fWqi`^8zhdM755$asWoZYOhYP+N#CT(q#lk+}atf?ny8nU7PyYqkk z@AH42_q^wMkEkmDC#-sf$JR>#-~$o+Mhv7@2Zs`g7Ki*!L3RLlISrwxzc4!p(yGFD zf_1bnJ@dm&84M(14}p0PXe)7+(&<{VPShL$X$KTI=}6%D{&ae-TAr#~G?0uu0_J0H zasVTIZmD)^(cUa7y?_AQ{hB{>q_wrVE`xz&D2d?|&`?DmR(Qz-oG_O9JbY)NxbRk8 z2BP*WK(w6XTSXr?mfR`EY)oC7A6Dhr3eD4Rtcl%Ina^7V$3^@a4?k6*IpbtQ4tV|BDH}lu`fl%mpLvu3-QvxSZ{iJ3G z1_@t37|WPTP0e1YT(pFjyN3r~z%1(QcTPizc`pa zcdwm3f1flbuIz~1(XkKMSSc(s@KLx#c?-5L9^O{PAX!`-u}V_oX7L4s0GDeT^knA$ z6qVsJg|MZH!H;5X8Elh#U`RdvSQn&d6LQ`Uzbq_wAz53*|Bchng0pb`HfI=7wLx%7M@sj&hjbGd+fH6xrrbc&r-&-c_N3<~T-)ukioVZ8^hs~5F&aDNx@&rx60f<-N&L40OxA4x zkeZk~U$lywfS{M3`E_*Hn`>{k15M$X5+_y&p#EuE!rsZ;X@UMqUPWIoI?nPi6e|Fb zzhMJ_-c0sY(4I0<^_yMPKUCldr6||{Y993QT-LhjD pU;$_Wt^r;Dg+b}B!mX)V!aq=CK}l(IaB2Vm002ovPDHLkV1js_#RmWY diff --git a/amcr_viewer/lokality.png b/amcr_viewer/lokality.png new file mode 100644 index 0000000000000000000000000000000000000000..e909cb2b90745a2cd799644e9461f3c41c707b0e GIT binary patch literal 877 zcmV-z1CsoSP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10{Tfr zK~zYIwUl2-m3J7&KhN)dj|SV=+NR9Vg((Ky5p(`emBqa zeZHUP;rHVws>;g@`@aO~(*32ju|8-X>HhXq?8`a_XR`R!!lB07UAcS!61G8ataG!d z90qCta;9Kq#Lb-+*aD0L1CBGDYQ2B_{;~i^Y;gM zgjx}qRL9*2SkFqfqWzhQ_IH*9oR@8u!tnr2zvY^DTe7J_!F?-!H+2*EWWjRqCK_oE z0?ge(Pc-qd5q|K^eIlOiZu2*#OFE0J0vQ6zJe0Ab?C&Lwdd~4`=bot%KJ@vFGg+7j znyU3-_gJQ^qfU$+o6R|{YfZ%7i!gIHiva?qz6X0N{-|r*Z!Q<58f80~0J6>XCb}L6 z0@Ozaih`!cr3ztxV9lW)81tq)uSoy&$t%;92dV>&mJ#y+BR~3UmSgXDVSxDE)J=iQ z-lFT8f!=6mXJ0H)@_zvfK06V&Rn=SpA_zYjnOcFE)Rb~XF3M_@dJI*BeZa~-`A+`E z;cMNh!wWV5*z?!X8>-p{;38?nd=4N;`>N4Z*MSWvTb3Aj7f>;44k5p3Z!GbJJ3T#U zEPGg>U`ENImJ{8B7_Onb9 + + +akcelokality From d6d520e612d742050c048d55c11083edce8340b9 Mon Sep 17 00:00:00 2001 From: david-spacil Date: Mon, 9 Mar 2026 18:08:29 +0100 Subject: [PATCH 2/3] =?UTF-8?q?na=C4=8D=C3=ADt=C3=A1n=C3=AD=20metadat=20pr?= =?UTF-8?q?o=20lokality?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- amcr_viewer/amcr_tools.py | 171 ++++++++++++++++++++++++-------------- 1 file changed, 110 insertions(+), 61 deletions(-) diff --git a/amcr_viewer/amcr_tools.py b/amcr_viewer/amcr_tools.py index 266b107..9dac666 100644 --- a/amcr_viewer/amcr_tools.py +++ b/amcr_viewer/amcr_tools.py @@ -74,24 +74,24 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): else: base_params[key] = str(value).strip() - docs_akce = [] + docs = [] current_page = 0 - BATCH_AKCE = 500 + BATCH_DOCS = 500 MAX_LIMIT = 20000 seen_ids = set() target_pian_ids_count = 0 while True: - base_params['rows'] = BATCH_AKCE + base_params['rows'] = BATCH_DOCS if current_page > 0: base_params['page'] = current_page elif 'page' in base_params: del base_params['page'] try: - resp_akce = requests.get(url, params=base_params, timeout=30) - resp_json = resp_akce.json() + resp_docs = requests.get(url, params=base_params, timeout=30) + resp_json = resp_docs.json() data = resp_json.get('response', {}) batch_docs = data.get('docs', []) num_found = data.get('numFound', 0) @@ -106,12 +106,12 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): seen_ids.add(ident) new_docs.append(d) - docs_akce.extend(new_docs) - print(f"Strana {current_page} stažena. Celkem záznamů: {len(docs_akce)} / {num_found}") + docs.extend(new_docs) + print(f"Strana {current_page} stažena. Celkem záznamů: {len(docs)} / {num_found}") - if len(docs_akce) >= num_found: + if len(docs) >= num_found: break - if len(docs_akce) >= MAX_LIMIT: + if len(docs) >= MAX_LIMIT: iface.messageBar().pushMessage("AMCR", f"Limit {MAX_LIMIT} záznamů dosažen.", level=1) break @@ -122,8 +122,8 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): print(f"Chyba při stránkování na straně {current_page}: {e}") break - if not docs_akce: - iface.messageBar().pushMessage("AMCR", "Žádné akce nenalezeny.", level=1) + if not docs: + iface.messageBar().pushMessage("AMCR", "Žádné záznamy nenalezeny.", level=1) return # ========================================== @@ -133,29 +133,29 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): target_pian_ids = set() actions_with_geom = 0 - for akce in docs_akce: - piani = akce.get('az_dj_pian', []) + for doc in docs: + piani = doc.get('az_dj_pian', []) if not piani: continue actions_with_geom += 1 def g(key, default=""): - val = akce.get(key) + val = doc.get(key) if isinstance(val, list): return str(val[0]) if val else default return str(val) if val is not None else default def g_list(key, translate=False): - val = akce.get(key, []) + val = doc.get(key, []) if not isinstance(val, list): val = [val] if val else [] if translate: return ", ".join([tr_code(str(x)) for x in val if x]) return ", ".join([str(x) for x in val if x]) - az_chranene = akce.get('az_chranene_udaje', {}) - akce_chranene = akce.get('akce_chranene_udaje', {}) + az_chranene = doc.get('az_chranene_udaje', {}) + chranene = doc.get('akce_chranene_udaje') or doc.get('lokalita_chranene_udaje') or {} dalsi_kat = az_chranene.get('dalsi_katastr', []) dalsi_kat_str = "" @@ -163,28 +163,43 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): items = [x.get('value', '') if isinstance(x, dict) else str(x) for x in dalsi_kat] dalsi_kat_str = ", ".join([i for i in items if i]) - lokalizace = akce_chranene.get('lokalizace_okolnosti', "") + lokalizace = chranene.get('lokalizace_okolnosti', "") + lokalita_nazev = chranene.get('nazev', "") + lokalita_popis = chranene.get('popis', "") - # Prepate metadata for fieldwork event + # Prepate common metadata meta = { - "ident_cely": akce.get('ident_cely', ''), + "ident_cely": doc.get('ident_cely', ''), "az_okres": g('az_okres'), "katastr": g_list('katastr'), - "dalsi_katastr": dalsi_kat_str, - "akce_hlavni_vedouci": g('akce_hlavni_vedouci'), - "akce_organizace": tr_code(g('akce_organizace')), - "akce_specifikace_data": tr_code(g('akce_specifikace_data')), - "akce_datum_zahajeni": g('akce_datum_zahajeni'), - "akce_datum_ukonceni": g('akce_datum_ukonceni'), - "akce_hlavni_typ": tr_code(g('akce_hlavni_typ')), - "akce_vedlejsi_typ": g_list('akce_vedlejsi_typ', translate=True), - "lokalizace_okolnosti": str(lokalizace) if lokalizace else "", - "akce_je_nz": "Ano" if akce.get('akce_je_nz') is True else "Ne", + "dalsi_katastr": dalsi_kat_str, "pristupnost": g('pristupnost'), "loc": g_list('loc') } + + if typ_dat == "akce": + meta.update({ + "akce_hlavni_vedouci": g('akce_hlavni_vedouci'), + "akce_organizace": tr_code(g('akce_organizace')), + "akce_specifikace_data": tr_code(g('akce_specifikace_data')), + "akce_datum_zahajeni": g('akce_datum_zahajeni'), + "akce_datum_ukonceni": g('akce_datum_ukonceni'), + "akce_hlavni_typ": tr_code(g('akce_hlavni_typ')), + "akce_vedlejsi_typ": g_list('akce_vedlejsi_typ', translate=True), + "lokalizace_okolnosti": str(lokalizace) if lokalizace else "", + "akce_je_nz": "Ano" if doc.get('akce_je_nz') is True else "Ne", + }) + + elif typ_dat == "lokalita": + meta.update({ + "lokalita_nazev": lokalita_nazev, + "lokalita_popis": lokalita_popis, + "lokalita_zachovalost": tr_code(g('lokalita_zachovalost')), + "lokalita_druh": tr_code(g('lokalita_druh')), + "lokalita_typ": tr_code(g('lokalita_typ_lokality')), + }) - djs = akce.get('az_dokumentacni_jednotka', []) + djs = doc.get('az_dokumentacni_jednotka', []) for dj in djs: if filters and filters.get('posevidence') == 'true' and dj.get('dj_negativni_jednotka') is True: @@ -206,7 +221,7 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): pian_lookup[dj_pian_value].append(dj_meta) if not target_pian_ids: - iface.messageBar().pushMessage("AMCR", f"Nalezeno {len(docs_akce)} akcí, ale žádná nemá geometrii.", level=1) + iface.messageBar().pushMessage("AMCR", f"Nalezeno {len(docs)} akcí, ale žádná nemá geometrii.", level=1) return @@ -218,7 +233,7 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): docs_pian = [] BATCH_PIAN = 50 - iface.messageBar().pushMessage("AMCR", f"Akcí: {len(docs_akce)} (z toho {actions_with_geom} s mapou). Stahuji {total_pians} unikátních geometrií, vykresluji {target_pian_ids_count} geometrií...", level=1) + iface.messageBar().pushMessage("AMCR", f"Akcí: {len(docs)} (z toho {actions_with_geom} s mapou). Stahuji {total_pians} unikátních geometrií, vykresluji {target_pian_ids_count} geometrií...", level=1) # Seznam polí pro PIAN fl_pian = ["ident_cely", "pian_typ", "pian_chranene_udaje", "pian_presnost"] @@ -251,6 +266,11 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): vl_point = QgsVectorLayer("Point?crs=epsg:5514", "AMCR Body", "memory") layers = [vl_poly, vl_line, vl_point] + if typ_dat == "akce": + archeologicky_zaznam = "Akce" + elif typ_dat == "lokalita": + archeologicky_zaznam = "ID lokality" + # Definice sloupců atributové tabulky cols = [ QgsField("PIAN", QVariant.String), @@ -259,24 +279,37 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): QgsField("Dokumentační jednotka", QVariant.String), QgsField("Typ dokumentační jednotky", QVariant.String), QgsField("Definiční bod(y) (WGS-84)", QVariant.String), - QgsField("Akce", QVariant.String), + QgsField(archeologicky_zaznam, QVariant.String), QgsField("Odkaz do Digitálního archivu AMČR", QVariant.String), QgsField("Okres", QVariant.String), QgsField("Katastr", QVariant.String), - QgsField("Další katastry", QVariant.String), - QgsField("Vedoucí akce", QVariant.String), - QgsField("Organizace", QVariant.String), - QgsField("Specifikace data", QVariant.String), - QgsField("Datum zahájeni", QVariant.String), - QgsField("Datum ukončení", QVariant.String), - QgsField("Hlavní typ", QVariant.String), - QgsField("Vedlejší typ", QVariant.String), - QgsField("Zjištění", QVariant.String), - QgsField("Akce – lokalizace", QVariant.String), - QgsField("Akce – nahrazuje NZ", QVariant.String), - QgsField("Přístupnost", QVariant.String) + QgsField("Další katastry", QVariant.String) ] + if typ_dat == "akce": + cols += [ + QgsField("Vedoucí akce", QVariant.String), + QgsField("Organizace", QVariant.String), + QgsField("Specifikace data", QVariant.String), + QgsField("Datum zahájeni", QVariant.String), + QgsField("Datum ukončení", QVariant.String), + QgsField("Hlavní typ", QVariant.String), + QgsField("Vedlejší typ", QVariant.String), + QgsField("Zjištění", QVariant.String), + QgsField("Akce – lokalizace", QVariant.String), + QgsField("Akce – nahrazuje NZ", QVariant.String), + ] + elif typ_dat == "lokalita": + cols += [ + QgsField("Název lokality", QVariant.String), + QgsField("Popis lokality", QVariant.String), + QgsField("Typ lokality", QVariant.String), + QgsField("Druh lokality", QVariant.String), + QgsField("Zachovalost", QVariant.String) + ] + + cols.append(QgsField("Přístupnost", QVariant.String)) + for vl in layers: vl.dataProvider().addAttributes(cols) vl.updateFields() @@ -317,7 +350,7 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): for meta in metas: feat = QgsFeature() feat.setGeometry(geom) - feat.setAttributes([ + atributy = [ pid, pian_presnost, pian_typ, @@ -328,19 +361,35 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): "https://digiarchiv.aiscr.cz/id/" + meta['ident_cely'], meta['az_okres'], meta['katastr'], - meta['dalsi_katastr'], - meta['akce_hlavni_vedouci'], - meta['akce_organizace'], - meta['akce_specifikace_data'], - meta['akce_datum_zahajeni'], - meta['akce_datum_ukonceni'], - meta['akce_hlavni_typ'], - meta['akce_vedlejsi_typ'], - meta['dj_negativni'], - meta['lokalizace_okolnosti'], - meta['akce_je_nz'], - meta['pristupnost'] - ]) + meta['dalsi_katastr'] + ] + if typ_dat == "akce": + atributy += [ + meta['akce_hlavni_vedouci'], + meta['akce_organizace'], + meta['akce_specifikace_data'], + meta['akce_datum_zahajeni'], + meta['akce_datum_ukonceni'], + meta['akce_hlavni_typ'], + meta['akce_vedlejsi_typ'], + meta['dj_negativni'], + meta['lokalizace_okolnosti'], + meta['akce_je_nz'] + ] + + elif typ_dat == "lokalita": + atributy += [ + meta['lokalita_nazev'], + meta['lokalita_popis'], + meta['lokalita_typ'], + meta['lokalita_druh'], + meta['lokalita_zachovalost'] + ] + + atributy.append(meta['pristupnost']) + + feat.setAttributes(atributy) + t = geom.type() if t == QgsWkbTypes.PolygonGeometry: feats_p.append(feat) @@ -363,7 +412,7 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): added += len(f) if added > 0: - iface.messageBar().pushMessage("AMCR", f"Hotovo. Akcí: {len(docs_akce)} (s geom: {actions_with_geom}). Vykresleno: {added} prvků.", level=0) + iface.messageBar().pushMessage("AMCR", f"Hotovo. Akcí: {len(docs)} (s geom: {actions_with_geom}). Vykresleno: {added} prvků.", level=0) else: iface.messageBar().pushMessage("AMCR", "Žádná data k zobrazení.", level=1) From 36835c825d7fd1e90269a353ef52aac1bf1b52c2 Mon Sep 17 00:00:00 2001 From: david-spacil Date: Tue, 10 Mar 2026 11:11:54 +0100 Subject: [PATCH 3/3] changed push messages to be more general updated Readme --- .gitignore | 5 +++++ README.md | 14 +++++++------- amcr_viewer/amcr_tools.py | 10 +++++----- amcr_viewer/metadata.txt | 7 ++++--- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index b7faf40..ed51dcb 100644 --- a/.gitignore +++ b/.gitignore @@ -205,3 +205,8 @@ cython_debug/ marimo/_static/ marimo/_lsp/ __marimo__/ + + + +README_files/ +README.html diff --git a/README.md b/README.md index 2de90a8..9736062 100644 --- a/README.md +++ b/README.md @@ -12,14 +12,13 @@ ## 1. Overview -**AMCR Viewer** is a QGIS plugin designed to facilitate direct access to the Digital Archive of the Archaeological Map of the Czech Republic (AMČR). It allows researchers to **query, retrieve, and visualize Fieldwork events[^1] data (metadata and geometry) directly within the GIS environment**, eliminating the need to manually export data from the web interface. **Only publicly accessible data are supported at the time** (accessibility = anonymous). +**AMCR Viewer** is a QGIS plugin designed to facilitate direct access to the Digital Archive of the Archaeological Map of the Czech Republic (AMČR). It allows researchers to **query, retrieve, and visualize *Fieldwork events* and *Sites* data (metadata and geometry) directly within the GIS environment**, eliminating the need to manually export data from the web interface. **Only publicly accessible data are supported at the time** (accessibility = anonymous). -[^1]: Only Fieldwork events (Akce) are supported at the time. ### Key Features * **Spatial Querying:** Option to filter records based on the current map canvas extent (Bounding Box). -* **Advanced Attribute Filtering:** Supports multi-criteria filtering using controlled vocabularies (Cadastral Area, District, Period, Type of Fieldwork event, Organization, Fieldwork Manager). +* **Advanced Attribute Filtering:** Supports multi-criteria filtering using controlled vocabularies. * **Dynamic Geometry Retrieval:** Automatically downloads and categorizes spatial data into Point, Line, and Polygon layers. * **Semantic Interoperability:** Automatically translates internal system codes into human-readable labels using the AIS CR API. @@ -44,14 +43,14 @@ ### 3.1 Data Retrieval -To initiate a search query, click the **Load AMCR Data** icon. The filter dialog provides the following options: +To initiate a search query, click either the **Stáhnout data akcí** or the **Stáhnout data lokalit** icon from the dropdown menu. The filter dialog provides the following options. Shown options vary based on the choosed tool. * **Spatial Filter:** *Checkbox "Limit search to current map extent":* If checked, the query is restricted to the geographical area currently visible in the QGIS canvas. If unchecked, the query searches the entire database (use with caution regarding data volume). -* It is possible to view only those Fieldwork events with positive outcome, if "Positive findings only" is checked. Only PIANs marked as (or rather PIANs belonging to Documentation units marked as) "Type of evidence" = "positive" are rendered. +* It is possible to view only those Fieldwork events with positive outcome, if "Positive findings only" is checked. Only *PIANs* marked as (or rather *PIANs* belonging to Documentation units marked as) "Type of evidence" = "positive" are rendered. * **Attribute Filters:** - * The dialog utilizes "Picker" widgets for controlled vocabularies (Region, District, Cadastral area, Organisation, Period, Activity Area, PIAN accuracy. + * The dialog utilizes "Picker" widgets for controlled vocabularies (common: Region, District, Cadastral area, Period, Activity Area, *PIAN* accuracy; *events* related: Organisation, Researcher, Event type; *sites* related: Site type and class, Level of confidence, State of preservation). * Click **Select...** to open a searchable selection window. Multiple values can be selected simultaneously (Logic: OR). @@ -104,7 +103,7 @@ The plugin interacts with three primary endpoints of the AIS CR infrastructure: ### 4.3 Data Persistence * **Vocabularies:** Static vocabularies (e.g., Periods, Regions) are stored in `codelists/heslar.csv`. -* **Dynamic Data:** The list of investigators is downloaded on-demand and cached in `codelists/vedouci.csv`. +* **Dynamic Data:** The list of researchers is downloaded on-demand and cached in `codelists/vedouci.csv`. * **Layers:** Output layers are created as `memory` layers. They are non-persistent and will be lost if QGIS is closed without saving. ### 4.4 Constraints @@ -115,3 +114,4 @@ The plugin interacts with three primary endpoints of the AIS CR infrastructure: ## 6. Links and resources * [AMCR/Digiarchive Documentation](https://amcr-help.aiscr.cz/) (only in Czech). +* [AMCR Viewer tutorial](https://amcr-help.aiscr.cz/digiarchiv/qgis-viewer.html) (only in Czech). diff --git a/amcr_viewer/amcr_tools.py b/amcr_viewer/amcr_tools.py index 9dac666..dc64df5 100644 --- a/amcr_viewer/amcr_tools.py +++ b/amcr_viewer/amcr_tools.py @@ -46,7 +46,7 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): url = "https://digiarchiv.aiscr.cz/api/search/query" - iface.messageBar().pushMessage("AMCR", "Hledám akce...", level=1) + iface.messageBar().pushMessage("AMCR", "Hledám záznamy...", level=1) QApplication.setOverrideCursor(Qt.WaitCursor) try: @@ -221,7 +221,7 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): pian_lookup[dj_pian_value].append(dj_meta) if not target_pian_ids: - iface.messageBar().pushMessage("AMCR", f"Nalezeno {len(docs)} akcí, ale žádná nemá geometrii.", level=1) + iface.messageBar().pushMessage("AMCR", f"Nalezeno {len(docs)} záznamů, ale žádný nemá geometrii.", level=1) return @@ -233,7 +233,7 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): docs_pian = [] BATCH_PIAN = 50 - iface.messageBar().pushMessage("AMCR", f"Akcí: {len(docs)} (z toho {actions_with_geom} s mapou). Stahuji {total_pians} unikátních geometrií, vykresluji {target_pian_ids_count} geometrií...", level=1) + iface.messageBar().pushMessage("AMCR", f"Záznamů: {len(docs)} (z toho {actions_with_geom} s mapou). Stahuji {total_pians} unikátních geometrií, vykresluji {target_pian_ids_count} geometrií...", level=1) # Seznam polí pro PIAN fl_pian = ["ident_cely", "pian_typ", "pian_chranene_udaje", "pian_presnost"] @@ -269,7 +269,7 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): if typ_dat == "akce": archeologicky_zaznam = "Akce" elif typ_dat == "lokalita": - archeologicky_zaznam = "ID lokality" + archeologicky_zaznam = "Lokalita" # Definice sloupců atributové tabulky cols = [ @@ -412,7 +412,7 @@ def load_amcr_data(canvas, bb, filters=None, typ_dat="akce"): added += len(f) if added > 0: - iface.messageBar().pushMessage("AMCR", f"Hotovo. Akcí: {len(docs)} (s geom: {actions_with_geom}). Vykresleno: {added} prvků.", level=0) + iface.messageBar().pushMessage("AMCR", f"Hotovo. Záznamů: {len(docs)} (s geom: {actions_with_geom}). Vykresleno: {added} prvků.", level=0) else: iface.messageBar().pushMessage("AMCR", "Žádná data k zobrazení.", level=1) diff --git a/amcr_viewer/metadata.txt b/amcr_viewer/metadata.txt index 490d1f7..80eb118 100644 --- a/amcr_viewer/metadata.txt +++ b/amcr_viewer/metadata.txt @@ -1,16 +1,17 @@ # This file contains metadata for your plugin. -# This file should be included when you package your plugin.# Mandatory items: +# This file should be included when you package your plugin. +# Mandatory items: [general] name=AMČR Viewer qgisMinimumVersion=3.4 description=Viewing and downloading the AMČR data. -version=1.1.0 +version=1.2.0 author=David Spáčil email=spacil@arub.cz -about=This plugin is intended for downloading the data (Fieldwork events data only, at the time) from the Digiarchive of the Archaeological Map of the Czech Republic (AMCR). As of now, only publicly accessible data can be downloaded. +about=This plugin is intended for downloading the data (Fieldwork events data only, at the time) from the Digiarchive of the Archaeological Map of the Czech Republic (https://digiarchiv.aiscr.cz/). As of now, only publicly accessible data can be downloaded. tracker=https://github.com/ARUP-CAS/aiscr-qgis-amcr-viewer/issues repository=https://github.com/ARUP-CAS/aiscr-qgis-amcr-viewer