IPython Notebook Notes

Page Contents

Useful Links...

Widgets, Interact And MPLD3

Wow, some of the Python stuff available is just immense. This is an example of using the IPython HTML widgets, interact, and MPLD3 to display on demand different a particular graph which can be panned and zoomed! The example code might not be the best... I'm still learning this, but I'm just wowed at how easy Python and its surrounding support libraries makes doing this sort if thing!

It's worth noting that the Python distro I had, had a slightly out of date IPython so I needed to do a pip install --upgrade ipython to update everything to take advantage of the latest widget library.

On my Ubuntu machine, at the time of writing, I also had to upgrade various things, including matplotlib for MPLD3 from version 1.1.0 to 1.3.0:

sudo pip install --upgrade ipython
sudo pip install --upgrade pyzmq
sudo pip install --upgrade tornado
sudo pip install jsonschema
sudo easy_install -U distribute
sudo pip install --upgrade matplotlib

So... a quick example using MPLD3 and widgets...

import numpy as np
from IPython.html import widgets
from IPython import display
import matplotlib.pyplot as plt, mpld3
%matplotlib inline # Make sure matplotlib graphs are displayed inline in cell HTML output

graphChoice = widgets.Select(options=['a', 'b', 'c', 'd'])
plotBtn     = widgets.Button(description="Plot")

def PlotIt(btn):
    display.clear_output()    
    fig, ax = plt.subplots()
    x = np.linspace(-10,10,25)
    if graphChoice.value == 'a': y = np.power(x, 2)
    if graphChoice.value == 'b': y = np.power(x, 3)
    if graphChoice.value == 'c': y = -np.power(x, 2)
    if graphChoice.value == 'd': y = -np.power(x, 3)
    ax.plot(x,y, marker='x')
    
    # This plugin will display graph coordinates of the mouse when it
    # hovers over the graph in the bottom right! It must be linked to the
    # matplotlib figure and called before mpld3.display().
    mpld3.plugins.connect(fig, mpld3.plugins.MousePosition()) 

    # Use this to display the mpld3 figure...
    mpld3Fig = mpld3.display(fig) # Auto removes `fig` for us
    display.display(mpld3Fig)

plotBtn.on_click(PlotIt)
display.display(graphChoice)
display.display(plotBtn)
			

You can see this in action using the online nbviewer... Hover over the graph with your mouse cursor. At the bottom left some grey icons will pop-up. Click on the pan icon and then you can pan through the graph by draging it and zoom using the mouse scroll wheel... all real time and interactive in your browser window.

One slightly annoying thing is that the notebook viewer doesn't display the interactive widgets so although you can see the mpld3 interactive graph in action, you can't see the widgets in action which would allow you to select what graph you want to see. Download the notebook and run locally for that part of the demo.

You can read about mpld3 plugins here.

Displaying a JavaScript alert() on error

from IPython import display
# ... snip ...
if some_error_condition:
   warnstr = "your message here"
   display.display(display.Javascript('alert("{}")'.format(warnstr)))

Widening A Widget

The standard width of the select widgets can be a little small... Tell them to be as wide as possible like this:

my_widget = widgets.SelectMultiple(options=...)
my_widget.width = "100%"

Or in the constructor....

my_widget = widgets.SelectMultiple(options=..., width="100%")

Highlight MPLD3 Lines On Mouse Over

I found the example for visualising random walks which used the mouseover and mouseout D3 events (D3 is the JS library for SVG drawing and graphs that MPLD3 uses) to highlight lines by changing their opacity.I wanted to do this using line width.

The solution is an easy one. Just change the lines like the following:

d3.select(this).transition().duration(50)
  .style("stroke-opacity", alpha_fg);

To the following:

d3.select(this).style("stroke-width", "5px");

I ran this with the LineLabelTooltip plugin as shown below.

for idx in range(len(lines)):
   mpld3.plugins.connect(fig, mpld3.plugins.LineLabelTooltip(lines[idx], names[idx], location = "mouse"))
mpld3.plugins.connect(fig, HighlightLines(lines, names))

The problem was that HightLightLines was removing the event handler for LineLabelToolTip and replacing it with its own. The impact being that the line highlighting worked but the tool tips did not. The solution was found in the D3 documentation for events: If an event listener was already registered for the same type on the selected element, the existing listener is removed before the new listener is added. To register multiple listeners for the same event type, the type may be followed by an optional namespace, such as "click.foo" and "click.bar". The solution therefore is to change the event registration to this as follows:

obj.elements().on("mouseover.your-identifier-here", ....)

With this addition the HightLightLines no longer clobbers events already registered for the D3 object (in this case a line).

CSS For Notebook Output HTML

I wanted to format the output HTML style of HTML generated in NB cells but without effecting the formatting of the NB itself... just the output of cells!

Credits to the following two SO threads...

The last thread discusses being able to put the CSS styling in a markdown cell as one of the solutions. However, this didn't work for me. I found it worked by displaying the HTML element that contained the style tag...

Ouput_css_1.ipynb demonstrates the first situation where I have output a CSS stylesheet for the output HTML from the NB cells, but although most of the new CSS properties I set are obeyed, `vertical-align` for a table cell is not. That was annoying...

Ouput_css_2.ipynb demonstrates a first attempt to fix the above problem. By making the CSS properties that were previously not obeyed !important they are then implemented. The disadvantage here is that I have to smatter my style sheet with !important tags rather than using the cascading and inheritance properties of CSS. Seems cludgey to me...

Ouput_css_3.ipynb tries a different approach. The output from the NB cells are all placed in DIVs with a class .output_html. The NB style sheet includes CSS definitions for children of nodes with the .output_html class and it is these that are overriding the settings I want to make. The approach here is to define styles for elements that are the children of .output_html nodes...