17

In MATLAB, there is a very convenient option to copy the current figure to the clipboard. Although Python/numpy/scipy/matplotlib is a great alternative to MATLAB, such an option is unfortunately missing.

Can this option easily be added to Matplotlib figures? Preferably, all MPL figures should automatically benefit from this functionality.

I'm using MPL's Qt4Agg backend, with PySide.

EelkeSpaak
  • 2,757
  • 2
  • 17
  • 37

5 Answers5

14

Yes, it can. The idea is to replace the default plt.figure with a custom one (a technique known as monkey patching) that injects a keyboard handler for copying to the clipboard. The following code will allow you to copy any MPL figure to the clipboard by pressing Ctrl+C:

import io
import matplotlib.pyplot as plt
from PySide.QtGui import QApplication, QImage

def add_clipboard_to_figures():
    # use monkey-patching to replace the original plt.figure() function with
    # our own, which supports clipboard-copying
    oldfig = plt.figure

    def newfig(*args, **kwargs):
        fig = oldfig(*args, **kwargs)
        def clipboard_handler(event):
            if event.key == 'ctrl+c':
                # store the image in a buffer using savefig(), this has the
                # advantage of applying all the default savefig parameters
                # such as background color; those would be ignored if you simply
                # grab the canvas using Qt
                buf = io.BytesIO()
                fig.savefig(buf)
                QApplication.clipboard().setImage(QImage.fromData(buf.getvalue()))
                buf.close()

        fig.canvas.mpl_connect('key_press_event', clipboard_handler)
        return fig

    plt.figure = newfig

add_clipboard_to_figures()

Note that if you want to use from matplotlib.pyplot import * (e.g. in an interactive session), you need to do so after you've executed the above code, otherwise the figure you import into the default namespace will be the unpatched version.

Community
  • 1
  • 1
EelkeSpaak
  • 2,757
  • 2
  • 17
  • 37
  • For me it seems I can't choose the format by `fig.savefig(buf, format='svg')`. The image I got is still a bitmap image. I am using python 36 with matplotlib 2.2.2, Qt4Agg backend, on win 7 64. – Alex Jan 26 '19 at 03:25
  • I think it is because QImage renders it to a bitmap. So the real question is, how to copy paste vector format images like svg? – Alex Jan 26 '19 at 03:34
8

EelkeSpaak's solution was packed in a nice module: addcopyfighandler

Simply install by pip install addcopyfighandler, and import the module after importing matplotlib or pyplot.

Vaiaro
  • 908
  • 1
  • 9
  • 20
  • 1
    A more detailed answer to this suggestion follows: https://stackoverflow.com/a/63382231/13499978 – emgf_co Jun 21 '21 at 16:02
2

The last comment is very useful.

  1. Install the package with

    pip install addcopyfighandler

  2. Import the module after importing matplotlib, for instance:

    import matplotlib.pyplot as plt
    import addcopyfighandler

  3. Use ctr + C to copy the Figure to the clipboard

And enjoy.

emgf_co
  • 343
  • 2
  • 12
  • 1
    This answer would be far more complete (and informative and respectable) if you explained what the two lines between `import matplotlib.pyplot as plt` and `import addcopyfighandler` actually achieved and why they were necessary. – Bernd Wechner Feb 28 '23 at 02:51
  • Thanks. In fact, these two lines are unnecessary. I removed them. – emgf_co Mar 09 '23 at 15:09
2

Building on the solution described in EelkeSpaak's answer, we can write a function to do the work instead of monkey-patching matplotlib's Figure class:

import io
import matplotlib.pyplot as plt
import numpy as np

from PyQt5.QtGui import QImage
from PyQt5.QtWidgets import QApplication

# Example figure.
fig, ax = plt.subplots()
X = np.linspace(0, 2*np.pi)
Y = np.sin(X)
ax.plot(X, Y)

def add_figure_to_clipboard(event):
    if event.key == "ctrl+c":
       with io.BytesIO() as buffer:
            fig.savefig(buffer)
            QApplication.clipboard().setImage(QImage.fromData(buffer.getvalue()))

fig.canvas.mpl_connect('key_press_event', add_figure_to_clipboard)

Please note that this variant uses Qt5.

Guimoute
  • 4,407
  • 3
  • 12
  • 28
2

I enabled ctrl-c to copy figures to the clipboard by adding toolbar: toolmanager to my matplotlibrc.

  1. Locate your rc file by typing
  import matplotlib
  print(matplotlib.matplotlib_fname())

in the python interpreter.

Then paste

toolbar: toolmanager

into the file using your favorite editor.

Alternatively, the following bash one-liner will do the trick:

echo "toolbar: toolmanager" >> $(python -c "import matplotlib;print(matplotlib.matplotlib_fname())")

Note that this needs to be done for each python interpreter. So if you make a new anaconda environment, you will have to repeat the process.

kilodalton
  • 111
  • 1
  • 2