Initial steps towards interactive documentation via JupyterLite - #728

Merged
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs
Mar 28, 2024
Merged

Initial steps towards interactive documentation via JupyterLite#728
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs

Conversation

@agriyakhetarpal

@agriyakhetarpalagriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
Collaborator

Description

This PR adds interactive documentation via JupyterLite Pyodide-enabled kernels and tests them on Read the Docs.

The key changes here are:

  1. It enables the JupyterLite Pyodide kernel and the JupyterLite Sphinx extension for the documentation, for both building locally and for the hosted documentation on Read the Docs (this can be seen in the PR previews).
  2. It enables the JupyterLite extension for all of the doctest-based examples in the API reference wherever applicable, and adds a warning at the top of the notebook to warn users about how experimental these changes are.
  3. The style guidelines have been mimicked from those for SciPy, through this PR: DOC: Add support for interactive examples with jupyterlite-sphinx scipy/scipy#20019

Following this, users shall be able to run all of the examples by loading an installation of PyWavelets in notebooks inside the documentation, which can be opened in new tabs too, as necessary.

Footnotes

This is meant to address certain sections of gh-706, however, further follow-ups are required to enable interactivity for the rest of the available examples.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

@rgommers

Copy link
Copy Markdown
Member

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

It did actually build: https://pywavelets--728.org.readthedocs.build/en/728/. I'll check why there's no entry in the list of CI jobs here.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Thanks for the link! I'll use that for now and for future PRs. It is a bit strange, but as a workaround, we can use this GitHub Action: https://github.com/readthedocs/actions/tree/v1/preview if needed. It looks like it is a pretty easy to configure?

@rgommers

Copy link
Copy Markdown
Member

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

Thank you! It does show up here now – we can switch to the PR preview action at any time, if all we need is just a link. It will require write permissions to edit the PR description.

@agriyakhetarpal

agriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
CollaboratorAuthor

The Wavelet object example that you mentioned on Slack does not seem to be working – but I think that is because it's configured incorrectly (it is placed in the documentation in a .. sourcecode:: directive).

On the same page, other basic examples, i.e., those under an

Examples
--------

section and elsewhere are working wherever this heading is mentioned in the docstring, for example – this is for listing down the different types of Wavelet families available in PyWavelets. The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

The code snippet does take a bit to load, and did not work unless I opened it in a new tab (maybe I have way too many open tabs or something?) This example does work, and I confirmed via

importpywtprint(pywt.__version__)

that we have 1.4.1 being loaded currently. So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

@rgommers

Copy link
Copy Markdown
Member

The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

This is still WIP, right? It looks like this:

image

compared to in SciPy (which uses the same theme and plugins):

image

So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Yes, I shall improve the styling here – there are a couple of guides available about this in the JupyterLite docs, or I can follow the footsteps of the SciPy docs and re-use a similar style narrative.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

I personally don't think it is a good idea to merge this on the development version of the documentation when we do not have the nightly wheels set up, but a suitable workaround for now could be to make a note about this to users in the currently added admonition – referencing that the version of PyWavelets available may be a bit outdated and therefore some of the examples might not work?

I will make and verify some additional changes to ensure that the button is available on all of the examples running under the doctests. Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

@rgommers

Copy link
Copy Markdown
Member

There are no new functions in the 1.5.0 and 1.6.0 releases, and only a very small amount of behavioral changes (e.g., stricter input validation); there is nothing that will affect how the examples behave AFAIK.

Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

Yes, the Usage examples will likely require using the NotebookLite directive. I just tested the display for all of the doctest-based examples, which are making use of the TryExamples directive (enabled by global_enable_try_examples = True in conf.py). All of them are working as expected on all but the following pages under API reference (where there are no doctest-based examples, but other code-block based examples are present):

  1. Other functions
  2. Overview of multilevel wavelet decompositions
  3. Signal extension modes
  4. Multiresolution Analysis

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

One thing that isn't working so far and what I'm currently investigating is the size of the JupyterLite notebook that gets loaded, for example:

This screenshot displays the PyWavelets documentation deployed with Sphinx locally, where a page from the API reference is currently open.

is too short and doesn't expand to display all of the code cells, in comparison to the deployment showcased in scipy/scipy#20019. It might get fixed with a try-examples.json file that I am missing.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

It might be fixed with a try-examples.json file that I am missing.

This was indeed the missing thing, now everything works!

@agriyakhetarpalagriyakhetarpal changed the title [WIP]: Interactive documentation via JupyterLiteInitial steps towards interactive documentation via JupyterLiteMar 22, 2024
@agriyakhetarpal
agriyakhetarpal marked this pull request as ready for review March 22, 2024 07:48
@rgommers

Copy link
Copy Markdown
Member

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

Sure, if you know how to do it then why not do it straight away. All I was trying to say is that incremental improvements are okay too.

This is starting to look pretty good!

This commit moves the example for the function `pywt.data.demo_signal()` to the doctests for the
function instead of having it inside reST.
This shall render the example interactive through
the use of JupyterLite and the TryExamples
Sphinx directive.
@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, I have now restructured:

  • an example for pywt.data.demo_signal() from the Other functions page – I moved it to the doctests for the function so as to let jupyterlite-sphinx be able to access it, and, similarly,
  • most of the other examples that were interlaced with .. sourcecode:: python directives. They use the newer directive, which seems to offer code syntax highlighting by default.

Some more points:

  1. The Overview of multilevel wavelet decompositions page has its its reference files in doc/pyplots/ and they are end-to-end examples of analyses. It would be better to club changes to them in another PR, and so is the case for the Signal extension modes page; it contains a plotting example and some in-line examples, which I have marked with the .. try_examples:: directive manually like those mentioned in point 2 (side note: it is good thing PyWavelets isn't doesn't have a massive documentation reference haha).
  2. Also, Multiresolution Analysis, a.k.a. pywt.mra does not have any examples in the docstrings (just the two scripts in the demo/ folder).
  3. For the CWT examples, there are some that contain the # doctest: +SKIP label (but only inside the JupyterLite notebook, not the Sphinx docs). Is there something we can do about them – we don't want to break the doctests either? I do not think it is a big deal, though.

This is ready for another review, whenever you get a chance to do so! The aftermath of this PR can take care of the other pages. Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such (the latter would be better and more stable in its configuration – it's developed more actively).


P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, this is strange. I am receiving errors like File Load Error for 158988af_6816_4f65_a71c_affe1c6d5d90.ipynb when I try to start the kernel on any example on Read the Docs, but it works perfectly locally. The button is right-aligned too, and not left-aligned as I had configured it.

Edit: seems to be resolved now!

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Another thing I am noticing right now: the "Try it in your browser" text works on code snippets in docstrings under the

Examples
--------

heading, but it does not propagate to custom in-line examples, i.e., where we are using the .. try_examples:: directive manually – the button still shows the default "Try it with Jupyterlite" text instead of getting it from conf.py. jupyterlite-sphinx does offer a :button_text option to configure a particular example's button's text, but if it isn't present – it should consider the global configuration value.

This is as observed on the Continuous Wavelet Transform (CWT) page, and I think this is a bug. Let me file this on jupyterlite-sphinx's issue tracker.

@rgommersrgommers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, very nice work @agriyakhetarpal! The styling looks polished now, and all the examples I tried worked as expected. I think this is ready to go in, time for testing in the wild and seeing if we get any feedback/issues.

The last 5 commits are all useful, and I had zero comments on them.

A few responses:

  • .. sourcecode:: is obsolete indeed
  • Regarding pywt.mra not having examples: it'd be welcome if they were contributed, but it's a minor thing and unrelated to the interactive docs work
  • Re # doctest: +SKIP: in principle not that hard to get rid of, but I'd like to wait until SciPy updates its approach to doing that. It has nicer skip comments that actually say what the issue is (e.g., # may vary for output that, you guessed, can vary)

Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such

myst-nb seems fine to me.

P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

I like how it looks! Happy to stay with your choice here.

@rgommers
rgommers merged commit 8c63926 into PyWavelets:mainMar 28, 2024
@agriyakhetarpal
agriyakhetarpal deleted the test-interactive-docs branch March 28, 2024 22:30
@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Actually, I was working on submitting a PR today for the issue I opened over at jupyterlite-sphinx and tagged above – I should have asked you here to hold off on merging this :) But that's not a big deal and it is a minor fix too. I hope to be done with that soon, and I can always put up another PR.

@rgommers

Copy link
Copy Markdown
Member

That's perfectly okay I think - I'm sure there will be several follow-up PRs to this one to fix some issues and polish the experience.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@agriyakhetarpal@rgommers
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Initial steps towards interactive documentation via JupyterLite - #728

Merged
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs
Mar 28, 2024
Merged

Initial steps towards interactive documentation via JupyterLite#728
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs

Conversation

@agriyakhetarpal

@agriyakhetarpalagriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
Collaborator

Description

This PR adds interactive documentation via JupyterLite Pyodide-enabled kernels and tests them on Read the Docs.

The key changes here are:

  1. It enables the JupyterLite Pyodide kernel and the JupyterLite Sphinx extension for the documentation, for both building locally and for the hosted documentation on Read the Docs (this can be seen in the PR previews).
  2. It enables the JupyterLite extension for all of the doctest-based examples in the API reference wherever applicable, and adds a warning at the top of the notebook to warn users about how experimental these changes are.
  3. The style guidelines have been mimicked from those for SciPy, through this PR: DOC: Add support for interactive examples with jupyterlite-sphinx scipy/scipy#20019

Following this, users shall be able to run all of the examples by loading an installation of PyWavelets in notebooks inside the documentation, which can be opened in new tabs too, as necessary.

Footnotes

This is meant to address certain sections of gh-706, however, further follow-ups are required to enable interactivity for the rest of the available examples.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

@rgommers

Copy link
Copy Markdown
Member

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

It did actually build: https://pywavelets--728.org.readthedocs.build/en/728/. I'll check why there's no entry in the list of CI jobs here.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Thanks for the link! I'll use that for now and for future PRs. It is a bit strange, but as a workaround, we can use this GitHub Action: https://github.com/readthedocs/actions/tree/v1/preview if needed. It looks like it is a pretty easy to configure?

@rgommers

Copy link
Copy Markdown
Member

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

Thank you! It does show up here now – we can switch to the PR preview action at any time, if all we need is just a link. It will require write permissions to edit the PR description.

@agriyakhetarpal

agriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
CollaboratorAuthor

The Wavelet object example that you mentioned on Slack does not seem to be working – but I think that is because it's configured incorrectly (it is placed in the documentation in a .. sourcecode:: directive).

On the same page, other basic examples, i.e., those under an

Examples
--------

section and elsewhere are working wherever this heading is mentioned in the docstring, for example – this is for listing down the different types of Wavelet families available in PyWavelets. The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

The code snippet does take a bit to load, and did not work unless I opened it in a new tab (maybe I have way too many open tabs or something?) This example does work, and I confirmed via

importpywtprint(pywt.__version__)

that we have 1.4.1 being loaded currently. So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

@rgommers

Copy link
Copy Markdown
Member

The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

This is still WIP, right? It looks like this:

image

compared to in SciPy (which uses the same theme and plugins):

image

So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Yes, I shall improve the styling here – there are a couple of guides available about this in the JupyterLite docs, or I can follow the footsteps of the SciPy docs and re-use a similar style narrative.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

I personally don't think it is a good idea to merge this on the development version of the documentation when we do not have the nightly wheels set up, but a suitable workaround for now could be to make a note about this to users in the currently added admonition – referencing that the version of PyWavelets available may be a bit outdated and therefore some of the examples might not work?

I will make and verify some additional changes to ensure that the button is available on all of the examples running under the doctests. Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

@rgommers

Copy link
Copy Markdown
Member

There are no new functions in the 1.5.0 and 1.6.0 releases, and only a very small amount of behavioral changes (e.g., stricter input validation); there is nothing that will affect how the examples behave AFAIK.

Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

Yes, the Usage examples will likely require using the NotebookLite directive. I just tested the display for all of the doctest-based examples, which are making use of the TryExamples directive (enabled by global_enable_try_examples = True in conf.py). All of them are working as expected on all but the following pages under API reference (where there are no doctest-based examples, but other code-block based examples are present):

  1. Other functions
  2. Overview of multilevel wavelet decompositions
  3. Signal extension modes
  4. Multiresolution Analysis

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

One thing that isn't working so far and what I'm currently investigating is the size of the JupyterLite notebook that gets loaded, for example:

This screenshot displays the PyWavelets documentation deployed with Sphinx locally, where a page from the API reference is currently open.

is too short and doesn't expand to display all of the code cells, in comparison to the deployment showcased in scipy/scipy#20019. It might get fixed with a try-examples.json file that I am missing.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

It might be fixed with a try-examples.json file that I am missing.

This was indeed the missing thing, now everything works!

@agriyakhetarpalagriyakhetarpal changed the title [WIP]: Interactive documentation via JupyterLiteInitial steps towards interactive documentation via JupyterLiteMar 22, 2024
@agriyakhetarpal
agriyakhetarpal marked this pull request as ready for review March 22, 2024 07:48
@rgommers

Copy link
Copy Markdown
Member

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

Sure, if you know how to do it then why not do it straight away. All I was trying to say is that incremental improvements are okay too.

This is starting to look pretty good!

This commit moves the example for the function `pywt.data.demo_signal()` to the doctests for the
function instead of having it inside reST.
This shall render the example interactive through
the use of JupyterLite and the TryExamples
Sphinx directive.
@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, I have now restructured:

  • an example for pywt.data.demo_signal() from the Other functions page – I moved it to the doctests for the function so as to let jupyterlite-sphinx be able to access it, and, similarly,
  • most of the other examples that were interlaced with .. sourcecode:: python directives. They use the newer directive, which seems to offer code syntax highlighting by default.

Some more points:

  1. The Overview of multilevel wavelet decompositions page has its its reference files in doc/pyplots/ and they are end-to-end examples of analyses. It would be better to club changes to them in another PR, and so is the case for the Signal extension modes page; it contains a plotting example and some in-line examples, which I have marked with the .. try_examples:: directive manually like those mentioned in point 2 (side note: it is good thing PyWavelets isn't doesn't have a massive documentation reference haha).
  2. Also, Multiresolution Analysis, a.k.a. pywt.mra does not have any examples in the docstrings (just the two scripts in the demo/ folder).
  3. For the CWT examples, there are some that contain the # doctest: +SKIP label (but only inside the JupyterLite notebook, not the Sphinx docs). Is there something we can do about them – we don't want to break the doctests either? I do not think it is a big deal, though.

This is ready for another review, whenever you get a chance to do so! The aftermath of this PR can take care of the other pages. Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such (the latter would be better and more stable in its configuration – it's developed more actively).


P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, this is strange. I am receiving errors like File Load Error for 158988af_6816_4f65_a71c_affe1c6d5d90.ipynb when I try to start the kernel on any example on Read the Docs, but it works perfectly locally. The button is right-aligned too, and not left-aligned as I had configured it.

Edit: seems to be resolved now!

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Another thing I am noticing right now: the "Try it in your browser" text works on code snippets in docstrings under the

Examples
--------

heading, but it does not propagate to custom in-line examples, i.e., where we are using the .. try_examples:: directive manually – the button still shows the default "Try it with Jupyterlite" text instead of getting it from conf.py. jupyterlite-sphinx does offer a :button_text option to configure a particular example's button's text, but if it isn't present – it should consider the global configuration value.

This is as observed on the Continuous Wavelet Transform (CWT) page, and I think this is a bug. Let me file this on jupyterlite-sphinx's issue tracker.

@rgommersrgommers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, very nice work @agriyakhetarpal! The styling looks polished now, and all the examples I tried worked as expected. I think this is ready to go in, time for testing in the wild and seeing if we get any feedback/issues.

The last 5 commits are all useful, and I had zero comments on them.

A few responses:

  • .. sourcecode:: is obsolete indeed
  • Regarding pywt.mra not having examples: it'd be welcome if they were contributed, but it's a minor thing and unrelated to the interactive docs work
  • Re # doctest: +SKIP: in principle not that hard to get rid of, but I'd like to wait until SciPy updates its approach to doing that. It has nicer skip comments that actually say what the issue is (e.g., # may vary for output that, you guessed, can vary)

Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such

myst-nb seems fine to me.

P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

I like how it looks! Happy to stay with your choice here.

@rgommers
rgommers merged commit 8c63926 into PyWavelets:mainMar 28, 2024
@agriyakhetarpal
agriyakhetarpal deleted the test-interactive-docs branch March 28, 2024 22:30
@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Actually, I was working on submitting a PR today for the issue I opened over at jupyterlite-sphinx and tagged above – I should have asked you here to hold off on merging this :) But that's not a big deal and it is a minor fix too. I hope to be done with that soon, and I can always put up another PR.

@rgommers

Copy link
Copy Markdown
Member

That's perfectly okay I think - I'm sure there will be several follow-up PRs to this one to fix some issues and polish the experience.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@agriyakhetarpal@rgommers
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Initial steps towards interactive documentation via JupyterLite - #728

Merged
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs
Mar 28, 2024
Merged

Initial steps towards interactive documentation via JupyterLite#728
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs

Conversation

@agriyakhetarpal

@agriyakhetarpalagriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
Collaborator

Description

This PR adds interactive documentation via JupyterLite Pyodide-enabled kernels and tests them on Read the Docs.

The key changes here are:

  1. It enables the JupyterLite Pyodide kernel and the JupyterLite Sphinx extension for the documentation, for both building locally and for the hosted documentation on Read the Docs (this can be seen in the PR previews).
  2. It enables the JupyterLite extension for all of the doctest-based examples in the API reference wherever applicable, and adds a warning at the top of the notebook to warn users about how experimental these changes are.
  3. The style guidelines have been mimicked from those for SciPy, through this PR: DOC: Add support for interactive examples with jupyterlite-sphinx scipy/scipy#20019

Following this, users shall be able to run all of the examples by loading an installation of PyWavelets in notebooks inside the documentation, which can be opened in new tabs too, as necessary.

Footnotes

This is meant to address certain sections of gh-706, however, further follow-ups are required to enable interactivity for the rest of the available examples.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

@rgommers

Copy link
Copy Markdown
Member

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

It did actually build: https://pywavelets--728.org.readthedocs.build/en/728/. I'll check why there's no entry in the list of CI jobs here.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Thanks for the link! I'll use that for now and for future PRs. It is a bit strange, but as a workaround, we can use this GitHub Action: https://github.com/readthedocs/actions/tree/v1/preview if needed. It looks like it is a pretty easy to configure?

@rgommers

Copy link
Copy Markdown
Member

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

Thank you! It does show up here now – we can switch to the PR preview action at any time, if all we need is just a link. It will require write permissions to edit the PR description.

@agriyakhetarpal

agriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
CollaboratorAuthor

The Wavelet object example that you mentioned on Slack does not seem to be working – but I think that is because it's configured incorrectly (it is placed in the documentation in a .. sourcecode:: directive).

On the same page, other basic examples, i.e., those under an

Examples
--------

section and elsewhere are working wherever this heading is mentioned in the docstring, for example – this is for listing down the different types of Wavelet families available in PyWavelets. The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

The code snippet does take a bit to load, and did not work unless I opened it in a new tab (maybe I have way too many open tabs or something?) This example does work, and I confirmed via

importpywtprint(pywt.__version__)

that we have 1.4.1 being loaded currently. So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

@rgommers

Copy link
Copy Markdown
Member

The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

This is still WIP, right? It looks like this:

image

compared to in SciPy (which uses the same theme and plugins):

image

So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Yes, I shall improve the styling here – there are a couple of guides available about this in the JupyterLite docs, or I can follow the footsteps of the SciPy docs and re-use a similar style narrative.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

I personally don't think it is a good idea to merge this on the development version of the documentation when we do not have the nightly wheels set up, but a suitable workaround for now could be to make a note about this to users in the currently added admonition – referencing that the version of PyWavelets available may be a bit outdated and therefore some of the examples might not work?

I will make and verify some additional changes to ensure that the button is available on all of the examples running under the doctests. Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

@rgommers

Copy link
Copy Markdown
Member

There are no new functions in the 1.5.0 and 1.6.0 releases, and only a very small amount of behavioral changes (e.g., stricter input validation); there is nothing that will affect how the examples behave AFAIK.

Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

Yes, the Usage examples will likely require using the NotebookLite directive. I just tested the display for all of the doctest-based examples, which are making use of the TryExamples directive (enabled by global_enable_try_examples = True in conf.py). All of them are working as expected on all but the following pages under API reference (where there are no doctest-based examples, but other code-block based examples are present):

  1. Other functions
  2. Overview of multilevel wavelet decompositions
  3. Signal extension modes
  4. Multiresolution Analysis

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

One thing that isn't working so far and what I'm currently investigating is the size of the JupyterLite notebook that gets loaded, for example:

This screenshot displays the PyWavelets documentation deployed with Sphinx locally, where a page from the API reference is currently open.

is too short and doesn't expand to display all of the code cells, in comparison to the deployment showcased in scipy/scipy#20019. It might get fixed with a try-examples.json file that I am missing.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

It might be fixed with a try-examples.json file that I am missing.

This was indeed the missing thing, now everything works!

@agriyakhetarpalagriyakhetarpal changed the title [WIP]: Interactive documentation via JupyterLiteInitial steps towards interactive documentation via JupyterLiteMar 22, 2024
@agriyakhetarpal
agriyakhetarpal marked this pull request as ready for review March 22, 2024 07:48
@rgommers

Copy link
Copy Markdown
Member

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

Sure, if you know how to do it then why not do it straight away. All I was trying to say is that incremental improvements are okay too.

This is starting to look pretty good!

This commit moves the example for the function `pywt.data.demo_signal()` to the doctests for the
function instead of having it inside reST.
This shall render the example interactive through
the use of JupyterLite and the TryExamples
Sphinx directive.
@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, I have now restructured:

  • an example for pywt.data.demo_signal() from the Other functions page – I moved it to the doctests for the function so as to let jupyterlite-sphinx be able to access it, and, similarly,
  • most of the other examples that were interlaced with .. sourcecode:: python directives. They use the newer directive, which seems to offer code syntax highlighting by default.

Some more points:

  1. The Overview of multilevel wavelet decompositions page has its its reference files in doc/pyplots/ and they are end-to-end examples of analyses. It would be better to club changes to them in another PR, and so is the case for the Signal extension modes page; it contains a plotting example and some in-line examples, which I have marked with the .. try_examples:: directive manually like those mentioned in point 2 (side note: it is good thing PyWavelets isn't doesn't have a massive documentation reference haha).
  2. Also, Multiresolution Analysis, a.k.a. pywt.mra does not have any examples in the docstrings (just the two scripts in the demo/ folder).
  3. For the CWT examples, there are some that contain the # doctest: +SKIP label (but only inside the JupyterLite notebook, not the Sphinx docs). Is there something we can do about them – we don't want to break the doctests either? I do not think it is a big deal, though.

This is ready for another review, whenever you get a chance to do so! The aftermath of this PR can take care of the other pages. Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such (the latter would be better and more stable in its configuration – it's developed more actively).


P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, this is strange. I am receiving errors like File Load Error for 158988af_6816_4f65_a71c_affe1c6d5d90.ipynb when I try to start the kernel on any example on Read the Docs, but it works perfectly locally. The button is right-aligned too, and not left-aligned as I had configured it.

Edit: seems to be resolved now!

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Another thing I am noticing right now: the "Try it in your browser" text works on code snippets in docstrings under the

Examples
--------

heading, but it does not propagate to custom in-line examples, i.e., where we are using the .. try_examples:: directive manually – the button still shows the default "Try it with Jupyterlite" text instead of getting it from conf.py. jupyterlite-sphinx does offer a :button_text option to configure a particular example's button's text, but if it isn't present – it should consider the global configuration value.

This is as observed on the Continuous Wavelet Transform (CWT) page, and I think this is a bug. Let me file this on jupyterlite-sphinx's issue tracker.

@rgommersrgommers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, very nice work @agriyakhetarpal! The styling looks polished now, and all the examples I tried worked as expected. I think this is ready to go in, time for testing in the wild and seeing if we get any feedback/issues.

The last 5 commits are all useful, and I had zero comments on them.

A few responses:

  • .. sourcecode:: is obsolete indeed
  • Regarding pywt.mra not having examples: it'd be welcome if they were contributed, but it's a minor thing and unrelated to the interactive docs work
  • Re # doctest: +SKIP: in principle not that hard to get rid of, but I'd like to wait until SciPy updates its approach to doing that. It has nicer skip comments that actually say what the issue is (e.g., # may vary for output that, you guessed, can vary)

Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such

myst-nb seems fine to me.

P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

I like how it looks! Happy to stay with your choice here.

@rgommers
rgommers merged commit 8c63926 into PyWavelets:mainMar 28, 2024
@agriyakhetarpal
agriyakhetarpal deleted the test-interactive-docs branch March 28, 2024 22:30
@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Actually, I was working on submitting a PR today for the issue I opened over at jupyterlite-sphinx and tagged above – I should have asked you here to hold off on merging this :) But that's not a big deal and it is a minor fix too. I hope to be done with that soon, and I can always put up another PR.

@rgommers

Copy link
Copy Markdown
Member

That's perfectly okay I think - I'm sure there will be several follow-up PRs to this one to fix some issues and polish the experience.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@agriyakhetarpal@rgommers
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Initial steps towards interactive documentation via JupyterLite - #728

Merged
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs
Mar 28, 2024
Merged

Initial steps towards interactive documentation via JupyterLite#728
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs

Conversation

@agriyakhetarpal

@agriyakhetarpalagriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
Collaborator

Description

This PR adds interactive documentation via JupyterLite Pyodide-enabled kernels and tests them on Read the Docs.

The key changes here are:

  1. It enables the JupyterLite Pyodide kernel and the JupyterLite Sphinx extension for the documentation, for both building locally and for the hosted documentation on Read the Docs (this can be seen in the PR previews).
  2. It enables the JupyterLite extension for all of the doctest-based examples in the API reference wherever applicable, and adds a warning at the top of the notebook to warn users about how experimental these changes are.
  3. The style guidelines have been mimicked from those for SciPy, through this PR: DOC: Add support for interactive examples with jupyterlite-sphinx scipy/scipy#20019

Following this, users shall be able to run all of the examples by loading an installation of PyWavelets in notebooks inside the documentation, which can be opened in new tabs too, as necessary.

Footnotes

This is meant to address certain sections of gh-706, however, further follow-ups are required to enable interactivity for the rest of the available examples.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

@rgommers

Copy link
Copy Markdown
Member

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

It did actually build: https://pywavelets--728.org.readthedocs.build/en/728/. I'll check why there's no entry in the list of CI jobs here.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Thanks for the link! I'll use that for now and for future PRs. It is a bit strange, but as a workaround, we can use this GitHub Action: https://github.com/readthedocs/actions/tree/v1/preview if needed. It looks like it is a pretty easy to configure?

@rgommers

Copy link
Copy Markdown
Member

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

Thank you! It does show up here now – we can switch to the PR preview action at any time, if all we need is just a link. It will require write permissions to edit the PR description.

@agriyakhetarpal

agriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
CollaboratorAuthor

The Wavelet object example that you mentioned on Slack does not seem to be working – but I think that is because it's configured incorrectly (it is placed in the documentation in a .. sourcecode:: directive).

On the same page, other basic examples, i.e., those under an

Examples
--------

section and elsewhere are working wherever this heading is mentioned in the docstring, for example – this is for listing down the different types of Wavelet families available in PyWavelets. The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

The code snippet does take a bit to load, and did not work unless I opened it in a new tab (maybe I have way too many open tabs or something?) This example does work, and I confirmed via

importpywtprint(pywt.__version__)

that we have 1.4.1 being loaded currently. So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

@rgommers

Copy link
Copy Markdown
Member

The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

This is still WIP, right? It looks like this:

image

compared to in SciPy (which uses the same theme and plugins):

image

So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Yes, I shall improve the styling here – there are a couple of guides available about this in the JupyterLite docs, or I can follow the footsteps of the SciPy docs and re-use a similar style narrative.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

I personally don't think it is a good idea to merge this on the development version of the documentation when we do not have the nightly wheels set up, but a suitable workaround for now could be to make a note about this to users in the currently added admonition – referencing that the version of PyWavelets available may be a bit outdated and therefore some of the examples might not work?

I will make and verify some additional changes to ensure that the button is available on all of the examples running under the doctests. Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

@rgommers

Copy link
Copy Markdown
Member

There are no new functions in the 1.5.0 and 1.6.0 releases, and only a very small amount of behavioral changes (e.g., stricter input validation); there is nothing that will affect how the examples behave AFAIK.

Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

Yes, the Usage examples will likely require using the NotebookLite directive. I just tested the display for all of the doctest-based examples, which are making use of the TryExamples directive (enabled by global_enable_try_examples = True in conf.py). All of them are working as expected on all but the following pages under API reference (where there are no doctest-based examples, but other code-block based examples are present):

  1. Other functions
  2. Overview of multilevel wavelet decompositions
  3. Signal extension modes
  4. Multiresolution Analysis

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

One thing that isn't working so far and what I'm currently investigating is the size of the JupyterLite notebook that gets loaded, for example:

This screenshot displays the PyWavelets documentation deployed with Sphinx locally, where a page from the API reference is currently open.

is too short and doesn't expand to display all of the code cells, in comparison to the deployment showcased in scipy/scipy#20019. It might get fixed with a try-examples.json file that I am missing.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

It might be fixed with a try-examples.json file that I am missing.

This was indeed the missing thing, now everything works!

@agriyakhetarpalagriyakhetarpal changed the title [WIP]: Interactive documentation via JupyterLiteInitial steps towards interactive documentation via JupyterLiteMar 22, 2024
@agriyakhetarpal
agriyakhetarpal marked this pull request as ready for review March 22, 2024 07:48
@rgommers

Copy link
Copy Markdown
Member

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

Sure, if you know how to do it then why not do it straight away. All I was trying to say is that incremental improvements are okay too.

This is starting to look pretty good!

This commit moves the example for the function `pywt.data.demo_signal()` to the doctests for the
function instead of having it inside reST.
This shall render the example interactive through
the use of JupyterLite and the TryExamples
Sphinx directive.
@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, I have now restructured:

  • an example for pywt.data.demo_signal() from the Other functions page – I moved it to the doctests for the function so as to let jupyterlite-sphinx be able to access it, and, similarly,
  • most of the other examples that were interlaced with .. sourcecode:: python directives. They use the newer directive, which seems to offer code syntax highlighting by default.

Some more points:

  1. The Overview of multilevel wavelet decompositions page has its its reference files in doc/pyplots/ and they are end-to-end examples of analyses. It would be better to club changes to them in another PR, and so is the case for the Signal extension modes page; it contains a plotting example and some in-line examples, which I have marked with the .. try_examples:: directive manually like those mentioned in point 2 (side note: it is good thing PyWavelets isn't doesn't have a massive documentation reference haha).
  2. Also, Multiresolution Analysis, a.k.a. pywt.mra does not have any examples in the docstrings (just the two scripts in the demo/ folder).
  3. For the CWT examples, there are some that contain the # doctest: +SKIP label (but only inside the JupyterLite notebook, not the Sphinx docs). Is there something we can do about them – we don't want to break the doctests either? I do not think it is a big deal, though.

This is ready for another review, whenever you get a chance to do so! The aftermath of this PR can take care of the other pages. Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such (the latter would be better and more stable in its configuration – it's developed more actively).


P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, this is strange. I am receiving errors like File Load Error for 158988af_6816_4f65_a71c_affe1c6d5d90.ipynb when I try to start the kernel on any example on Read the Docs, but it works perfectly locally. The button is right-aligned too, and not left-aligned as I had configured it.

Edit: seems to be resolved now!

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Another thing I am noticing right now: the "Try it in your browser" text works on code snippets in docstrings under the

Examples
--------

heading, but it does not propagate to custom in-line examples, i.e., where we are using the .. try_examples:: directive manually – the button still shows the default "Try it with Jupyterlite" text instead of getting it from conf.py. jupyterlite-sphinx does offer a :button_text option to configure a particular example's button's text, but if it isn't present – it should consider the global configuration value.

This is as observed on the Continuous Wavelet Transform (CWT) page, and I think this is a bug. Let me file this on jupyterlite-sphinx's issue tracker.

@rgommersrgommers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, very nice work @agriyakhetarpal! The styling looks polished now, and all the examples I tried worked as expected. I think this is ready to go in, time for testing in the wild and seeing if we get any feedback/issues.

The last 5 commits are all useful, and I had zero comments on them.

A few responses:

  • .. sourcecode:: is obsolete indeed
  • Regarding pywt.mra not having examples: it'd be welcome if they were contributed, but it's a minor thing and unrelated to the interactive docs work
  • Re # doctest: +SKIP: in principle not that hard to get rid of, but I'd like to wait until SciPy updates its approach to doing that. It has nicer skip comments that actually say what the issue is (e.g., # may vary for output that, you guessed, can vary)

Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such

myst-nb seems fine to me.

P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

I like how it looks! Happy to stay with your choice here.

@rgommers
rgommers merged commit 8c63926 into PyWavelets:mainMar 28, 2024
@agriyakhetarpal
agriyakhetarpal deleted the test-interactive-docs branch March 28, 2024 22:30
@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Actually, I was working on submitting a PR today for the issue I opened over at jupyterlite-sphinx and tagged above – I should have asked you here to hold off on merging this :) But that's not a big deal and it is a minor fix too. I hope to be done with that soon, and I can always put up another PR.

@rgommers

Copy link
Copy Markdown
Member

That's perfectly okay I think - I'm sure there will be several follow-up PRs to this one to fix some issues and polish the experience.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@agriyakhetarpal@rgommers
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Initial steps towards interactive documentation via JupyterLite - #728

Merged
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs
Mar 28, 2024
Merged

Initial steps towards interactive documentation via JupyterLite#728
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs

Conversation

@agriyakhetarpal

@agriyakhetarpalagriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
Collaborator

Description

This PR adds interactive documentation via JupyterLite Pyodide-enabled kernels and tests them on Read the Docs.

The key changes here are:

  1. It enables the JupyterLite Pyodide kernel and the JupyterLite Sphinx extension for the documentation, for both building locally and for the hosted documentation on Read the Docs (this can be seen in the PR previews).
  2. It enables the JupyterLite extension for all of the doctest-based examples in the API reference wherever applicable, and adds a warning at the top of the notebook to warn users about how experimental these changes are.
  3. The style guidelines have been mimicked from those for SciPy, through this PR: DOC: Add support for interactive examples with jupyterlite-sphinx scipy/scipy#20019

Following this, users shall be able to run all of the examples by loading an installation of PyWavelets in notebooks inside the documentation, which can be opened in new tabs too, as necessary.

Footnotes

This is meant to address certain sections of gh-706, however, further follow-ups are required to enable interactivity for the rest of the available examples.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

@rgommers

Copy link
Copy Markdown
Member

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

It did actually build: https://pywavelets--728.org.readthedocs.build/en/728/. I'll check why there's no entry in the list of CI jobs here.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Thanks for the link! I'll use that for now and for future PRs. It is a bit strange, but as a workaround, we can use this GitHub Action: https://github.com/readthedocs/actions/tree/v1/preview if needed. It looks like it is a pretty easy to configure?

@rgommers

Copy link
Copy Markdown
Member

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

Thank you! It does show up here now – we can switch to the PR preview action at any time, if all we need is just a link. It will require write permissions to edit the PR description.

@agriyakhetarpal

agriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
CollaboratorAuthor

The Wavelet object example that you mentioned on Slack does not seem to be working – but I think that is because it's configured incorrectly (it is placed in the documentation in a .. sourcecode:: directive).

On the same page, other basic examples, i.e., those under an

Examples
--------

section and elsewhere are working wherever this heading is mentioned in the docstring, for example – this is for listing down the different types of Wavelet families available in PyWavelets. The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

The code snippet does take a bit to load, and did not work unless I opened it in a new tab (maybe I have way too many open tabs or something?) This example does work, and I confirmed via

importpywtprint(pywt.__version__)

that we have 1.4.1 being loaded currently. So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

@rgommers

Copy link
Copy Markdown
Member

The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

This is still WIP, right? It looks like this:

image

compared to in SciPy (which uses the same theme and plugins):

image

So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Yes, I shall improve the styling here – there are a couple of guides available about this in the JupyterLite docs, or I can follow the footsteps of the SciPy docs and re-use a similar style narrative.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

I personally don't think it is a good idea to merge this on the development version of the documentation when we do not have the nightly wheels set up, but a suitable workaround for now could be to make a note about this to users in the currently added admonition – referencing that the version of PyWavelets available may be a bit outdated and therefore some of the examples might not work?

I will make and verify some additional changes to ensure that the button is available on all of the examples running under the doctests. Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

@rgommers

Copy link
Copy Markdown
Member

There are no new functions in the 1.5.0 and 1.6.0 releases, and only a very small amount of behavioral changes (e.g., stricter input validation); there is nothing that will affect how the examples behave AFAIK.

Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

Yes, the Usage examples will likely require using the NotebookLite directive. I just tested the display for all of the doctest-based examples, which are making use of the TryExamples directive (enabled by global_enable_try_examples = True in conf.py). All of them are working as expected on all but the following pages under API reference (where there are no doctest-based examples, but other code-block based examples are present):

  1. Other functions
  2. Overview of multilevel wavelet decompositions
  3. Signal extension modes
  4. Multiresolution Analysis

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

One thing that isn't working so far and what I'm currently investigating is the size of the JupyterLite notebook that gets loaded, for example:

This screenshot displays the PyWavelets documentation deployed with Sphinx locally, where a page from the API reference is currently open.

is too short and doesn't expand to display all of the code cells, in comparison to the deployment showcased in scipy/scipy#20019. It might get fixed with a try-examples.json file that I am missing.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

It might be fixed with a try-examples.json file that I am missing.

This was indeed the missing thing, now everything works!

@agriyakhetarpalagriyakhetarpal changed the title [WIP]: Interactive documentation via JupyterLiteInitial steps towards interactive documentation via JupyterLiteMar 22, 2024
@agriyakhetarpal
agriyakhetarpal marked this pull request as ready for review March 22, 2024 07:48
@rgommers

Copy link
Copy Markdown
Member

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

Sure, if you know how to do it then why not do it straight away. All I was trying to say is that incremental improvements are okay too.

This is starting to look pretty good!

This commit moves the example for the function `pywt.data.demo_signal()` to the doctests for the
function instead of having it inside reST.
This shall render the example interactive through
the use of JupyterLite and the TryExamples
Sphinx directive.
@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, I have now restructured:

  • an example for pywt.data.demo_signal() from the Other functions page – I moved it to the doctests for the function so as to let jupyterlite-sphinx be able to access it, and, similarly,
  • most of the other examples that were interlaced with .. sourcecode:: python directives. They use the newer directive, which seems to offer code syntax highlighting by default.

Some more points:

  1. The Overview of multilevel wavelet decompositions page has its its reference files in doc/pyplots/ and they are end-to-end examples of analyses. It would be better to club changes to them in another PR, and so is the case for the Signal extension modes page; it contains a plotting example and some in-line examples, which I have marked with the .. try_examples:: directive manually like those mentioned in point 2 (side note: it is good thing PyWavelets isn't doesn't have a massive documentation reference haha).
  2. Also, Multiresolution Analysis, a.k.a. pywt.mra does not have any examples in the docstrings (just the two scripts in the demo/ folder).
  3. For the CWT examples, there are some that contain the # doctest: +SKIP label (but only inside the JupyterLite notebook, not the Sphinx docs). Is there something we can do about them – we don't want to break the doctests either? I do not think it is a big deal, though.

This is ready for another review, whenever you get a chance to do so! The aftermath of this PR can take care of the other pages. Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such (the latter would be better and more stable in its configuration – it's developed more actively).


P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, this is strange. I am receiving errors like File Load Error for 158988af_6816_4f65_a71c_affe1c6d5d90.ipynb when I try to start the kernel on any example on Read the Docs, but it works perfectly locally. The button is right-aligned too, and not left-aligned as I had configured it.

Edit: seems to be resolved now!

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Another thing I am noticing right now: the "Try it in your browser" text works on code snippets in docstrings under the

Examples
--------

heading, but it does not propagate to custom in-line examples, i.e., where we are using the .. try_examples:: directive manually – the button still shows the default "Try it with Jupyterlite" text instead of getting it from conf.py. jupyterlite-sphinx does offer a :button_text option to configure a particular example's button's text, but if it isn't present – it should consider the global configuration value.

This is as observed on the Continuous Wavelet Transform (CWT) page, and I think this is a bug. Let me file this on jupyterlite-sphinx's issue tracker.

@rgommersrgommers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, very nice work @agriyakhetarpal! The styling looks polished now, and all the examples I tried worked as expected. I think this is ready to go in, time for testing in the wild and seeing if we get any feedback/issues.

The last 5 commits are all useful, and I had zero comments on them.

A few responses:

  • .. sourcecode:: is obsolete indeed
  • Regarding pywt.mra not having examples: it'd be welcome if they were contributed, but it's a minor thing and unrelated to the interactive docs work
  • Re # doctest: +SKIP: in principle not that hard to get rid of, but I'd like to wait until SciPy updates its approach to doing that. It has nicer skip comments that actually say what the issue is (e.g., # may vary for output that, you guessed, can vary)

Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such

myst-nb seems fine to me.

P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

I like how it looks! Happy to stay with your choice here.

@rgommers
rgommers merged commit 8c63926 into PyWavelets:mainMar 28, 2024
@agriyakhetarpal
agriyakhetarpal deleted the test-interactive-docs branch March 28, 2024 22:30
@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Actually, I was working on submitting a PR today for the issue I opened over at jupyterlite-sphinx and tagged above – I should have asked you here to hold off on merging this :) But that's not a big deal and it is a minor fix too. I hope to be done with that soon, and I can always put up another PR.

@rgommers

Copy link
Copy Markdown
Member

That's perfectly okay I think - I'm sure there will be several follow-up PRs to this one to fix some issues and polish the experience.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@agriyakhetarpal@rgommers
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Initial steps towards interactive documentation via JupyterLite - #728

Merged
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs
Mar 28, 2024
Merged

Initial steps towards interactive documentation via JupyterLite#728
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs

Conversation

@agriyakhetarpal

@agriyakhetarpalagriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
Collaborator

Description

This PR adds interactive documentation via JupyterLite Pyodide-enabled kernels and tests them on Read the Docs.

The key changes here are:

  1. It enables the JupyterLite Pyodide kernel and the JupyterLite Sphinx extension for the documentation, for both building locally and for the hosted documentation on Read the Docs (this can be seen in the PR previews).
  2. It enables the JupyterLite extension for all of the doctest-based examples in the API reference wherever applicable, and adds a warning at the top of the notebook to warn users about how experimental these changes are.
  3. The style guidelines have been mimicked from those for SciPy, through this PR: DOC: Add support for interactive examples with jupyterlite-sphinx scipy/scipy#20019

Following this, users shall be able to run all of the examples by loading an installation of PyWavelets in notebooks inside the documentation, which can be opened in new tabs too, as necessary.

Footnotes

This is meant to address certain sections of gh-706, however, further follow-ups are required to enable interactivity for the rest of the available examples.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

@rgommers

Copy link
Copy Markdown
Member

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

It did actually build: https://pywavelets--728.org.readthedocs.build/en/728/. I'll check why there's no entry in the list of CI jobs here.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Thanks for the link! I'll use that for now and for future PRs. It is a bit strange, but as a workaround, we can use this GitHub Action: https://github.com/readthedocs/actions/tree/v1/preview if needed. It looks like it is a pretty easy to configure?

@rgommers

Copy link
Copy Markdown
Member

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

Thank you! It does show up here now – we can switch to the PR preview action at any time, if all we need is just a link. It will require write permissions to edit the PR description.

@agriyakhetarpal

agriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
CollaboratorAuthor

The Wavelet object example that you mentioned on Slack does not seem to be working – but I think that is because it's configured incorrectly (it is placed in the documentation in a .. sourcecode:: directive).

On the same page, other basic examples, i.e., those under an

Examples
--------

section and elsewhere are working wherever this heading is mentioned in the docstring, for example – this is for listing down the different types of Wavelet families available in PyWavelets. The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

The code snippet does take a bit to load, and did not work unless I opened it in a new tab (maybe I have way too many open tabs or something?) This example does work, and I confirmed via

importpywtprint(pywt.__version__)

that we have 1.4.1 being loaded currently. So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

@rgommers

Copy link
Copy Markdown
Member

The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

This is still WIP, right? It looks like this:

image

compared to in SciPy (which uses the same theme and plugins):

image

So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Yes, I shall improve the styling here – there are a couple of guides available about this in the JupyterLite docs, or I can follow the footsteps of the SciPy docs and re-use a similar style narrative.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

I personally don't think it is a good idea to merge this on the development version of the documentation when we do not have the nightly wheels set up, but a suitable workaround for now could be to make a note about this to users in the currently added admonition – referencing that the version of PyWavelets available may be a bit outdated and therefore some of the examples might not work?

I will make and verify some additional changes to ensure that the button is available on all of the examples running under the doctests. Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

@rgommers

Copy link
Copy Markdown
Member

There are no new functions in the 1.5.0 and 1.6.0 releases, and only a very small amount of behavioral changes (e.g., stricter input validation); there is nothing that will affect how the examples behave AFAIK.

Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

Yes, the Usage examples will likely require using the NotebookLite directive. I just tested the display for all of the doctest-based examples, which are making use of the TryExamples directive (enabled by global_enable_try_examples = True in conf.py). All of them are working as expected on all but the following pages under API reference (where there are no doctest-based examples, but other code-block based examples are present):

  1. Other functions
  2. Overview of multilevel wavelet decompositions
  3. Signal extension modes
  4. Multiresolution Analysis

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

One thing that isn't working so far and what I'm currently investigating is the size of the JupyterLite notebook that gets loaded, for example:

This screenshot displays the PyWavelets documentation deployed with Sphinx locally, where a page from the API reference is currently open.

is too short and doesn't expand to display all of the code cells, in comparison to the deployment showcased in scipy/scipy#20019. It might get fixed with a try-examples.json file that I am missing.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

It might be fixed with a try-examples.json file that I am missing.

This was indeed the missing thing, now everything works!

@agriyakhetarpalagriyakhetarpal changed the title [WIP]: Interactive documentation via JupyterLiteInitial steps towards interactive documentation via JupyterLiteMar 22, 2024
@agriyakhetarpal
agriyakhetarpal marked this pull request as ready for review March 22, 2024 07:48
@rgommers

Copy link
Copy Markdown
Member

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

Sure, if you know how to do it then why not do it straight away. All I was trying to say is that incremental improvements are okay too.

This is starting to look pretty good!

This commit moves the example for the function `pywt.data.demo_signal()` to the doctests for the
function instead of having it inside reST.
This shall render the example interactive through
the use of JupyterLite and the TryExamples
Sphinx directive.
@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, I have now restructured:

  • an example for pywt.data.demo_signal() from the Other functions page – I moved it to the doctests for the function so as to let jupyterlite-sphinx be able to access it, and, similarly,
  • most of the other examples that were interlaced with .. sourcecode:: python directives. They use the newer directive, which seems to offer code syntax highlighting by default.

Some more points:

  1. The Overview of multilevel wavelet decompositions page has its its reference files in doc/pyplots/ and they are end-to-end examples of analyses. It would be better to club changes to them in another PR, and so is the case for the Signal extension modes page; it contains a plotting example and some in-line examples, which I have marked with the .. try_examples:: directive manually like those mentioned in point 2 (side note: it is good thing PyWavelets isn't doesn't have a massive documentation reference haha).
  2. Also, Multiresolution Analysis, a.k.a. pywt.mra does not have any examples in the docstrings (just the two scripts in the demo/ folder).
  3. For the CWT examples, there are some that contain the # doctest: +SKIP label (but only inside the JupyterLite notebook, not the Sphinx docs). Is there something we can do about them – we don't want to break the doctests either? I do not think it is a big deal, though.

This is ready for another review, whenever you get a chance to do so! The aftermath of this PR can take care of the other pages. Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such (the latter would be better and more stable in its configuration – it's developed more actively).


P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, this is strange. I am receiving errors like File Load Error for 158988af_6816_4f65_a71c_affe1c6d5d90.ipynb when I try to start the kernel on any example on Read the Docs, but it works perfectly locally. The button is right-aligned too, and not left-aligned as I had configured it.

Edit: seems to be resolved now!

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Another thing I am noticing right now: the "Try it in your browser" text works on code snippets in docstrings under the

Examples
--------

heading, but it does not propagate to custom in-line examples, i.e., where we are using the .. try_examples:: directive manually – the button still shows the default "Try it with Jupyterlite" text instead of getting it from conf.py. jupyterlite-sphinx does offer a :button_text option to configure a particular example's button's text, but if it isn't present – it should consider the global configuration value.

This is as observed on the Continuous Wavelet Transform (CWT) page, and I think this is a bug. Let me file this on jupyterlite-sphinx's issue tracker.

@rgommersrgommers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, very nice work @agriyakhetarpal! The styling looks polished now, and all the examples I tried worked as expected. I think this is ready to go in, time for testing in the wild and seeing if we get any feedback/issues.

The last 5 commits are all useful, and I had zero comments on them.

A few responses:

  • .. sourcecode:: is obsolete indeed
  • Regarding pywt.mra not having examples: it'd be welcome if they were contributed, but it's a minor thing and unrelated to the interactive docs work
  • Re # doctest: +SKIP: in principle not that hard to get rid of, but I'd like to wait until SciPy updates its approach to doing that. It has nicer skip comments that actually say what the issue is (e.g., # may vary for output that, you guessed, can vary)

Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such

myst-nb seems fine to me.

P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

I like how it looks! Happy to stay with your choice here.

@rgommers
rgommers merged commit 8c63926 into PyWavelets:mainMar 28, 2024
@agriyakhetarpal
agriyakhetarpal deleted the test-interactive-docs branch March 28, 2024 22:30
@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Actually, I was working on submitting a PR today for the issue I opened over at jupyterlite-sphinx and tagged above – I should have asked you here to hold off on merging this :) But that's not a big deal and it is a minor fix too. I hope to be done with that soon, and I can always put up another PR.

@rgommers

Copy link
Copy Markdown
Member

That's perfectly okay I think - I'm sure there will be several follow-up PRs to this one to fix some issues and polish the experience.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@agriyakhetarpal@rgommers
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Initial steps towards interactive documentation via JupyterLite - #728

Merged
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs
Mar 28, 2024
Merged

Initial steps towards interactive documentation via JupyterLite#728
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs

Conversation

@agriyakhetarpal

@agriyakhetarpalagriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
Collaborator

Description

This PR adds interactive documentation via JupyterLite Pyodide-enabled kernels and tests them on Read the Docs.

The key changes here are:

  1. It enables the JupyterLite Pyodide kernel and the JupyterLite Sphinx extension for the documentation, for both building locally and for the hosted documentation on Read the Docs (this can be seen in the PR previews).
  2. It enables the JupyterLite extension for all of the doctest-based examples in the API reference wherever applicable, and adds a warning at the top of the notebook to warn users about how experimental these changes are.
  3. The style guidelines have been mimicked from those for SciPy, through this PR: DOC: Add support for interactive examples with jupyterlite-sphinx scipy/scipy#20019

Following this, users shall be able to run all of the examples by loading an installation of PyWavelets in notebooks inside the documentation, which can be opened in new tabs too, as necessary.

Footnotes

This is meant to address certain sections of gh-706, however, further follow-ups are required to enable interactivity for the rest of the available examples.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

@rgommers

Copy link
Copy Markdown
Member

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

It did actually build: https://pywavelets--728.org.readthedocs.build/en/728/. I'll check why there's no entry in the list of CI jobs here.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Thanks for the link! I'll use that for now and for future PRs. It is a bit strange, but as a workaround, we can use this GitHub Action: https://github.com/readthedocs/actions/tree/v1/preview if needed. It looks like it is a pretty easy to configure?

@rgommers

Copy link
Copy Markdown
Member

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

Thank you! It does show up here now – we can switch to the PR preview action at any time, if all we need is just a link. It will require write permissions to edit the PR description.

@agriyakhetarpal

agriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
CollaboratorAuthor

The Wavelet object example that you mentioned on Slack does not seem to be working – but I think that is because it's configured incorrectly (it is placed in the documentation in a .. sourcecode:: directive).

On the same page, other basic examples, i.e., those under an

Examples
--------

section and elsewhere are working wherever this heading is mentioned in the docstring, for example – this is for listing down the different types of Wavelet families available in PyWavelets. The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

The code snippet does take a bit to load, and did not work unless I opened it in a new tab (maybe I have way too many open tabs or something?) This example does work, and I confirmed via

importpywtprint(pywt.__version__)

that we have 1.4.1 being loaded currently. So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

@rgommers

Copy link
Copy Markdown
Member

The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

This is still WIP, right? It looks like this:

image

compared to in SciPy (which uses the same theme and plugins):

image

So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Yes, I shall improve the styling here – there are a couple of guides available about this in the JupyterLite docs, or I can follow the footsteps of the SciPy docs and re-use a similar style narrative.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

I personally don't think it is a good idea to merge this on the development version of the documentation when we do not have the nightly wheels set up, but a suitable workaround for now could be to make a note about this to users in the currently added admonition – referencing that the version of PyWavelets available may be a bit outdated and therefore some of the examples might not work?

I will make and verify some additional changes to ensure that the button is available on all of the examples running under the doctests. Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

@rgommers

Copy link
Copy Markdown
Member

There are no new functions in the 1.5.0 and 1.6.0 releases, and only a very small amount of behavioral changes (e.g., stricter input validation); there is nothing that will affect how the examples behave AFAIK.

Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

Yes, the Usage examples will likely require using the NotebookLite directive. I just tested the display for all of the doctest-based examples, which are making use of the TryExamples directive (enabled by global_enable_try_examples = True in conf.py). All of them are working as expected on all but the following pages under API reference (where there are no doctest-based examples, but other code-block based examples are present):

  1. Other functions
  2. Overview of multilevel wavelet decompositions
  3. Signal extension modes
  4. Multiresolution Analysis

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

One thing that isn't working so far and what I'm currently investigating is the size of the JupyterLite notebook that gets loaded, for example:

This screenshot displays the PyWavelets documentation deployed with Sphinx locally, where a page from the API reference is currently open.

is too short and doesn't expand to display all of the code cells, in comparison to the deployment showcased in scipy/scipy#20019. It might get fixed with a try-examples.json file that I am missing.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

It might be fixed with a try-examples.json file that I am missing.

This was indeed the missing thing, now everything works!

@agriyakhetarpalagriyakhetarpal changed the title [WIP]: Interactive documentation via JupyterLiteInitial steps towards interactive documentation via JupyterLiteMar 22, 2024
@agriyakhetarpal
agriyakhetarpal marked this pull request as ready for review March 22, 2024 07:48
@rgommers

Copy link
Copy Markdown
Member

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

Sure, if you know how to do it then why not do it straight away. All I was trying to say is that incremental improvements are okay too.

This is starting to look pretty good!

This commit moves the example for the function `pywt.data.demo_signal()` to the doctests for the
function instead of having it inside reST.
This shall render the example interactive through
the use of JupyterLite and the TryExamples
Sphinx directive.
@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, I have now restructured:

  • an example for pywt.data.demo_signal() from the Other functions page – I moved it to the doctests for the function so as to let jupyterlite-sphinx be able to access it, and, similarly,
  • most of the other examples that were interlaced with .. sourcecode:: python directives. They use the newer directive, which seems to offer code syntax highlighting by default.

Some more points:

  1. The Overview of multilevel wavelet decompositions page has its its reference files in doc/pyplots/ and they are end-to-end examples of analyses. It would be better to club changes to them in another PR, and so is the case for the Signal extension modes page; it contains a plotting example and some in-line examples, which I have marked with the .. try_examples:: directive manually like those mentioned in point 2 (side note: it is good thing PyWavelets isn't doesn't have a massive documentation reference haha).
  2. Also, Multiresolution Analysis, a.k.a. pywt.mra does not have any examples in the docstrings (just the two scripts in the demo/ folder).
  3. For the CWT examples, there are some that contain the # doctest: +SKIP label (but only inside the JupyterLite notebook, not the Sphinx docs). Is there something we can do about them – we don't want to break the doctests either? I do not think it is a big deal, though.

This is ready for another review, whenever you get a chance to do so! The aftermath of this PR can take care of the other pages. Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such (the latter would be better and more stable in its configuration – it's developed more actively).


P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, this is strange. I am receiving errors like File Load Error for 158988af_6816_4f65_a71c_affe1c6d5d90.ipynb when I try to start the kernel on any example on Read the Docs, but it works perfectly locally. The button is right-aligned too, and not left-aligned as I had configured it.

Edit: seems to be resolved now!

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Another thing I am noticing right now: the "Try it in your browser" text works on code snippets in docstrings under the

Examples
--------

heading, but it does not propagate to custom in-line examples, i.e., where we are using the .. try_examples:: directive manually – the button still shows the default "Try it with Jupyterlite" text instead of getting it from conf.py. jupyterlite-sphinx does offer a :button_text option to configure a particular example's button's text, but if it isn't present – it should consider the global configuration value.

This is as observed on the Continuous Wavelet Transform (CWT) page, and I think this is a bug. Let me file this on jupyterlite-sphinx's issue tracker.

@rgommersrgommers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, very nice work @agriyakhetarpal! The styling looks polished now, and all the examples I tried worked as expected. I think this is ready to go in, time for testing in the wild and seeing if we get any feedback/issues.

The last 5 commits are all useful, and I had zero comments on them.

A few responses:

  • .. sourcecode:: is obsolete indeed
  • Regarding pywt.mra not having examples: it'd be welcome if they were contributed, but it's a minor thing and unrelated to the interactive docs work
  • Re # doctest: +SKIP: in principle not that hard to get rid of, but I'd like to wait until SciPy updates its approach to doing that. It has nicer skip comments that actually say what the issue is (e.g., # may vary for output that, you guessed, can vary)

Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such

myst-nb seems fine to me.

P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

I like how it looks! Happy to stay with your choice here.

@rgommers
rgommers merged commit 8c63926 into PyWavelets:mainMar 28, 2024
@agriyakhetarpal
agriyakhetarpal deleted the test-interactive-docs branch March 28, 2024 22:30
@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Actually, I was working on submitting a PR today for the issue I opened over at jupyterlite-sphinx and tagged above – I should have asked you here to hold off on merging this :) But that's not a big deal and it is a minor fix too. I hope to be done with that soon, and I can always put up another PR.

@rgommers

Copy link
Copy Markdown
Member

That's perfectly okay I think - I'm sure there will be several follow-up PRs to this one to fix some issues and polish the experience.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@agriyakhetarpal@rgommers
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Initial steps towards interactive documentation via JupyterLite - #728

Merged
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs
Mar 28, 2024
Merged

Initial steps towards interactive documentation via JupyterLite#728
rgommers merged 11 commits into
PyWavelets:mainfrom
agriyakhetarpal:test-interactive-docs

Conversation

@agriyakhetarpal

@agriyakhetarpalagriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
Collaborator

Description

This PR adds interactive documentation via JupyterLite Pyodide-enabled kernels and tests them on Read the Docs.

The key changes here are:

  1. It enables the JupyterLite Pyodide kernel and the JupyterLite Sphinx extension for the documentation, for both building locally and for the hosted documentation on Read the Docs (this can be seen in the PR previews).
  2. It enables the JupyterLite extension for all of the doctest-based examples in the API reference wherever applicable, and adds a warning at the top of the notebook to warn users about how experimental these changes are.
  3. The style guidelines have been mimicked from those for SciPy, through this PR: DOC: Add support for interactive examples with jupyterlite-sphinx scipy/scipy#20019

Following this, users shall be able to run all of the examples by loading an installation of PyWavelets in notebooks inside the documentation, which can be opened in new tabs too, as necessary.

Footnotes

This is meant to address certain sections of gh-706, however, further follow-ups are required to enable interactivity for the rest of the available examples.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

@rgommers

Copy link
Copy Markdown
Member

The RTD PR preview fails to appear here, @rgommers – could you please help debug?

It did actually build: https://pywavelets--728.org.readthedocs.build/en/728/. I'll check why there's no entry in the list of CI jobs here.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Thanks for the link! I'll use that for now and for future PRs. It is a bit strange, but as a workaround, we can use this GitHub Action: https://github.com/readthedocs/actions/tree/v1/preview if needed. It looks like it is a pretty easy to configure?

@rgommers

Copy link
Copy Markdown
Member

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

I added an integration. Not too happy with how many permissions the RTD Oauth app wants, but all right - let's see if that worked.

Thank you! It does show up here now – we can switch to the PR preview action at any time, if all we need is just a link. It will require write permissions to edit the PR description.

@agriyakhetarpal

agriyakhetarpal commented Mar 14, 2024

Copy link
Copy Markdown
CollaboratorAuthor

The Wavelet object example that you mentioned on Slack does not seem to be working – but I think that is because it's configured incorrectly (it is placed in the documentation in a .. sourcecode:: directive).

On the same page, other basic examples, i.e., those under an

Examples
--------

section and elsewhere are working wherever this heading is mentioned in the docstring, for example – this is for listing down the different types of Wavelet families available in PyWavelets. The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

The code snippet does take a bit to load, and did not work unless I opened it in a new tab (maybe I have way too many open tabs or something?) This example does work, and I confirmed via

importpywtprint(pywt.__version__)

that we have 1.4.1 being loaded currently. So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

@rgommers

Copy link
Copy Markdown
Member

The size of the kernel is a tad too small – I'll configure that with other aesthetic changes, such as the size and shape of the "Try it" button(s).

This is still WIP, right? It looks like this:

image

compared to in SciPy (which uses the same theme and plugins):

image

So, my immediate next step will be to configure how to import plus install the nightly WASM wheel, as noted in the links under this section.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Yes, I shall improve the styling here – there are a couple of guides available about this in the JupyterLite docs, or I can follow the footsteps of the SciPy docs and re-use a similar style narrative.

Can you do that in a follow-up PR? This should be merge-able while using the PyWavelets version shipped by Pyodide.

I personally don't think it is a good idea to merge this on the development version of the documentation when we do not have the nightly wheels set up, but a suitable workaround for now could be to make a note about this to users in the currently added admonition – referencing that the version of PyWavelets available may be a bit outdated and therefore some of the examples might not work?

I will make and verify some additional changes to ensure that the button is available on all of the examples running under the doctests. Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

@rgommers

Copy link
Copy Markdown
Member

There are no new functions in the 1.5.0 and 1.6.0 releases, and only a very small amount of behavioral changes (e.g., stricter input validation); there is nothing that will affect how the examples behave AFAIK.

Do we need to add the button to the Usage examples too, or just these API reference examples would be enough for this PR?

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

I'd say API reference is a good first step here. I'm assuming that that is automatic, while Usage examples will require inserting directives into the .rst files - is that correct? If so, let's do API reference only to get some experience, and leave Usage examples for later.

Yes, the Usage examples will likely require using the NotebookLite directive. I just tested the display for all of the doctest-based examples, which are making use of the TryExamples directive (enabled by global_enable_try_examples = True in conf.py). All of them are working as expected on all but the following pages under API reference (where there are no doctest-based examples, but other code-block based examples are present):

  1. Other functions
  2. Overview of multilevel wavelet decompositions
  3. Signal extension modes
  4. Multiresolution Analysis

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

One thing that isn't working so far and what I'm currently investigating is the size of the JupyterLite notebook that gets loaded, for example:

This screenshot displays the PyWavelets documentation deployed with Sphinx locally, where a page from the API reference is currently open.

is too short and doesn't expand to display all of the code cells, in comparison to the deployment showcased in scipy/scipy#20019. It might get fixed with a try-examples.json file that I am missing.

@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

It might be fixed with a try-examples.json file that I am missing.

This was indeed the missing thing, now everything works!

@agriyakhetarpalagriyakhetarpal changed the title [WIP]: Interactive documentation via JupyterLiteInitial steps towards interactive documentation via JupyterLiteMar 22, 2024
@agriyakhetarpal
agriyakhetarpal marked this pull request as ready for review March 22, 2024 07:48
@rgommers

Copy link
Copy Markdown
Member

These can be updated in a separate PR as necessary, but I am happy to try configuring those examples to the doctests here too.

Sure, if you know how to do it then why not do it straight away. All I was trying to say is that incremental improvements are okay too.

This is starting to look pretty good!

This commit moves the example for the function `pywt.data.demo_signal()` to the doctests for the
function instead of having it inside reST.
This shall render the example interactive through
the use of JupyterLite and the TryExamples
Sphinx directive.
@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, I have now restructured:

  • an example for pywt.data.demo_signal() from the Other functions page – I moved it to the doctests for the function so as to let jupyterlite-sphinx be able to access it, and, similarly,
  • most of the other examples that were interlaced with .. sourcecode:: python directives. They use the newer directive, which seems to offer code syntax highlighting by default.

Some more points:

  1. The Overview of multilevel wavelet decompositions page has its its reference files in doc/pyplots/ and they are end-to-end examples of analyses. It would be better to club changes to them in another PR, and so is the case for the Signal extension modes page; it contains a plotting example and some in-line examples, which I have marked with the .. try_examples:: directive manually like those mentioned in point 2 (side note: it is good thing PyWavelets isn't doesn't have a massive documentation reference haha).
  2. Also, Multiresolution Analysis, a.k.a. pywt.mra does not have any examples in the docstrings (just the two scripts in the demo/ folder).
  3. For the CWT examples, there are some that contain the # doctest: +SKIP label (but only inside the JupyterLite notebook, not the Sphinx docs). Is there something we can do about them – we don't want to break the doctests either? I do not think it is a big deal, though.

This is ready for another review, whenever you get a chance to do so! The aftermath of this PR can take care of the other pages. Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such (the latter would be better and more stable in its configuration – it's developed more actively).


P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Okay, this is strange. I am receiving errors like File Load Error for 158988af_6816_4f65_a71c_affe1c6d5d90.ipynb when I try to start the kernel on any example on Read the Docs, but it works perfectly locally. The button is right-aligned too, and not left-aligned as I had configured it.

Edit: seems to be resolved now!

@agriyakhetarpal

agriyakhetarpal commented Mar 22, 2024

Copy link
Copy Markdown
CollaboratorAuthor

Another thing I am noticing right now: the "Try it in your browser" text works on code snippets in docstrings under the

Examples
--------

heading, but it does not propagate to custom in-line examples, i.e., where we are using the .. try_examples:: directive manually – the button still shows the default "Try it with Jupyterlite" text instead of getting it from conf.py. jupyterlite-sphinx does offer a :button_text option to configure a particular example's button's text, but if it isn't present – it should consider the global configuration value.

This is as observed on the Continuous Wavelet Transform (CWT) page, and I think this is a bug. Let me file this on jupyterlite-sphinx's issue tracker.

@rgommersrgommers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, very nice work @agriyakhetarpal! The styling looks polished now, and all the examples I tried worked as expected. I think this is ready to go in, time for testing in the wild and seeing if we get any feedback/issues.

The last 5 commits are all useful, and I had zero comments on them.

A few responses:

  • .. sourcecode:: is obsolete indeed
  • Regarding pywt.mra not having examples: it'd be welcome if they were contributed, but it's a minor thing and unrelated to the interactive docs work
  • Re # doctest: +SKIP: in principle not that hard to get rid of, but I'd like to wait until SciPy updates its approach to doing that. It has nicer skip comments that actually say what the issue is (e.g., # may vary for output that, you guessed, can vary)

Maybe we should use nbsphinx or Myst-NB to render them as actual notebooks when they have been converted to such

myst-nb seems fine to me.

P.S. I modified the CSS to make the buttons left-aligned instead of being right-aligned (like SciPy's were). I feel that the left-aligned buttons look better under a left-aligned heading, but that's just my preference. Do you have thoughts on that?

I like how it looks! Happy to stay with your choice here.

@rgommers
rgommers merged commit 8c63926 into PyWavelets:mainMar 28, 2024
@agriyakhetarpal
agriyakhetarpal deleted the test-interactive-docs branch March 28, 2024 22:30
@agriyakhetarpal

Copy link
Copy Markdown
CollaboratorAuthor

Actually, I was working on submitting a PR today for the issue I opened over at jupyterlite-sphinx and tagged above – I should have asked you here to hold off on merging this :) But that's not a big deal and it is a minor fix too. I hope to be done with that soon, and I can always put up another PR.

@rgommers

Copy link
Copy Markdown
Member

That's perfectly okay I think - I'm sure there will be several follow-up PRs to this one to fix some issues and polish the experience.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@agriyakhetarpal@rgommers