JS9 with Python and Jupyter

Connecting Python to JS9

The pyjs9.py module connects Python and JS9. It is available on GitHub:   https://github.com/ericmandel/pyjs9.

The JS9 class constructor connects to a single JS9 instance in a web page. Once the connection is made, the returned JS9 object supports the JS9 Public API and a shorter command-line syntax. You also can send/retrieve numpy arrays and astropy (or pyfits) hdulists to/from JS9.

pyjs9 communicates with the JS9 back-end server (which communicates with the browser itself). By default, pyjs9 utilizes the requests module to communicate with the back-end server. However, if you install the socketIO_client, pyjs9 will use the faster, persistent socket.io protocol.

Install pyjs9 from the GitHub repository using pip, as usual:

    > pip install git+https://github.com/ericmandel/pyjs9.git#egg=pyjs9
or from a local copy:
    > pip install /path/to/local/copy

Mandatory dependencies for pyjs9 are:

Optional dependencies for pyjs9 are:

To run pyjs9:

    > # ensure JS9 node-server is running ...
    > # visit your local JS9 web page in your browser ...
    > python
    ... (startup messages) ...
    >>> import pyjs9
    >>>
    >>> j = pyjs9.JS9()        # default: connect to 'http://localhost'
    >>>
    >>> j.GetColormap()
    {'bias': 0.5, 'colormap': 'grey', 'contrast': 1}
    >>> j.SetColormap('red')
    >>> j.cmap()
    'red 1 0.5'
    >>>
    >>> hdul = j.GetFITS()
    >>> hdul.info()
    Filename: (No file associated with this HDUList)
    No.    Name         Type      Cards   Dimensions   Format
    0    PRIMARY     PrimaryHDU       6   (1024, 1024)   int32   
    >>>
    >>> narr = j.GetNumpy()
    >>> narr.shape
    (1024, 1024)

If you have internet connectivity, visit the JS9 web page at https://js9.si.edu with your browser and:

    > python
    ... (startup messages) ...
    >>> import pyjs9
    >>>
    >>> j = pyjs9.JS9('js9.si.edu')        # connect to JS9 web site
    >>>
    >>> j.GetColormap()
    {'bias': 0.5, 'colormap': 'grey', 'contrast': 1}
    >>>
    >>> # etc ...

Adding JS9 to Jupyter (aka IPython)

We are working on integrating JS9 into Jupyter properly. For now, you can utilize Jupyter's %%html construct to load JS9 into a cell for display. You simply add JS9 divs to cell and load the JS9 CSS and Javascript code.

To simplify matters, the JS9 CSS files are combined together into a file called js9-allinone.css and the JS9 Javascript files are combined into a file called js9-allinone.js. These can be loaded in a cell after the JS9 divs are defined:

    %%html
    <div class="JS9Menubar"></div>
    <div class="JS9"></div>
    <link type="text/css" rel="stylesheet" href="//js9.si.edu/jupyter/js9-allinone.css">
    <script type="text/javascript" src="//js9.si.edu/jupyter/js9-allinone.js"></script>
In this example, the JS9 display and menubar will be loaded into the Jupyter page. You can then drag and drop FITS images onto the display or use the File:open local file... option to load FITS data. Once an image is loaded, you can pan, zoom, scale, change colormaps, etc, and also utilize JS9 plugins (panner, magnifier, browser analysis, etc.) as usual. NB: Obviously, the JS9 install files and directories (other than all-in-one .css and .js files) are not available in this mode, leading to the following limitations:

Note that you also can use Jupyter's %%html syntax to define an HTML iframe that will display an existing JS9 web page:

    %%html
    <iframe src="https://js9.si.edu" width=1000 height=750></iframe>
or perhaps better still:
    %%html
    <iframe src="https://js9.si.edu/js9/js9.html" width=100% height=900></iframe>
Since you are now accessing an existing web site, all JS9 functions should work as expected ... except for the use of locally stored preferences (i.e. the Preferences plugin) in Firefox. Currently, Firefox throws a security exception when an iframe tries to access local storage, so this function does not work.

We will continue to improve the Jupyter/JS9 connection. Please send us your comments and suggestions.

Last updated: June 8, 2016