mpld3: matplotlib to D3js

http://mpld3.github.io

  • Package by Jake Vanderplas (hey that's me!)

  • Reads the object structure of matplotlib figures and converts them to D3js

  • An extensible plugin system for adding new interactivity

  • Because it uses mpl, it is automatically compatible with PrettyPlotLib, ggplot, and Seaborn

In [1]:
#%run talktools
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from IPython.display import HTML

# CSS formatting
from IPython.display import HTML
HTML("""
<style>
h1 {text-align:center; color:#111133; font-size: 220%;}
h2 {text-align:center; color:#111155; font-size: 150%;}
h3 {text-align:center; font-size: 140%;}
</style>
""")
Out[1]:

As we saw, matplotlib can be used with the IPython notebook to embed visualizations...

In [2]:
x, y = np.random.normal(0, 1, [2, 100])
c, s = 800 * np.random.random([2, 100])

fig = plt.figure()
points = plt.scatter(x, y, c=c, s=s, alpha=0.3)
plt.grid(color="lightgray");

But this is annoyingly static...

The Solution: translate matplotlib to D3js!

In [3]:
import mpld3
mpld3.enable_notebook()
fig
Out[3]:

What is this actually doing?

Using the mplexporter package to scrape info from the matplotlib object

Outputs a JSON representation of the figure

In [4]:
mpld3.fig_to_dict(fig)
Out[4]:
{'axes': [{'axes': [{'fontsize': 10.0,
     'grid': {'alpha': 1.0,
      'color': '#D3D3D3',
      'dasharray': '2,2',
      'gridOn': True},
     'nticks': 9,
     'position': 'bottom',
     'scale': 'linear',
     'tickformat': None,
     'tickvalues': None},
    {'fontsize': 10.0,
     'grid': {'alpha': 1.0,
      'color': '#D3D3D3',
      'dasharray': '2,2',
      'gridOn': True},
     'nticks': 6,
     'position': 'left',
     'scale': 'linear',
     'tickformat': None,
     'tickvalues': None}],
   'axesbg': '#FFFFFF',
   'axesbgalpha': None,
   'bbox': (0.125, 0.125, 0.77500000000000002, 0.77500000000000002),
   'collections': [{'alphas': [0.3],
     'edgecolors': ['#000000'],
     'edgewidths': (1.0,),
     'facecolors': ['#00A0FF',
      '#FFDA00',
      '#00E4F7',
      '#EDFF08',
      '#FF2C00',
      '#15FFE1',
      '#93FF63',
      '#0000A8',
      '#12FCE4',
      '#FF7A00',
      '#96FF5F',
      '#0000F5',
      '#0000AC',
      '#FFC000',
      '#001CFF',
      '#0000FA',
      '#00007F',
      '#BA0000',
      '#004CFF',
      '#BF0000',
      '#EAFF0C',
      '#D10000',
      '#0074FF',
      '#F7F400',
      '#0078FF',
      '#007CFF',
      '#FF2C00',
      '#BAFF3C',
      '#A0FF56',
      '#FF8500',
      '#FF9F00',
      '#840000',
      '#FFDA00',
      '#0058FF',
      '#02E8F4',
      '#00D4FF',
      '#D4FF22',
      '#8D0000',
      '#FFDA00',
      '#9AFF5C',
      '#0088FF',
      '#000088',
      '#009CFF',
      '#0000B1',
      '#0070FF',
      '#FFDA00',
      '#F4F802',
      '#FF9F00',
      '#004CFF',
      '#0014FF',
      '#DA0000',
      '#FF3B00',
      '#79FF7D',
      '#0074FF',
      '#08F0ED',
      '#7F0000',
      '#FF3400',
      '#00C4FF',
      '#000CFF',
      '#A30000',
      '#F4F802',
      '#80FF76',
      '#FE1200',
      '#25FFD0',
      '#910000',
      '#FF3000',
      '#FF4A00',
      '#70FF86',
      '#FFAE00',
      '#7F0000',
      '#1FFFD7',
      '#3FFFB7',
      '#0004FF',
      '#00C8FF',
      '#9A0000',
      '#FE1200',
      '#42FFB3',
      '#0000D1',
      '#E7FF0F',
      '#0000C3',
      '#00DCFE',
      '#2CFFCA',
      '#00DCFE',
      '#FF7E00',
      '#0000D5',
      '#D4FF22',
      '#0024FF',
      '#0048FF',
      '#32FFC3',
      '#AC0000',
      '#FFD700',
      '#960000',
      '#0014FF',
      '#93FF63',
      '#A6FF4F',
      '#80FF76',
      '#008CFF',
      '#910000',
      '#7CFF79',
      '#B60000'],
     'id': 'el323334398123792',
     'offsetcoordinates': 'data',
     'offsets': 'data01',
     'pathcoordinates': 'display',
     'paths': [([[0.0, -0.5],
        [0.13260155, -0.5],
        [0.25978993539242673, -0.44731684579412084],
        [0.3535533905932738, -0.3535533905932738],
        [0.44731684579412084, -0.25978993539242673],
        [0.5, -0.13260155],
        [0.5, 0.0],
        [0.5, 0.13260155],
        [0.44731684579412084, 0.25978993539242673],
        [0.3535533905932738, 0.3535533905932738],
        [0.25978993539242673, 0.44731684579412084],
        [0.13260155, 0.5],
        [0.0, 0.5],
        [-0.13260155, 0.5],
        [-0.25978993539242673, 0.44731684579412084],
        [-0.3535533905932738, 0.3535533905932738],
        [-0.44731684579412084, 0.25978993539242673],
        [-0.5, 0.13260155],
        [-0.5, 0.0],
        [-0.5, -0.13260155],
        [-0.44731684579412084, -0.25978993539242673],
        [-0.3535533905932738, -0.3535533905932738],
        [-0.25978993539242673, -0.44731684579412084],
        [-0.13260155, -0.5],
        [0.0, -0.5]],
       ['M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'Z'])],
     'pathtransforms': [[28.3790117504894,
       0.0,
       0.0,
       28.3790117504894,
       0.0,
       0.0],
      [12.544108538668796, 0.0, 0.0, 12.544108538668796, 0.0, 0.0],
      [8.966858506099467, 0.0, 0.0, 8.966858506099467, 0.0, 0.0],
      [3.3220322204370265, 0.0, 0.0, 3.3220322204370265, 0.0, 0.0],
      [23.800792172694816, 0.0, 0.0, 23.800792172694816, 0.0, 0.0],
      [19.922823523772802, 0.0, 0.0, 19.922823523772802, 0.0, 0.0],
      [3.4481980766934877, 0.0, 0.0, 3.4481980766934877, 0.0, 0.0],
      [25.63453156837916, 0.0, 0.0, 25.63453156837916, 0.0, 0.0],
      [20.141961145391594, 0.0, 0.0, 20.141961145391594, 0.0, 0.0],
      [13.315443812884896, 0.0, 0.0, 13.315443812884896, 0.0, 0.0],
      [12.969255327387865, 0.0, 0.0, 12.969255327387865, 0.0, 0.0],
      [25.421806983794152, 0.0, 0.0, 25.421806983794152, 0.0, 0.0],
      [21.71258367234107, 0.0, 0.0, 21.71258367234107, 0.0, 0.0],
      [23.332123945881413, 0.0, 0.0, 23.332123945881413, 0.0, 0.0],
      [23.132686275277607, 0.0, 0.0, 23.132686275277607, 0.0, 0.0],
      [4.972397587147349, 0.0, 0.0, 4.972397587147349, 0.0, 0.0],
      [25.666173952436115, 0.0, 0.0, 25.666173952436115, 0.0, 0.0],
      [19.865426867718696, 0.0, 0.0, 19.865426867718696, 0.0, 0.0],
      [16.272530943531162, 0.0, 0.0, 16.272530943531162, 0.0, 0.0],
      [13.220647236401469, 0.0, 0.0, 13.220647236401469, 0.0, 0.0],
      [15.17688652337327, 0.0, 0.0, 15.17688652337327, 0.0, 0.0],
      [29.45475348744967, 0.0, 0.0, 29.45475348744967, 0.0, 0.0],
      [25.167005803062708, 0.0, 0.0, 25.167005803062708, 0.0, 0.0],
      [25.588535884853403, 0.0, 0.0, 25.588535884853403, 0.0, 0.0],
      [25.699404412178794, 0.0, 0.0, 25.699404412178794, 0.0, 0.0],
      [29.111789634815334, 0.0, 0.0, 29.111789634815334, 0.0, 0.0],
      [31.08327547554408, 0.0, 0.0, 31.08327547554408, 0.0, 0.0],
      [7.099890423192904, 0.0, 0.0, 7.099890423192904, 0.0, 0.0],
      [14.483675649549793, 0.0, 0.0, 14.483675649549793, 0.0, 0.0],
      [28.966809559659296, 0.0, 0.0, 28.966809559659296, 0.0, 0.0],
      [8.274376221214922, 0.0, 0.0, 8.274376221214922, 0.0, 0.0],
      [26.394043630584342, 0.0, 0.0, 26.394043630584342, 0.0, 0.0],
      [21.744040524798816, 0.0, 0.0, 21.744040524798816, 0.0, 0.0],
      [16.693920097508006, 0.0, 0.0, 16.693920097508006, 0.0, 0.0],
      [1.0536501362986839, 0.0, 0.0, 1.0536501362986839, 0.0, 0.0],
      [20.915139657824753, 0.0, 0.0, 20.915139657824753, 0.0, 0.0],
      [31.198511667086002, 0.0, 0.0, 31.198511667086002, 0.0, 0.0],
      [27.30064723087659, 0.0, 0.0, 27.30064723087659, 0.0, 0.0],
      [30.967934447068476, 0.0, 0.0, 30.967934447068476, 0.0, 0.0],
      [9.864212095926193, 0.0, 0.0, 9.864212095926193, 0.0, 0.0],
      [17.464625633724463, 0.0, 0.0, 17.464625633724463, 0.0, 0.0],
      [18.57132271860369, 0.0, 0.0, 18.57132271860369, 0.0, 0.0],
      [21.8658982682885, 0.0, 0.0, 21.8658982682885, 0.0, 0.0],
      [5.1384737670300655, 0.0, 0.0, 5.1384737670300655, 0.0, 0.0],
      [25.746788967406168, 0.0, 0.0, 25.746788967406168, 0.0, 0.0],
      [10.577222254664052, 0.0, 0.0, 10.577222254664052, 0.0, 0.0],
      [16.586356054058466, 0.0, 0.0, 16.586356054058466, 0.0, 0.0],
      [21.377421328006104, 0.0, 0.0, 21.377421328006104, 0.0, 0.0],
      [23.245623701850505, 0.0, 0.0, 23.245623701850505, 0.0, 0.0],
      [27.958521200201364, 0.0, 0.0, 27.958521200201364, 0.0, 0.0],
      [31.026111505749522, 0.0, 0.0, 31.026111505749522, 0.0, 0.0],
      [27.00844690234355, 0.0, 0.0, 27.00844690234355, 0.0, 0.0],
      [28.73186258987124, 0.0, 0.0, 28.73186258987124, 0.0, 0.0],
      [28.14361080430599, 0.0, 0.0, 28.14361080430599, 0.0, 0.0],
      [25.484832121728132, 0.0, 0.0, 25.484832121728132, 0.0, 0.0],
      [15.18768261863322, 0.0, 0.0, 15.18768261863322, 0.0, 0.0],
      [27.190923345291594, 0.0, 0.0, 27.190923345291594, 0.0, 0.0],
      [3.704160861756436, 0.0, 0.0, 3.704160861756436, 0.0, 0.0],
      [18.634144276110177, 0.0, 0.0, 18.634144276110177, 0.0, 0.0],
      [29.799630271437213, 0.0, 0.0, 29.799630271437213, 0.0, 0.0],
      [24.013011236302482, 0.0, 0.0, 24.013011236302482, 0.0, 0.0],
      [11.690642719942812, 0.0, 0.0, 11.690642719942812, 0.0, 0.0],
      [29.469480826190235, 0.0, 0.0, 29.469480826190235, 0.0, 0.0],
      [29.618421150791896, 0.0, 0.0, 29.618421150791896, 0.0, 0.0],
      [21.540148270560127, 0.0, 0.0, 21.540148270560127, 0.0, 0.0],
      [28.111270336613703, 0.0, 0.0, 28.111270336613703, 0.0, 0.0],
      [30.11051748188495, 0.0, 0.0, 30.11051748188495, 0.0, 0.0],
      [3.098167988613516, 0.0, 0.0, 3.098167988613516, 0.0, 0.0],
      [24.56174883085312, 0.0, 0.0, 24.56174883085312, 0.0, 0.0],
      [22.42659291654955, 0.0, 0.0, 22.42659291654955, 0.0, 0.0],
      [17.845489025445644, 0.0, 0.0, 17.845489025445644, 0.0, 0.0],
      [23.943897488718434, 0.0, 0.0, 23.943897488718434, 0.0, 0.0],
      [18.77771874458468, 0.0, 0.0, 18.77771874458468, 0.0, 0.0],
      [27.651888081328025, 0.0, 0.0, 27.651888081328025, 0.0, 0.0],
      [15.903876496713789, 0.0, 0.0, 15.903876496713789, 0.0, 0.0],
      [26.78946533457776, 0.0, 0.0, 26.78946533457776, 0.0, 0.0],
      [26.390277263908942, 0.0, 0.0, 26.390277263908942, 0.0, 0.0],
      [28.439596933535757, 0.0, 0.0, 28.439596933535757, 0.0, 0.0],
      [31.11518169536111, 0.0, 0.0, 31.11518169536111, 0.0, 0.0],
      [28.492099310412087, 0.0, 0.0, 28.492099310412087, 0.0, 0.0],
      [8.20528156865004, 0.0, 0.0, 8.20528156865004, 0.0, 0.0],
      [21.27543644359992, 0.0, 0.0, 21.27543644359992, 0.0, 0.0],
      [17.21889948123688, 0.0, 0.0, 17.21889948123688, 0.0, 0.0],
      [19.938754162912232, 0.0, 0.0, 19.938754162912232, 0.0, 0.0],
      [31.05435216670084, 0.0, 0.0, 31.05435216670084, 0.0, 0.0],
      [20.425956928273138, 0.0, 0.0, 20.425956928273138, 0.0, 0.0],
      [29.942810141572334, 0.0, 0.0, 29.942810141572334, 0.0, 0.0],
      [4.739945301310055, 0.0, 0.0, 4.739945301310055, 0.0, 0.0],
      [30.945573908391086, 0.0, 0.0, 30.945573908391086, 0.0, 0.0],
      [26.35033458064681, 0.0, 0.0, 26.35033458064681, 0.0, 0.0],
      [20.91436171804812, 0.0, 0.0, 20.91436171804812, 0.0, 0.0],
      [29.00240827770605, 0.0, 0.0, 29.00240827770605, 0.0, 0.0],
      [5.773326577619996, 0.0, 0.0, 5.773326577619996, 0.0, 0.0],
      [7.65047630817394, 0.0, 0.0, 7.65047630817394, 0.0, 0.0],
      [18.375415784256003, 0.0, 0.0, 18.375415784256003, 0.0, 0.0],
      [29.353786501807335, 0.0, 0.0, 29.353786501807335, 0.0, 0.0],
      [21.535160835309316, 0.0, 0.0, 21.535160835309316, 0.0, 0.0],
      [9.789998893438792, 0.0, 0.0, 9.789998893438792, 0.0, 0.0],
      [24.77757621505208, 0.0, 0.0, 24.77757621505208, 0.0, 0.0],
      [12.87651885981072, 0.0, 0.0, 12.87651885981072, 0.0, 0.0]],
     'xindex': 0,
     'yindex': 1,
     'zorder': 1}],
   'id': 'el323334397983696',
   'images': [],
   'lines': [],
   'markers': [],
   'paths': [],
   'sharex': [],
   'sharey': [],
   'texts': [],
   'xdomain': (-4.0, 4.0),
   'xlim': (-4.0, 4.0),
   'xscale': 'linear',
   'ydomain': (-2.0, 3.0),
   'ylim': (-2.0, 3.0),
   'yscale': 'linear',
   'zoomable': True}],
 'data': {'data01': [[1.3532663743799784, 1.2395114239966636],
   [-1.047213941658857, -0.40664182698652673],
   [-0.2258886129385939, 1.7951244514010243],
   [0.6338872795250976, -0.19802002271296193],
   [-0.8124040243926312, 0.34651816907136535],
   [0.07846056895995548, -0.549327375319428],
   [1.3341383627640548, -0.3466473104299951],
   [0.05161170467384658, 0.8701155511820821],
   [0.05091500899851696, 1.8472986577806054],
   [1.4169126844224698, -0.16278346742463337],
   [0.2745421449994285, -1.0612465735556247],
   [0.16469516655284638, -0.30753141275702095],
   [-0.007925430069479421, -0.4177688021254553],
   [0.21010530764762386, -0.428099546212898],
   [2.0003427593358336, -0.09427326798277638],
   [-0.3881033143958605, 0.5901989630313988],
   [0.725343993714144, -0.815667579808153],
   [1.2973341387206574, -0.39548669876234416],
   [0.925814885559926, -0.376483052115425],
   [-1.1747003222845114, -0.1254461637731876],
   [-0.3101395813203754, -0.134947029899888],
   [-1.433008143336566, 2.3829138926832636],
   [-0.8581799530359342, -0.15430723491257725],
   [0.4139948677216675, -1.3603375013827932],
   [0.2669469698974498, 0.3607672036227731],
   [-0.10584187746023341, 0.5079076873603735],
   [-0.6533145683630557, -0.14882873474083638],
   [-0.0729289269415523, -0.7050562068895232],
   [0.160264396930278, -0.5357346854553133],
   [0.4077576815647146, -0.8180606686190671],
   [-0.5819153324172338, 0.7064266371401604],
   [-0.19412331710861697, -0.12882779776080325],
   [-0.31086500124466115, 0.5555112717189509],
   [0.16955436909460012, 1.303542186910975],
   [-2.822356073866985, -0.7520734667567512],
   [2.8471788356686445, -0.5945135103416962],
   [-0.6678840251202416, 0.2865284715287692],
   [0.6400057221873338, -1.1573372719894033],
   [-1.147797166086597, 0.3268265396531751],
   [1.5418424661241625, -0.24702382227761258],
   [0.5143096371888688, 0.1488750938969045],
   [-1.4360591622009733, -0.3501020076026483],
   [-0.1007453758809331, -0.629271725259336],
   [0.08832291553163, 0.22484612333211576],
   [0.28899354481361206, -1.2005518091924627],
   [0.5938395957047787, 1.0788762781420804],
   [-1.114754814390533, -0.3211661455045672],
   [1.0069548100017942, -1.0611608492610647],
   [1.2677500738386163, 0.3186042103867772],
   [-0.21320880670731576, -0.13732772816819527],
   [-0.5985694205097175, 1.9643950029897608],
   [0.5804876213281703, -1.6826002849589636],
   [0.6133309712922849, -0.4141463785384575],
   [-1.1025354444797746, 0.48892177517981694],
   [0.7740007622412731, 0.9384388953793596],
   [1.5858408765871412, -0.195863649843589],
   [0.9050285327400797, 0.5052741829648668],
   [0.5301829236414499, 1.9288262388717554],
   [0.5926411319150986, -0.13781141132437202],
   [-0.4319108868066063, -0.1214438907990014],
   [-1.4455594096521305, -0.26050117442208287],
   [1.3791403095139407, 0.41126218437325507],
   [1.303570006507727, 0.6069781314679026],
   [0.42851027306726197, -0.22069006962675997],
   [-0.6631240200831412, -0.4473585059288857],
   [1.0438883781462245, 0.2900112447704415],
   [-2.007504969424275, -0.37328747321722355],
   [0.250386986222237, -0.6202776898539063],
   [0.14848813778649356, -0.026388298225536327],
   [-0.9499398347515013, 0.19488513572012683],
   [-0.7926735432857931, 0.20723108853507363],
   [-0.9441305871001102, 0.20522586187041994],
   [0.26426907410107786, -0.023240287668746862],
   [0.7975308673889631, -0.681505950513367],
   [0.27245788714873853, -0.6207460229221919],
   [-1.853937638180583, 0.18889677731391594],
   [0.1265975832991032, 1.053464291988132],
   [0.9980439565989615, -0.23345902357977796],
   [-0.1097540129406351, -0.28405698032106447],
   [-0.7519576136420723, 0.056638483852095356],
   [-0.6627895114782915, 0.5765271713845989],
   [0.13120208390452465, 0.9825943627143522],
   [0.27877571149743996, 0.2543922218305604],
   [1.1278303738772, -0.2006391780047112],
   [-2.5122639880258015, 1.1285465220394728],
   [0.48343467966638987, 0.6702929397639165],
   [-0.6021947400264485, 1.5764529774841523],
   [-1.166974286157769, -0.2585098030979472],
   [-0.6770470850477514, 1.563189465719086],
   [-1.4035092448121866, -1.1105604086579122],
   [-0.5590505164731143, 0.852337662482413],
   [-0.06434234713592306, -1.2207334222323765],
   [0.30956898853279646, -0.8365648638931428],
   [-0.5521251386832189, -0.16851395942332204],
   [0.8624021794326409, 0.16893174589469592],
   [1.1415270967023723, -1.2339714902333412],
   [0.09770556253245943, 0.39632322662992825],
   [-0.43856454359354724, 0.3852825272229884],
   [0.6341993627975028, 0.4684747563190834],
   [-1.1730465362480262, 0.36610229371224534]]},
 'height': 320.0,
 'id': 'el323334328933648',
 'plugins': [{'type': 'reset'},
  {'button': True, 'enabled': False, 'type': 'zoom'},
  {'button': True, 'enabled': False, 'type': 'boxzoom'}],
 'width': 480.0}

This is interpreted by mpld3.js

~1500 line JS library

mpld3 produces a pure client-side view of a Matplotlib plot

No requirement for a server-side callback!

Easy to embed on any static website

But there's more... mpld3 allows you to add plugins:

Plugins = endless possibilities for interactive behavior!

Tooltip Plugin:

In [5]:
from mpld3 import plugins

labels = ['Point {0}'.format(i) for i in range(100)]

tooltips = plugins.PointLabelTooltip(points, labels)
plugins.connect(fig, tooltips)
fig
Out[5]:

Linked Brushing plugin:

In [6]:
from sklearn.datasets import load_iris
iris = load_iris()

# dither the data for clearer plotting
iris.data += 0.1 * np.random.random(iris.data.shape)

fig, ax = plt.subplots(4, 4, sharex="col", sharey="row", figsize=(8, 8))
fig.subplots_adjust(left=0.05, right=0.95, bottom=0.05, top=0.95,
                    hspace=0.1, wspace=0.1)

for i in range(4):
    for j in range(4):
        points = ax[3 - i, j].scatter(iris.data[:, j], iris.data[:, i],
                                      c=iris.target, s=40, alpha=0.6)

# remove tick labels
for axi in ax.flat:
    for axis in [axi.xaxis, axi.yaxis]:
        axis.set_major_formatter(plt.NullFormatter())

# Here we connect the linked brush plugin
plugins.connect(fig, plugins.LinkedBrush(points))
/Users/jakevdp/anaconda/lib/python2.7/site-packages/numpy/oldnumeric/__init__.py:11: ModuleDeprecationWarning: The oldnumeric module will be dropped in Numpy 1.9
  warnings.warn(_msg, ModuleDeprecationWarning)

Custom Plugins:

Just write a bit of Python + JS

In [7]:
from mpld3 import plugins, utils


class HighlightLines(plugins.PluginBase):
    """A plugin to highlight lines on hover"""

    JAVASCRIPT = """
    mpld3.register_plugin("linehighlight", LineHighlightPlugin);
    LineHighlightPlugin.prototype = Object.create(mpld3.Plugin.prototype);
    LineHighlightPlugin.prototype.constructor = LineHighlightPlugin;
    LineHighlightPlugin.prototype.requiredProps = ["line_ids"];
    LineHighlightPlugin.prototype.defaultProps = {alpha_bg:0.3, alpha_fg:1.0}
    function LineHighlightPlugin(fig, props){
        mpld3.Plugin.call(this, fig, props);
    };

    LineHighlightPlugin.prototype.draw = function(){
      for(var i=0; i<this.props.line_ids.length; i++){
         var obj = mpld3.get_element(this.props.line_ids[i]),
             alpha_fg = this.props.alpha_fg;
             alpha_bg = this.props.alpha_bg;
         obj.elements()
             .on("mouseover", function(d, i){
                            d3.select(this).transition().duration(50)
                              .style("stroke-opacity", alpha_fg); })
             .on("mouseout", function(d, i){
                            d3.select(this).transition().duration(200)
                              .style("stroke-opacity", alpha_bg); });
      }
    };
    """
    def __init__(self, lines):
        self.lines = lines
        self.dict_ = {"type": "linehighlight",
                      "line_ids": [utils.get_id(line) for line in lines],
                      "alpha_bg": lines[0].get_alpha(),
                      "alpha_fg": 1.0}


x = np.linspace(0, 10, 100)
y = 0.1 * (np.random.random((50, 100)) - 0.5)
y = y.cumsum(1)

fig, ax = plt.subplots(subplot_kw={'xticks': [], 'yticks': []})
lines = ax.plot(x, y.T, color='blue', lw=4, alpha=0.1)
plugins.connect(fig, HighlightLines(lines))
In [8]:
# from http://mpld3.github.io/examples/heart_path.html

import matplotlib as mpl
import matplotlib.path as mpath
import matplotlib.patches as mpatches

class LinkedDragPlugin(plugins.PluginBase):
    JAVASCRIPT = r"""
    mpld3.register_plugin("drag", DragPlugin);
    DragPlugin.prototype = Object.create(mpld3.Plugin.prototype);
    DragPlugin.prototype.constructor = DragPlugin;
    DragPlugin.prototype.requiredProps = ["idpts", "idline", "idpatch"];
    DragPlugin.prototype.defaultProps = {}
    function DragPlugin(fig, props){
        mpld3.Plugin.call(this, fig, props);
    };

    DragPlugin.prototype.draw = function(){
        var patchobj = mpld3.get_element(this.props.idpatch, this.fig);
        var ptsobj = mpld3.get_element(this.props.idpts, this.fig);
        var lineobj = mpld3.get_element(this.props.idline, this.fig);

        var drag = d3.behavior.drag()
            .origin(function(d) { return {x:ptsobj.ax.x(d[0]),
                                          y:ptsobj.ax.y(d[1])}; })
            .on("dragstart", dragstarted)
            .on("drag", dragged)
            .on("dragend", dragended);

        lineobj.path.attr("d", lineobj.datafunc(ptsobj.offsets));
        patchobj.path.attr("d", patchobj.datafunc(ptsobj.offsets,
                                                  patchobj.pathcodes));
        lineobj.data = ptsobj.offsets;
        patchobj.data = ptsobj.offsets;

        ptsobj.elements()
           .data(ptsobj.offsets)
           .style("cursor", "default")
           .call(drag);

        function dragstarted(d) {
          d3.event.sourceEvent.stopPropagation();
          d3.select(this).classed("dragging", true);
        }

        function dragged(d, i) {
          d[0] = ptsobj.ax.x.invert(d3.event.x);
          d[1] = ptsobj.ax.y.invert(d3.event.y);
          d3.select(this)
            .attr("transform", "translate(" + [d3.event.x,d3.event.y] + ")");
          lineobj.path.attr("d", lineobj.datafunc(ptsobj.offsets));
          patchobj.path.attr("d", patchobj.datafunc(ptsobj.offsets,
                                                    patchobj.pathcodes));
        }

        function dragended(d, i) {
          d3.select(this).classed("dragging", false);
        }
    }

    mpld3.register_plugin("drag", DragPlugin);
    """

    def __init__(self, points, line, patch):
        if isinstance(points, mpl.lines.Line2D):
            suffix = "pts"
        else:
            suffix = None

        self.dict_ = {"type": "drag",
                      "idpts": utils.get_id(points, suffix),
                      "idline": utils.get_id(line),
                      "idpatch": utils.get_id(patch)}


fig, ax = plt.subplots(figsize=(8, 6))

Path = mpath.Path
path_data = [
    (Path.MOVETO, (1.58, -2.57)),
    (Path.CURVE4, (0.35, -1.1)),
    (Path.CURVE4, (-1.75, 2.0)),
    (Path.CURVE4, (0.375, 2.0)),
    (Path.LINETO, (0.85, 1.15)),
    (Path.CURVE4, (2.2, 3.2)),
    (Path.CURVE4, (3, 0.05)),
    (Path.CURVE4, (2.0, -0.5)),
    (Path.CLOSEPOLY, (1.58, -2.57)),
    ]
codes, verts = zip(*path_data)
path = mpath.Path(verts, codes)
patch = mpatches.PathPatch(path, facecolor='r', alpha=0.5)
ax.add_patch(patch)

# plot control points and connecting lines
x, y = zip(*path.vertices[:-1])
points = ax.plot(x, y, 'go', ms=10)
line = ax.plot(x, y, '-k')

ax.grid(True, color='gray', alpha=0.5)
ax.axis('equal')
ax.set_title("Drag Points to Change Path", fontsize=18)

plugins.connect(fig, LinkedDragPlugin(points[0], line[0], patch))