0

I try to add the datacursor functionality to my bar chart by using the following code:

datacursor(hover=True, formatter=self.formatter)

No error happens but tooltip doesn't show when I hover my mouse pointer over a bar.

I try to put the following code (and this one works perfectly) into a QWidget:

import numpy as np
import matplotlib.pyplot as plt
from mpldatacursor import datacursor

label = ['a', 'b', 'c', 'd']
x = [1, 2, 3, 4]
y = [10, 20, 30, 40]

fig, ax = plt.subplots()
ax.bar(x, y, align='center', color='lightblue')
ax.margins(0.05)
ax.set_ylim(bottom=0)

def formatter(**kwargs):
    dist = abs(np.array(x) - kwargs['x'])
    i = dist.argmin()
    return '\n'.join(label[i])

datacursor(hover=True, formatter=formatter)
plt.show()

Here my current code.

back_end:

from PyQt5 import QtCore, QtGui, QtWidgets
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget
from front_end import Ui_MainWindow
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.pyplot as plt
from mpldatacursor import datacursor

class Ui_MainWindow(QMainWindow, Ui_MainWindow):

    def __init__(self, parent=None):
        super(Ui_MainWindow, self).__init__(parent)
        self.setupUi(self)
        self.graph = MyCanvas()      
        self.gridLayout.addWidget(self.graph, 0, 0, 1, 1)
        self.populate()

    def populate(self):
        self.graph.figure.clf()
        self.axes= self.graph.figure.add_subplot(111)       
        label = ['a', 'b', 'c', 'd']
        x = [1, 2, 3, 4]
        y = [10, 20, 30, 40]
        datacursor(hover=True, formatter=self.formatter)
        self.axes.bar(x, y, align='center', bottom=0, color='b')

    def formatter(**kwargs):
        x = [1, 2, 3, 4]
        dist = abs(np.array(x) - kwargs['x'])
        i = dist.argmin()
        return '\n'.join(label[i])

class MyCanvas(FigureCanvas):
    def __init__(self, *args, **kwargs):
        self.figure = plt.figure()
        FigureCanvas.__init__(self, self.figure)
        self.figure.patch.set_facecolor("None")
        self.figure.subplots_adjust(left=0.08, bottom=0.10, right=0.99, top=0.97)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    prog = Ui_MainWindow()
    prog.show()
    sys.exit(app.exec_())

front_end:

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(625, 460)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.widget = QtWidgets.QWidget(self.centralwidget)
        self.widget.setObjectName("widget")
        self.gridLayout.addWidget(self.widget, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 625, 21))
        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"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())
11
  • When asking about undesired behaviour always provide a minimal reproducible example. I tried to make your code runnable but needed to give up half-way... just make sure someone can copy it from the question without needing to guess about missing things. Commented Jul 21, 2018 at 22:17
  • So to be more precise: What is x inside the formatter method? It's nowhere defined. Commented Jul 21, 2018 at 22:43
  • Thank you for your comment. I added the code for the front_end. Hope it will help. Thank you. Commented Jul 21, 2018 at 22:43
  • Yeah, but without x being defined the code can't run. Commented Jul 21, 2018 at 22:45
  • @ImportanceOfBeingErnest a question, even if FigureCanvasQTAgg is used, will the native matplotlib events continue to be handled? Commented Jul 21, 2018 at 22:49

1 Answer 1

1

There are several issues.

  • x and label that are used inside of the formatter method need to be defined. A good solution would be to make them class variables.
  • The formatter method should be a method of the class. Hence it would best be defined as one by using the self argument.
  • Naming the class in use the same as an imported class may lead to confusion, best name it differently.
  • The datacursor needs to know which objects to work on, hence one would need to first define the bar plot and later call the datacursor function with those bars as argument.
  • There is no need to join anything on the return of the formatter, just return the label to show.

This should then look like

class MyWindow(QMainWindow, Ui_MainWindow):

    # ....

    def populate(self):
        self.graph.figure.clf()
        self.axes= self.graph.figure.add_subplot(111)       
        self.label = ['a', 'b', 'c', 'd']
        self.x = [1, 2, 3, 4]
        self.y = [10, 20, 30, 40]
        bars = self.axes.bar(self.x, self.y, align='center', bottom=0, color='b')
        datacursor(bars, hover=True, formatter=self.formatter)

    def formatter(self, **kwargs):
        dist = abs(np.array(self.x) - kwargs['x'])
        i = dist.argmin()
        return self.label[i]
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.