How do (can) I use a custom.js file under Jupyter notebook?

13,898

Solution 1

Using custom.js still works for me, but it seems to move around a fair bit.

Currently (version 4.2.3) as well as in the documentation for the upcoming 5.0 release, it's at ~/.jupyter/custom/custom.js. See the documentation at http://jupyter-notebook.readthedocs.io/en/latest/examples/Notebook/JavaScript%20Notebook%20Extensions.html#custom.js

You can show the path to and content of custom.js by executing this snippet in a notebook:

from jupyter_core.paths import jupyter_config_dir
jupyter_dir = jupyter_config_dir()
import os.path
custom_js_path = os.path.join(jupyter_dir, 'custom', 'custom.js')
print("searching for custom.js in ", custom_js_path)
#  my custom js
if os.path.isfile(custom_js_path):
    with open(custom_js_path) as f:
        print(f.read())
else:
    print("You don't have a custom.js file")

Solution 2

How do I get things working again? Do I just not need to wait for app_initialized any more?

I don't have deep insight into the recommended way to do this, but with Jupyter/IPython 4.0, waiting on "notebook_loaded.Notebook" instead of "app_initialized.NotebookApp" works. i.e. use this line:

    events.on("notebook_loaded.Notebook", function () {

Solution 3

This question has arisen on the Github issue tracker - Issues with jupyter 4.0 - and links to a recent update that appears to simplify the loading of extensions: code update:

"By editing notebook.json manually. By default it is located at ~/.jupyter/nbconfig/notebook.json:"

{
    "load_extensions": {
      "notify": true,
      "theme_toggle": true
  }
}

Adding things like "code_folding/main": true also seem to work.

So my understanding is that this would replace the use of custom.js for loading the extensions?

Solution 4

The app_initialized.NotebookApp event is still fired if you look the notebook static/notebook/js/main.js code.

but you have to listen at this event using the define() function from requireJS:

define([
  'base/js/namespace',
  'base/js/events'
], function(IPython, events) {
   events.on('app_initialized.NotebookApp', function() {
     // Your Code
   });
});

Here your callback will be executed.

If you put in your custom.js :

 require(['base/js/namespace', 'base/js/events'], function(IPython, events) {
     events.on('notebook_loaded.Notebook', function() {
        console.log('require & notebook_loaded.Notebook');
    });
     events.on('app_initialized.NotebookApp', function() {
        console.log('require & app_initialized.NotebookApp');
     });
 });

 define(['base/js/namespace', 'base/js/events'], function(IPython, events) {
     events.on('notebook_loaded.Notebook', function() {
        console.log('define & notebook_loaded.Notebook');
    });
     events.on('app_initialized.NotebookApp', function() {
         console.log('define & app_initialized.NotebookApp');
     });
 });

The result in the console will be :

define() & app_initialized.NotebookApp
define() & notebook_loaded.Notebook
require() & notebook_loaded.Notebook

I guess that with the require() you register to an event that had already happen...

require() is waiting for all dependencies and submodules to be intialized... which might be too late for the app_initialized.NotebookApp event.

Share:
13,898

Related videos on Youtube

Mike
Author by

Mike

I am a theoretical astrophysicist -- at least I try to be when I'm not programming.

Updated on June 16, 2022

Comments

  • Mike
    Mike almost 2 years

    In the IPython notebook (v3.1, for example), I could add a ~/.ipython/profile_default/static/custom/custom.js file to execute some custom JavaScript. For example, I could do something like this:

    require(['base/js/namespace', 'base/js/events'], function(IPython, events) {
        console.log("A");
        events.on('app_initialized.NotebookApp', function() {
            console.log("B");
        });
        console.log("C");
    });
    

    Then, in the JS console, I would see A, followed by B, followed by C.

    Now, as of version 4.0, they've split it out into the Jupyter notebook. The same file gets loaded (despite the fact that it's under ~/.ipython, rather than under ~/.jupyter), and the code gets executed. However, I no longer see the B line. I guess the app isn't getting initialized. I still see it get triggered in the source code, but does that comes later, or is it just not working?

    How do I get things working again? Do I just not need to wait for app_initialized any more? Is any of this documented somewhere?

    Edit

    This page seems to suggest that the way to do it nowadays is to create a custom extension and put all the action in the load_ipython_extension function. Is that right? If so, how about mathjax? And CodeMirror options?

  • MHH
    MHH over 8 years
    > Is any of this documented somewhere? -- I don't know the answer, but maybe we can get @minrk to comment here.
  • Agile Bean
    Agile Bean over 5 years
    do you still need to do this for jupyter 5.0+?