Open luizkeng opened 4 years ago
Hi @anntzer !
I've got how to fix the first issue. @jorgesmok had a similar problem and suggested to set the canvas Focus Policy to Qt.ClickFocus. Finally the bindings worked fine!! I would edit my last post, but I decided to keep the first issue and the solution in the case of anyone need in the future. Anyway, the second one strangely persists.
I have written a fair ampunt of Qt GUIs myself, so things should work fine there. What was your focus? Matplotlib sets the default to Qt.StrongFocus which should include ClickFocus.
Do you have an example to repro the second case? e.g. the code and tell me where to click. Otherwise it's always tricky to investigate.
The focus was on the widget, but if I didn't include set the canvas Focus Policy to Qt.ClickFocus (or even to Qt.StrongFocus) nothing works.
I'll try to build a example to mimetize the my own problem and put it here soon.
In the following code I think you can see what I talked about alignment. Between the x points 1 and 2 the "Sample" annotation stays on the left, however for 14 - 15 x points it appears at right.
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QMenu, QVBoxLayout, QSizePolicy, QMessageBox, QWidget, QPushButton
from PyQt5.QtGui import QIcon
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import mplcursors
import random
class App(QMainWindow):
def __init__(self):
super().__init__()
self.left = 10
self.top = 10
self.title = 'PyQt5 matplotlib example - pythonspot.com'
self.width = 640
self.height = 400
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
m = PlotCanvas(self, width=5, height=4)
m.move(0,0)
self.show()
class PlotCanvas(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)
FigureCanvas.__init__(self, fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self,
QSizePolicy.Expanding,
QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
self.plot()
def plot(self):
data = [random.random() for i in range(25)]
ax = self.figure.add_subplot(111)
ax.plot(data, 'r-')
ax.set_title('PyQt Matplotlib Example')
self.draw()
mpl_cursor = mplcursors.cursor(ax, hover = 2)
@mpl_cursor.connect("add")
def on_add(sel):
sel.annotation.set(text = f"Sample: {sel.artist.get_label()}\nX: {sel.target[0]} \nY: {sel.target[1]}", ha = "left", va="center")
sel.annotation.set_ha('left')
sel.annotation.set_weight('bold')
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Ah yes. This is more or less intentional: I need to keep the annotation within the figure (I can't draw outside of the figure and cropping the annotation would be pretty bad), so I detect whether the annotation on the left or on the right of the selected point; then based on that info I pick the alignment (left or right). You can force the position (as in the bar.py example) in which case I'll also leave whatever alignment you set (if any), but if you don't then alignment will be autopicked for you, which I guess I could also avoid if you explicitly set an alignment? How does that look to you? Also I guess this behavior could be better documented...
Oh yeah. I got it. For me it's ok.
I have only one more question: how can a set the alignment of the text inside the annotation? I observed, in the aforementioned example, that when annotation is left the text goes right. Also, when annotation is right, the text goes left. I'm attaching two example to make it more clear.
Looking at the docs again, I think the behavior is alluded to in the Note under https://mplcursors.readthedocs.io/en/latest/#customization. It's not really explicit; OTOH I'm not sure I really want to emphasize it too much as it's a bit obscure.
I think keeping user-set alignments is reasonable, but a quick try suggests it will be slightly tricky to achieve. Please consider submitting a PR; otherwise I'll try to work on a fix myself but can't make any schedule guarantees.
Hello @anntzer ,
Is there any special care when we use mplcursors in a PyQt embedded matplotlib graph? I observed two issues in this context:
Until now I could not manage how to change the 'deselect' action from right button to middle button of mouse. I set up a dict for bindings argument with '2' to 'deselect' key, but no response. Indeed, when I did that the right click lost the remove functionality, but the middle button was not able to remove.
Another issue is related to horizontal alignment of annotation. I'm using _sel.annotation.setha('right') , but even outside of PyQt environment its not having instantaneous effect. It's strange because only after some clicks (and sometimes in specific points) the annotation "wake-up" and start to follow the _setha instructions.
Do you have any idea of how to fix these issues?
Anyway, thanks for your attention.