【PyQt】 QtDesigner에 Basemap을 포함 (격상 사용)

소개



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을 선택하고 드래그 앤 드롭으로 화면에 배치합니다.



    이 QWidget의 이름은 "worldMap"으로 둡니다. 여기에 Basemap을 포함시킬 것입니다.



    여기서 일단 파일을 저장해 둡시다. 이름은 "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_())
    
    

    클래스가 2개 있습니다만, BasemapSample 클래스는 방금 작성한 UI 파일을 상속해 표시하는 것, WorldMap 클래스는 UI 파일로 작성한 worldMap(QWidget)의 격상처 클래스가 됩니다.

    격상하다



    QtDesigner로 돌아갑니다. 배치한 QWidget을 마우스 오른쪽 버튼으로 클릭하면 메뉴가 표시됩니다. 그 중에서 "격상 대상 지정..."을 선택합니다.



    "격상된 위젯"이라는 화면이 나옵니다. 하단의 새로운 격상된 클래스의 곳에, 격상된 클래스명, 헤더 파일을 입력하는 필드가 있으므로, 다음과 같이 입력합니다.



    "추가"버튼을 누르고 "격상"을 하여 화면을 닫습니다.
    그러면 객체 인스펙터의 worldMap 클래스가 QWidget에서 격상된 WorldMap이 되어 있음을 알 수 있습니다.



    여기까지 할 수 있으면, 파일을 보존해, 다시 .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
    
    

    실행해보기



    파일을 실행해 봅니다.



    배치한 QWidget 부분에 무사히 Basemap이 내장되었습니다.

    자신이 배치하고 싶은 GUI가 QtDesigner에 없는 경우는, 스스로 클래스를 작성해, 격상을 해 봅시다.

    좋은 웹페이지 즐겨찾기