LoginSignup
3
2

More than 3 years have passed since last update.

【PyQt】QtDesigner上にBasemapを埋め込む(格上げを使う)

Last updated at Posted at 2019-05-25

はじめに

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で簡単にマップを描画するを参考に。

@mac
$ 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」を選択し、ドラッグ&ドロップで画面に配置します。

スクリーンショット 2019-05-25 17.00.17.png

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

スクリーンショット 2019-05-25 17.00.56.png

ここで一旦ファイルを保存しておきましょう。名前は「world_map.ui」とします。
保存したら、作成した.uiファイルを.pyファイルに変換しましょう。

$ pyuic5 world_map.ui > world_map_ui.py

Basemapの実体を作成

Basemapの実体をもつファイルを作成します。名前は「basemap_sample.py」とし、内容は以下のようにしました。

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の上で右クリックするとメニューが表示されます。その中の「格上げ先を指定...」を選択します。

スクリーンショット 2019-05-25 17.04.23.png

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

スクリーンショット 2019-05-25 18.14.10.png

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

スクリーンショット 2019-05-25 18.19.22.png

ここまで出来たら、ファイルを保存し、改めて.ui > .py 変換をします。

$ pyuic5 world_map.ui > world_map_ui.py

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

実行してみる

ファイルを実行してみます。

スクリーンショット 2019-05-25 18.23.20.png

配置したQWidgetの部分に無事、Basemapが埋め込まれました。

自分が配置したいGUIがQtDesigner上にない場合は、自分でクラスを作成し、格上げをしてみましょう。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2