Skip to content

Dragging Legend not working properly #24755

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
inxp opened this issue Dec 17, 2022 · 2 comments
Open

Dragging Legend not working properly #24755

inxp opened this issue Dec 17, 2022 · 2 comments
Labels

Comments

@inxp
Copy link

inxp commented Dec 17, 2022

Bug summary

This may not be a bug. It is my use case.

I have embedded matplotlib in PyQt5 and I am using Ctrl+C to copy the figure to clipboard (for pasting to ppt)

So in the minimum example attached, pressing Ctrl+C reduces figure size to specified size (6x4). This is kind of a print preview for me. So I adjust legend/annotations in the smaller figure.

Dragging legend is not working properly in the smaller figure. It used to work in older versions for me. So I went through the changes. Reverting the change done in the following line of blit function of /backends/backend_qt.py fixes the problem (Changed as part of #17478)

self.repaint(l, self.rect().height() - t, w, h)
to
self.repaint(l, int(self.renderer.height / self.device_pixel_ratio)- t, w, h)

For the normal figure self.rect().height() is equal to int(self.renderer.height / self.device_pixel_ratio)

But for the smaller figure self.rect().height() is different from int(self.renderer.height / self.device_pixel_ratio)

Is this ok?

Thanks

Code for reproduction

import io
import sys
from PyQt5.QtWidgets import QWidget, QApplication, QShortcut, QVBoxLayout
from PyQt5.QtCore import QMimeData
from PyQt5.QtGui import QKeySequence

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

import random

class Window(QWidget):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.figure = Figure()

        data = [random.random() for _ in range(10)]

        ax = self.figure.add_subplot(111)
        ax.plot(data, '*-',label='RandomData')
        legend = ax.legend()
        
        self.canvas = FigureCanvas(self.figure)
        self.canvas.draw()

        legend.set_draggable(True,use_blit=True) # Dragging is not ok in smaller figure/ ok in normal figure
        # legend.set_draggable(True) # Dragging is ok in smaller figure when blitting is off


        ctc = QShortcut(QKeySequence("Ctrl+C"), self)
        ctc.activated.connect(self.copy_to_clipboard)

        layout = QVBoxLayout()
        layout.addWidget(self.canvas)
        self.setLayout(layout)

    def copy_to_clipboard(self):
        fig = self.canvas.figure
        fig.set_size_inches(6,4)
        buf = io.BytesIO()
        fig.savefig(buf,dpi=300,transparent=True,bbox_inches='tight')
        mimeData = QMimeData()
        mimeData.setData("PNG",buf.getvalue())
        QApplication.clipboard().setMimeData(mimeData)
        buf.close()

    
if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = Window()
    main.showMaximized()
    sys.exit(app.exec_())

Actual outcome

N5hiEqY3Hg

Expected outcome

gUBmnxj0rD

Additional information

No response

Operating system

Windows

Matplotlib Version

3.6.2

Matplotlib Backend

PyQt5

Python version

3.8.10

Jupyter version

NA

Installation

pip

@anntzer
Copy link
Contributor

anntzer commented Dec 17, 2022

This seems to occur because when a figure has no attached manager (as in the case of full embedding, which you use), its size (figsize/renderer size) can become different from the FigureCanvas widget size (because set_size_inches can't adjust it; indeed I can imagine cases of fixed GUI layout where this is impossible to do). Short of forbidding calls to set_size_inches in this case (you seem to have a reasonable, though perhaps slightly unusual, use case), I guess we just need to avoid assuming that these two sizes are equal, and your proposed patch indeed seems reasonable; one important point, though, is that renderer.height is not part of the guaranteed renderer API, so the correct expression is, I believe, something like self.repaint(l, int(self.figure.get_figheight() * self.figure.dpi / self.device_pixel_ratio) - t, w, h).

@inxp
Copy link
Author

inxp commented Dec 18, 2022

Confirming that self.repaint(l, int(self.figure.get_figheight() * self.figure.dpi / self.device_pixel_ratio) - t, w, h) is working. For now I will monkey patch blit function in my program.

@tacaswell tacaswell added this to the v3.8.0 milestone Dec 18, 2022
@ksunden ksunden removed this from the v3.8.0 milestone Sep 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants