将叶图保存在 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
main.py
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()