はじめに
QtDesignerのGUI上にBasemapを埋め込みたい。でも、QtDesignerのウィジェットボックスにはBasemapなんてない。そんな時はウィジェットの格上げをしましょう。
環境
- macOS
- python=3.6.4
- PyQt5=5.12.1
- basemap=1.1.0
- QtDesigner=5.6.2
Basemapインストール
まずはBasemapのインストールをします。
matplotlib.basemapで簡単にマップを描画するを参考に。
$ xcode-select --install
$ brew install geos
$ brew install wget
$ wget https://github.com/matplotlib/basemap/archive/v1.1.0.tar.gz
$ tar zxvf v1.1.0.tar.gz
$ cd basemap-1.1.0
$ python setup.py install
先頭のxcode-select --installは、geosのインストール時にエラーが出たため、こちらを参考に加えました。
インストールが出来たら、サンプルが動くことを確認しましょう。
UIファイルの作成
QtDesigner上で、Basemapを埋め込む準備をします。QtDesignerの基本的な使い方は以下を参考にして下さい。
[入門]PyQtでHello Worldを表示する
QtDesignerで新規ファイルを作成し、ウィジェットボックスから「Widget」を選択し、ドラッグ&ドロップで画面に配置します。

このQWidgetの名前は「worldMap」としておきます。ここにBasemapを埋め込むことになります。

ここで一旦ファイルを保存しておきましょう。名前は「world_map.ui」とします。
保存したら、作成した.uiファイルを.pyファイルに変換しましょう。
$ pyuic5 world_map.ui > world_map_ui.py
Basemapの実体を作成
Basemapの実体をもつファイルを作成します。名前は「basemap_sample.py」とし、内容は以下のようにしました。
import sys
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from mpl_toolkits.basemap import Basemap
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QWidget
from world_map_ui import Ui_MainWindow
class BasemapSample(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(BasemapSample, self).__init__(parent)
self.setupUi(self)
class WorldMap(QWidget):
def __init__(self, parent):
super(WorldMap, self).__init__(parent)
self._fig = Figure(figsize=(4.0, 3.0), dpi=100)
axes = self._fig.add_axes([0.0, 0.0, 1.0, 1.0])
self._canvas = FigureCanvas(self._fig)
self._canvas.setParent(parent)
map = Basemap(projection='cyl', resolution='c', ellps="WGS84", ax=axes)
map.drawcoastlines()
map.drawmapboundary(fill_color='#bce2e8')
map.fillcontinents(color='#80aba9',lake_color='#bce2e8')
self._canvas.draw()
# サイズ調整
def setGeometry(self, rect):
super().setGeometry(rect)
self._canvas.setGeometry(rect)
dpi = self._fig.get_dpi()
self._fig.set_size_inches(rect.width() / dpi,
rect.height() / dpi)
if __name__ == '__main__':
argvs = sys.argv
app = QApplication(argvs)
basemap_sample = BasemapSample()
basemap_sample.show()
sys.exit(app.exec_())
クラスが二つありますが、BasemapSampleクラスは先ほど作成したUIファイルを継承し表示するもの、WorldMapクラスはUIファイルで作成したworldMap(QWidget)の格上げ先クラスになります。
格上げをする
QtDesignerに戻ります。配置したQWidgetの上で右クリックするとメニューが表示されます。その中の「格上げ先を指定...」を選択します。

「格上げされたウィジェット」という画面が出てきます。下部の新しい格上げされたクラスのところに、格上げされたクラス名、ヘッダファイルを入力するフィールドがあるので、以下のようにインプットします。

「追加」ボタンを押し、「格上げ」をして画面を閉じます。
すると、オブジェクトインスペクタ上の、worldMapのクラスがQWidgetから、格上げしたWorldMapになっていることがわかります。

ここまで出来たら、ファイルを保存し、改めて.ui > .py 変換をします。
$ pyuic5 world_map.ui > world_map_ui.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.worldMap = WorldMap(self.centralwidget)
self.worldMap.setGeometry(QtCore.QRect(60, 40, 680, 440))
self.worldMap.setObjectName("worldMap")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
from basemap_sample import WorldMap
実行してみる
ファイルを実行してみます。

配置したQWidgetの部分に無事、Basemapが埋め込まれました。
自分が配置したいGUIがQtDesigner上にない場合は、自分でクラスを作成し、格上げをしてみましょう。