Skip to article frontmatterSkip to article content

Markdown & Jupyter Notebook

Jupyter Book 2 (JB2) supports both Markdown files and Jupyter Notebooks as content sources.

Markdown

Markdown is a simple markup language: plain text that is formatted with small pieces of ‘code’. This allows you to create rich, interactive books that combine text, code, and visualizations. This text can then be quickly exported to various other formats such as PDF, Word, HTML, etc.

Documents made in MyST Markdown can be converted to many different formats. These can be saved as JSON, or rendered to a website (like this one!) or any number of formats including PDF & LaTeX, Word, React, or JATS. Picture taken from the MYST documentation .

Documents made in MyST Markdown can be converted to many different formats. These can be saved as JSON, or rendered to a website (like this one!) or any number of formats including PDF & LaTeX, Word, React, or JATS. Picture taken from the MYST documentation [1].

See below for an example of the Markdown language and how it is rendered in JB2.

rendered
markdown

This is a heading

This is a paragraph with bold and italic text.

  • This is a list item

  • Another list item

In the next chapter we cover most of the basic Markdown syntax you will need to create your own content.

Jupyter Notebooks

Jupyter Notebooks are interactive documents that combine live code, equations, visualizations, and narrative text made with Markdown. They are widely used for data analysis, scientific research, and teaching, allowing users to run code in a step-by-step manner and see immediate results.

JB2 allows to include Jupyter Notebooks directly in your book, making it easy to share interactive content with your readers. It also allows to run code cells and display the output directly in the book. Check the output below by first clicking the ON-button at the top right of this page. This loads the server. Once it is ready, you can run the code cell below by clicking the play button.

print("Hello, World!")

Cell Tags and Hiding Input

Cell tags in Jupyter Notebooks are metadata labels that you can assign to individual cells. They are useful for customizing the behavior of cells, such as hiding code input.

To hide the input of a code cell (so only the output is visible), you can add a tag like hide_input to that cell. JB2 recognizes this tag and will hide the code input when rendering or exporting the notebook.

Source
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib.transforms import Affine2D
from ipywidgets import interact
import ipywidgets as widgets

# Constants
start = [0, 0]

L = 2
m = 10 #kg
g = 9.81 #kgm/s^2
t = np.linspace(0,5,100)

def Fw(theta,mu):
    return mu*m*g*np.cos(theta)

def Fzx(theta):
    return m*g*np.sin(theta)

def update(theta,mu):
    # Compute arrow end coordinates
    end = np.array([L * np.cos(theta), L * np.sin(theta)])

    # Clear figure
    plt.clf()
    fig, axs = plt.subplots(1,2, figsize=(10, 5), gridspec_kw={'wspace': 0.4})
    
    # first plot showing angle and box
    ax = axs[0]
    ax.set_xlim(0, 2)
    ax.set_ylim(0, 2)
    ax.set_aspect('equal')
    ax.grid(True)

    if Fw(theta,mu)>Fzx(theta):
        ax.text(1.5, 1.5, 'Stable', fontsize=12)
    else:
        ax.text(1.5, 1.5, 'Sliding', fontsize=12)
    # Draw arrow
    ax.arrow(start[0], start[1], end[0], end[1],
             head_width=0, head_length=0, fc='black', ec='black')

    # Box properties
    box_width = 0.4
    box_height = 0.2

    # Create unrotated rectangle at (0,0)
    rect = Rectangle((-box_width / 2, 0 ),
                     box_width, box_height,
                     linewidth=1, edgecolor='red', facecolor='lightgray')

    # Compute arrow end coordinates
    end = start + np.array([L * np.cos(theta), L * np.sin(theta)])

    # Compute midpoint of arrow
    mid = start + np.array([L/2 * np.cos(theta), L/2 * np.sin(theta)])
    
    # Transformation: rotate around origin, then translate to arrow tip
    trans = (Affine2D()
             .rotate(theta)
             .translate(mid[0], mid[1]) + ax.transData)

    rect.set_transform(trans)
    ax.add_patch(rect)

    # second plot showing motion with and without friction
    ax2 = axs[1]
    
    ax2.set_xlabel('$t$(s)')
    ax2.set_ylabel('$s$(m)')
    
    
    ax2.plot(t,1/2*g*np.sin(theta)*t**2,'k-',label='without friction')
    
    if Fw(theta,mu)>Fzx(theta):
        ax2.plot(t,np.zeros(len(t)),'r-',label='with friction')
    else:
        ax2.plot(t,1/2*g*(np.sin(theta)-mu*np.cos(theta))*t**2,'r-',label='with friction')
        
  
    ax2.set_ylim(0,120)
    ax2.legend()
    
   
    
    plt.show()

# Use FloatSlider for smooth interaction
interact(update, theta=widgets.FloatSlider(min=0, max=np.pi/2, step=np.pi/16, value=np.pi/4),
         mu=widgets.FloatSlider(min=0, max=1, step=0.05, value=1))

To add a tag:

  1. Select the cell.

  2. Open the “View” menu and enable the “Cell Toolbar” → “Tags”.

  3. Add the tag hide_input (or another tag recognized by your toolchain).

This feature is especially useful for creating clean, reader-friendly notebooks where you want to focus on results rather than code details, see below.

The code above provides a semi-interactive simulation: you are able to change two parameters but cannot control/adapt the code itself. This will be available in the near feature.

Footnotes