Skip to content
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

Exporting a single jupyter cell output #3039

Open
toqduj opened this issue Nov 11, 2017 · 21 comments
Open

Exporting a single jupyter cell output #3039

toqduj opened this issue Nov 11, 2017 · 21 comments

Comments

@toqduj
Copy link

toqduj commented Nov 11, 2017

I checked the current issues and could not find a similar request:

We would very much like to be able to export the output from a highlighted cell to PDF or PNG or anything, really. Apparently this is possible in Mathematica, but not yet in Jupyter Notebook.

The background comes from this: We're able to style Pandas Dataframes to show them just the way we need for our certification reports. However, after that, there is no "pyplot.savefig"-like function to store the output thereof in a format that would allow us to include it in other documents.

Googling for solutions to such issues brings up a host of stackOverflow semi-answers that offer only a very convoluted way to recreate / rebuild the table somewhere else (using plotly or matplotlib tables). That's a big waste of the effort put into the pandas styler.

Since Jupyter already allows you to export the entire notebook, is it possible to implement this on a per-cell basis as well, preferably only the cell output?

@jcb91
Copy link
Contributor

jcb91 commented Nov 12, 2017

To clarify a little, what actually is the output you're seeing? I guess whatever the pyplot renderer provides? Could you provide an example notebook (e.g. as a gist) that produces the kind of output you'd like to be able to save?

@dsblank
Copy link
Member

dsblank commented Nov 12, 2017 via email

@takluyver
Copy link
Member

You should be able to do something like this:

data, metadata = get_ipython().display_formatter.format(obj)
with open('table.html', 'w') as f:
    f.write(data['text/html'])  # Assuming the object has an HTML representation

That could be wrapped up in a little utility function.

For a pandas DataFrame, it's going to wind up calling df.to_html() - you can call that directly to have more control over the options, but the snippet above should work for anything that defines an HTML repesentation.

@toqduj
Copy link
Author

toqduj commented Nov 14, 2017

Good point. Hang on while I fish out an example... Take, for example this dataFrame with styled formatting:

inputDict = {
    "$D_n$" : [np.pi, np.sqrt(np.pi), 2 * np.sqrt(np.pi)],
    "$\sigma_n$" : 2*[np.pi, np.sqrt(np.pi), 2 * np.sqrt(np.pi)],
    "$\phi$" : 3*[np.pi, np.sqrt(np.pi), 2 * np.sqrt(np.pi)]
}

HStest = pandas.DataFrame() # we populate the HStest DataFrame with the items in the tuple.

for key, item in inputDict.items():
    indata = {
        "parameter" : key,
        "mean" : item[0],
        "standard deviation" : item[1],
        "expanded standard deviation" : item[2],
        "relative expanded standard deviation" : item[2] / item[0]
    }
    HStest = HStest.append(pandas.DataFrame(data = indata, index = [0]), ignore_index = True)

HStest.set_index("parameter", inplace = True) 

hs = HStest.loc[:,[  # show the content in this order:
    "mean", 
    "standard deviation", 
    "expanded standard deviation", 
    "relative expanded standard deviation"]].style.format(
    {"mean": '{:.2e}', # use this style for these columns:
     "standard deviation": '{:.2e}', 
     "expanded standard deviation": '{:.2e}', 
     "relative expanded standard deviation": "{:.2%}"})

If I display hs, I see the following nicely formatted table:
screen shot 2017-11-14 at 15 11 19

However, when I export the HTML code that comes out of hs.render(), which is what looks pretty in jupyter notebook, and load that in a separate tab, I only see the following:

screen shot 2017-11-14 at 15 13 32

Gone is the nice style sheet, the rendering of the LaTex labels, etc, I only see a shit table with some cruft at the top. There seems to be no way of exporting the look of the table in the JP Notebook together with the table.

@takluyver
Copy link
Member

The notebook has some default CSS that applies to your output - the bits relating to tables are here:

The Latex labels are rendered by a Javascript library called Mathjax.

You could probably put the HTML output into nbconvert's HTML template, which loads the notebook's CSS and the Mathjax library, to make something like the output in the notebook.

@toqduj
Copy link
Author

toqduj commented Nov 15, 2017

@takluyver So what you're saying is: "yes, there is no easy way to export the output of a single cell" :).. However, what you mentioned might be implemented as a strategy to do just that if nbconvert is modified to allow the specification of output cells?

@takluyver
Copy link
Member

Yup. I don't think it even needs much modification of nbconvert: you could probably feed it a notebook with one cell which has one output, and use some recently added options to tell it to hide the input part of the cell.

@mpacer
Copy link
Member

mpacer commented Nov 15, 2017

In theory one could use tags as an inverse from the current tag removal rules and only include those cells that are tagged. This would mean a new preprocessor, but that's not too much.

@toqduj if you're interested, I'm going to be on vacation for a while, but you can look at https://github.com/jupyter/nbconvert/blob/master/nbconvert/preprocessors/tagremove.py to get an idea of what would need to be implemented.

Then it would be a matter of tagging the cells you want and exporting using an appropriate config file.

If you want multiple individual cells exported as separate files, you could also make it more complicated and instead of doing it as a single pass operation, create a separate document for each of your tags that you specify as being included. If you wanted only individual cells for this model that would require using a unique tag for each… but that's not impossible. This would probably be implemented as a separate exporter and not included in nbconvert core (though I could be persuaded otherwise). I would use the model we have for handling external output files in the notebook by writing a zip. That would mean that it would work with the eventual nbconvert service that I'm working on (which communicates RESTfully so it can only return a single file).

There's also another approach (that works but isn't general enough for nbconvert AFAICT) where you use one tag, and each cell with that tag is exported to a separate document. This would be implemented at the exporter level.

@mortcanty
Copy link

I'm not very familiar with nbconvert but I am writing a textbook in LaTeX which makes many references to individual cells in Jupyter notebooks. I'm resorting to screenshots converted to eps to integrate the cells into the text, not really acceptable. The ability to export a highlighted cell (both input and output) as png or eps would be fantastic. Or any trick with nbconvert which can accomplish something similar?

@takluyver
Copy link
Member

takluyver commented Dec 13, 2017

At the moment, probably the most practical approach to that situation is to use nbconvert to convert the whole notebook to latex - nbconvert --to latex notebook.ipynb - and then open the result in your editor, and copy the pieces you need into your document.

@mortcanty
Copy link

mortcanty commented Dec 14, 2017 via email

@toqduj
Copy link
Author

toqduj commented Dec 20, 2017

Screenshots and manual edits of jupyter notebooks are not really suitable for our purpose: the production of reference material certification documents with easily updated graphics for the statistical evaluation.

One solution that could make sense is that by @mpacer. While it's still not easy to do automatically, at least the graphics won't shift from one to the other, and the nice formatting of the styler wouldn't be lost...

@matanox
Copy link

matanox commented Aug 26, 2018

I humbly think that programmatically exporting pieces of a notebook to HTML (maybe other formats as well don't know) can be extra helpful, for making data available to peers that do not care about code or intermediary results on some cells. Ideally, exporting to a viewer that has different tabs, because people not used to Jupyter aren't comfortable with one long scroll. How to avoid developing too much of this to keep this feature suggestion healthy is more of an art, but this can help in regularly disseminating notebook generated data without all the fuss.

Happy to hear what other people think, and/or existing ways this can be accomplished..

@psychemedia
Copy link

psychemedia commented Feb 26, 2019

I started looking at ways of grabbing formatted pandas HTML tables into a png here. It's not very convenient though — it requires selenium automation, for a start.

import os
import time
from selenium import webdriver
 
#Via https://stackoverflow.com/a/52572919/454773
def setup_screenshot(driver,path):
    ''' Grab screenshot of browser rendered HTML.
        Ensure the browser is sized to display all the HTML content. '''
    # Ref: https://stackoverflow.com/a/52572919/
    original_size = driver.get_window_size()
    required_width = driver.execute_script('return document.body.parentNode.scrollWidth')
    required_height = driver.execute_script('return document.body.parentNode.scrollHeight')
    driver.set_window_size(required_width, required_height)
    # driver.save_screenshot(path)  # has scrollbar
    driver.find_element_by_tag_name('body').screenshot(path)  # avoids scrollbar
    driver.set_window_size(original_size['width'], original_size['height'])
 
def getTableImage(url, fn='dummy_table', basepath='.', path='.', delay=5, height=420, width=800):
    ''' Render HTML file in browser and grab a screenshot. '''
    browser = webdriver.Chrome()
 
    browser.get(url)
    #Give the html some time to load
    time.sleep(delay)
    imgpath='{}/{}.png'.format(path,fn)
    imgfn = '{}/{}'.format(basepath, imgpath)
    imgfile = '{}/{}'.format(os.getcwd(),imgfn)
 
    setup_screenshot(browser,imgfile)
    browser.quit()
    os.remove(imgfile.replace('.png','.html'))
    #print(imgfn)
    return imgpath
 
def getTablePNG(tablehtml, basepath='.', path='testpng', fnstub='testhtml'):
    ''' Save HTML table as: {basepath}/{path}/{fnstub}.png '''
    if not os.path.exists(path):
        os.makedirs('{}/{}'.format(basepath, path))
    fn='{cwd}/{basepath}/{path}/{fn}.html'.format(cwd=os.getcwd(), basepath=basepath, path=path,fn=fnstub)
    tmpurl='file://{fn}'.format(fn=fn)
    with open(fn, 'w') as out:
        out.write(tablehtml)
    return getTableImage(tmpurl, fnstub, basepath, path)
 
#call as: getTablePNG(s)
#where s is a string containing html, eg s = df.style.render()

However, I did start looking around for lighter Javascript only solutions (fragmentary notes) which might provide a better starting point? For example:

  • HTML2Canvas, which allows you to take “[s]creenshots with JavaScript” and export them as PNG files;
  • TableExport, which seems to work with jspdf (“the leading HTML5 client solution for generating PDFs”) and jsPDF-AutoTable (a “jsPDF plugin for generating PDF tables with javascript”) to allow you to export an HTML table as a PDF.

@wesinator
Copy link

Would also be useful to have a menu item to export cell code to a separate Python file.
So users don't have to manually copy and paste into a text editor

Should this be filed as a new issue ?

@psychemedia
Copy link

psychemedia commented Jul 5, 2019

In passing, I note this repo that appeared recently, but I've not had a chance to see what it actually does yet...

@als0052
Copy link

als0052 commented Feb 7, 2020

Just as a note for anyone who finds this after Jan. 2020, the Pandas API has added new features in version 1.0.0 to export to markdown tables. I haven't tried it but it sounds like it could be a workaround to OP's application.

That being said, I'd also like the ability to select a single cell in a notebook and export it as .tex. Currently I'm combing through a full exported .tex notebook to pick out the cells I want. At the very least it'd be nice to export an in cell and out cell as an image.

@TomNicholas
Copy link

TomNicholas commented Feb 9, 2020

I also think that easily saving the output of a single cell (as png/html) would be a useful feature. I think some people here are suggesting a new cell magic, while others are talking about a notebook button or right-click option?

As you said @takluyver you can do the former with nbconvert, but is the best way really to run nbconvert on the entire current notebook from within the notebook? This requires getting the name of the current notebook (already a bit of a hack apparently), and then running nbconvert on that file, but it seems circuitous. Also would there be problems if the notebook hasn't been saved? And what if the notebook is password-protected?

Might there be a better way to access the cell output using the %%capture cell magic or something? Then wrap it up to make a new %%save_output cell magic maybe?

I can use %%capture to save the png output of my cell in a rudimentary way, but that also suppresses the output of the cell, which I don't want to do, and you can only access the output in a later cell:

[1]: # setup
...  %matplotlib inline
...  import xarray as xr
...  ds = xr.tutorial.open_dataset('air_temperature')
...  da = ds['air']
...  da = da.sel(time='2014-12-31T18:00:00')

[2]: %%capture out
...  da.plot()

[3]: f = open('./output', 'wb')
...  f.write(out.outputs[1].data['image/png'])
...  f.close()

@jpjpjp
Copy link

jpjpjp commented Jan 11, 2021

I read this whole thread...and ended up taking a screenshot and using that as the PNG. Won't work when there is more than a screenful of output, but....

@rrtucci
Copy link

rrtucci commented Jan 5, 2022

I read this whole thread...and ended up taking a screenshot and using that as the PNG. Won't work when there is more than a screenful of output, but....

Even though you are half joking, IMHO there is much wisdom in your statement. It is possible to select a cell in jupyter notebooks. Why can't one extend the print screen software so that it takes a png snapshot of just the selected cell? This would include a picture of the widgets in their current state and of interactive plots

@adrijanik
Copy link

Just found this thread now when I search for a way to copy to clipboard button for the cell output or save-to-file button for the output. Although I can simply highlight all the text and copy it to clipboard, a useful feature for me would be: save-output-of-the-cell-after-it-finished-running. I have a very long output and there are some times that I just don't think I need everything saved or simply forget about saving because I'm just experimenting and then the notebook is running for an hour and I see the outputs are afterall interesting and I want to just save it to file with a single click from within jupyter notebook. It could be just a small icon that appears upon hoovering over top-right corner of a cell output or code which gives an option to save to clipboard and save to file and/or an option in Current Outputs next to toggle and clear (see below screenshot with my clunky drawings)
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.