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

Hiding code input but not output? #15

Closed
jhconning opened this issue Jan 20, 2016 · 16 comments
Closed

Hiding code input but not output? #15

jhconning opened this issue Jan 20, 2016 · 16 comments

Comments

@jhconning
Copy link

The documentation has a nice discussion of how to hide code cells and their output entirely. It is however also frequently useful to hide just the code and not the output for some or all code-cells in a notebook (e.g. to make an HTML only report). I've seen some rendered html that seems to go further by offering code-folding buttons on the rendered html.

Is there a way to hide just the code input but not the output with nbsphinx? For reference, with jupyter's nbconvert one can use templates and a command as such:

jupyter nbconvert your_notebook.ipynb --to html --template output_toggle_html

where the template is like the one adapted from this SO answer

@mgeier
Copy link
Member

mgeier commented Jan 21, 2016

I've heard and read about this request (with regards to nbconvert) a few times, it seems quite common.

I thought about implementing this in nbsphinx, but I wanted to wait until it's supported in the Jupyter live notebook and in nbconvert, because I wanted to re-use whatever notebook/cell metadata they are using.

I'm not really a fan of removing code completely, but I think the code-folding option would be great.

I have no clue how to do such a thing in HTML/CSS, can you provide an example for that?

Do you have an idea how this could be realized in LaTeX?
Folding would work in the literal sense on a piece of paper, but I don't think this would be a practical solution (except if you have some kind of Origami printer).
Probably the code could be collected and referenced in a "list of code cells" similar to a "list of figures"?

As a quick hack to remove all input cells, you can search for "block input" in nbsphinx.py and remove the following lines up to (but not including) the line with "endblock input".
Theoretically, you can also change this in your own template file called nbsphinx-rst.tpl in the _templates/ directory with the following content (but I didn't test if that really works):

{% extends 'nbsphinx-rst.tpl' %}
{% block input %}
{% endblock input %}

This only looses a little bit of CSS, namely padding-top: 5px;, which you should move to div.nboutput.

Completely removing the input on a per-notebook and per-cell basis would be simple, I'd just have to extend the supported notebook/cell metadata.
As I said, I would like to wait for the "official" metadata, but if you can't wait, we'd have to come up with nbsphinx-specific metadata for the time being. Any suggestions?

@jhconning
Copy link
Author

Thanks for the reply and sorry for my slow response.

I agree that it would make sense to wait for the 'official cell metadata conventions. The metadata tagging that one can now apply for creating Slideshows (enabled via the \View \Cell Toolbar \Slideshow in Jupyter) includes a 'Skip' tag. When that is chosen for a cell, that cell is not displayed in Slideshow mode. But I suspect you are talking about a different set of metadata.

Code folding would be a very nice option. Hiding all output does come in handy. I plan to write up economics lecture notes that involve many plots and optimization, but most of the students will not have had prior python exposure. I do want them to learn python but it would be nice if students, at least on a first pass, they had the option to read the rendered notebook without the code. Code for some plots in particular can get long and distracting. I want them to understand the Economics content first, and then turn on the code so that they start understanding how to use python.

I'm afraid I can't be much use with HTML/CSS, as most of this is beyond my capabilities (I'm more of an end user), but this Stackoverflow thread has HTML/javascript to add a javascript button to hide/display all code which works nicely in the notebook or nbviewer.

I did briefly try using a template file as you suggested, but it didn't seem to do anything (I put the _templates folder. I haven't had time to explore further.

Thanks again for your detailed discussion of the issue. I can live without code hiding for now but am glad to hear it is something you are considering.

@mgeier
Copy link
Member

mgeier commented Feb 5, 2016

I think the slideshow "skip" tag should be orthogonal to "nbsphinx: hidden", both are very different uses but you might want both in the same notebook.

As I said, I like code folding, but I'll not try to implement this on my own. If somebody submits a PR, I'm willing to consider it.

Sorry that I misled you about the template customization. I mixed up nbconvert templates and Sphinx templates. What I wrote works only for the latter.
In your case, you should try to directly edit the file nbsphinx.py.

I'm still not sure if your use case is acually the best use of a Jupyter notebook ...
What about having separate notebooks (or plain *.py files) that generate figures as local image files (e.g. with matplotlib's savefig() command), which you can then use in another notebook as a "normal" image.
You still wouldn't need to commit those images, they could be auto-generated on demand.
What do you think about that?

@jhconning
Copy link
Author

I agree on 'skip' and 'hidden', and also agree it's best to wait for an agreed standard.

I'm not sure if I completely understand your last suggestion. Is the idea that I'd always have paired notebooks. One with the code and savefig and another that just keeps the markdown but pulls in the images?

Something like that could be made to work but would seem to require keeping two notebook/scripts for each project. For me the beauty of jupyter notebooks -- and nbsphinx is becoming a crucial element in the workflow -- is its promise of convergence: one single document can be used as an interactive notebook, displayed as a slideshow, or rendered beautifully by Sphinx on a website or as a PDF document. If the we had the option of setting a tag to enable code-hiding/folding on some pages/cells, that would be icing on the cake. But it is not a very high priority --- my audience can learn to read or skip python code in the meantime.

I will try the edits to nbsphinx that you suggested as soon as I have time and report back when I can. Thanks again

@mgeier
Copy link
Member

mgeier commented Feb 7, 2016

I don't mean a strict one-to-one pairing, probably it makes sense to have a Jupyter notebook (or .py script) for each figure, or for a group of figures, or a huge one for all figures ...
Code that is re-used for several figures should probably be moved to a common .py file.
You can still include a nice syntax-highlighted version of that in your docs by using the literalinclude directive.

I also like the possibility to keep explanatory text, equations, images, code and resulting plots in one document, but that doesn't mean everything has to be in one single huge notebook. At some point this will also get hard to manage.
And since you seem to want your students to see the code generating the figure not at the first time they work through the text, why not just move it to a separate place and just include the resulting plot as an image and add a link to the code that generated the plots?
This way, the code wouldn't be distracting but still easily available if somebody wants to have a look.

I still think that code folding would be a nice feature to use occasionally, but it has a large potential for being over-used.

@jhconning
Copy link
Author

I will explore some of those ideas, thanks

and I am closing this issue since it does seem that any good solution involves waiting to see whatever notebook/cell metadata conventions the jupyter project settles on for hiding cells.

@keluc
Copy link

keluc commented Sep 5, 2017

With the release of [jupyter] [ANN] nbconvert 5.2.1 release it tested if its possible to hide all input. My test showed that this is indeed possible when you add an extra conf option in the init methode of class Exporter (see 'TemplateExporter'):

            config=traitlets.config.Config(
                {'HighlightMagicsPreprocessor': {'enabled': True},
                'TemplateExporter':{
                "exclude_output": False,
                "exclude_input": True,
                "exclude_input_prompt": True,
                "exclude_output_prompt": True,
                "exclude_markdown": False,
                "exclude_code_cell": False}}),
            filters={
                'convert_pandoc': convert_pandoc,
                'markdown2rst': markdown2rst,
                'get_empty_lines': _get_empty_lines,
                'extract_toctree': _extract_toctree,
                'get_output_type': _get_output_type,
                'json_dumps': json.dumps,
            })

Remaining issue: in my example above it appears that the first output prompt is not hidden. The next output prompts are hidden.

Question: if it's possible to work with (an) extra argument(s) in the source rst file in addition to the notebook name you could indicate for which notebook you want to use such settings.

PS with the release [ANN] nbconvert 5.3.0 — now with tag-based element filtering! you can do tag based filtering but that was not my use case.

@mgeier
Copy link
Member

mgeier commented Sep 6, 2017

@keluc Thanks for checking this out!

in my example above it appears that the first output prompt is not hidden

I don't know why that happens. Can you please provide an example notebook file and exact instructions how to reproduce this?

Question: if it's possible to work with (an) extra argument(s) in the source rst file in addition to the notebook name you could indicate for which notebook you want to use such settings.

Do you mean as part of the toctree directive?
I don't think it's possible to add any arguments there.
But it could be handled like most other nbsphinx options: as a global setting in conf.py and a per-notebook setting in the notebook metadata.

@keluc
Copy link

keluc commented Sep 6, 2017

Ok, I'll provide an example next week.
With respect to the 2nd element, in sphinx you can work with arguments in a directive but maybe it's not possible for the current the nbsphinx solution?
For example if you take another solution RunNotebook you could use some extra (optional) arguments like:
.. notebook:: example1.ipynb
.. notebook:: example2.ipynb True

Which can be used to tailor the config settings:

class NotebookDirective(Directive):
    ...
    required_arguments = 1
    optional_arguments = 1
   ....
    def run(self): 
        ....
        nb_path = self.arguments[0]
        #'True'=with input cells 'False' = no input cells
        try:
          nb_withInput = self.arguments[1]
        except:
          nb_withInput = 'False'
        ...

@mgeier
Copy link
Member

mgeier commented Sep 11, 2017

@keluc nbsphinx doesn't have anything like the notebook directive (although it was proposed in #33).
With nbsphinx, Jupyter notebooks are simply Sphinx source files, and those are typically controlled by a toctree directive, and I don't think that it is possible to pass options there (but of course I could be wrong).

@YohanObadia
Copy link

YohanObadia commented Jun 26, 2019

Would it not be possible to rely on a notebook cell metadata information hide_input ?

{
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "hide_input": true
   }

This would allow the customization to be done on a per-cell level inside a notebook.
There are cases when you want to hide a cell and others when you might want to keep it, inside the same notebook.

@mgeier
Copy link
Member

mgeier commented Jul 28, 2019

Sure, it would be possible.

There have been previous discussions about this in #15, #17, #65, #86 and #185.

Feel free to add suggestions to these issues/PRs, or create a new PR!

I think the most reasonable course of action is to limit this feature to HTML output and implement a "toggle" button similar to the one used in https://jupyter.org/jupyter-book/features/hiding.

I'm open for a PR is somebody wants to implement this.

@psychemedia
Copy link

psychemedia commented Nov 23, 2019

I note that nbconvert has a --no-input flag to hide input cells on export [release note and PR].

I also note (nbformat docs) the following metadata elements supported at the cell level in the jupyter notebook namespace:

Key Value Interpretation
source_hidden bool Whether the cell's source should be shown
outputs_hidden bool Whether the cell's outputs should be shown

although I'm still not clear how / when they apply and at what versions of various things (nbconvert, notebook JupyterLab they started to apply, if at all.

Tag based filtering in nbconvert is also possible [docs] using the TagRemovePreprocessor and commands of the form jupyter nbconvert my.ipynb --TagRemovePreprocessor.remove_cell_tags='{"my_removetag"}' and the following traitlets:

  • remove_cell_tags: removes cells
  • remove_input_tags: removes inputs
  • remove_all_outputs_tag: removes all outputs
  • remove_single_output_tag: removes individual outputs

@ferrine
Copy link

ferrine commented Apr 30, 2023

Hi! I was really struggling to configure nbsphinx for my needs.

  • I had to patch it so I can control the behaviour of input and output display.
  • I would say the proposed way in the documentation is totally not enough.
  • I also found that I need more from the template itself in future.

I leave this snippet for those who:

  1. is looking for more control over the nbsphinx template
  2. just want to exclude input/output cells based on tags
# ./ext/nbsphinx.py
# extensions = [..., "ext.nbsphinx", ...]
"""Patching latest nbsphinx
"""
from nbsphinx import RST_TEMPLATE
from nbsphinx import setup
import nbsphinx
import re


BLOCK_REGEX = r'(({{% block {block} -%}}\n)(.*?)({{% endblock {block} %}}\n))'
PATCH_TEMPLATE = r'{{% block {block} -%}}\n{patch}{{% endblock {block} %}}\n'


def search(block, template):
    pattern = BLOCK_REGEX.format(block=block)
    m = re.search(pattern, template, re.DOTALL)
    assert m is not None, f"Block {block} is not found"
    return m.group(3)

def patch(block, template, patch):
    pattern = BLOCK_REGEX.format(block=block)
    sub = PATCH_TEMPLATE.format(block=block, patch=patch)
    return re.sub(pattern, sub, template, flags=re.DOTALL)

def remove_block_on_tag(block, tags, template):
    content = search(block, RST_TEMPLATE)
    conditions = [f"{t!r} in cell.metadata.tags" for t in tags]
    content1 = f"""\
{{%- if {" or ".join(conditions)} -%}}
{{%- else -%}}
{content}
{{%- endif -%}}
"""
    return patch(block, template, content1)

RST_TEMPLATE = remove_block_on_tag("input", ["remove_cell", "remove_input"], RST_TEMPLATE)
RST_TEMPLATE = remove_block_on_tag("nboutput", ["remove_cell", "remove_output"], RST_TEMPLATE)
nbsphinx.RST_TEMPLATE = RST_TEMPLATE
__all__ = ["setup"]

@kostrykin
Copy link

I note that nbconvert has a --no-input flag to hide input cells on export [release note and PR].

I also note (nbformat docs) the following metadata elements supported at the cell level in the jupyter notebook namespace:

Key Value Interpretation
source_hidden bool Whether the cell's source should be shown
outputs_hidden bool Whether the cell's outputs should be shown
although I'm still not clear how / when they apply and at what versions of various things (nbconvert, notebook JupyterLab they started to apply, if at all.

Tag based filtering in nbconvert is also possible [docs] using the TagRemovePreprocessor and commands of the form jupyter nbconvert my.ipynb --TagRemovePreprocessor.remove_cell_tags='{"my_removetag"}' and the following traitlets:

  • remove_cell_tags: removes cells
  • remove_input_tags: removes inputs
  • remove_all_outputs_tag: removes all outputs
  • remove_single_output_tag: removes individual outputs

Just came here because I'm looking for a way to remove the source of a cell when using nbsphinx. Just to be clear: source_hidden does not work with nbsphinx, right? Here is the full metadata code that I tried:

   "metadata": {
    "jupyter": {
     "source_hidden": true
    }
   },

@mgeier
Copy link
Member

mgeier commented Sep 1, 2024

Just to be clear: source_hidden does not work with nbsphinx, right?

Correct, this is not implemented yet.

I have mentioned multiple issues and open PRs here: #15 (comment)
In the meantime there have been newer developments in #303 and #436.

Feel free to help out!

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

No branches or pull requests

7 participants