47

How can I copy to the clipboard the output of a cell in a Jupyter notebook, without having to select it with drag-and-drop?

enter image description here

Franck Dernoncourt
  • 77,520
  • 72
  • 342
  • 501
  • 5
    Not exactly on point, because you would need to select with the mouse, but I found this helpful. You can use `Shift`+`Right mouse button` to access the browser's native context menu. (Works in Chrome 76, and should work in most modern browsers). – Stephen McAteer Aug 29 '19 at 22:55

10 Answers10

34

Jupyter notebook runs in browser so you can use some javascript to select and copy cells to clipboard. After some trial and error I came up with this bookmarklet:

javascript:(function%20()%20%7B%20function%20SelectText(element)%20%7B%20var%20range%3B%20var%20selection%3B%20if%20(document.body.createTextRange)%20%7B%20range%20%3D%20document.body.createTextRange()%3B%20range.moveToElementText(element)%3B%20range.select()%3B%20copy2clipboard(range.text%2C%20element.innerHTML)%3B%20document.getSelection().removeAllRanges()%3B%20%7D%20else%20if%20(window.getSelection)%20%7B%20selection%20%3D%20window.getSelection()%3B%20range%20%3D%20document.createRange()%3B%20range.selectNodeContents(element)%3B%20selection.removeAllRanges()%3B%20selection.addRange(range)%3B%20copy2clipboard(selection.toString()%2C%20element.innerHTML)%3B%20selection.removeAllRanges()%3B%20%7D%20%7D%3B%20function%20copy2clipboard(text%2C%20html)%20%7B%20function%20listener(e)%20%7B%20e.clipboardData.setData('text%2Fplain'%2C%20text)%3B%20e.clipboardData.setData('text%2Fhtml'%2C%20html)%3B%20e.preventDefault()%3B%20%7D%20document.addEventListener('copy'%2C%20listener)%3B%20document.execCommand('copy')%3B%20document.removeEventListener('copy'%2C%20listener)%3B%20%7D%3B%20%24('%23notebook-container').on('mouseenter'%2C%20'.input%2C%20.output_wrapper'%2C%20function%20()%20%7B%20if%20(%24(this).find('i%3Alast').length)%20%7B%20%24(this).find('i%3Alast').show()%3B%20%7D%20else%20%7B%20%24(this).css(%7B%20'position'%3A%20'relative'%20%7D).append(%24('%3Ci%20style%3D%22position%3Aabsolute%3B%20top%3A7px%3B%20left%3A%207px%3B%22%20class%3D%22fa-copy%20fa%22%3E%3C%2Fi%3E').on('click'%2C%20function%20()%20%7B%20SelectText(%24(this).parent().find('.input_area%2C%20.output')%20%5B0%5D)%3B%20%24(this).slideUp()%3B%20%7D))%3B%20%7D%20%7D)%3B%20%24('%23notebook-container').on('mouseleave'%2C%20'.input%2C%20.output_wrapper'%2C%20function%20()%20%7B%20%24(this).find('i%3Alast').hide()%3B%20%7D)%3B%20%7D)%20()%3B

Add it to your bookmarks and run it on a notebook page.

How it works

  1. For every input and output cell it adds a small copy icon that shows on hover.
  2. Clicking on copy icon selects a corresponding cell content, sends it to clipboard and then deselects it. Content is copied in text/plain and text/html format so it can be used to copy text, tables, images and plots with formatting.
  3. After coping, icon disappears to give some feedback and shows on next hover event.

It should work on any modern browser including IE11.

Here is decoded source:

(function () {
  function SelectText(element) {
    var range;
    var selection;
    if (document.body.createTextRange) {
      range = document.body.createTextRange();
      range.moveToElementText(element);
      range.select();
      copy2clipboard(range.text, element.innerHTML);
      document.getSelection().removeAllRanges();
    } else if (window.getSelection) {
      selection = window.getSelection();
      range = document.createRange();
      range.selectNodeContents(element);
      selection.removeAllRanges();
      selection.addRange(range);
      copy2clipboard(selection.toString(), element.innerHTML);
      selection.removeAllRanges();
    }
  };
  function copy2clipboard(text, html) {
    function listener(e) {
      e.clipboardData.setData('text/plain', text);
      e.clipboardData.setData('text/html', html);
      e.preventDefault();
    }
    document.addEventListener('copy', listener);
    document.execCommand('copy');
    document.removeEventListener('copy', listener);
  };
  $('#notebook-container').on('mouseenter', '.input, .output_wrapper', function () {
    if ($(this).find('i:last').length) {
      $(this).find('i:last').show();
    } else {
      $(this).css({
        'position': 'relative'
      }).append($('<i style=\"position:absolute; top:7px; left: 7px;\" class=\"fa-copy fa\"></i>').on('click', function () {
        SelectText($(this).parent().find('.input_area, .output') [0]);
        $(this).slideUp();
      }));
    }
  });
  $('#notebook-container').on('mouseleave', '.input, .output_wrapper', function () {
    $(this).find('i:last').hide();
  });
}) ();

Bookmarklet is created by removing newlines from code and running it through encodeURIComponent() function.

Old answer

There are several ways to copy data to clipboard in python using tkinter, win32 or ctypes. But if you are using Jupyter notebook, you probably also using pandas.

import pandas as pd
df = pd.DataFrame(['Copy me to clipboard'])
df.to_clipboard(index=False,header=False)
Community
  • 1
  • 1
mx0
  • 6,445
  • 12
  • 49
  • 54
  • thanks. It's a bit inconvenient to have to add such piece of code in each cell the output of which one wishes to copy to the clipboard though. – Franck Dernoncourt May 28 '17 at 17:23
  • 2
    I agree - isn't there a way to just copy paste without it selecting the entire page? – Reddspark Aug 23 '17 at 16:36
  • 1
    Also, this would'nt work if your jupyter server is running on a different machine. – Shayan RC Oct 14 '17 at 06:59
  • 2
    @FranckDernoncourt I've added better solution. – mx0 Apr 05 '18 at 19:44
  • 1
    OMG you have just improved my life so much! This also enables reasonable copy+paste of tables (pandas!) into tools like Evernote and OneNote, for which you really want the HTML. – srs Aug 24 '18 at 09:06
  • 3
    I LOVE THIS! Here's the one liner: `pd.DataFrame(['Copy me to clipboard']).to_clipboard(index=False,header=False)` so you don't create a retained data frame. – RufusVS Sep 17 '18 at 16:29
  • I just tried the trick, but multiline strings get pasted with \n instead of actually generating new lines. Anyway to get the formatted string out so it pastes with newlines? – RufusVS Sep 17 '18 at 16:34
  • @RufusVS do you mean javascript or pandas version? – mx0 Sep 18 '18 at 17:03
  • I was trying to use the pandas version as in my earlier comment, but the main thing is: I generate a table which appears in the cells output. I then copy and paste from the output and paste it into a cell. Format is maintained with manual cut-and-paste. Lazy as I am, I'd like the cell to put the output to the clipboard directly for immediate pasting (so I don't have to go through the area-select process.) I'll see if I can make the javascript answer work for me. – RufusVS Sep 18 '18 at 17:49
  • @RufusVS try passing `line_terminator=''` to `to_clipboard()`. Default value is `\n`. – mx0 Sep 18 '18 at 18:27
  • @mx0 pd.DataFrame.to_clipboard() doesn't recognize line_terminator as a keyword argument. It has sep, which didn't seem to help. – RufusVS Sep 18 '18 at 21:38
  • 2
    refer [here](https://mreidsma.github.io/bookmarklets/installing.html) on how to run bookmarklet – Venkatachalam May 01 '20 at 10:14
  • This is great. Can it be added to [jupyter_contrib_nbextensions](https://github.com/ipython-contrib/jupyter_contrib_nbextensions)? – omasoud Jan 06 '22 at 05:44
21

You can try using pyperclip - a third-party package that copies strings to the system clipboard.

Given

import pyperclip as clip


# Sample Data
res = [(str(x*100), x) for x in range(1, 10)]
res

Output

[('100', 1), ('200', 2), ('300', 3),
 ('400', 4), ('500', 5), ('600', 6), 
 ('700', 7), ('800', 8), ('900', 9)]

Code

clip.copy(f"{res}")
#clip.copy("{}".format(res))                           # python < 3.6
clip.paste()                                           # or Ctrl + V

Output

[('100', 1), ('200', 2), ('300', 3),
 ('400', 4), ('500', 5), ('600', 6),
 ('700', 7), ('800', 8), ('900', 9)]
pylang
  • 40,867
  • 14
  • 129
  • 121
19

I use Jupyter Labs. You can right click on the output cell that you want to copy and select

Create New View for Output. That will put the output in a separate screen. On the new output screen, it will let you copy using CRTL + C or using right click.

Hope this helps.

cdon045
  • 191
  • 1
  • 2
5

This uses the mouse, but requires no dragging (which can take a long time if you have a lot of pages of text) and is simpler than the code solutions:

  1. Select the first character of the output enter image description here
  2. Go to the bottom of the output by using the scrollbar (this is the faster part)
  3. Shift-click the bottom of the output, extending the selection from first to last character
  4. Hit ctrl-C to copy
4

On Ubuntu 19.10 / Firefox browser, I can select output cell content as a whole by clicking 3 times consecutively, then as usual CTRL+C to copy.

RobC
  • 22,977
  • 20
  • 73
  • 80
bhakyuz
  • 97
  • 4
4

This can work in Jupyter Lab 3.1.4. Right-click (or click with two fingers on a Mac trackpad) in the cell output area.

A menu will pop up, where the top option is "Copy Output to Clipboard".

menu

ELinda
  • 2,658
  • 1
  • 10
  • 9
1

In the example below the actual text is not output (though it could be if changing line 6 of the function) instead the one line confirmation that a number of lines have been made available on the clipboard is shown.

The all_data_str is a string whose content will be made available on the clipboard, write your own generation function named dump_data_array.

The paste action is triggered when the user clicks a button which invokes the function:

def on_button_clipboard(b):
    out_data.clear_output()
    all_data_str=dump_data_array(da)
    with out_data:
        lineCount=all_data_str.count('\n')-1;
        html_div = '<div id="pasting_to_clipboard">'+str(lineCount)+' lines pasted, you can now ^V into Excel</div>'
        display(HTML(html_div))
        js = """<script>
function copyToClipboard(text) {
    var dummy = document.createElement("textarea");
    document.body.appendChild(dummy);
    dummy.value = text;
    dummy.select();
    document.execCommand("copy");
    document.body.removeChild(dummy);
}
        </script>"""
        display(HTML(js))
        js2 = "<script>copyToClipboard(`" + all_data_str + "`);</script>"
        display(HTML(js2))
jluu
  • 347
  • 3
  • 7
0

On MacOs using pbcopy and pbpaste:


[1]: copy_value = 'Copy This'

# Copy value to clipboard
[2]: !echo {copy_value} | pbcopy

# Or, copy value to clipboard without trailing newline
[3]: !echo {copy_value} | tr -d '\n'| pbcopy

# Paste value from clipboard
[4]: paste_value = !pbpaste

# Confirm
[5]: copy_value == paste_value[0]
[5]: True

Stipy
  • 51
  • 3
0

for e.g. colab:

from IPython.display import HTML
text = 'hello'
HTML(f"<button onclick=navigator.clipboard.writeText('{text}')>Copy</button>")
o17t H1H' S'k
  • 2,541
  • 5
  • 31
  • 52
-1
  1. Select text of output cell.
  2. Click and drag content into a text editor (other window). Finish.
  • The first sentence of the question state "...without having to select it with drag-and-drop?" – Tzane Aug 29 '23 at 13:52