Sadie LaBounty
Sadie LaBounty

Reputation: 379

PyQt and MatPlotLib - Connecting QComboBox to Plot Function

I need to connect a comboBox to a plot function defined within a method of a separate class as seen below. The desired result is that the range selected in the comboBox's items is what is plotted in the figure so it will also be necessary to refresh the canvas upon selection which I could also use advice on.

There are two ways I can think of attaining this result but both are problematic. Ideally, the comboBox would be defined within the class containing the plot function to avoid the difficulty of connecting it to the class(method(function))) from outside the class but I don't think this is possible. Alternatively, it could be defined in setupUI but then how would I connect it to the plot function? Is it possible to reach a class's method's function from outside that class? Advice on either approach will be appreciated. I have condensed the code as much as I can.

import math
import matplotlib
import numpy as np
from PyQt4 import QtCore, QtGui
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class MyMplCanvas(FigureCanvas):

    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = fig.add_subplot(111)

        self.compute_initial_figure()

        FigureCanvas.__init__(self, fig)
        self.setParent(parent)

        FigureCanvas.setSizePolicy(self,
                                   QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

    def compute_initial_figure(self):
        pass

class UsersPerCountryAndPlatformBar(MyMplCanvas):

    def compute_initial_figure(self):

        A_B = [['Afghanistan', 'Albania', 'Algeria', 'American Samoa', 'Angola'], [1, 9, 7, 1, 1], [1, 7, 2, 0, 1], \
    [0, 4, 3, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
        C_F = [['Cambodia', 'Canada', 'Chile', 'China', 'Colombia'], [13, 189, 12, 5, 10], [5, 115, 6, 64, 7], \
    [1, 11, 1, 2, 4], [2, 12, 0, 2, 0], [2, 5, 0, 0, 0]]

        def plot(X_Y):
            summedX_Y = []
            for i in range(len(X_Y[0])):
                summedX_Y.append(X_Y[1][i] + X_Y[2][i] + X_Y[3][i] + X_Y[4][i] + X_Y[5][i])

            def roundup(x):
                return int(math.ceil(x / 10.0)) * 10

            N = len(X_Y[0])
            ind = np.arange(N)
            width = 0.75
            colors = ['yellowgreen', 'paleturquoise', 'royalblue', 'lightsteelblue', 'firebrick']

            print [x + y for x, y in zip(X_Y[1], X_Y[2])]
            print [x + y + z for x, y, z in zip(X_Y[1], X_Y[2], X_Y[3])]
            print [x + y + z + i for x, y, z, i in zip(X_Y[1], X_Y[2], X_Y[3], X_Y[4])]

            p1 = self.axes.bar(ind, X_Y[1], width, color = colors[0])
            p2 = self.axes.bar(ind, X_Y[2], width, bottom = X_Y[1], color = colors[1])
            p3 = self.axes.bar(ind, X_Y[3], width, bottom = [x + y for x, y in zip(X_Y[1], X_Y[2])], color = colors[2])
            p4 = self.axes.bar(ind, X_Y[4], width, bottom = [x + y + z for x, y, z in zip(X_Y[1], X_Y[2], X_Y[3])], color = colors[3])
            p5 = self.axes.bar(ind, X_Y[5], width, bottom = [x + y + z + i for x, y, z, i in zip(X_Y[1], X_Y[2], X_Y[3], X_Y[4])], color = colors[4])

            self.axes.set_ylabel('Count')
            self.axes.set_title('Users Per Country And Platform')
            self.axes.set_xticks(ind)
            self.axes.set_xticklabels(countrylabels, fontsize = 8)
            self.axes.set_yticklabels(np.arange(0, max(summedX_Y), roundup(max(summedX_Y) / 10)))
            self.axes.legend((p1[0], p2[0], p3[0], p4[0], p5[0]), ('Android', 'iOS', 'Windows', 'OS X', 'WebGL'))

            '''comboBox = QtGui.QComboBox(self)
            comboBox.addItem('A_B')
            comboBox.addItem('C_F')
            comboBox.activated[str].connect(compute_initial_figure(plot(text)))'''
            # should plot(A_B) or (C_F) as selected

class Ui_MainWindow(object):

    def setupUi(self, MainWindow):

        self.main_widget = QtGui.QWidget(MainWindow)
        l = QtGui.QVBoxLayout(self.main_widget)
        UPCP = UsersPerCountryAndPlatformBar(self.main_widget, width = 10, height = 5, dpi = 100)
        l.addWidget(UPCP)
        self.main_widget.setFocus()
        MainWindow.setCentralWidget(self.main_widget)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Upvotes: 0

Views: 995

Answers (1)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339062

You can have a look at the code down below. I removed the doubly subclassing for better readability.

compute_initial_figure is called when the FigureCanvas is initialized.
The combo sits in the mainwindow class and is connected to an update function. This function converts the text from the combobox to some data which is passed to the plot function.

import math
import numpy as np
from PyQt4 import QtGui

from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas



class UsersPerCountryAndPlatformBar(FigureCanvas):

    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        FigureCanvas.__init__(self, fig)

        self.axes = fig.add_subplot(111)
        self.compute_initial_figure()

    def compute_initial_figure(self):

        A_B = [['Afghanistan', 'Albania', 'Algeria', 'American Samoa', 'Angola'], [1, 9, 7, 1, 1], [1, 7, 2, 0, 1], \
                [0, 4, 3, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
        C_F = [['Cambodia', 'Canada', 'Chile', 'China', 'Colombia'], [13, 189, 12, 5, 10], [5, 115, 6, 64, 7], \
                [1, 11, 1, 2, 4], [2, 12, 0, 2, 0], [2, 5, 0, 0, 0]]
        self.data = {"A_B" : A_B, "C_F" : C_F}
        self.updatefig("A_B")

    def updatefig(self, text):
        self.plot(self.data[text])

    def plot(self, X_Y):
        self.axes.clear()
        summedX_Y = []
        for i in range(len(X_Y[0])):
            summedX_Y.append(X_Y[1][i] + X_Y[2][i] + X_Y[3][i] + X_Y[4][i] + X_Y[5][i])

        def roundup(x):
            return int(math.ceil(x / 10.0)) * 10

        N = len(X_Y[0])
        ind = np.arange(N)
        width = 0.75
        colors = ['yellowgreen', 'paleturquoise', 'royalblue', 'lightsteelblue', 'firebrick']

        print [x + y for x, y in zip(X_Y[1], X_Y[2])]
        print [x + y + z for x, y, z in zip(X_Y[1], X_Y[2], X_Y[3])]
        print [x + y + z + i for x, y, z, i in zip(X_Y[1], X_Y[2], X_Y[3], X_Y[4])]

        p1 = self.axes.bar(ind, X_Y[1], width, color = colors[0])
        p2 = self.axes.bar(ind, X_Y[2], width, bottom = X_Y[1], color = colors[1])
        p3 = self.axes.bar(ind, X_Y[3], width, bottom = [x + y for x, y in zip(X_Y[1], X_Y[2])], color = colors[2])
        p4 = self.axes.bar(ind, X_Y[4], width, bottom = [x + y + z for x, y, z in zip(X_Y[1], X_Y[2], X_Y[3])], color = colors[3])
        p5 = self.axes.bar(ind, X_Y[5], width, bottom = [x + y + z + i for x, y, z, i in zip(X_Y[1], X_Y[2], X_Y[3], X_Y[4])], color = colors[4])

        self.axes.set_ylabel('Count')
        self.axes.set_title('Users Per Country And Platform')
        self.axes.set_xticks(ind)
        #self.axes.set_xticklabels(countrylabels, fontsize = 8)
        self.axes.set_yticklabels(np.arange(0, max(summedX_Y), roundup(max(summedX_Y) / 10)))
        self.axes.legend((p1[0], p2[0], p3[0], p4[0], p5[0]), ('Android', 'iOS', 'Windows', 'OS X', 'WebGL'))
        self.draw_idle()

class Ui_MainWindow(object):

    def setupUi(self, MainWindow):

        self.main_widget = QtGui.QWidget(MainWindow)
        l = QtGui.QVBoxLayout(self.main_widget)

        self.main_widget.setFocus()
        MainWindow.setCentralWidget(self.main_widget)

        self.UPCP = UsersPerCountryAndPlatformBar(self.main_widget, width = 10, height = 5, dpi = 100)

        comboBox = QtGui.QComboBox(MainWindow)
        comboBox.addItem('A_B')
        comboBox.addItem('C_F')
        comboBox.activated[str].connect(self.UPCP.updatefig)
        l.addWidget(comboBox)
        l.addWidget(self.UPCP)

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Upvotes: 1

Related Questions