Skip to content

Commit

Permalink
Allow the default thumbnail to be the last image in a notebook
Browse files Browse the repository at this point in the history
The `nbsphinx_thumbnail_default` configuration key controls whether
the default thumbnail for a notebook is the default icon, if it is
'none' (the default). If it is 'last' and a notebook has any valid
image outputs, the last of these will be used for the thumbnail.
  • Loading branch information
angus-g committed Jan 30, 2023
1 parent b487710 commit dd19350
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 27 deletions.
10 changes: 10 additions & 0 deletions doc/configuration.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,16 @@
"See [Specifying Thumbnails](gallery/thumbnail-from-conf-py.ipynb)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `nbsphinx_thumbnail_default`\n",
"\n",
"If `'none'`, the default image will be used if one isn't specified (see [Specifying Thumbnails](gallery/thumbnail-from-conf-py.ipynb)).\n",
"Otherwise, if `'last'`, the last image in the notebook will be used as a thumbnail if one isn't specified."
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down
90 changes: 63 additions & 27 deletions src/nbsphinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@
'text/plain',
)

MIME_TYPE_SUFFIXES = {
'image/svg+xml': '.svg',
'image/png': '.png',
'image/jpeg': '.jpg',
}

# The default rst template name is changing in nbconvert 6, so we substitute
# it in to the *extends* directive.
RST_TEMPLATE = """
Expand Down Expand Up @@ -928,6 +934,7 @@ def from_notebook_node(self, nb, resources=None, **kw):
resources['nbsphinx_widgets'] = True

thumbnail = {}
thumbnail_filename = None

def warning(msg, *args):
logger.warning(
Expand All @@ -937,64 +944,92 @@ def warning(msg, *args):
thumbnail['filename'] = _BROKEN_THUMBNAIL

for cell_index, cell in enumerate(nb.cells):
if 'nbsphinx-thumbnail' in cell.metadata:
# figure out if this cell is explicitly tagged
# but if it's not, we'll default to the last figure in the notebook
# if one exists
metadata_cell = 'nbsphinx-thumbnail' in cell.metadata
tagged_cell = 'nbsphinx_thubnail' in cell.metadata.get('tags',[])
thumbnail_cell = metadata_cell or tagged_cell

if metadata_cell:
data = cell.metadata['nbsphinx-thumbnail'].copy()
output_index = data.pop('output-index', -1)
tooltip = data.pop('tooltip', '')

if data:
warning('Invalid key(s): %s', set(data))
break
elif 'nbsphinx-thumbnail' in cell.metadata.get('tags', []):
else:
output_index = -1
tooltip = ''
else:
continue

if cell.cell_type != 'code':
warning('Only allowed in code cells; cell %s has type "%s"',
if thumbnail_cell:
warning('Only allowed in code cells; cell %s has type "%s"',
cell_index, cell.cell_type)
break

continue

if thumbnail and thumbnail_cell:
warning('Only allowed onced per notebook')
break
if thumbnail:
warning('Only allowed once per notebook')
break

if not cell.outputs:
warning('No outputs in cell %s', cell_index)
break
if tooltip:
thumbnail['tooltip'] = tooltip
if thumbnail_cell:
warning('No outputs in cell %s', cell_index)
break

continue

if output_index == -1:
output_index = len(cell.outputs) - 1
elif output_index >= len(cell.outputs):
warning('Invalid "output-index" in cell %s: %s',
cell_index, output_index)
cell_index, output_index)
break

out = cell.outputs[output_index]

if out.output_type not in {'display_data', 'execute_result'}:
warning('Unsupported output type in cell %s/output %s: "%s"',
if thumbnail_cell:
warning('Unsupported output type in cell %s/output %s: "%s"',
cell_index, output_index, out.output_type)
break
break

continue

for mime_type in DISPLAY_DATA_PRIORITY_HTML:
if mime_type not in out.data:
continue
if mime_type == 'image/svg+xml':
suffix = '.svg'
elif mime_type == 'image/png':
suffix = '.png'
elif mime_type == 'image/jpeg':
suffix = '.jpg'
else:
if mime_type not in out.data or mime_type not in MIME_TYPE_SUFFIXES:
continue
thumbnail['filename'] = '{}_{}_{}{}'.format(

thumbnail_filename = '{}_{}_{}{}'.format(
resources['unique_key'],
cell_index,
output_index,
suffix,
MIME_TYPE_SUFFIXES[mime_type],
)
break
else:
warning('Unsupported MIME type(s) in cell %s/output %s: %s',
if thumbnail_cell:
warning('Unsupported MIME type(s) in cell %s/output %s: %s',
cell_index, output_index, set(out.data))
break

continue

if thumbnail_cell:
thumbnail['filename'] = thumbnail_filename
if tooltip:
thumbnail['tooltip'] = tooltip

break

else:
# default to the last figure in the notebook, if it's a valid thumbnail
if thumbnail_filename and config.nbsphinx_thumbnail_default == 'last':
thumbnail['filename'] = thumbnail_filename

resources['nbsphinx_thumbnail'] = thumbnail
return rststr, resources

Expand Down Expand Up @@ -2441,6 +2476,7 @@ def setup(app):
app.add_config_value('nbsphinx_widgets_path', None, rebuild='html')
app.add_config_value('nbsphinx_widgets_options', {}, rebuild='html')
app.add_config_value('nbsphinx_thumbnails', {}, rebuild='html')
app.add_config_value('nbsphinx_thumbnail_default', 'none', rebuild='html')
app.add_config_value('nbsphinx_assume_equations', True, rebuild='env')

app.add_directive('nbinput', NbInput)
Expand Down

0 comments on commit dd19350

Please sign in to comment.