簡體   English   中英

使用folium在python中添加一個大的shapefile來映射

[英]Add a large shapefile to map in python using folium

我正在使用 python、PyQt5 和 Qt 設計器在我的應用程序中顯示葉子地圖。 由於 Qt 設計器中沒有地圖小部件,我添加了一個通用小部件,然后將其提升為我的自定義地圖小部件。 一切正常。 這是我推廣的小部件的 python 代碼:

import io

import folium

from PyQt5 import QtWebEngineWidgets
from PyQt5.QtWidgets import *

class LeafWidget (QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        m = folium.Map(
            location=[40, -120] , zoom_start=10
        )
        self.view = QtWebEngineWidgets.QWebEngineView()
       
        data = io.BytesIO()
       
        m.save(data, close_file=False)
        self.view.setHtml(data.getvalue().decode())
        self.layout = QVBoxLayout(self)
        self.layout.addWidget(self.view)
        self.show()

這很好用,我可以在我的應用程序中看到地圖。

我還試圖在這張地圖上顯示一個 GIS shapefile。 我做了一些研究,似乎我無法將 GIS shapefile (.shp) 直接添加到大葉地圖。 因此,我嘗試先將其轉換為 json,然后將 json 添加到地圖頂部。 我修改了我的代碼,如下所示,將 .shp 文件添加到映射中:

import io

import folium
import os.path

from PyQt5 import QtWebEngineWidgets
from PyQt5.QtWidgets  import *
import geopandas as gpd

class LeafWidget (QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        m = folium.Map(
            location=[40, -120] , zoom_start=10
        )
        self.view = QtWebEngineWidgets.QWebEngineView()
        # converting shp to geojson
        shp_file = gpd.read_file('input/2015_loaded_NoCC.shp')
        shp_file.to_file('myshpfile.json', driver='GeoJSON')
        shp = os.path.join('', 'myshpfile.json')
        data = io.BytesIO()
        folium.GeoJson(shp).add_to(m)
        m.save(data, close_file=False)
        self.view.setHtml(data.getvalue().decode())
        self.layout = QVBoxLayout(self)
        self.layout.addWidget(self.view)
        self.show()

但現在我的地圖根本不顯示。 它只是一個空白空間,控制台或錯誤日志中沒有錯誤。 如果我使用“m.save('map.html')”將地圖保存為 HTML 文件,它會保存文件,當我打開它時,它會在地圖上顯示 json 文件,但由於某種原因,添加 shp-->json 文件后,我在我的應用程序中顯示地圖的方式不起作用。 我究竟做錯了什么?

正如在這些問題( 12 )和官方文檔中已經指出的那樣:

void QWebEnginePage::setHtml(const QString &html, const QUrl &baseUrl = QUrl())

將此頁面的內容設置為 html。 baseUrl 是可選的,用於解析文檔中的相對 URL,例如引用的圖像或樣式表。

html 立即加載; 外部對象是異步加載的。

如果 html 中的腳本運行時間超過默認腳本超時(當前為 10 秒),例如由於被模態 JavaScript 警報對話框阻止,則此方法將在超時后盡快返回並加載任何后續 html異步。

使用此方法時,除非另有說明,否則 Web 引擎假定外部資源(例如 JavaScript 程序或樣式表)以 UTF-8 編碼。 例如,可以通過 HTML 腳本標簽的 charset 屬性指定外部腳本的編碼。 編碼也可以由 Web 服務器指定。

這是一個等效於 setContent(html, "text/html", baseUrl) 的便捷函數。

注意:此方法不會影響頁面的會話或全局歷史記錄。

警告:此函數僅適用於 HTML,對於其他 MIME 類型(例如 XHTML 和 SVG),應改用 setContent()。

警告:內容將在通過 IPC 發送到渲染器之前進行百分比編碼。 這可能會增加其大小。 百分比編碼內容的最大大小為 2 兆字節減去 30 字節。

(強調我的)

setHtml()不支持大於 2MB 的內容,因此在您的特定情況下有兩種解決方案:

  • 將大葉地圖保存在 html 文件中:

     import io import os from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets CURRENT_DIR = os.path.dirname(os.path.realpath(__file__)) class LeafWidget(QtWidgets.QWidget): def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent) self.view = QtWebEngineWidgets.QWebEngineView() shp_filename = os.path.join(CURRENT_DIR, "input", "2015_loaded_NoCC.shp") shp_file = gpd.read_file(shp_filename) shp_file_json_str = shp_file.to_json() m = folium.Map(location=[40, -120], zoom_start=10) folium.GeoJson(shp_file_json_str).add_to(m) tmp_file = QtCore.QTemporaryFile("XXXXXX.html", self) if tmp_file.open(): m.save(tmp_file.fileName()) url = QtCore.QUrl.fromLocalFile(tmp_file.fileName()) self.view.load(url) lay = QtWidgets.QVBoxLayout(self) lay.addWidget(self.view) def main(): app = QtWidgets.QApplication([]) w = LeafWidget() w.show() app.exec_() if __name__ == "__main__": main()
  • 使用 QWebEngineUrlSchemeHandler 返回 html:

    qfolium.py

     import json import io from PyQt5 import QtCore, QtWebEngineCore, QtWebEngineWidgets class FoliumSchemeHandler(QtWebEngineCore.QWebEngineUrlSchemeHandler): def __init__(self, app): super().__init__(app) self.m_app = app def requestStarted(self, request): url = request.requestUrl() name = url.host() m = self.m_app.process(name, url.query()) if m is None: request.fail(QtWebEngineCore.QWebEngineUrlRequestJob.UrlNotFound) return data = io.BytesIO() m.save(data, close_file=False) raw_html = data.getvalue() buf = QtCore.QBuffer(parent=self) request.destroyed.connect(buf.deleteLater) buf.open(QtCore.QIODevice.WriteOnly) buf.write(raw_html) buf.seek(0) buf.close() request.reply(b"text/html", buf) class FoliumApplication(QtCore.QObject): scheme = b"folium" def __init__(self, parent=None): super().__init__(parent) scheme = QtWebEngineCore.QWebEngineUrlScheme(self.scheme) QtWebEngineCore.QWebEngineUrlScheme.registerScheme(scheme) self.m_functions = dict() def init_handler(self, profile=None): if profile is None: profile = QtWebEngineWidgets.QWebEngineProfile.defaultProfile() handler = profile.urlSchemeHandler(self.scheme) if handler is not None: profile.removeUrlSchemeHandler(handler) self.m_handler = FoliumSchemeHandler(self) profile.installUrlSchemeHandler(self.scheme, self.m_handler) def register(self, name): def decorator(f): self.m_functions[name] = f return f return decorator def process(self, name, query): f = self.m_functions.get(name) if f is None: print("not found") return items = QtCore.QUrlQuery(query).queryItems() params_json = dict(items).get("json", None) if params_json is not None: return f(**json.loads(params_json)) return f() def create_url(self, name, params=None): url = QtCore.QUrl() url.setScheme(self.scheme.decode()) url.setHost(name) if params is not None: params_json = json.dumps(params) query = QtCore.QUrlQuery() query.addQueryItem("json", params_json) url.setQuery(query) return url

    主文件

    import io import os import folium from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets import geopandas as gpd from qfolium import FoliumApplication CURRENT_DIR = os.path.dirname(os.path.realpath(__file__)) folium_app = FoliumApplication() @folium_app.register("load_shapefile") def load_shapefile(latitude, longitude, zoom_start, shp_filename): shp_file = gpd.read_file(shp_filename) shp_file_json_str = shp_file.to_json() m = folium.Map( location=[latitude, longitude], zoom_start=zoom_start ) folium.GeoJson(shp_file_json_str).add_to(m) print(m) return m class LeafWidget(QtWidgets.QWidget): def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent) self.view = QtWebEngineWidgets.QWebEngineView() lay = QtWidgets.QVBoxLayout(self) lay.addWidget(self.view) self.resize(640, 480) shp_filename = os.path.join(CURRENT_DIR, "input", "2015_loaded_NoCC.shp") params = { "shp_filename": shp_filename, "latitude": 40, "longitude": -120, "zoom_start": 5, } url = folium_app.create_url("load_shapefile", params=params) self.view.load(url) def main(): app = QtWidgets.QApplication([]) folium_app.init_handler() w = LeafWidget() w.show() app.exec_() if __name__ == "__main__": main()

所以問題是我的 Geojson 文件顯然太大了。 大約 34MB 的 51k 記錄和 folium 不知何故無法處理它。 我測試了一個較小的 json 文件,它可以工作。 所以,現在的問題是我還有什么其他選項可以顯示地圖和這個大 shapefile/json?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM