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

Add documentation of myst-nb format #458

Merged
merged 22 commits into from
Mar 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
fb53678
Add explanation of myst-nb format
chrisjsewell Mar 17, 2020
d37f73a
Rename `nb-cell`/`nb-raw` to `code-cell`/`raw-cell`
chrisjsewell Mar 17, 2020
726e907
change extension mystnb -> mnb
chrisjsewell Mar 17, 2020
6b5d4df
Addition of MyST-NB to jupyter labextension
chrisjsewell Mar 17, 2020
790fb00
remove nbformat from front-matter
chrisjsewell Mar 17, 2020
316bc2e
remove accidental addition of notebook
chrisjsewell Mar 17, 2020
397d6ca
remove .md extension
chrisjsewell Mar 17, 2020
424756a
move myst functions functions to top of file
chrisjsewell Mar 17, 2020
62351f4
make myst's default extension `.md`
chrisjsewell Mar 17, 2020
0780e24
use only the major version of myst-parser
chrisjsewell Mar 17, 2020
3263403
Add to tests
chrisjsewell Mar 17, 2020
72a4ac7
Allow the notebook to be returned from `matches_mystnb`
chrisjsewell Mar 17, 2020
b9eb714
add test
chrisjsewell Mar 17, 2020
ee2ae39
Update test_ipynb_to_myst.py
chrisjsewell Mar 17, 2020
6d2084e
Update MyST default to `.md` in nbextension
chrisjsewell Mar 17, 2020
9735b58
Add store_line_numbers option for myst_to_notebook
chrisjsewell Mar 18, 2020
f80299a
propogate store_line_numbers to matches_mystnb
chrisjsewell Mar 18, 2020
d922b14
minor fix
chrisjsewell Mar 18, 2020
f9a4a78
Update MyST default to `.md` in labextension
chrisjsewell Mar 18, 2020
1a3796e
Update CHANGELOG.md
chrisjsewell Mar 18, 2020
71a91c3
remove unintentional file commits
chrisjsewell Mar 18, 2020
c7384a8
add link to myst-highlight
chrisjsewell Mar 18, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions demo/Benchmarking Jupytext.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@

# Let's see if we have myst-parser installed here
try:
jupytext.writes(notebook, fmt='mystnb')
JUPYTEXT_FORMATS.append('mystnb')
jupytext.writes(notebook, fmt='myst')
JUPYTEXT_FORMATS.append('myst')
except jupytext.formats.JupytextFormatError as err:
print(str(err))

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
---
jupytext:
formats: ipynb,.pct.py:percent,.lgt.py:light,.spx.py:sphinx,md,Rmd,.pandoc.md:pandoc,.myst.md:myst
text_representation:
extension: '.md'
format_name: myst
format_version: '0.7'
jupytext_version: 1.4.0+dev
kernelspec:
display_name: Python 3
language: python
name: python3
nbformat: 4
nbformat_minor: 2
---

# A quick insight at world population
Expand All @@ -15,7 +20,7 @@ In the below we retrieve population data from the
[World Bank](http://www.worldbank.org/)
using the [wbdata](https://github.com/OliverSherouse/wbdata) python package

```{nb-code} ipython3
```{code-cell} ipython3
import pandas as pd
import wbdata as wb

Expand All @@ -26,15 +31,15 @@ pd.options.display.max_columns = 20
Corresponding indicator is found using search method - or, directly,
the World Bank site.

```{nb-code} ipython3
```{code-cell} ipython3
wb.search_indicators('Population, total') # SP.POP.TOTL
# wb.search_indicators('area')
# => https://data.worldbank.org/indicator is easier to use
```

Now we download the population data

```{nb-code} ipython3
```{code-cell} ipython3
indicators = {'SP.POP.TOTL': 'Population, total',
'AG.SRF.TOTL.K2': 'Surface area (sq. km)',
'AG.LND.TOTL.K2': 'Land area (sq. km)',
Expand All @@ -45,20 +50,20 @@ data

World is one of the countries

```{nb-code} ipython3
```{code-cell} ipython3
data.loc['World']
```

Can we classify over continents?

```{nb-code} ipython3
```{code-cell} ipython3
data.loc[(slice(None), '2017-01-01'), :]['Population, total'].dropna(
).sort_values().tail(60).index.get_level_values('country')
```

Extract zones manually (in order of increasing population)

```{nb-code} ipython3
```{code-cell} ipython3
zones = ['North America', 'Middle East & North Africa',
'Latin America & Caribbean', 'Europe & Central Asia',
'Sub-Saharan Africa', 'South Asia',
Expand All @@ -67,19 +72,19 @@ zones = ['North America', 'Middle East & North Africa',

And extract population information (and check total is right)

```{nb-code} ipython3
```{code-cell} ipython3
population = data.loc[zones]['Population, total'].swaplevel().unstack()
population = population[zones]
assert all(data.loc['World']['Population, total'] == population.sum(axis=1))
```

## Stacked area plot with matplotlib

```{nb-code} ipython3
```{code-cell} ipython3
import matplotlib.pyplot as plt
```

```{nb-code} ipython3
```{code-cell} ipython3
plt.clf()
plt.figure(figsize=(10, 5), dpi=100)
plt.stackplot(population.index, population.values.T / 1e9)
Expand All @@ -97,14 +102,14 @@ selected legends) are
[on their way](https://github.com/plotly/plotly.js/pull/2960) at Plotly. For
now we just do a stacked bar plot.

```{nb-code} ipython3
```{code-cell} ipython3
import plotly.offline as offline
import plotly.graph_objs as go

offline.init_notebook_mode()
```

```{nb-code} ipython3
```{code-cell} ipython3
bars = [go.Bar(x=population.index, y=population[zone], name=zone)
for zone in zones]
fig = go.Figure(data=bars,
Expand Down
71 changes: 71 additions & 0 deletions docs/formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,77 @@ See for instance how our `World population.ipynb` notebook is [represented](http

If you wish to use that format, please install `pandoc` in version 2.7.2 or above, with e.g. `conda install pandoc -c conda-forge`.

### MyST Markdown

[MyST (Markedly Structured Text)][myst-parser] is a markdown flavor that "implements the best parts of reStructuredText". It provides a way to call Sphinx directives and roles from within Markdown,
using a *slight* extension of CommonMark markdown.
[MyST-NB][myst-nb] builds on this markdown flavor, to offer direct conversion of Jupyter Notebooks into Sphinx documents.

Similar to the jupytext Markdown format, MyST Markdown uses code blocks to contain code cells.
The difference though, is that the metadata is contained in a YAML block:

````md
```{code-cell} ipython3
---
other:
more: true
tags: [hide-output, show-input]
---

print("Hallo!")
```
````

The `ipython3` here is purely optional, as an aide for syntax highlighting.
In the round-trip, it is copied from `notebook.metadata.language_info.pygments_lexer`.

Also, where possible the conversion will use the short-hand metadata format
(see the [MyST guide](https://myst-parser.readthedocs.io/en/latest/using/syntax.html#parameterizing-directives)):

````md
```{code-cell} ipython3
:tags: [hide-output, show-input]

print("Hallo!")
```
````

Raw cells are also represented in a similare fashion:

````md
```{raw-cell}
:raw_mimetype: text/html

<b>Bold text<b>
```
````

Markdown cells are not wrapped. If a markdown cell has metadata, or
directly proceeds another markdown cell, then a [block break] will be inserted
above it, with an (optional) single line JSON representation of the metadata:

```md
+++ {"slide": true}

This is a markdown cell with metadata

+++

This is a new markdown cell with no metadata
```

See for instance how our `World population.ipynb` notebook is [represented](https://github.com/mwouts/jupytext/blob/master/demo/World%20population.myst.md#) in the `myst` format.

If you wish to use that format, please install `conda install -c conda-forge myst-parser`,
or `pip install jupytext[myst]`.

**Tip**: You can use the [myst-highlight] VS Code extension to provide better syntax highlighting for this format.

[myst-parser]: https://myst-parser.readthedocs.io
[myst-nb]: https://myst-nb.readthedocs.io
[block break]: https://myst-parser.readthedocs.io/en/latest/using/syntax.html#block-breaks
[myst-highlight]: https://marketplace.visualstudio.com/items?itemName=ExecutableBookProject.myst-highlight

## Notebooks as scripts

### The `light` format
Expand Down
20 changes: 14 additions & 6 deletions jupytext/formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
is_myst_available,
myst_version,
myst_extensions,
matches_mystnb,
)


Expand Down Expand Up @@ -196,6 +197,8 @@ def get_format_implementation(ext, format_name=None):
if formats_for_extension:
if ext in ['.md', '.markdown'] and format_name == 'pandoc':
raise JupytextFormatError('Please install pandoc>=2.7.2')
if ext in myst_extensions() and format_name == MYST_FORMAT_NAME:
raise JupytextFormatError('Please install myst-parser')

raise JupytextFormatError("Format '{}' is not associated to extension '{}'. "
"Please choose one of: {}.".format(format_name, ext,
Expand Down Expand Up @@ -229,6 +232,8 @@ def read_format_from_metadata(text, ext):

def guess_format(text, ext):
"""Guess the format and format options of the file, given its extension and content"""
if matches_mystnb(text, ext):
return MYST_FORMAT_NAME, {}
lines = text.splitlines()

metadata = read_metadata(text, ext)
Expand Down Expand Up @@ -463,11 +468,14 @@ def long_form_one_format(jupytext_format, metadata=None, update=None, auto_ext_r
if not jupytext_format:
return {}

common_name_to_ext = {'notebook': 'ipynb',
'rmarkdown': 'Rmd',
'markdown': 'md',
'script': 'auto',
'c++': 'cpp'}
common_name_to_ext = {
'notebook': 'ipynb',
'rmarkdown': 'Rmd',
'markdown': 'md',
'script': 'auto',
'c++': 'cpp',
'myst': 'md'
}
if jupytext_format.lower() in common_name_to_ext:
jupytext_format = common_name_to_ext[jupytext_format.lower()]

Expand Down Expand Up @@ -539,7 +547,7 @@ def short_form_one_format(jupytext_format):

if jupytext_format.get('format_name'):
if jupytext_format['extension'] not in ['.md', '.markdown', '.Rmd'] or \
jupytext_format['format_name'] == 'pandoc':
jupytext_format['format_name'] in ['pandoc', MYST_FORMAT_NAME]:
fmt = fmt + ':' + jupytext_format['format_name']

return fmt
Expand Down
6 changes: 3 additions & 3 deletions jupytext/jupytext.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from .languages import default_language_from_metadata_and_ext, set_main_and_cell_language
from .pep8 import pep8_lines_between_cells
from .pandoc import md_to_notebook, notebook_to_md
from .myst import myst_extensions, myst_to_notebook, notebook_to_myst
from .myst import myst_extensions, myst_to_notebook, notebook_to_myst, MYST_FORMAT_NAME


class TextNotebookConverter(NotebookReader, NotebookWriter):
Expand Down Expand Up @@ -55,7 +55,7 @@ def reads(self, s, **_):
if self.fmt.get('format_name') == 'pandoc':
return md_to_notebook(s)

if self.ext in myst_extensions():
if self.fmt.get('format_name') == MYST_FORMAT_NAME:
return myst_to_notebook(s)

lines = s.splitlines()
Expand Down Expand Up @@ -127,7 +127,7 @@ def writes(self, nb, metadata=None, **kwargs):
metadata=metadata,
cells=cells))

if self.ext in myst_extensions():
if self.fmt.get('format_name') == MYST_FORMAT_NAME or self.ext in myst_extensions(no_md=True):
pygments_lexer = metadata.get("language_info", {}).get("pygments_lexer", None)
metadata = insert_jupytext_info_and_filter_metadata(metadata, self.ext, self.implementation)

Expand Down
Loading