Skip to content

Instantly share code, notes, and snippets.

@mprat
Last active January 18, 2024 20:22
Show Gist options
  • Save mprat/a843b08e315621d91a667124a243abeb to your computer and use it in GitHub Desktop.
Save mprat/a843b08e315621d91a667124a243abeb to your computer and use it in GitHub Desktop.
nbconvert configuration for converting a Jupyter notebook into an HTML output with images saved separately, intended to be embedded into a Jekyll site.
{%- extends 'display_priority.tpl' -%}
{% block codecell %}
<div class="cell border-box-sizing code_cell rendered">
{{ super() }}
</div>
{%- endblock codecell %}
{% block input_group -%}
<div class="input">
{{ super() }}
</div>
{% endblock input_group %}
{% block output_group %}
<div class="output_wrapper">
<div class="output">
{{ super() }}
</div>
</div>
{% endblock output_group %}
{% block in_prompt -%}
<div class="prompt input_prompt">
{%- if cell.execution_count is defined -%}
In&nbsp;[{{ cell.execution_count|replace(None, "&nbsp;") }}]:
{%- else -%}
In&nbsp;[&nbsp;]:
{%- endif -%}
</div>
{%- endblock in_prompt %}
{% block empty_in_prompt -%}
<div class="prompt input_prompt">
</div>
{%- endblock empty_in_prompt %}
{#
output_prompt doesn't do anything in HTML,
because there is a prompt div in each output area (see output block)
#}
{% block output_prompt %}
{% endblock output_prompt %}
{% block input %}
<div class="inner_cell">
<div class="input_area">
{{ cell.source | highlight_code(metadata=cell.metadata) }}
</div>
</div>
{%- endblock input %}
{% block output %}
<div class="output_area">
{% block output_area_prompt %}
<div class="prompt output_prompt">
{%- if cell.execution_count is defined -%}
Out[{{ cell.execution_count|replace(None, "&nbsp;") }}]:
{%- else -%}
Out[&nbsp;]:
{%- endif -%}
</div>
{% endblock output_area_prompt %}
{{ super() }}
</div>
{% endblock output %}
{% block markdowncell scoped %}
<div class="cell border-box-sizing text_cell rendered">
{{ self.empty_in_prompt() }}
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
{{ cell.source | markdown2html | strip_files_prefix }}
</div>
</div>
</div>
{%- endblock markdowncell %}
{% block unknowncell scoped %}
unknown type {{ cell.type }}
{% endblock unknowncell %}
{% block execute_result -%}
{%- set extra_class="output_execute_result" -%}
{% block data_priority scoped %}
{{ super() }}
{% endblock %}
{%- set extra_class="" -%}
{%- endblock execute_result %}
{% block stream_stdout -%}
<div class="output_subarea output_stream output_stdout output_text">
<pre>
{{- output.text | ansi2html -}}
</pre>
</div>
{%- endblock stream_stdout %}
{% block stream_stderr -%}
<div class="output_subarea output_stream output_stderr output_text">
<pre>
{{- output.text | ansi2html -}}
</pre>
</div>
{%- endblock stream_stderr %}
{% block data_svg scoped -%}
<div class="output_svg output_subarea {{ extra_class }}">
{%- if output.svg_filename %}
<img src="{{ output.svg_filename | jekyllimgurl }}"
{%- else %}
{{ output.data['image/svg+xml'] | svg_filter }}
{%- endif %}
</div>
{%- endblock data_svg %}
{% block data_html scoped -%}
<div class="output_html rendered_html output_subarea {{ extra_class }}">
{{ output.data['text/html'] }}
</div>
{%- endblock data_html %}
{% block data_markdown scoped -%}
<div class="output_markdown rendered_html output_subarea {{ extra_class }}">
{{ output.data['text/markdown'] | markdown2html }}
</div>
{%- endblock data_markdown %}
{% block data_png scoped %}
<div class="output_png output_subarea {{ extra_class }}">
{%- if 'image/png' in output.metadata.get('filenames', {}) %}
<img src="{{ output.metadata.filenames['image/png'] | jekyllimgurl }}"
{%- else %}
<img src="data:image/png;base64,{{ output.data['image/png'] }}"
{%- endif %}
{%- set width=output | get_metadata('width', 'image/png') -%}
{%- if width is not none %}
width={{ width }}
{%- endif %}
{%- set height=output | get_metadata('height', 'image/png') -%}
{%- if height is not none %}
height={{ height }}
{%- endif %}
{%- if output | get_metadata('unconfined', 'image/png') %}
class="unconfined"
{%- endif %}
>
</div>
{%- endblock data_png %}
{% block data_jpg scoped %}
<div class="output_jpeg output_subarea {{ extra_class }}">
{%- if 'image/jpeg' in output.metadata.get('filenames', {}) %}
<img src="{{ output.metadata.filenames['image/jpeg'] | jekyllimgurl }}"
{%- else %}
<img src="data:image/jpeg;base64,{{ output.data['image/jpeg'] }}"
{%- endif %}
{%- set width=output | get_metadata('width', 'image/jpeg') -%}
{%- if width is not none %}
width={{ width }}
{%- endif %}
{%- set height=output | get_metadata('height', 'image/jpeg') -%}
{%- if height is not none %}
height={{ height }}
{%- endif %}
{%- if output | get_metadata('unconfined', 'image/jpeg') %}
class="unconfined"
{%- endif %}
>
</div>
{%- endblock data_jpg %}
{% block data_latex scoped %}
<div class="output_latex output_subarea {{ extra_class }}">
{{ output.data['text/latex'] }}
</div>
{%- endblock data_latex %}
{% block error -%}
<div class="output_subarea output_text output_error">
<pre>
{{- super() -}}
</pre>
</div>
{%- endblock error %}
{%- block traceback_line %}
{{ line | ansi2html }}
{%- endblock traceback_line %}
{%- block data_text scoped %}
<div class="output_text output_subarea {{ extra_class }}">
<pre>
{{- output.data['text/plain'] | ansi2html -}}
</pre>
</div>
{%- endblock -%}
{%- block data_javascript scoped %}
{% set div_id = uuid4() %}
<div id="{{ div_id }}"></div>
<div class="output_subarea output_javascript {{ extra_class }}">
<script type="text/javascript">
var element = $('#{{ div_id }}');
{{ output.data['application/javascript'] }}
</script>
</div>
{%- endblock -%}
{%- block data_widget_state scoped %}
{% set div_id = uuid4() %}
{% set datatype_list = output.data | filter_data_type %}
{% set datatype = datatype_list[0]%}
<div id="{{ div_id }}"></div>
<div class="output_subarea output_widget_state {{ extra_class }}">
<script type="text/javascript">
var element = $('#{{ div_id }}');
</script>
<script type="{{ datatype }}">
{{ output.data[datatype] | json_dumps }}
</script>
</div>
{%- endblock data_widget_state -%}
{%- block data_widget_view scoped %}
{% set div_id = uuid4() %}
{% set datatype_list = output.data | filter_data_type %}
{% set datatype = datatype_list[0]%}
<div id="{{ div_id }}"></div>
<div class="output_subarea output_widget_view {{ extra_class }}">
<script type="text/javascript">
var element = $('#{{ div_id }}');
</script>
<script type="{{ datatype }}">
{{ output.data[datatype] | json_dumps }}
</script>
</div>
{%- endblock data_widget_view -%}
{%- block footer %}
{% set mimetype = 'application/vnd.jupyter.widget-state+json'%}
{% if mimetype in nb.metadata.get("widgets",{})%}
<script type="{{ mimetype }}">
{{ nb.metadata.widgets[mimetype] | json_dumps }}
</script>
{% endif %}
{{ super() }}
{%- endblock footer-%}
def jekyllurl(path):
"""
Take the filepath of an image output by the ExportOutputProcessor
and convert it into a URL we can use with Jekyll
"""
return path.replace("../..", "")
def svg_filter(svg_xml):
"""
Remove the DOCTYPE and XML version lines from
the inline XML SVG
"""
svgstr = "".join(svg_xml)
start_index = svgstr.index("<svg")
end_index = svgstr.index("</svg>")
return svgstr[start_index:end_index + 6]
c = get_config()
c.NbConvertApp.export_format = 'html'
c.NbConvertApp.output_files_dir = '../../assets/imgs/{notebook_name}'
c.HTMLExporter.preprocessors = [
'nbconvert.preprocessors.ExecutePreprocessor',
'nbconvert.preprocessors.coalesce_streams',
'nbconvert.preprocessors.ExtractOutputPreprocessor']
c.HTMLExporter.template_file = 'jekyll.tpl'
c.HTMLExporter.filters = {"jekyllimgurl": jekyllurl, "svg_filter": svg_filter}
c.ExecutePreprocessor.allow_errors = True
c.FilesWriter.build_directory = "_includes/notebooks/"
@rdeits
Copy link

rdeits commented Jul 25, 2022

This is a comment!

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