I want to plot a data-frame
in one of the tabs of my application. I'm using python 3.6.9 and PyQt5.
I implemented a TabWidget
from another answer. In one of those tabs I used MplCanvas
from Plotting with Matplotlib to plot a data from my data-frame
. Needed classes:
class TabWidget(QtWidgets.QTabWidget):
def __init__(self, *args, **kwargs):
QtWidgets.QTabWidget.__init__(self, *args, **kwargs)
self.setTabBar(TabBar(self))
self.setTabPosition(QtWidgets.QTabWidget.West)
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=6.4, height=4.8, dpi=394):
fig = Figure(figsize= (width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
super(MplCanvas, self).__init__(fig)
class TabBar(QtWidgets.QTabBar):
def tabSizeHint(self, index):
s = QtWidgets.QTabBar.tabSizeHint(self, index)
s.transpose()
return s
def paintEvent(self, event):
painter = QtWidgets.QStylePainter(self)
opt = QtWidgets.QStyleOptionTab()
for i in range(self.count()):
self.initStyleOption(opt, i)
painter.drawControl(QtWidgets.QStyle.CE_TabBarTabShape, opt)
painter.save()
s = opt.rect.size()
s.transpose()
r = QtCore.QRect(QtCore.QPoint(), s)
r.moveCenter(opt.rect.center())
opt.rect = r
c = self.tabRect(i).center()
painter.translate(c)
painter.rotate(90)
painter.translate(-c)
painter.drawControl(QtWidgets.QStyle.CE_TabBarTabLabel, opt)
painter.restore()
The QMainWindow
of application:
class App(QMainWindow):
def __init__(self):
super().__init__()
self.title = 'PLOT APP'
self.left = 0
self.top = 0
self.width = 1024
self.height = 600
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.tab_widget = MyTabWidget(self, self.width, self.height)
self.setCentralWidget(self.tab_widget)
self.show()
And to run the application:
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
And the MyTabWidget
class in which I implemented my code:
class MyTabWidget(QWidget):
def __init__(self, parent, width, height):
super(QWidget, self).__init__(parent)
self.layout = QVBoxLayout(self)
# creating a tab bar
self.tab = TabWidget()
self.new_df = self.prepare_data()
self.layout_gauges = QHBoxLayout(self)
self.layout_plot = QVBoxLayout(self)
self.canvas = MplCanvas(self, width=10, height=8, dpi=100)
self.toolbar = NavigationToolbar(self.canvas, self)
self.comboBox = QtWidgets.QComboBox(self)
# widgets associated with tab
self.graphs_tab = QWidget()
# assigning tab to tab-bar
self.tab.addTab(self.graphs_tab, "Graphs")
# graphs tab
self.graphs_tab.layout = QVBoxLayout(self)
self.layout_combobox_time_filter = QHBoxLayout(self)
self.layout_combobox = QHBoxLayout(self)
self.draw_graphs()
self.graphs_tab.setLayout(self.graphs_tab.layout)
self.layout.addWidget(self.tab)
self.setLayout(self.layout)
self.tab.resize(300, self.ertefa)
self.tab.show()
def draw_graphs(self):
for item in self.new_df.columns[1:]:
self.comboBox.addItem(str(item))
self.comboBox.setMaximumWidth(200)
self.comboBox.activated[str].connect(self.draw_plot)
self.layout_combobox.addWidget(self.comboBox)
self.layout_combobox.setAlignment(QtCore.Qt.AlignRight)
self.layout_combobox_time_filter.addLayout(self.layout_combobox.layout())
self.canvas.axes.plot(self.new_df.index, self.new_df.loc[:, self.comboBox.currentText()])
self.label = self.canvas.axes.set_xlabel('Time', fontsize=9)
self.label = self.canvas.axes.set_ylabel(self.comboBox.currentText(), fontsize=9)
self.canvas.axes.legend(str(self.comboBox.currentText()))
self.canvas.draw()
self.graphs_tab.layout.addWidget(self.toolbar)
self.graphs_tab.layout.addWidget(self.canvas)
self.graphs_tab.layout.addLayout(self.layout_combobox_time_filter.layout())
def draw_plot(self):
self.canvas.axes.plot(self.new_df.index, self.new_df.loc[:, self.comboBox.currentText()])
self.label = self.canvas.axes.set_xlabel('Time', fontsize=9)
self.label = self.canvas.axes.set_ylabel(self.comboBox.currentText(), fontsize=9)
self.canvas.axes.legend(self.comboBox.currentText())
self.canvas.draw()
def prepare_data(self):
# extract data from file
sensor = pd.read_excel("file.xlsx")
return df_new
The default values for width
and height
are (width=6.4, height=4.8)
based on documentation.
My screen size is 1024 * 600
pixel. Then I create an instance of this class as follows and assign a NavigationToolbar
to it:
self.canvas = MplCanvas(self, width=10, height=7, dpi=100)
self.toolbar = NavigationToolbar(self.canvas, self)
I plot my data-frame as following:
self.canvas.axes.plot(self.new_df.index, self.new_df.loc[:, self.comboBox.currentText()])
self.label = self.canvas.axes.set_xlabel('Time', fontsize=9)
self.label = self.canvas.axes.set_ylabel(self.comboBox.currentText(), fontsize=9)
self.canvas.axes.legend(str(self.comboBox.currentText()))
self.canvas.draw()
but every time I change the width
and height
of the canvas its dimensions don't change.
What is wrong with my code or my understanding of this?
And the legend of the plot isn't completely displayed, as the picture indicates, only the first character of the legend is shown. How to fix it?
Ok, I found the problem. in MplCanvas
where the fig
object is initialized, tight_layout
property should be set to True
.
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=6.4, height=4.8, dpi=394):
fig = Figure(figsize= (width, height), dpi=dpi, tight_layout=True)
self.axes = fig.add_subplot(111)
super(MplCanvas, self).__init__(fig)
But the legend is shown with one character only.