Skip to content

Commit

Permalink
ENH, DOC: Add support for interactive examples for NumPy with `jupyte…
Browse files Browse the repository at this point in the history
…rlite-sphinx` (numpy#26745)
  • Loading branch information
agriyakhetarpal authored Jan 28, 2025
1 parent cb8b623 commit 62b43b9
Show file tree
Hide file tree
Showing 30 changed files with 333 additions and 24 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ Thumbs.db
doc/source/savefig/
doc/source/**/generated/
doc/source/release/notes-towncrier.rst
doc/source/.jupyterlite.doit.db

# Things specific to this project #
###################################
Expand Down
2 changes: 2 additions & 0 deletions doc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ help:

clean:
-rm -rf build/*
-rm -rf source/.jupyterlite.doit.db
-rm -rf source/contents/*.ipynb
find . -name generated -type d -prune -exec rm -rf "{}" ";"

gitwash-update:
Expand Down
3 changes: 2 additions & 1 deletion doc/neps/roadmap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ planned improvements. Adding more tutorials is underway in the
`numpy-tutorials repo <https://github.com/numpy/numpy-tutorials>`__.

We also intend to make all the example code in our documentation interactive -
work is underway to do so via ``jupyterlite-sphinx`` and Pyodide.
work is underway to do so via ``jupyterlite-sphinx`` and Pyodide. NumPy 2.3.0
provides interactive documentation for examples as a pilot for this effort.

Our website (https://numpy.org) is in good shape. Further work on expanding the
number of languages that the website is translated in is desirable. As are
Expand Down
10 changes: 10 additions & 0 deletions doc/release/upcoming_changes/26745.highlight.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Interactive examples in the NumPy documentation
-----------------------------------------------

The NumPy documentation includes a number of examples that
can now be run interactively in your browser using WebAssembly
and Pyodide.

Please note that the examples are currently experimental in
nature and may not work as expected for all methods in the
public API.
46 changes: 43 additions & 3 deletions doc/source/_static/numpy.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
@import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;0,900;1,400;1,700;1,900&family=Open+Sans:ital,wght@0,400;0,600;1,400;1,600&display=swap');

.navbar-brand img {
height: 75px;
height: 75px;
}

.navbar-brand {
height: 75px;
height: 75px;
}

body {
Expand Down Expand Up @@ -71,4 +72,43 @@ div.admonition-legacy>.admonition-title::after {

div.admonition-legacy>.admonition-title {
background-color: var(--pst-color-warning-bg);
}
}

/* Buttons for JupyterLite-enabled interactive examples */

.try_examples_button {
color: white;
background-color: var(--pst-color-info);
border: none;
padding: 5px 10px;
border-radius: 0.25rem;
margin-top: 3px; /* better alignment under admonitions */
margin-bottom: 5px !important; /* fix uneven button sizes under admonitions */
box-shadow: 0 2px 5px rgba(108, 108, 108, 0.2);
font-weight: bold;
font-size: small;
}

/* Use more acccessible colours for text in dark mode */
[data-theme=dark] .try_examples_button {
color: black;
}

.try_examples_button:hover {
transform: scale(1.02);
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
cursor: pointer;
}

.try_examples_button_container {
display: flex;
justify-content: flex-start;
gap: 10px;
margin-bottom: 20px;
}

/* Better gaps for examples buttons under admonitions */

.try_examples_outer_iframe {
margin-top: 0.4em;
}
14 changes: 14 additions & 0 deletions doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class PyTypeObject(ctypes.Structure):
'sphinx_copybutton',
'sphinx_design',
'sphinx.ext.imgconverter',
'jupyterlite_sphinx',
]

skippable_extensions = [
Expand Down Expand Up @@ -601,4 +602,17 @@ class NumPyLexer(CLexer):
('c:identifier', 'PyHeapTypeObject'),
]

# -----------------------------------------------------------------------------
# Interactive documentation examples via JupyterLite
# -----------------------------------------------------------------------------

global_enable_try_examples = True
try_examples_global_button_text = "Try it in your browser!"
try_examples_global_warning_text = (
"NumPy's interactive examples are experimental and may not always work"
" as expected, with high load times especially on low-resource platforms,"
" and the version of NumPy might not be in sync with the one you are"
" browsing the documentation for. If you encounter any issues, please"
" report them on the"
" [NumPy issue tracker](https://github.com/numpy/numpy/issues)."
)
5 changes: 5 additions & 0 deletions doc/source/jupyter_lite_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"LiteBuildConfig": {
"no_sourcemaps": true
}
}
22 changes: 19 additions & 3 deletions doc/source/reference/arrays.classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -417,22 +417,28 @@ alias for "matrix "in NumPy.

Example 1: Matrix creation from a string

.. try_examples::

>>> import numpy as np
>>> a = np.asmatrix('1 2 3; 4 5 3')
>>> print((a*a.T).I)
[[ 0.29239766 -0.13450292]
[-0.13450292 0.08187135]]
[-0.13450292 0.08187135]]


Example 2: Matrix creation from a nested sequence

.. try_examples::

>>> import numpy as np
>>> np.asmatrix([[1,5,10],[1.0,3,4j]])
matrix([[ 1.+0.j, 5.+0.j, 10.+0.j],
[ 1.+0.j, 3.+0.j, 0.+4.j]])

Example 3: Matrix creation from an array

.. try_examples::

>>> import numpy as np
>>> np.asmatrix(np.random.rand(3,3)).T
matrix([[4.17022005e-01, 3.02332573e-01, 1.86260211e-01],
Expand Down Expand Up @@ -469,6 +475,8 @@ array actually get written to disk.

Example:

.. try_examples::

>>> import numpy as np

>>> a = np.memmap('newfile.dat', dtype=float, mode='w+', shape=1000)
Expand Down Expand Up @@ -617,6 +625,8 @@ This default iterator selects a sub-array of dimension :math:`N-1`
from the array. This can be a useful construct for defining recursive
algorithms. To loop over the entire array requires :math:`N` for-loops.

.. try_examples::

>>> import numpy as np
>>> a = np.arange(24).reshape(3,2,4) + 10
>>> for val in a:
Expand All @@ -641,8 +651,9 @@ As mentioned previously, the flat attribute of ndarray objects returns
an iterator that will cycle over the entire array in C-style
contiguous order.

.. try_examples::

>>> import numpy as np
>>> a = np.arange(24).reshape(3,2,4) + 10
>>> for i, val in enumerate(a.flat):
... if i%5 == 0: print(i, val)
0 10
Expand All @@ -666,9 +677,12 @@ N-dimensional enumeration
Sometimes it may be useful to get the N-dimensional index while
iterating. The ndenumerate iterator can achieve this.

.. try_examples::

>>> import numpy as np
>>> for i, val in np.ndenumerate(a):
... if sum(i)%5 == 0: print(i, val)
... if sum(i)%5 == 0:
print(i, val)
(0, 0, 0) 10
(1, 1, 3) 25
(2, 0, 3) 29
Expand All @@ -689,6 +703,8 @@ objects as inputs and returns an iterator that returns tuples
providing each of the input sequence elements in the broadcasted
result.

.. try_examples::

>>> import numpy as np
>>> for val in np.broadcast([[1, 0], [2, 3]], [0, 1]):
... print(val)
Expand Down
37 changes: 36 additions & 1 deletion doc/source/reference/arrays.datetime.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ letters, for a "Not A Time" value.

.. admonition:: Example

.. try_examples::

A simple ISO date:

>>> import numpy as np
Expand Down Expand Up @@ -95,6 +97,8 @@ datetime type with generic units.

.. admonition:: Example

.. try_examples::

>>> import numpy as np

>>> np.array(['2007-07-13', '2006-01-13', '2010-08-13'], dtype='datetime64')
Expand All @@ -109,6 +113,8 @@ POSIX timestamps with the given unit.

.. admonition:: Example

.. try_examples::

>>> import numpy as np

>>> np.array([0, 1577836800], dtype='datetime64[s]')
Expand All @@ -124,6 +130,8 @@ example :func:`arange` can be used to generate ranges of dates.

.. admonition:: Example

.. try_examples::

All the dates for one month:

>>> import numpy as np
Expand All @@ -146,6 +154,8 @@ because the moment of time is still being represented exactly.

.. admonition:: Example

.. try_examples::

>>> import numpy as np

>>> np.datetime64('2005') == np.datetime64('2005-01-01')
Expand Down Expand Up @@ -175,6 +185,8 @@ data type also accepts the string "NAT" in place of the number for a "Not A Time

.. admonition:: Example

.. try_examples::

>>> import numpy as np

>>> np.timedelta64(1, 'D')
Expand All @@ -191,6 +203,8 @@ simple datetime calculations.

.. admonition:: Example

.. try_examples::

>>> import numpy as np

>>> np.datetime64('2009-01-01') - np.datetime64('2008-01-01')
Expand Down Expand Up @@ -226,6 +240,8 @@ calculating the averaged values from the 400 year leap-year cycle.

.. admonition:: Example

.. try_examples::

>>> import numpy as np

>>> a = np.timedelta64(1, 'Y')
Expand Down Expand Up @@ -307,6 +323,8 @@ specified in business days to datetimes with a unit of 'D' (day).

.. admonition:: Example

.. try_examples::

>>> import numpy as np

>>> np.busday_offset('2011-06-23', 1)
Expand All @@ -323,6 +341,8 @@ The rules most typically used are 'forward' and 'backward'.

.. admonition:: Example

.. try_examples::

>>> import numpy as np

>>> np.busday_offset('2011-06-25', 2)
Expand All @@ -347,6 +367,8 @@ is necessary to get a desired answer.

.. admonition:: Example

.. try_examples::

The first business day on or after a date:

>>> import numpy as np
Expand All @@ -370,6 +392,8 @@ weekmask.

.. admonition:: Example

.. try_examples::

>>> import numpy as np

>>> np.busday_offset('2012-05', 1, roll='forward', weekmask='Sun')
Expand All @@ -386,6 +410,8 @@ To test a `datetime64` value to see if it is a valid day, use :func:`is_busday`.

.. admonition:: Example

.. try_examples::

>>> import numpy as np

>>> np.is_busday(np.datetime64('2011-07-15')) # a Friday
Expand All @@ -405,6 +431,8 @@ dates, use :func:`busday_count`:

.. admonition:: Example

.. try_examples::

>>> import numpy as np

>>> np.busday_count(np.datetime64('2011-07-11'), np.datetime64('2011-07-18'))
Expand All @@ -417,6 +445,8 @@ how many of them are valid dates, you can do this:

.. admonition:: Example

.. try_examples::

>>> import numpy as np

>>> a = np.arange(np.datetime64('2011-07-11'), np.datetime64('2011-07-18'))
Expand Down Expand Up @@ -466,6 +496,8 @@ given below.
23:59:60.450 UTC" is a valid timestamp which is not parseable by
`datetime64`:

.. try_examples::

>>> import numpy as np

>>> np.datetime64("2016-12-31 23:59:60.450")
Expand All @@ -481,6 +513,8 @@ given below.
Compute the number of SI seconds between "2021-01-01 12:56:23.423 UTC" and
"2001-01-01 00:00:00.000 UTC":

.. try_examples::

>>> import numpy as np

>>> (
Expand All @@ -501,7 +535,8 @@ given below.
where UT is `universal time
<https://en.wikipedia.org/wiki/Universal_Time>`_:


.. try_examples::

>>> import numpy as np

>>> a = np.datetime64("0000-01-01", "us")
Expand Down
Loading

0 comments on commit 62b43b9

Please sign in to comment.