python-mpld3/0000755000175500017550000000000012412607537013155 5ustar debacledebaclepython-mpld3/MANIFEST.in0000644000175500017550000000030512410130733014674 0ustar debacledebacleinclude *.md include _mpld3_setup.py include version.py include visual_tests.py recursive-include examples *.py recursive-include notebooks *.ipynb recursive-include mpld3 *.py *.js include LICENSEpython-mpld3/bin/0000755000175500017550000000000012410130733013710 5ustar debacledebaclepython-mpld3/bin/version0000644000175500017550000000021712410130733015320 0ustar debacledebacle#!/usr/bin/env node process.argv.forEach(function (val, index, array) { if (index==2) console.log("mpld3.version = '" + val + "';"); });python-mpld3/bin/uglify0000755000175500017550000000157312410130733015143 0ustar debacledebacle#!/usr/bin/env node var fs = require("fs"), uglify = require("uglify-js"); var filename = process.argv[2], toplevel = uglify.parse(fs.readFileSync(filename, "utf8"), {filename: filename}), output = uglify.OutputStream({ascii_only: true}), compressor = uglify.Compressor(true), warn = uglify.AST_Node.warn; uglify.AST_Node.warn = function(s, o) { if (o.msg === "Accidental global?" && o.name === "d3" && o.line === 1 && !o.col) return; warn.apply(this, arguments); }; toplevel.figure_out_scope(); toplevel.scope_warnings({ undeclared: false, unreferenced: false, assign_to_global: true, func_arguments: false, nested_defuns: false, eval: false }); toplevel = toplevel.transform(compressor); toplevel.figure_out_scope(); toplevel.compute_char_frequency(true); toplevel.mangle_names(true); toplevel.print(output); require("util").print(output.get()); python-mpld3/examples/0000755000175500017550000000000012410130733014756 5ustar debacledebaclepython-mpld3/examples/html_tooltips.py0000644000175500017550000000272412410130733020236 0ustar debacledebacle""" HTML tooltip plugin =================== This is a demonstration of how to add rich HTML annotations to data plots. The Plugin is defined within mpld3, and the user-provided CSS controls the format of the information shown on hover. Use the toolbar buttons at the bottom-right of the plot to enable zooming and panning, and to reset the view. """ import matplotlib.pyplot as plt import numpy as np import pandas as pd import mpld3 from mpld3 import plugins # Define some CSS to control our custom labels css = """ table { border-collapse: collapse; } th { color: #ffffff; background-color: #000000; } td { background-color: #cccccc; } table, th, td { font-family:Arial, Helvetica, sans-serif; border: 1px solid black; text-align: right; } """ fig, ax = plt.subplots() ax.grid(True, alpha=0.3) N = 50 df = pd.DataFrame(index=range(N)) df['x'] = np.random.randn(N) df['y'] = np.random.randn(N) df['z'] = np.random.randn(N) labels = [] for i in range(N): label = df.ix[[i], :].T label.columns = ['Row {0}'.format(i)] # .to_html() is unicode; so make leading 'u' go away with str() labels.append(str(label.to_html())) points = ax.plot(df.x, df.y, 'o', color='b', mec='k', ms=15, mew=1, alpha=.6) ax.set_xlabel('x') ax.set_ylabel('y') ax.set_title('HTML tooltips', size=20) tooltip = plugins.PointHTMLTooltip(points[0], labels, voffset=10, hoffset=10, css=css) plugins.connect(fig, tooltip) mpld3.show() python-mpld3/examples/drag_points.py0000644000175500017550000000470312410130733017645 0ustar debacledebacle""" Draggable Points Example ======================== This example shows how a D3 plugin can be created to make plot elements draggable. A stopPropagation command is used to allow the drag behavior and pan/zoom behavior to work in tandem. """ import numpy as np import matplotlib.pyplot as plt import matplotlib as mpl import mpld3 from mpld3 import plugins, utils class DragPlugin(plugins.PluginBase): JAVASCRIPT = r""" mpld3.register_plugin("drag", DragPlugin); DragPlugin.prototype = Object.create(mpld3.Plugin.prototype); DragPlugin.prototype.constructor = DragPlugin; DragPlugin.prototype.requiredProps = ["id"]; DragPlugin.prototype.defaultProps = {} function DragPlugin(fig, props){ mpld3.Plugin.call(this, fig, props); mpld3.insert_css("#" + fig.figid + " path.dragging", {"fill-opacity": "1.0 !important", "stroke-opacity": "1.0 !important"}); }; DragPlugin.prototype.draw = function(){ var obj = mpld3.get_element(this.props.id); var drag = d3.behavior.drag() .origin(function(d) { return {x:obj.ax.x(d[0]), y:obj.ax.y(d[1])}; }) .on("dragstart", dragstarted) .on("drag", dragged) .on("dragend", dragended); obj.elements() .data(obj.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] = obj.ax.x.invert(d3.event.x); d[1] = obj.ax.y.invert(d3.event.y); d3.select(this) .attr("transform", "translate(" + [d3.event.x,d3.event.y] + ")"); } function dragended(d) { d3.select(this).classed("dragging", false); } } """ def __init__(self, points): if isinstance(points, mpl.lines.Line2D): suffix = "pts" else: suffix = None self.dict_ = {"type": "drag", "id": utils.get_id(points, suffix)} fig, ax = plt.subplots() np.random.seed(0) points = ax.plot(np.random.normal(size=20), np.random.normal(size=20), 'or', alpha=0.5, markersize=50, markeredgewidth=1) ax.set_title("Click and Drag", fontsize=18) plugins.connect(fig, DragPlugin(points[0])) mpld3.show() python-mpld3/examples/random_walk.py0000644000175500017550000000437712410130733017641 0ustar debacledebacle""" Visualizing Random Walks ======================== This shows the use of transparent lines to visualize random walk data. Thre is also a custom plugin defined which causes lines to be highlighted when the mouse hovers over them. Use the toolbar buttons at the bottom-right of the plot to enable zooming and panning, and to reset the view. """ import jinja2 import json import numpy as np import matplotlib.pyplot as plt import mpld3 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 example adds a custom D3 plugin allowing the user to drag the path control-points and see the effect on the path. Use the toolbar buttons at the bottom-right of the plot to enable zooming and panning, and to reset the view. """ import numpy as np import matplotlib.pyplot as plt import matplotlib as mpl import matplotlib.path as mpath import matplotlib.patches as mpatches import mpld3 from mpld3 import plugins, utils 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() 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)) mpld3.show() python-mpld3/examples/scatter_tooltip.py0000644000175500017550000000165012410130733020551 0ustar debacledebacle""" Scatter Plot With Tooltips ========================== A scatter-plot with tooltip labels on hover. Hover over the points to see the point labels. Use the toolbar buttons at the bottom-right of the plot to enable zooming and panning, and to reset the view. """ import matplotlib.pyplot as plt import numpy as np import mpld3 fig, ax = plt.subplots(subplot_kw=dict(axisbg='#EEEEEE')) N = 100 scatter = ax.scatter(np.random.normal(size=N), np.random.normal(size=N), c=np.random.random(size=N), s=1000 * np.random.random(size=N), alpha=0.3, cmap=plt.cm.jet) ax.grid(color='white', linestyle='solid') ax.set_title("Scatter Plot (with tooltips!)", size=20) labels = ['point {0}'.format(i + 1) for i in range(N)] tooltip = mpld3.plugins.PointLabelTooltip(scatter, labels=labels) mpld3.plugins.connect(fig, tooltip) mpld3.show() python-mpld3/examples/linked_brush.py0000644000175500017550000000216012410130733020000 0ustar debacledebacle""" Linked Brushing Example ======================= This example uses the standard Iris dataset and plots it with a linked brushing tool for dynamically exploring the data. The paintbrush button at the bottom left can be used to enable and disable the behavior. """ import numpy as np import matplotlib import matplotlib.pyplot as plt from sklearn.datasets import load_iris import mpld3 from mpld3 import plugins, utils data = load_iris() X = data.data y = data.target # dither the data for clearer plotting X += 0.1 * np.random.random(X.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(X[:, j], X[:, i], c=y, 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)) mpld3.show() python-mpld3/examples/custom_plugin.py0000644000175500017550000000477512410130733020235 0ustar debacledebacle""" Defining a Custom Plugin ======================== Test the custom plugin demoed on the `Pythonic Perambulations `_ blog. Hover over the points to see the associated sinusoid. Use the toolbar buttons at the bottom-right of the plot to enable zooming and panning, and to reset the view. """ import matplotlib import matplotlib.pyplot as plt import numpy as np import mpld3 from mpld3 import plugins, utils class LinkedView(plugins.PluginBase): """A simple plugin showing how multiple axes can be linked""" JAVASCRIPT = """ mpld3.register_plugin("linkedview", LinkedViewPlugin); LinkedViewPlugin.prototype = Object.create(mpld3.Plugin.prototype); LinkedViewPlugin.prototype.constructor = LinkedViewPlugin; LinkedViewPlugin.prototype.requiredProps = ["idpts", "idline", "data"]; LinkedViewPlugin.prototype.defaultProps = {} function LinkedViewPlugin(fig, props){ mpld3.Plugin.call(this, fig, props); }; LinkedViewPlugin.prototype.draw = function(){ var pts = mpld3.get_element(this.props.idpts); var line = mpld3.get_element(this.props.idline); var data = this.props.data; function mouseover(d, i){ line.data = data[i]; line.elements().transition() .attr("d", line.datafunc(line.data)) .style("stroke", this.style.fill); } pts.elements().on("mouseover", mouseover); }; """ def __init__(self, points, line, linedata): if isinstance(points, matplotlib.lines.Line2D): suffix = "pts" else: suffix = None self.dict_ = {"type": "linkedview", "idpts": utils.get_id(points, suffix), "idline": utils.get_id(line), "data": linedata} fig, ax = plt.subplots(2) # scatter periods and amplitudes np.random.seed(0) P = 0.2 + np.random.random(size=20) A = np.random.random(size=20) x = np.linspace(0, 10, 100) data = np.array([[x, Ai * np.sin(x / Pi)] for (Ai, Pi) in zip(A, P)]) points = ax[1].scatter(P, A, c=P + A, s=200, alpha=0.5) ax[1].set_xlabel('Period') ax[1].set_ylabel('Amplitude') # create the line object lines = ax[0].plot(x, 0 * x, '-w', lw=3, alpha=0.5) ax[0].set_ylim(-1, 1) ax[0].set_title("Hover over points to see lines") # transpose line data and add plugin linedata = data.transpose(0, 2, 1).tolist() plugins.connect(fig, LinkedView(points, lines[0], linedata)) mpld3.show() python-mpld3/examples/mouse_position.py0000644000175500017550000000155712410130733020414 0ustar debacledebacle""" Image with Mouse Position ========================= This example shows how mpld3 can display images using plt.imshow(). It also includes the mouse position plugin, so that the mouse coordinates are displayed in the lower-right corner. """ import matplotlib.pyplot as plt import numpy as np import mpld3 from mpld3 import plugins fig, ax = plt.subplots() x = np.linspace(-2, 2, 20) y = x[:, None] X = np.zeros((20, 20, 4)) X[:, :, 0] = np.exp(- (x - 1) ** 2 - (y) ** 2) X[:, :, 1] = np.exp(- (x + 0.71) ** 2 - (y - 0.71) ** 2) X[:, :, 2] = np.exp(- (x + 0.71) ** 2 - (y + 0.71) ** 2) X[:, :, 3] = np.exp(-0.25 * (x ** 2 + y ** 2)) im = ax.imshow(X, extent=(10, 20, 10, 20), origin='lower', zorder=1, interpolation='nearest') fig.colorbar(im, ax=ax) ax.set_title('An Image', size=20) plugins.connect(fig, plugins.MousePosition(fontsize=14)) mpld3.show() python-mpld3/examples/mpld3_logo.py0000644000175500017550000000724712410130733017401 0ustar debacledebacle""" mpld3 Logo Idea =============== This example shows how mpld3 can be used to generate relatively intricate vector graphics in the browser. This is an adaptation of a logo proposal by github user debjan, in turn based on both the matplotlib and D3js logos. """ # Author: Jake VanderPlas import matplotlib.pyplot as plt from matplotlib import image, patches, colors from matplotlib.colors import colorConverter import numpy as np import mpld3 imsize = np.array([319, 217]) center = [108.5, 108.5] max_radius = 108.5 radii = np.linspace(16, max_radius, 5) angles = np.arange(0, 360, 45) fig = plt.figure(figsize=imsize / 50.) ax = fig.add_axes([0, 0, 1, 1], frameon=False, xticks=[], yticks=[]) # Create a clip path for the elements clip_path = patches.Rectangle((0, 0), imsize[0], imsize[1], transform=ax.transData) # Create the background gradient x = np.array([0, 104, 196, 300]) y = np.linspace(150, 450, 86)[:, None] c = np.cos(-np.pi / 4) s = np.sin(-np.pi / 4) X, Y = (c * x - s * y) - 116, (s * x + c * y) C = np.arange(255).reshape((3, 85)).T C = C[::-1, :] cmap = colors.LinearSegmentedColormap.from_list("mpld3", [[0.97, 0.6, 0.29], [0.97, 0.59, 0.27], [0.97, 0.58, 0.25], [0.95, 0.44, 0.34], [0.92, 0.51, 0.29], [0.68, 0.21, 0.20]]) mesh = ax.pcolormesh(X, Y, C, cmap=cmap, shading='gourand', zorder=0) mesh.set_clip_path(clip_path) # cut-off the background to form the "D" and "3" using white patches # (this could also be done with a clip path) kwargs = dict(fc='white', ec='none', zorder=1) ax.add_patch(patches.Rectangle([0, 0], center[0], imsize[1], **kwargs)) ax.add_patch(patches.Circle(center, radii[2], **kwargs)) ax.add_patch(patches.Wedge(center, 127, -90, 90, width=18.5, **kwargs)) ax.add_patch(patches.Circle((252, 66), 18, **kwargs)) ax.add_patch(patches.Rectangle([216, 48], 36, 36, **kwargs)) ax.add_patch(patches.Wedge((252, 66), 101, -90, 40.1, width=35, **kwargs)) ax.add_patch(patches.Circle((252, 151), 18, **kwargs)) ax.add_patch(patches.Rectangle([216, 133], 36, 36, **kwargs)) ax.add_patch(patches.Wedge((252, 151), 101, -40.1, 90, width=35, **kwargs)) ax.add_patch(patches.Rectangle([-200, -200], 719, 200, **kwargs)) ax.add_patch(patches.Rectangle([-200, -200], 200, 617, **kwargs)) ax.add_patch(patches.Rectangle([-200, imsize[1]], 719, 200, **kwargs)) ax.add_patch(patches.Rectangle([imsize[0], -200], 200, 617, **kwargs)) # plot circles and lines for radius in radii: ax.add_patch(patches.Circle(center, radius, lw=0.5, ec='gray', fc='none', zorder=2)) for angle in angles: dx, dy = np.sin(np.radians(angle)), np.cos(np.radians(angle)) ax.plot([max_radius * (1 - dx), max_radius * (1 + dx)], [max_radius * (1 - dy), max_radius * (1 + dy)], '-', color='gray', lw=0.5, zorder=2) # plot wedges within the graph wedges = [(98, 231, 258, '#FF6600'), (85, 170, 205, '#FFC500'), (60, 80, 103, '#7DFF78'), (96, 45, 58, '#FD7C1A'), (73, 291, 308, '#CCFF28'), (47, 146, 155, '#28FFCC'), (25, 340, 360, '#004AFF')] for (radius, theta1, theta2, color) in wedges: ax.add_patch(patches.Wedge(center, radius, theta1, theta2, fc=color, ec='black', alpha=0.6, zorder=3)) for patch in ax.patches: patch.set_clip_path(clip_path) ax.set_xlim(0, imsize[0]) ax.set_ylim(imsize[1], 0) #plt.savefig('mpld3.png') mpld3.show() python-mpld3/create_example.py0000644000175500017550000000413112410130733016467 0ustar debacledebacleimport os import urllib2 import numpy as np import matplotlib.pyplot as plt from mpld3 import fig_to_d3, show_d3 # Download d3 file locally d3_filename = 'd3.v3.min.js' if not os.path.exists(d3_filename): page = urllib2.urlopen('http://d3js.org/d3.v3.min.js') with open(d3_filename, 'w') as f: f.write(page.read()) #---------------------------------------------------------------------- # create the figure and axes fig, ax = plt.subplots(2, 2, figsize=(8, 8), subplot_kw={'axisbg':'#EEEEEE'}) for axi in ax.flat: axi.grid(color='white', linestyle='solid') #---------------------------------------------------------------------- # first plot: an image x = np.linspace(-2, 2, 20) y = x[:, None] X = np.zeros((20, 20, 4)) X[:, :, 0] = np.exp(- (x - 1) ** 2 - (y) ** 2) X[:, :, 1] = np.exp(- (x + 0.71) ** 2 - (y - 0.71) ** 2) X[:, :, 2] = np.exp(- (x + 0.71) ** 2 - (y + 0.71) ** 2) X[:, :, 3] = np.exp(-0.25 * (x ** 2 + y ** 2)) ax[0, 0].imshow(X) ax[0, 0].set_title('An Image') ax[0, 0].grid() #---------------------------------------------------------------------- # second plot: scatter x = np.random.normal(size=100) y = np.random.normal(size=100) c = np.random.random(100) s = 100 + 500 * np.random.random(100) ax[0, 1].scatter(x, y, c=c, s=s, alpha=0.3) ax[0, 1].set_title('A Scatter Plot') #---------------------------------------------------------------------- # third plot: some random lines x = np.linspace(0, 10, 100) y = np.sin(x) dy = 0.4 ax[1, 0].plot(x, y, '--k', lw=2) for i in range(20): y_plot = np.convolve(np.ones(5) / 5., np.random.normal(y, dy), mode='same') ax[1, 0].plot(x, y_plot, '-b', lw=2, alpha=0.1) ax[1, 0].set_title('Transparent Lines') #---------------------------------------------------------------------- # fourth plot: filled regions x = np.linspace(0, 4 * np.pi, 100) y1 = np.sin(x / 2) y2 = np.sin(x) ax[1, 1].fill_between(x, y1, y2, where=y1 > y2, color='blue', alpha=0.3) ax[1, 1].fill_between(x, y1, y2, where=y1 <= y2, color='red', alpha=0.3) ax[1, 1].set_title('fill_between()') show_d3() python-mpld3/mpld3/0000755000175500017550000000000012410131434014156 5ustar debacledebaclepython-mpld3/mpld3/urls.py0000644000175500017550000000142212410130733015515 0ustar debacledebacle""" mpld3 URLs ========== URLs and filepaths for the mpld3 javascript libraries """ import os from . import __path__, __version__ import warnings __all__ = ["D3_URL", "MPLD3_URL", "MPLD3MIN_URL", "D3_LOCAL", "MPLD3_LOCAL", "MPLD3MIN_LOCAL"] WWW_JS_DIR = "https://mpld3.github.io/js/" D3_URL = WWW_JS_DIR + "d3.v3.min.js" MPLD3_URL = WWW_JS_DIR + "mpld3.v{0}.js".format(__version__) MPLD3MIN_URL = WWW_JS_DIR + "mpld3.v{0}.min.js".format(__version__) LOCAL_JS_DIR = os.path.join(__path__[0], "js") D3_LOCAL = os.path.join(LOCAL_JS_DIR, "d3.v3.min.js") MPLD3_LOCAL = os.path.join(LOCAL_JS_DIR, "mpld3.v{0}.js".format(__version__)) MPLD3MIN_LOCAL = os.path.join(LOCAL_JS_DIR, "mpld3.v{0}.min.js".format(__version__)) python-mpld3/mpld3/test_plots/0000755000175500017550000000000012410130733016357 5ustar debacledebaclepython-mpld3/mpld3/test_plots/test_hist.py0000644000175500017550000000072312410130733020741 0ustar debacledebacle"""Plot to test polygons""" import matplotlib.pyplot as plt import numpy as np import mpld3 def create_plot(): fig, ax = plt.subplots() ax.grid(color='gray') x = np.random.normal(size=500) ax.hist(x, 30, fc='blue', alpha=0.5) ax.xaxis.set_major_locator(plt.NullLocator()) return fig def test_hist(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_subplots.py0000644000175500017550000000141412410130733021643 0ustar debacledebacle"""Plot to test text""" import matplotlib.pyplot as plt import mpld3 from mpld3 import plugins def create_plot(): fig, ax = plt.subplots(2, 2, sharex='col', sharey='row') fig.subplots_adjust(hspace=0.3) for i in range(2): for j in range(2): txt = '({i}, {j})'.format(i=i, j=j) ax[i, j].set_title(txt, size=14) ax[i, j].text(0.5, 0.5, txt, size=40, ha='center') ax[i, j].grid(True, color='lightgray') ax[i, j].set_xlabel('xlabel') ax[i, j].set_ylabel('ylabel') plugins.connect(fig, plugins.MousePosition()) return fig def test_subplots(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_pandas_timeaxis.py0000644000175500017550000000110012410130733023131 0ustar debacledebacleimport matplotlib.pyplot as plt import numpy as np import mpld3 def create_plot(): try: import pandas as pd except: from nose import SkipTest raise SkipTest("pandas not installed") df2_index = pd.DatetimeIndex(start="2010-01-01", periods=100, freq='D') df2 = pd.DataFrame({'a': range(100)}, index=df2_index) ax = df2.plot(title="Datetime DF") return plt.gcf() def test_pandas_timeaxis(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_patches.py0000644000175500017550000000335312410130733021423 0ustar debacledebacle"""Plot to test patches""" import matplotlib.pyplot as plt from matplotlib import patches import numpy as np import mpld3 def create_plot(): fig, ax = plt.subplots() ax.grid(color='lightgray') rcolor = lambda: np.random.random(3) p = [patches.Arrow(0.75, 0.75, 0.5, 0.5), patches.Circle((1, 2), 0.4), patches.RegularPolygon((1, 3), 5, 0.4), patches.Rectangle((1.6, 0.75), 0.8, 0.5), patches.CirclePolygon((2, 2), 0.4), patches.Polygon([[1.75, 3], [2, 3.25], [2.25, 3], [2, 2.75], [1.75, 3]]), patches.Wedge((3, 1), 0.4, 0, 270), patches.Ellipse((3, 2), 0.6, 0.4), patches.Arc((3, 3), 0.5, 0.5, 270, 90)] for patch in p: patch.set_facecolor(rcolor()) patch.set_edgecolor(rcolor()) patch.set_alpha(0.5) patch.set_linewidth(2) ax.add_patch(patch) # add a static patch ax.add_patch(patches.Rectangle((0.3, 0.4), 0.4, 0.4, fc='yellow', ec='black', alpha=0.3, transform=ax.transAxes)) # add a patch with facecolor=None ax.add_patch(patches.Circle((4.0, 2.5), 0.4, facecolor='none', edgecolor='k')) # add a patch with edgecolor=None ax.add_patch(patches.Circle((4.0, 1.5), 0.4, facecolor='#9999FF', edgecolor='none', linewidth=2)) # make sure axes ratio is equal ax.set_xlim(0.5, 0.5 + 3. * 4. / 3.) ax.set_ylim(0.5, 3.5) ax.set_title("Various Patches", size=16) return fig def test_patches(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/__init__.py0000644000175500017550000000036612410130733020475 0ustar debacledebacle""" mpld3 tests """ # import matplotlib and set the backend to Agg. This needs to be done before # pyplot is imported: we set it here so that we don't have to set it in any # of the individual test files. import matplotlib matplotlib.use('Agg') python-mpld3/mpld3/test_plots/test_lines.py0000644000175500017550000000174112410130733021105 0ustar debacledebacle"""Plot to test line styles""" import matplotlib.pyplot as plt import mpld3 def create_plot(): fig, ax = plt.subplots() x = [0, 1] for i, color in enumerate(['red', 'green', '#0000FF']): x = 1 + 6 * i for j, alpha in enumerate([0.3, 0.6, 1.0]): for k, linestyle in enumerate(['solid', 'dashed', 'dashdot', 'dotted', '--']): y = 0.5 + k + 0.33 * j lines = ax.plot([x, x + 2.5, x + 5], [y, y + 0.2, y], lw=6 * alpha, c=color, ls=linestyle, alpha=alpha) if linestyle == '--': lines[0].set_dashes([8, 4, 2, 4, 2, 4]) ax.set_ylim(0, 5.5) ax.set_title("Line Styles, Widths, Transparencies", size=20) return fig def test_lines(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_text.py0000644000175500017550000000243112410130733020754 0ustar debacledebacle"""Plot to test text""" import matplotlib.pyplot as plt import mpld3 def create_plot(): fig, ax = plt.subplots() ax.grid(color='gray') # test font sizes x = 0.1 for y, size in zip([0.1, 0.3, 0.5, 0.7, 0.9], [8, 12, 16, 20, 24]): ax.text(x, y, "size={0}".format(size), size=size, ha='left') # test horizontal alignment x = 0.5 for y, align in zip([0.2, 0.4, 0.6], ['left', 'center', 'right']): ax.text(x, y, "ha=" + align, ha=align, size=20) # test vertical alignment y = 0.9 for x, align in zip([0.5, 0.7, 0.9], ['top', 'center', 'bottom']): ax.text(x, y, "va=" + align, ha='center', va=align, size=14) # test colors & rotations x = 0.8 for y, c, r in zip([0.15, 0.4, 0.65], ['red', 'blue', 'green'], [-45, 0, 45]): ax.text(x, y, "{0} rot={1}".format(c, r), size=18, color=c, rotation=r, ha='center', va='center') ax.set_xlabel('x label') ax.set_ylabel('y label') ax.set_title('title', size=20) return fig def test_text(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_nan.py0000644000175500017550000000121412410130733020542 0ustar debacledebacle"""Plot to test line styles""" import matplotlib.pyplot as plt import numpy as np import mpld3 def create_plot(): fig, ax = plt.subplots() np.random.seed(0) numPoints = 10 xx = np.arange(numPoints, dtype=float) xx[6] = np.nan yy = np.random.normal(size=numPoints) yy[3] = np.nan ax.plot(xx, yy, 'ks-', ms=10, mec='w', mew=3) ax.set_xlabel('x has uniform spacing') ax.set_ylabel('y includes a nan') ax.set_title('NaN test', size=14) return fig def test_nan(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_fill.py0000644000175500017550000000137012410130733020717 0ustar debacledebacle"""Plot to test text""" import matplotlib.pyplot as plt import numpy as np import mpld3 def create_plot(): fig, ax = plt.subplots() ax.grid(color='lightgray') x = np.linspace(0, 4 * np.pi, 1000) y1 = 0.5 * np.sin(0.5 * x) y2 = np.sin(x) y3 = np.cos(x) y1[450:550] = np.nan ax.fill(x, y1, alpha=0.3, facecolor='green') ax.fill_between(x, y2, y3, alpha=0.3, facecolor='red') ax.fill_between(x, -y2, -y3, alpha=0.3, facecolor='blue') ax.set_xlim(0, 4 * np.pi) ax.set_ylim(-1.1, 1.1) ax.set_title("fill() and fill_between()", size=18) return fig def test_fill(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_axis.py0000644000175500017550000000060312410130733020733 0ustar debacledebacle"""Plot to test ticker.FixedFormatter""" import matplotlib.pyplot as plt import numpy as np import mpld3 def create_plot(): positions, labels = [0, 1, 10], ['A','B','C'] plt.xticks(positions, labels) return plt.gcf() def test_axis(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_legend.py0000644000175500017550000000112312410130733021223 0ustar debacledebacle"""Plot to test legend""" import matplotlib.pyplot as plt import numpy as np import mpld3 def create_plot(): fig, ax = plt.subplots() x = np.linspace(0, 10, 100) ax.plot(x, np.sin(x), label='sin', lw=3, alpha=0.5) ax.plot(x, np.cos(x), label='cos', lw=3, alpha=0.5) ax.plot(x[::5], 0.5 * np.sin(x[::5] + 2), 'ob', label='dots') ax.legend(fancybox=True) ax.set_title("Legend test", size=20) return fig def test_legend(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_logscale.py0000644000175500017550000000124712410130733021565 0ustar debacledebacle"""Plot to test logscale""" import matplotlib.pyplot as plt import numpy as np import mpld3 def create_plot(): fig = plt.figure() fig.subplots_adjust(hspace=0.4, wspace=0.4) ax1 = fig.add_subplot(2, 2, 1) ax2 = fig.add_subplot(2, 2, 2, sharey=ax1, xscale='log') ax3 = fig.add_subplot(2, 2, 3, sharex=ax1, yscale='log') ax4 = fig.add_subplot(2, 2, 4, sharex=ax2, sharey=ax3) x = np.linspace(1, 1e2) y = x ** 2 for ax in [ax1, ax2, ax3, ax4]: ax.plot(x, y) return fig def test_logscale(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_contourf.py0000644000175500017550000000115512410130733021631 0ustar debacledebacle"""Plot to test line contours""" import matplotlib.pyplot as plt import numpy as np import matplotlib.mlab as mlab import mpld3 def create_plot(): x = np.linspace(-3.0, 3.0, 30) y = np.linspace(-2.0, 2.0, 30) X, Y = np.meshgrid(x, y) Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1) Z = 10.0 * (Z2 - Z1) fig, ax = plt.subplots() CS = ax.contourf(X, Y, Z, 30) return fig def test_contourf(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_line_HTMLtooltips.py0000644000175500017550000000102712410130733023341 0ustar debacledebacle"""Plot to test HTML line tooltip""" import matplotlib.pyplot as plt import mpld3 from mpld3 import plugins def create_plot(): fig, ax = plt.subplots() line, = ax.plot([0, 1, 3, 8, 5], '-', lw=5) label = '

Line {}

'.format('A') plugins.connect(fig, plugins.LineHTMLTooltip(line, label)) ax.set_title('Line with HTML Tooltip') return fig def test_line_tooltips(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_tooltips_basic.py0000644000175500017550000000102212410130733023001 0ustar debacledebacle"""Plot to test line styles""" import matplotlib.pyplot as plt import numpy as np import mpld3 from mpld3 import plugins def create_plot(): fig, ax = plt.subplots() points = ax.plot(range(10), 'o', ms=20) plugins.connect(fig, plugins.PointLabelTooltip(points[0], location="top left")) return fig def test_tooltips_basic(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_tooltips_labels.py0000644000175500017550000000120312410130733023163 0ustar debacledebacle"""Plot to test line styles""" import matplotlib.pyplot as plt import numpy as np import mpld3 from mpld3 import plugins def create_plot(): fig, ax = plt.subplots() colors = plt.rcParams['axes.color_cycle'] points = [] for i, color in enumerate(colors): points = ax.plot(i, 0, 'o', c=color, ms=20) plugins.connect(fig, plugins.PointLabelTooltip(points[0], [color])) ax.set_xlim(-1, len(colors) + 1) return fig def test_tooltips_labels(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_date.py0000644000175500017550000000113512410130733020705 0ustar debacledebacle"""Plot to test date axis""" import matplotlib.pyplot as plt import numpy as np import matplotlib import datetime import time import mpld3 def create_plot(): otimes = [datetime.date(2013, 12, i) for i in range(1, 11)] times = matplotlib.dates.date2num(otimes) np.random.seed(0) fig, ax = plt.subplots() ax.xaxis_date() fig.autofmt_xdate() ax.plot(times, np.random.random(len(times)), "-", linewidth=3) return fig def test_date(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_interactive_legend.py0000644000175500017550000000144712410130733023631 0ustar debacledebacle"""Plot to test legend""" import matplotlib.pyplot as plt import numpy as np import mpld3 from mpld3 import plugins def create_plot(): fig, ax = plt.subplots() x = np.linspace(0, 10, 100) l1 = ax.plot(x, np.sin(x), label='sin', lw=3, alpha=0.2) l2 = ax.plot(x, np.cos(x), label='cos', lw=3, alpha=0.2) l3 = ax.plot(x[::5], 0.5 * np.sin(x[::5] + 2), 'ob', label='dots', alpha=0.2) labels = ['sin', 'cos', 'dots'] interactive_legend = plugins.InteractiveLegendPlugin([l1, l2, l3], labels) plugins.connect(fig, interactive_legend) ax.set_title("Interactive legend test", size=20) return fig def test_legend(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_markers.py0000644000175500017550000000141412410130733021434 0ustar debacledebacle"""Plot to test line styles""" import matplotlib.pyplot as plt import numpy as np import mpld3 def create_plot(): fig, ax = plt.subplots() np.random.seed(0) numPoints = 10 for marker in ['oc', 'vr', '^g', '+k', 'db']: ax.plot(np.random.normal(size=numPoints), np.random.normal(size=numPoints), marker, ms=5+20*np.random.uniform(), alpha=0.5*np.random.uniform(), mew=1) ax.set_xlabel('this is x') ax.set_ylabel('this is y') ax.set_title('Marker test!', size=14) ax.grid(color='lightgray', alpha=0.7) return fig def test_markers(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_errorbar.py0000644000175500017550000000121212410130733021602 0ustar debacledebacle""" Test Error bars """ import matplotlib.pyplot as plt import numpy as np import mpld3 def create_plot(): np.random.seed(1) x = np.linspace(0, 10, 100) y = np.sin(x) xdata = 10 * np.random.random(25) dy = 0.2 + 0.2 * np.random.random(xdata.shape) ydata = np.random.normal(np.sin(xdata), dy) fig, ax = plt.subplots() ax.plot(x, y, lw=2, alpha=0.5) ax.errorbar(xdata, ydata, dy, fmt='ok', ecolor='gray', label='errors') ax.legend() return fig def test_errorbar(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_line_tooltips.py0000644000175500017550000000077212410130733022662 0ustar debacledebacle"""Plot to test line styles""" import matplotlib.pyplot as plt import numpy as np import mpld3 from mpld3 import plugins def create_plot(): fig, ax = plt.subplots() line, = ax.plot([0, 1, 3, 8, 5], '-', lw=5) plugins.connect(fig, plugins.LineLabelTooltip(line, ['Line A'])) ax.set_title('Line with Tooltip') return fig def test_line_tooltips(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_imshow.py0000644000175500017550000000164512410130733021304 0ustar debacledebacle"""Plot to test imshow""" import matplotlib.pyplot as plt import numpy as np import mpld3 def create_plot(): fig, ax = plt.subplots() x = np.linspace(-2, 2, 20) y = x[:, None] X = np.zeros((20, 20, 4)) X[:, :, 0] = np.exp(- (x - 1) ** 2 - (y) ** 2) X[:, :, 1] = np.exp(- (x + 0.71) ** 2 - (y - 0.71) ** 2) X[:, :, 2] = np.exp(- (x + 0.71) ** 2 - (y + 0.71) ** 2) X[:, :, 3] = np.exp(-0.25 * (x ** 2 + y ** 2)) im = ax.imshow(X, extent=(10, 20, 10, 20), origin='lower', zorder=1, interpolation='nearest') fig.colorbar(im, ax=ax) ax.text(16, 16, "overlaid text") ax.text(16, 15, "covered text", zorder=0) ax.set_title('An Image', size=20) ax.set_xlim(9, 21) ax.set_ylim(9, 21) return fig def test_imshow(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_contour.py0000644000175500017550000000122312410130733021457 0ustar debacledebacle"""Plot to test line contours""" import matplotlib.pyplot as plt import numpy as np import matplotlib.mlab as mlab import mpld3 def create_plot(): x = np.linspace(-3.0, 3.0, 30) y = np.linspace(-2.0, 2.0, 30) X, Y = np.meshgrid(x, y) Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1) Z = 10.0 * (Z2 - Z1) fig, ax = plt.subplots() CS = ax.contour(X, Y, Z) ax.clabel(CS, inline=True, fontsize=10) return fig def test_contour(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/test_plots/test_line_collections.py0000644000175500017550000000170212410130733023315 0ustar debacledebacle"""Plot to test line collections""" import matplotlib.pyplot as plt import numpy as np from matplotlib.collections import LineCollection import mpld3 def create_plot(): t = np.linspace(0, 10, 100) x = 0.1 * t * np.cos(np.pi * t) y = 0.1 * t * np.sin(np.pi * t) points = np.array([x, y]).T.reshape(100, 1, 2) segments = np.hstack([points[:-1], points[1:]]) lc = LineCollection(segments, cmap=plt.cm.jet, norm=plt.Normalize(0, 10), array=t, linewidths=3) fig, ax = plt.subplots() ax.add_collection(lc) plt.xlim(-1, 1) plt.ylim(-1, 1) ax.set_title("Line Collections", size=18) ax.xaxis.set_major_formatter(plt.NullFormatter()) ax.yaxis.set_major_formatter(plt.NullFormatter()) return fig def test_line_collections(): fig = create_plot() html = mpld3.fig_to_html(fig) plt.close(fig) if __name__ == "__main__": mpld3.show(create_plot()) python-mpld3/mpld3/utils.py0000644000175500017550000001072212410130733015673 0ustar debacledebacle""" mpld3 Utilities =============== Utility routines for the mpld3 package """ import os import re import shutil import warnings from functools import wraps from . import urls # Make sure that DeprecationWarning gets printed warnings.simplefilter("always", DeprecationWarning) def html_id_ok(objid, html5=False): """Check whether objid is valid as an HTML id attribute. If html5 == True, then use the more liberal html5 rules. """ if html5: return not re.search('\s', objid) else: return bool(re.match("^[a-zA-Z][a-zA-Z0-9\-\.\:\_]*$", objid)) def get_id(obj, suffix="", prefix="el", warn_on_invalid=True): """Get a unique id for the object""" if not suffix: suffix = "" if not prefix: prefix = "" objid = prefix + str(os.getpid()) + str(id(obj)) + suffix if warn_on_invalid and not html_id_ok(objid): warnings.warn('"{0}" is not a valid html ID. This may cause problems') return objid def deprecated(func, old_name, new_name): """Decorator to mark functions as deprecated.""" @wraps(func) def new_func(*args, **kwargs): warnings.warn(("{0} is deprecated and will be removed. " "Use {1} instead".format(old_name, new_name)), category=DeprecationWarning) return func(*args, **kwargs) new_func.__doc__ = ("*%s is deprecated: use %s instead*\n\n " % (old_name, new_name)) + new_func.__doc__ return new_func def write_ipynb_local_js(location=None, d3_src=None, mpld3_src=None): """ Write the mpld3 and d3 javascript libraries to the given file location. This utility is used by the IPython notebook tools to enable easy use of mpld3 with no web connection. Parameters ---------- location : string (optioal) the directory in which the d3 and mpld3 javascript libraries will be written. If not specified, the IPython nbextensions directory will be used. If IPython doesn't support nbextensions (< 2.0), the current working directory will be used. d3_src : string (optional) the source location of the d3 library. If not specified, the standard path in mpld3.urls.D3_LOCAL will be used. mpld3_src : string (optional) the source location of the mpld3 library. If not specified, the standard path in mpld3.urls.MPLD3_LOCAL will be used. Returns ------- d3_url, mpld3_url : string The URLs to be used for loading these js files. """ if location is None: try: from IPython.html import install_nbextension except ImportError: location = os.getcwd() nbextension = False else: nbextension = True else: nbextension = False if d3_src is None: d3_src = urls.D3_LOCAL if mpld3_src is None: mpld3_src = urls.MPLD3_LOCAL d3js = os.path.basename(d3_src) mpld3js = os.path.basename(mpld3_src) if not os.path.exists(d3_src): raise ValueError("d3 src not found at '{0}'".format(d3_src)) if not os.path.exists(mpld3_src): raise ValueError("mpld3 src not found at '{0}'".format(mpld3_src)) if nbextension: # IPython 2.0+. # This will not work if a url prefix is added prefix = '/nbextensions/' try: install_nbextension([d3_src, mpld3_src]) except IOError: # files may be read only. We'll try deleting them and re-installing from IPython.utils.path import get_ipython_dir nbext = os.path.join(get_ipython_dir(), "nbextensions") for src in [d3_src, mpld3_src]: dest = os.path.join(nbext, os.path.basename(src)) if os.path.exists(dest): os.remove(dest) install_nbextension([d3_src, mpld3_src]) else: # IPython < 2.0 or explicit path. # This won't work if users have changed the kernel directory. prefix = '/files/' d3_dest = os.path.join(location, d3js) mpld3_dest = os.path.join(location, mpld3js) for src, dest in [(d3_src, d3_dest), (mpld3_src, mpld3_dest)]: try: shutil.copyfile(src, dest) except IOError: # file may be read only. We'll try deleting it first if os.path.exists(dest): os.remove(dest) shutil.copyfile(src, dest) return prefix + d3js, prefix + mpld3js python-mpld3/mpld3/__init__.py0000644000175500017550000000212512410130733016270 0ustar debacledebacle""" Interactive D3 rendering of matplotlib images ============================================= Functions: General Use ---------------------- :func:`fig_to_html` convert a figure to an html string :func:`fig_to_dict` convert a figure to a dictionary representation :func:`show` launch a web server to view an d3/html figure representation :func:`save_html` save a figure to an html file :func:`save_json` save a JSON representation of a figure to file Functions: IPython Notebook --------------------------- :func:`display` display a figure in an IPython notebook :func:`enable_notebook` enable automatic D3 display of figures in the IPython notebook. :func:`disable_notebook` disable automatic D3 display of figures in the IPython """ __all__ = ["__version__", "fig_to_html", "fig_to_dict", "fig_to_d3", "display_d3", "display", "show_d3", "show", "save_html", "save_json", "enable_notebook", "disable_notebook", "plugins", "urls"] from .__about__ import __version__ from . import plugins from . import urls from ._display import * python-mpld3/mpld3/_server.py0000644000175500017550000000666112410130733016207 0ustar debacledebacle""" A Simple server used to show mpld3 images. """ import sys import threading import webbrowser import socket import itertools import random IPYTHON_WARNING = """ Note: if you're in the IPython notebook, mpld3.show() is not the best command to use. Consider using mpld3.display(), or mpld3.enable_notebook(). See more information at http://mpld3.github.io/quickstart.html . You must interrupt the kernel to end this command """ try: # Python 2.x import BaseHTTPServer as server except ImportError: # Python 3.x from http import server def generate_handler(html, files=None): if files is None: files = {} class MyHandler(server.BaseHTTPRequestHandler): def do_GET(self): """Respond to a GET request.""" if self.path == '/': self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() self.wfile.write("" "mpld3 plot" "\n".encode()) self.wfile.write(html.encode()) self.wfile.write("".encode()) elif self.path in files: content_type, content = files[self.path] self.send_response(200) self.send_header("Content-type", content_type) self.end_headers() self.wfile.write(content.encode()) else: self.send_error(404) return MyHandler def find_open_port(ip, port, n=50): """Find an open port near the specified port""" ports = itertools.chain((port + i for i in range(n)), (port + random.randint(-2 * n, 2 * n))) for port in ports: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) result = s.connect_ex((ip, port)) s.close() if result != 0: return port raise ValueError("no open ports found") def serve_and_open(html, ip='127.0.0.1', port=8888, n_retries=50, files=None, ipython_warning=True): """Start a server serving the given HTML, and open a browser Parameters ---------- html : string HTML to serve ip : string (default = '127.0.0.1') ip address at which the HTML will be served. port : int (default = 8888) the port at which to serve the HTML n_retries : int (default = 50) the number of nearby ports to search if the specified port is in use. files : dictionary (optional) dictionary of extra content to serve ipython_warning : bool (optional) if True (default), then print a warning if this is used within IPython """ port = find_open_port(ip, port, n_retries) Handler = generate_handler(html, files) srvr = server.HTTPServer((ip, port), Handler) if ipython_warning: try: __IPYTHON__ except: pass else: print(IPYTHON_WARNING) # Start the server print("Serving to http://{0}:{1}/ [Ctrl-C to exit]".format(ip, port)) sys.stdout.flush() # Use a thread to open a web browser pointing to the server b = lambda: webbrowser.open('http://{0}:{1}'.format(ip, port)) threading.Thread(target=b).start() try: srvr.serve_forever() except (KeyboardInterrupt, SystemExit): print("\nstopping Server...") srvr.server_close() python-mpld3/mpld3/js/0000755000175500017550000000000012412635402014600 5ustar debacledebaclepython-mpld3/mpld3/js/mpld3.v0.3git.min.js0000644000175500017550000010722312410351464020136 0ustar debacledebacle!function(t){function s(t){var s={};for(var o in t)s[o]=t[o];return s}function o(t,s){t="undefined"!=typeof t?t:10,s="undefined"!=typeof s?s:"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";for(var o=s.charAt(Math.round(Math.random()*(s.length-11))),e=1;t>e;e++)o+=s.charAt(Math.round(Math.random()*(s.length-1)));return o}function e(s,o){var e=t.interpolate([s[0].valueOf(),s[1].valueOf()],[o[0].valueOf(),o[1].valueOf()]);return function(t){var s=e(t);return[new Date(s[0]),new Date(s[1])]}}function i(t){return"undefined"==typeof t}function r(t){return null==t||i(t)}function n(t,s){return t.length>0?t[s%t.length]:null}function a(){function s(s,n){var a=t.functor(o),p=t.functor(e),h=[],l=[],c=0,d=-1,u=0,f=!1;if(!n){n=["M"];for(var y=1;yc;)i.call(this,s[c],c)?(h.push(a.call(this,s[c],c),p.call(this,s[c],c)),c++):(h=null,c=u);h?f&&h.length>0?(l.push("M",h[0],h[1]),f=!1):(l.push(n[d]),l=l.concat(h)):f=!0}return c!=s.length&&console.warn("Warning: not all vertices used in Path"),l.join(" ")}var o=function(t){return t[0]},e=function(t){return t[1]},i=function(){return!0},r={M:1,m:1,L:1,l:1,Q:2,q:2,T:1,t:1,S:2,s:2,C:3,c:3,Z:0,z:0};return s.x=function(t){return arguments.length?(o=t,s):o},s.y=function(t){return arguments.length?(e=t,s):e},s.defined=function(t){return arguments.length?(i=t,s):i},s.call=s,s}function p(){function t(t){return s.forEach(function(s){t=s(t)}),t}var s=Array.prototype.slice.call(arguments,0),o=s.length;return t.domain=function(o){return arguments.length?(s[0].domain(o),t):s[0].domain()},t.range=function(e){return arguments.length?(s[o-1].range(e),t):s[o-1].range()},t.step=function(t){return s[t]},t}function h(t,s){if(O.call(this,t,s),this.cssclass="mpld3-"+this.props.xy+"grid","x"==this.props.xy)this.transform="translate(0,"+this.ax.height+")",this.position="bottom",this.scale=this.ax.xdom,this.tickSize=-this.ax.height;else{if("y"!=this.props.xy)throw"unrecognized grid xy specifier: should be 'x' or 'y'";this.transform="translate(0,0)",this.position="left",this.scale=this.ax.ydom,this.tickSize=-this.ax.width}}function l(t,s){O.call(this,t,s);var o={bottom:[0,this.ax.height],top:[0,0],left:[0,0],right:[this.ax.width,0]},e={bottom:"x",top:"x",left:"y",right:"y"};this.transform="translate("+o[this.props.position]+")",this.props.xy=e[this.props.position],this.cssclass="mpld3-"+this.props.xy+"axis",this.scale=this.ax[this.props.xy+"dom"]}function c(t,s){if("undefined"==typeof s){if(this.ax=null,this.fig=null,"display"!==this.trans)throw"ax must be defined if transform != 'display'"}else this.ax=s,this.fig=s.fig;if(this.zoomable="data"===t,this.x=this["x_"+t],this.y=this["y_"+t],"undefined"==typeof this.x||"undefined"==typeof this.y)throw"unrecognized coordinate code: "+t}function d(t,s){O.call(this,t,s),this.data=t.fig.get_data(this.props.data),this.pathcodes=this.props.pathcodes,this.pathcoords=new c(this.props.coordinates,this.ax),this.offsetcoords=new c(this.props.offsetcoordinates,this.ax),this.datafunc=a()}function u(t,s){O.call(this,t,s),(null==this.props.facecolors||0==this.props.facecolors.length)&&(this.props.facecolors=["none"]),(null==this.props.edgecolors||0==this.props.edgecolors.length)&&(this.props.edgecolors=["none"]);var o=this.ax.fig.get_data(this.props.offsets);(null===o||0===o.length)&&(o=[null]);var e=Math.max(this.props.paths.length,o.length);if(o.length===e)this.offsets=o;else{this.offsets=[];for(var i=0;e>i;i++)this.offsets.push(n(o,i))}this.pathcoords=new c(this.props.pathcoordinates,this.ax),this.offsetcoords=new c(this.props.offsetcoordinates,this.ax)}function f(s,o){O.call(this,s,o);var e=this.props;e.facecolor="none",e.edgecolor=e.color,delete e.color,e.edgewidth=e.linewidth,delete e.linewidth,this.defaultProps=d.prototype.defaultProps,d.call(this,s,e),this.datafunc=t.svg.line().interpolate("linear")}function y(s,o){O.call(this,s,o),this.marker=null!==this.props.markerpath?0==this.props.markerpath[0].length?null:F.path().call(this.props.markerpath[0],this.props.markerpath[1]):null===this.props.markername?null:t.svg.symbol(this.props.markername).size(Math.pow(this.props.markersize,2))();var e={paths:[this.props.markerpath],offsets:s.fig.get_data(this.props.data),xindex:this.props.xindex,yindex:this.props.yindex,offsetcoordinates:this.props.coordinates,edgecolors:[this.props.edgecolor],edgewidths:[this.props.edgewidth],facecolors:[this.props.facecolor],alphas:[this.props.alpha],zorder:this.props.zorder,id:this.props.id};this.requiredProps=u.prototype.requiredProps,this.defaultProps=u.prototype.defaultProps,u.call(this,s,e)}function g(t,s){O.call(this,t,s),this.coords=new c(this.props.coordinates,this.ax)}function m(t,s){O.call(this,t,s),this.text=this.props.text,this.position=this.props.position,this.coords=new c(this.props.coordinates,this.ax)}function x(s,o){function e(t){return new Date(t[0],t[1],t[2],t[3],t[4],t[5])}function i(t,s){return"date"!==t?s:[e(s[0]),e(s[1])]}function r(s,o,e){var i="date"===s?t.time.scale():"log"===s?t.scale.log():t.scale.linear();return i.domain(o).range(e)}O.call(this,s,o),this.axnum=this.fig.axes.length,this.axid=this.fig.figid+"_ax"+(this.axnum+1),this.clipid=this.axid+"_clip",this.props.xdomain=this.props.xdomain||this.props.xlim,this.props.ydomain=this.props.ydomain||this.props.ylim,this.sharex=[],this.sharey=[],this.elements=[];var n=this.props.bbox;this.position=[n[0]*this.fig.width,(1-n[1]-n[3])*this.fig.height],this.width=n[2]*this.fig.width,this.height=n[3]*this.fig.height,this.props.xdomain=i(this.props.xscale,this.props.xdomain),this.props.ydomain=i(this.props.yscale,this.props.ydomain),this.x=this.xdom=r(this.props.xscale,this.props.xdomain,[0,this.width]),this.y=this.ydom=r(this.props.yscale,this.props.ydomain,[this.height,0]),"date"===this.props.xscale&&(this.x=F.multiscale(t.scale.linear().domain(this.props.xlim).range(this.props.xdomain.map(Number)),this.xdom)),"date"===this.props.yscale&&(this.x=F.multiscale(t.scale.linear().domain(this.props.ylim).range(this.props.ydomain.map(Number)),this.ydom));for(var a=this.props.axes,p=0;p=t[0]&&s<=t[1]})),this.elem.call(this.axis)},F.Coordinates=c,c.prototype.xy=function(t,s,o){return s="undefined"==typeof s?0:s,o="undefined"==typeof o?1:o,[this.x(t[s]),this.y(t[o])]},c.prototype.x_data=function(t){return this.ax.x(t)},c.prototype.y_data=function(t){return this.ax.y(t)},c.prototype.x_display=function(t){return t},c.prototype.y_display=function(t){return t},c.prototype.x_axes=function(t){return t*this.ax.width},c.prototype.y_axes=function(t){return this.ax.height*(1-t)},c.prototype.x_figure=function(t){return t*this.fig.width-this.ax.position[0]},c.prototype.y_figure=function(t){return(1-t)*this.fig.height-this.ax.position[1]},F.Path=d,d.prototype=Object.create(O.prototype),d.prototype.constructor=d,d.prototype.requiredProps=["data"],d.prototype.defaultProps={xindex:0,yindex:1,coordinates:"data",facecolor:"green",edgecolor:"black",edgewidth:1,dasharray:"none",pathcodes:null,offset:null,offsetcoordinates:"data",alpha:1,zorder:1},d.prototype.nanFilter=function(t){return!isNaN(t[this.props.xindex])&&!isNaN(t[this.props.yindex])},d.prototype.draw=function(){if(this.datafunc.defined(this.nanFilter.bind(this)).x(function(t){return this.pathcoords.x(t[this.props.xindex])}).y(function(t){return this.pathcoords.y(t[this.props.yindex])}),this.path=this.ax.axes.append("svg:path").attr("d",this.datafunc(this.data,this.pathcodes)).attr("class","mpld3-path").style("stroke",this.props.edgecolor).style("stroke-width",this.props.edgewidth).style("stroke-dasharray",this.props.dasharray).style("stroke-opacity",this.props.alpha).style("fill",this.props.facecolor).style("fill-opacity",this.props.alpha).attr("vector-effect","non-scaling-stroke"),null!==this.props.offset){var t=this.offsetcoords.xy(this.props.offset);this.path.attr("transform","translate("+t+")")}},d.prototype.elements=function(){return this.path},d.prototype.zoomed=function(){if(this.pathcoords.zoomable&&this.path.attr("d",this.datafunc(this.data,this.pathcodes)),null!==this.props.offset&&this.offsetcoords.zoomable){var t=this.offsetcoords.xy(this.props.offset);this.path.attr("transform","translate("+t+")")}},F.PathCollection=u,u.prototype=Object.create(O.prototype),u.prototype.constructor=u,u.prototype.requiredProps=["paths","offsets"],u.prototype.defaultProps={xindex:0,yindex:1,pathtransforms:[],pathcoordinates:"display",offsetcoordinates:"data",offsetorder:"before",edgecolors:["#000000"],edgewidths:[1],facecolors:["#0000FF"],alphas:[1],zorder:2},u.prototype.transformFunc=function(s,o){var e=this.props.pathtransforms,i=0==e.length?"":t.transform("matrix("+n(e,o)+")").toString(),r=null===s||"undefined"==typeof s?"translate(0, 0)":"translate("+this.offsetcoords.xy(s,this.props.xindex,this.props.yindex)+")";return"after"===this.props.offsetorder?i+r:r+i},u.prototype.pathFunc=function(t,s){return a().x(function(t){return this.pathcoords.x(t[0])}.bind(this)).y(function(t){return this.pathcoords.y(t[1])}.bind(this)).apply(this,n(this.props.paths,s))},u.prototype.styleFunc=function(t,s){var o={stroke:n(this.props.edgecolors,s),"stroke-width":n(this.props.edgewidths,s),"stroke-opacity":n(this.props.alphas,s),fill:n(this.props.facecolors,s),"fill-opacity":n(this.props.alphas,s)},e="";for(var i in o)e+=i+":"+o[i]+";";return e},u.prototype.draw=function(){this.group=this.ax.axes.append("svg:g"),this.pathsobj=this.group.selectAll("paths").data(this.offsets).enter().append("svg:path").attr("d",this.pathFunc.bind(this)).attr("class","mpld3-path").attr("transform",this.transformFunc.bind(this)).attr("style",this.styleFunc.bind(this)).attr("vector-effect","non-scaling-stroke")},u.prototype.elements=function(){return this.group.selectAll("path")},u.prototype.zoomed=function(){"data"===this.props.pathcoordinates&&this.pathsobj.attr("d",this.pathFunc.bind(this)),"data"===this.props.offsetcoordinates&&this.pathsobj.attr("transform",this.transformFunc.bind(this))},F.Line=f,f.prototype=Object.create(d.prototype),f.prototype.constructor=f,f.prototype.requiredProps=["data"],f.prototype.defaultProps={xindex:0,yindex:1,coordinates:"data",color:"salmon",linewidth:2,dasharray:"none",alpha:1,zorder:2},F.Markers=y,y.prototype=Object.create(u.prototype),y.prototype.constructor=y,y.prototype.requiredProps=["data"],y.prototype.defaultProps={xindex:0,yindex:1,coordinates:"data",facecolor:"salmon",edgecolor:"black",edgewidth:1,alpha:1,markersize:6,markername:"circle",markerpath:null,zorder:3},y.prototype.pathFunc=function(){return this.marker},F.Image=g,g.prototype=Object.create(O.prototype),g.prototype.constructor=g,g.prototype.requiredProps=["data","extent"],g.prototype.defaultProps={alpha:1,coordinates:"data",zorder:1},g.prototype.draw=function(){this.image=this.ax.axes.append("svg:image").attr("class","mpld3-image").attr("xlink:href","data:image/png;base64,"+this.props.data).style({opacity:this.props.alpha}).attr("preserveAspectRatio","none"),this.zoomed()},g.prototype.elements=function(){return t.select(this.image)},g.prototype.zoomed=function(){var t=this.props.extent;this.image.attr("x",this.coords.x(t[0])).attr("y",this.coords.y(t[3])).attr("width",this.coords.x(t[1])-this.coords.x(t[0])).attr("height",this.coords.y(t[2])-this.coords.y(t[3]))},F.Text=m,m.prototype=Object.create(O.prototype),m.prototype.constructor=m,m.prototype.requiredProps=["text","position"],m.prototype.defaultProps={coordinates:"data",h_anchor:"start",v_baseline:"auto",rotation:0,fontsize:11,color:"black",alpha:1,zorder:3},m.prototype.draw=function(){this.obj="data"==this.props.coordinates?this.ax.axes.append("text"):this.ax.baseaxes.append("text"),this.obj.attr("class","mpld3-text").text(this.text).style("text-anchor",this.props.h_anchor).style("dominant-baseline",this.props.v_baseline).style("font-size",this.props.fontsize).style("fill",this.props.color).style("opacity",this.props.alpha),this.applyTransform()},m.prototype.elements=function(){return t.select(this.obj)},m.prototype.applyTransform=function(){var t=this.coords.xy(this.position);this.obj.attr("x",t[0]).attr("y",t[1]),this.props.rotation&&this.obj.attr("transform","rotate("+this.props.rotation+","+t+")")},m.prototype.zoomed=function(){this.coords.zoomable&&this.applyTransform()},F.Axes=x,x.prototype=Object.create(O.prototype),x.prototype.constructor=x,x.prototype.requiredProps=["xlim","ylim"],x.prototype.defaultProps={bbox:[.1,.1,.8,.8],axesbg:"#FFFFFF",axesbgalpha:1,gridOn:!1,xdomain:null,ydomain:null,xscale:"linear",yscale:"linear",zoomable:!0,axes:[{position:"left"},{position:"bottom"}],lines:[],paths:[],markers:[],texts:[],collections:[],sharex:[],sharey:[],images:[]},x.prototype.draw=function(){for(var s=0;s0&&this.buttons.forEach(function(t){t.actions.filter(s).length>0&&t.deactivate()})},F.Button=v,v.prototype=Object.create(O.prototype),v.prototype.constructor=v,v.prototype.setState=function(t){t?this.activate():this.deactivate()},v.prototype.click=function(){this.active?this.deactivate():this.activate()},v.prototype.activate=function(){this.toolbar.deactivate_by_action(this.actions),this.onActivate(),this.active=!0,this.toolbar.toolbar.select("."+this.cssclass).classed({pressed:!0}),this.sticky||this.deactivate()},v.prototype.deactivate=function(){this.onDeactivate(),this.active=!1,this.toolbar.toolbar.select("."+this.cssclass).classed({pressed:!1})},v.prototype.sticky=!1,v.prototype.actions=[],v.prototype.icon=function(){return""},v.prototype.onActivate=function(){},v.prototype.onDeactivate=function(){},v.prototype.onDraw=function(){},F.ButtonFactory=function(t){function s(t){v.call(this,t,this.buttonID)}if("string"!=typeof t.buttonID)throw"ButtonFactory: buttonID must be present and be a string";s.prototype=Object.create(v.prototype),s.prototype.constructor=s;for(var o in t)s.prototype[o]=t[o];return s},F.Plugin=A,A.prototype=Object.create(O.prototype),A.prototype.constructor=A,A.prototype.requiredProps=[],A.prototype.defaultProps={},A.prototype.draw=function(){},F.ResetPlugin=z,F.register_plugin("reset",z),z.prototype=Object.create(A.prototype),z.prototype.constructor=z,z.prototype.requiredProps=[],z.prototype.defaultProps={},F.ZoomPlugin=w,F.register_plugin("zoom",w),w.prototype=Object.create(A.prototype),w.prototype.constructor=w,w.prototype.requiredProps=[],w.prototype.defaultProps={button:!0,enabled:null},w.prototype.activate=function(){this.fig.enable_zoom()},w.prototype.deactivate=function(){this.fig.disable_zoom()},w.prototype.draw=function(){this.props.enabled?this.fig.enable_zoom():this.fig.disable_zoom()},F.BoxZoomPlugin=k,F.register_plugin("boxzoom",k),k.prototype=Object.create(A.prototype),k.prototype.constructor=k,k.prototype.requiredProps=[],k.prototype.defaultProps={button:!0,enabled:null},k.prototype.activate=function(){this.enable&&this.enable()},k.prototype.deactivate=function(){this.disable&&this.disable()},k.prototype.draw=function(){function t(t){if(this.enabled){var o=s.extent();s.empty()||t.set_axlim([o[0][0],o[1][0]],[o[0][1],o[1][1]])}t.axes.call(s.clear())}F.insert_css("#"+this.fig.figid+" rect.extent."+this.extentClass,{fill:"#fff","fill-opacity":0,stroke:"#999"});var s=this.fig.getBrush();this.enable=function(){this.fig.showBrush(this.extentClass),s.on("brushend",t.bind(this)),this.enabled=!0},this.disable=function(){this.fig.hideBrush(this.extentClass),this.enabled=!1},this.toggle=function(){this.enabled?this.disable():this.enable()},this.disable()},F.TooltipPlugin=_,F.register_plugin("tooltip",_),_.prototype=Object.create(A.prototype),_.prototype.constructor=_,_.prototype.requiredProps=["id"],_.prototype.defaultProps={labels:null,hoffset:0,voffset:10,location:"mouse"},_.prototype.draw=function(){function s(t,s){this.tooltip.style("visibility","visible").text(null===r?"("+t+")":n(r,s))}function o(){if("mouse"===a){var s=t.mouse(this.fig.canvas.node());this.x=s[0]+this.props.hoffset,this.y=s[1]-this.props.voffset}this.tooltip.attr("x",this.x).attr("y",this.y)}function e(){this.tooltip.style("visibility","hidden")}var i=F.get_element(this.props.id,this.fig),r=this.props.labels,a=this.props.location;this.tooltip=this.fig.canvas.append("text").attr("class","mpld3-tooltip-text").attr("x",0).attr("y",0).text("").style("visibility","hidden"),"bottom left"==a||"top left"==a?(this.x=i.ax.position[0]+5+this.props.hoffset,this.tooltip.style("text-anchor","beginning")):"bottom right"==a||"top right"==a?(this.x=i.ax.position[0]+i.ax.width-5+this.props.hoffset,this.tooltip.style("text-anchor","end")):this.tooltip.style("text-anchor","middle"),"bottom left"==a||"bottom right"==a?this.y=i.ax.position[1]+i.ax.height-5+this.props.voffset:("top left"==a||"top right"==a)&&(this.y=i.ax.position[1]+5+this.props.voffset),i.elements().on("mouseover",s.bind(this)).on("mousemove",o.bind(this)).on("mouseout",e.bind(this))},F.LinkedBrushPlugin=P,F.register_plugin("linkedbrush",P),P.prototype=Object.create(F.Plugin.prototype),P.prototype.constructor=P,P.prototype.requiredProps=["id"],P.prototype.defaultProps={button:!0,enabled:null},P.prototype.activate=function(){this.enable&&this.enable()},P.prototype.deactivate=function(){this.disable&&this.disable()},P.prototype.draw=function(){function s(s){l!=this&&(t.select(l).call(p.clear()),l=this,p.x(s.xdom).y(s.ydom))}function o(t){var s=h[t.axnum];if(s.length>0){var o=s[0].props.xindex,e=s[0].props.yindex,i=p.extent();p.empty()?c.selectAll("path").classed("mpld3-hidden",!1):c.selectAll("path").classed("mpld3-hidden",function(t){return i[0][0]>t[o]||i[1][0]t[e]||i[1][1]1?s[1]:""},"object"==typeof module&&module.exports?module.exports=F:this.mpld3=F,console.log("Loaded mpld3 version "+F.version)}(d3);python-mpld3/mpld3/js/mpld3.v0.3git.js0000644000175500017550000015563412410351464017365 0ustar debacledebacle!function(d3) { var mpld3 = { _mpld3IsLoaded: true, figures: [], plugin_map: {} }; mpld3.version = "0.3git"; mpld3.register_plugin = function(name, obj) { mpld3.plugin_map[name] = obj; }; mpld3.draw_figure = function(figid, spec) { var element = document.getElementById(figid); if (element === null) { throw figid + " is not a valid id"; } var fig = new mpld3.Figure(figid, spec); mpld3.figures.push(fig); fig.draw(); return fig; }; mpld3.cloneObj = mpld3_cloneObj; function mpld3_cloneObj(oldObj) { var newObj = {}; for (var key in oldObj) { newObj[key] = oldObj[key]; } return newObj; } mpld3.merge_objects = function(_) { var output = {}; var obj; for (var i = 0; i < arguments.length; i++) { obj = arguments[i]; for (var attr in obj) { output[attr] = obj[attr]; } } return output; }; mpld3.generate_id = function(N, chars) { console.warn("mpld3.generate_id is deprecated. " + "Use mpld3.generateId instead."); return mpld3_generateId(N, chars); }; mpld3.generateId = mpld3_generateId; function mpld3_generateId(N, chars) { N = typeof N !== "undefined" ? N : 10; chars = typeof chars !== "undefined" ? chars : "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; var id = chars.charAt(Math.round(Math.random() * (chars.length - 11))); for (var i = 1; i < N; i++) id += chars.charAt(Math.round(Math.random() * (chars.length - 1))); return id; } mpld3.get_element = function(id, fig) { var figs_to_search, ax, el; if (typeof fig === "undefined") { figs_to_search = mpld3.figures; } else if (typeof fig.length === "undefined") { figs_to_search = [ fig ]; } else { figs_to_search = fig; } for (var i = 0; i < figs_to_search.length; i++) { fig = figs_to_search[i]; if (fig.props.id === id) { return fig; } for (var j = 0; j < fig.axes.length; j++) { ax = fig.axes[j]; if (ax.props.id === id) { return ax; } for (var k = 0; k < ax.elements.length; k++) { el = ax.elements[k]; if (el.props.id === id) { return el; } } } } return null; }; mpld3.insert_css = function(selector, attributes) { var head = document.head || document.getElementsByTagName("head")[0]; var style = document.createElement("style"); var css = selector + " {"; for (var prop in attributes) { css += prop + ":" + attributes[prop] + "; "; } css += "}"; style.type = "text/css"; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); }; mpld3.process_props = function(obj, properties, defaults, required) { console.warn("mpld3.process_props is deprecated. " + "Plot elements should derive from mpld3.PlotElement"); Element.prototype = Object.create(mpld3_PlotElement.prototype); Element.prototype.constructor = Element; Element.prototype.requiredProps = required; Element.prototype.defaultProps = defaults; function Element(props) { mpld3_PlotElement.call(this, null, props); } var el = new Element(properties); return el.props; }; mpld3.interpolateDates = mpld3_interpolateDates; function mpld3_interpolateDates(a, b) { var interp = d3.interpolate([ a[0].valueOf(), a[1].valueOf() ], [ b[0].valueOf(), b[1].valueOf() ]); return function(t) { var i = interp(t); return [ new Date(i[0]), new Date(i[1]) ]; }; } function isUndefined(x) { return typeof x === "undefined"; } function isUndefinedOrNull(x) { return x == null || isUndefined(x); } function getMod(L, i) { return L.length > 0 ? L[i % L.length] : null; } mpld3.path = function() { return mpld3_path(); }; function mpld3_path(_) { var x = function(d, i) { return d[0]; }; var y = function(d, i) { return d[1]; }; var defined = function(d, i) { return true; }; var n_vertices = { M: 1, m: 1, L: 1, l: 1, Q: 2, q: 2, T: 1, t: 1, S: 2, s: 2, C: 3, c: 3, Z: 0, z: 0 }; function path(vertices, pathcodes) { var fx = d3.functor(x), fy = d3.functor(y); var points = [], segments = [], i_v = 0, i_c = -1, halt = 0, nullpath = false; if (!pathcodes) { pathcodes = [ "M" ]; for (var i = 1; i < vertices.length; i++) pathcodes.push("L"); } while (++i_c < pathcodes.length) { halt = i_v + n_vertices[pathcodes[i_c]]; points = []; while (i_v < halt) { if (defined.call(this, vertices[i_v], i_v)) { points.push(fx.call(this, vertices[i_v], i_v), fy.call(this, vertices[i_v], i_v)); i_v++; } else { points = null; i_v = halt; } } if (!points) { nullpath = true; } else if (nullpath && points.length > 0) { segments.push("M", points[0], points[1]); nullpath = false; } else { segments.push(pathcodes[i_c]); segments = segments.concat(points); } } if (i_v != vertices.length) console.warn("Warning: not all vertices used in Path"); return segments.join(" "); } path.x = function(_) { if (!arguments.length) return x; x = _; return path; }; path.y = function(_) { if (!arguments.length) return y; y = _; return path; }; path.defined = function(_) { if (!arguments.length) return defined; defined = _; return path; }; path.call = path; return path; } mpld3.multiscale = mpld3_multiscale; function mpld3_multiscale(_) { var args = Array.prototype.slice.call(arguments, 0); var N = args.length; function scale(x) { args.forEach(function(mapping) { x = mapping(x); }); return x; } scale.domain = function(x) { if (!arguments.length) return args[0].domain(); args[0].domain(x); return scale; }; scale.range = function(x) { if (!arguments.length) return args[N - 1].range(); args[N - 1].range(x); return scale; }; scale.step = function(i) { return args[i]; }; return scale; } mpld3.icons = { reset: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI\nWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gIcACMoD/OzIwAAAJhJREFUOMtjYKAx4KDUgNsMDAx7\nyNV8i4GB4T8U76VEM8mGYNNMtCH4NBM0hBjNMIwSsMzQ0MamcDkDA8NmQi6xggpUoikwQbIkHk2u\nE0rLI7vCBknBSyxeRDZAE6qHgQkq+ZeBgYERSfFPAoHNDNUDN4BswIRmKgxwEasP2dlsDAwMYlA/\n/mVgYHiBpkkGKscIDaPfVMmuAGnOTaGsXF0MAAAAAElFTkSuQmCC\n", move: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI\nWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gIcACQMfLHBNQAAANZJREFUOMud07FKA0EQBuAviaKB\nlFr7COJrpAyYRlKn8hECEkFEn8ROCCm0sBMRYgh5EgVFtEhsRjiO27vkBoZd/vn5d3b+XcrjFI9q\nxgXWkc8pUjOB93GMd3zgB9d1unjDSxmhWSHQqOJki+MtOuv/b3ZifUqctIrMxwhHuG1gim4Ma5kR\nWuEkXFgU4B0MW1Ho4TeyjX3s4TDq3zn8ALvZ7q5wX9DqLOHCDA95cFBAnOO1AL/ZdNopgY3fQcqF\nyriMe37hM9w521ZkkvlMo7o/8g7nZYQ/QDctp1nTCf0AAAAASUVORK5CYII=\n", zoom: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI\nWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gMPDiIRPL/2oQAAANBJREFUOMvF0b9KgzEcheHHVnCT\nKoI4uXbtLXgB3oJDJxevw1VwkoJ/NjepQ2/BrZRCx0ILFURQKV2kyOeSQpAmn7WDB0Lg955zEhLy\n2scdXlBggits+4WOQqjAJ3qYR7NGLrwXGU9+sGbEtlIF18FwmuBngZ+nCt6CIacC3Rx8LSl4xzgF\nn0tusBn4UyVhuA/7ZYIv5g+pE3ail25hN/qdmzCfpsJVjKKCZesDBwtzrAqGOMQj6vhCDRsY4ALH\nmOVObltR/xeG/jph6OD2r+Fv5lZBWEhMx58AAAAASUVORK5CYII=\n", brush: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI\nWXMAAEQkAABEJAFAZ8RUAAAAB3RJTUUH3gMCEiQKB9YaAgAAAWtJREFUOMuN0r1qVVEQhuFn700k\nnfEvBq0iNiIiOKXgH4KCaBeIhWARK/EibLwFCwVLjyAWaQzRGG9grC3URkHUBKKgRuWohWvL5pjj\nyTSLxcz7rZlZHyMiItqzFxGTEVF18/UoODNFxDIO4x12dkXqTcBPsCUzD+AK3ndFqhHwEsYz82gn\nN4dbmMRK9R/4KY7jAvbiWmYeHBT5Z4QCP8J1rGAeN3GvU3Mbl/Gq3qCDcxjLzOV+v78fq/iFIxFx\nPyJ2lNJpfBy2g59YzMyzEbEVLzGBJjOriLiBq5gaJrCIU3hcRCbwAtuwjm/Yg/V6I9NgDA1OR8RC\nZq6Vcd7iUwtn5h8fdMBdETGPE+Xe4ExELDRNs4bX2NfCUHe+7UExyfkCP8MhzOA7PuAkvrbwXyNF\nxF3MDqxiqlhXC7SPdaOKiN14g0u4g3H0MvOiTUSNY3iemb0ywmfMdfYyUmAJ2yPiBx6Wr/oy2Oqw\n+A1SupBzAOuE/AAAAABJRU5ErkJggg==\n" }; mpld3.Grid = mpld3_Grid; mpld3_Grid.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Grid.prototype.constructor = mpld3_Grid; mpld3_Grid.prototype.requiredProps = [ "xy" ]; mpld3_Grid.prototype.defaultProps = { color: "gray", dasharray: "2,2", alpha: "0.5", nticks: 10, gridOn: true, tickvalues: null, zorder: 0 }; function mpld3_Grid(ax, prop) { mpld3_PlotElement.call(this, ax, prop); this.cssclass = "mpld3-" + this.props.xy + "grid"; if (this.props.xy == "x") { this.transform = "translate(0," + this.ax.height + ")"; this.position = "bottom"; this.scale = this.ax.xdom; this.tickSize = -this.ax.height; } else if (this.props.xy == "y") { this.transform = "translate(0,0)"; this.position = "left"; this.scale = this.ax.ydom; this.tickSize = -this.ax.width; } else { throw "unrecognized grid xy specifier: should be 'x' or 'y'"; } } mpld3_Grid.prototype.draw = function() { this.grid = d3.svg.axis().scale(this.scale).orient(this.position).ticks(this.props.nticks).tickValues(this.props.tickvalues).tickSize(this.tickSize, 0, 0).tickFormat(""); this.elem = this.ax.axes.append("g").attr("class", this.cssclass).attr("transform", this.transform).call(this.grid); mpld3.insert_css("div#" + this.ax.fig.figid + " ." + this.cssclass + " .tick", { stroke: this.props.color, "stroke-dasharray": this.props.dasharray, "stroke-opacity": this.props.alpha }); mpld3.insert_css("div#" + this.ax.fig.figid + " ." + this.cssclass + " path", { "stroke-width": 0 }); }; mpld3_Grid.prototype.zoomed = function() { this.elem.call(this.grid); }; mpld3.Axis = mpld3_Axis; mpld3_Axis.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Axis.prototype.constructor = mpld3_Axis; mpld3_Axis.prototype.requiredProps = [ "position" ]; mpld3_Axis.prototype.defaultProps = { nticks: 10, tickvalues: null, tickformat: null, fontsize: "11px", fontcolor: "black", axiscolor: "black", scale: "linear", grid: {}, zorder: 0 }; function mpld3_Axis(ax, props) { mpld3_PlotElement.call(this, ax, props); var trans = { bottom: [ 0, this.ax.height ], top: [ 0, 0 ], left: [ 0, 0 ], right: [ this.ax.width, 0 ] }; var xy = { bottom: "x", top: "x", left: "y", right: "y" }; this.transform = "translate(" + trans[this.props.position] + ")"; this.props.xy = xy[this.props.position]; this.cssclass = "mpld3-" + this.props.xy + "axis"; this.scale = this.ax[this.props.xy + "dom"]; } mpld3_Axis.prototype.getGrid = function() { var gridprop = { nticks: this.props.nticks, zorder: this.props.zorder, tickvalues: this.props.tickvalues, xy: this.props.xy }; if (this.props.grid) { for (var key in this.props.grid) { gridprop[key] = this.props.grid[key]; } } return new mpld3_Grid(this.ax, gridprop); }; mpld3_Axis.prototype.draw = function() { if (this.props.tickvalues) { tick_labels = d3.scale.threshold().domain(this.props.tickvalues.slice(1)).range(this.props.tickformat); } else { tick_labels = null; } this.axis = d3.svg.axis().scale(this.scale).orient(this.props.position).ticks(this.props.nticks).tickValues(this.props.tickvalues).tickFormat(tick_labels); this.elem = this.ax.baseaxes.append("g").attr("transform", this.transform).attr("class", this.cssclass).call(this.axis); mpld3.insert_css("div#" + this.ax.fig.figid + " ." + this.cssclass + " line, " + " ." + this.cssclass + " path", { "shape-rendering": "crispEdges", stroke: this.props.axiscolor, fill: "none" }); mpld3.insert_css("div#" + this.ax.fig.figid + " ." + this.cssclass + " text", { "font-family": "sans-serif", "font-size": this.props.fontsize, fill: this.props.fontcolor, stroke: "none" }); }; mpld3_Axis.prototype.zoomed = function() { var d = this.axis.scale().domain(); if (this.props.tickvalues != null) { this.axis.tickValues(this.props.tickvalues.filter(function(v) { return v >= d[0] && v <= d[1]; })); } this.elem.call(this.axis); }; mpld3.Coordinates = mpld3_Coordinates; function mpld3_Coordinates(trans, ax) { if (typeof ax === "undefined") { this.ax = null; this.fig = null; if (this.trans !== "display") throw "ax must be defined if transform != 'display'"; } else { this.ax = ax; this.fig = ax.fig; } this.zoomable = trans === "data"; this.x = this["x_" + trans]; this.y = this["y_" + trans]; if (typeof this.x === "undefined" || typeof this.y === "undefined") throw "unrecognized coordinate code: " + trans; } mpld3_Coordinates.prototype.xy = function(d, ix, iy) { ix = typeof ix === "undefined" ? 0 : ix; iy = typeof iy === "undefined" ? 1 : iy; return [ this.x(d[ix]), this.y(d[iy]) ]; }; mpld3_Coordinates.prototype.x_data = function(x) { return this.ax.x(x); }; mpld3_Coordinates.prototype.y_data = function(y) { return this.ax.y(y); }; mpld3_Coordinates.prototype.x_display = function(x) { return x; }; mpld3_Coordinates.prototype.y_display = function(y) { return y; }; mpld3_Coordinates.prototype.x_axes = function(x) { return x * this.ax.width; }; mpld3_Coordinates.prototype.y_axes = function(y) { return this.ax.height * (1 - y); }; mpld3_Coordinates.prototype.x_figure = function(x) { return x * this.fig.width - this.ax.position[0]; }; mpld3_Coordinates.prototype.y_figure = function(y) { return (1 - y) * this.fig.height - this.ax.position[1]; }; mpld3.Path = mpld3_Path; mpld3_Path.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Path.prototype.constructor = mpld3_Path; mpld3_Path.prototype.requiredProps = [ "data" ]; mpld3_Path.prototype.defaultProps = { xindex: 0, yindex: 1, coordinates: "data", facecolor: "green", edgecolor: "black", edgewidth: 1, dasharray: "none", pathcodes: null, offset: null, offsetcoordinates: "data", alpha: 1, zorder: 1 }; function mpld3_Path(ax, props) { mpld3_PlotElement.call(this, ax, props); this.data = ax.fig.get_data(this.props.data); this.pathcodes = this.props.pathcodes; this.pathcoords = new mpld3_Coordinates(this.props.coordinates, this.ax); this.offsetcoords = new mpld3_Coordinates(this.props.offsetcoordinates, this.ax); this.datafunc = mpld3_path(); } mpld3_Path.prototype.nanFilter = function(d, i) { return !isNaN(d[this.props.xindex]) && !isNaN(d[this.props.yindex]); }; mpld3_Path.prototype.draw = function() { this.datafunc.defined(this.nanFilter.bind(this)).x(function(d) { return this.pathcoords.x(d[this.props.xindex]); }).y(function(d) { return this.pathcoords.y(d[this.props.yindex]); }); this.path = this.ax.axes.append("svg:path").attr("d", this.datafunc(this.data, this.pathcodes)).attr("class", "mpld3-path").style("stroke", this.props.edgecolor).style("stroke-width", this.props.edgewidth).style("stroke-dasharray", this.props.dasharray).style("stroke-opacity", this.props.alpha).style("fill", this.props.facecolor).style("fill-opacity", this.props.alpha).attr("vector-effect", "non-scaling-stroke"); if (this.props.offset !== null) { var offset = this.offsetcoords.xy(this.props.offset); this.path.attr("transform", "translate(" + offset + ")"); } }; mpld3_Path.prototype.elements = function(d) { return this.path; }; mpld3_Path.prototype.zoomed = function() { if (this.pathcoords.zoomable) { this.path.attr("d", this.datafunc(this.data, this.pathcodes)); } if (this.props.offset !== null && this.offsetcoords.zoomable) { var offset = this.offsetcoords.xy(this.props.offset); this.path.attr("transform", "translate(" + offset + ")"); } }; mpld3.PathCollection = mpld3_PathCollection; mpld3_PathCollection.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_PathCollection.prototype.constructor = mpld3_PathCollection; mpld3_PathCollection.prototype.requiredProps = [ "paths", "offsets" ]; mpld3_PathCollection.prototype.defaultProps = { xindex: 0, yindex: 1, pathtransforms: [], pathcoordinates: "display", offsetcoordinates: "data", offsetorder: "before", edgecolors: [ "#000000" ], edgewidths: [ 1 ], facecolors: [ "#0000FF" ], alphas: [ 1 ], zorder: 2 }; function mpld3_PathCollection(ax, props) { mpld3_PlotElement.call(this, ax, props); if (this.props.facecolors == null || this.props.facecolors.length == 0) { this.props.facecolors = [ "none" ]; } if (this.props.edgecolors == null || this.props.edgecolors.length == 0) { this.props.edgecolors = [ "none" ]; } var offsets = this.ax.fig.get_data(this.props.offsets); if (offsets === null || offsets.length === 0) offsets = [ null ]; var N = Math.max(this.props.paths.length, offsets.length); if (offsets.length === N) { this.offsets = offsets; } else { this.offsets = []; for (var i = 0; i < N; i++) this.offsets.push(getMod(offsets, i)); } this.pathcoords = new mpld3_Coordinates(this.props.pathcoordinates, this.ax); this.offsetcoords = new mpld3_Coordinates(this.props.offsetcoordinates, this.ax); } mpld3_PathCollection.prototype.transformFunc = function(d, i) { var t = this.props.pathtransforms; var transform = t.length == 0 ? "" : d3.transform("matrix(" + getMod(t, i) + ")").toString(); var offset = d === null || typeof d === "undefined" ? "translate(0, 0)" : "translate(" + this.offsetcoords.xy(d, this.props.xindex, this.props.yindex) + ")"; return this.props.offsetorder === "after" ? transform + offset : offset + transform; }; mpld3_PathCollection.prototype.pathFunc = function(d, i) { return mpld3_path().x(function(d) { return this.pathcoords.x(d[0]); }.bind(this)).y(function(d) { return this.pathcoords.y(d[1]); }.bind(this)).apply(this, getMod(this.props.paths, i)); }; mpld3_PathCollection.prototype.styleFunc = function(d, i) { var styles = { stroke: getMod(this.props.edgecolors, i), "stroke-width": getMod(this.props.edgewidths, i), "stroke-opacity": getMod(this.props.alphas, i), fill: getMod(this.props.facecolors, i), "fill-opacity": getMod(this.props.alphas, i) }; var ret = ""; for (var key in styles) { ret += key + ":" + styles[key] + ";"; } return ret; }; mpld3_PathCollection.prototype.draw = function() { this.group = this.ax.axes.append("svg:g"); this.pathsobj = this.group.selectAll("paths").data(this.offsets).enter().append("svg:path").attr("d", this.pathFunc.bind(this)).attr("class", "mpld3-path").attr("transform", this.transformFunc.bind(this)).attr("style", this.styleFunc.bind(this)).attr("vector-effect", "non-scaling-stroke"); }; mpld3_PathCollection.prototype.elements = function(d) { return this.group.selectAll("path"); }; mpld3_PathCollection.prototype.zoomed = function() { if (this.props.pathcoordinates === "data") { this.pathsobj.attr("d", this.pathFunc.bind(this)); } if (this.props.offsetcoordinates === "data") { this.pathsobj.attr("transform", this.transformFunc.bind(this)); } }; mpld3.Line = mpld3_Line; mpld3_Line.prototype = Object.create(mpld3_Path.prototype); mpld3_Line.prototype.constructor = mpld3_Line; mpld3_Line.prototype.requiredProps = [ "data" ]; mpld3_Line.prototype.defaultProps = { xindex: 0, yindex: 1, coordinates: "data", color: "salmon", linewidth: 2, dasharray: "none", alpha: 1, zorder: 2 }; function mpld3_Line(ax, props) { mpld3_PlotElement.call(this, ax, props); var pathProps = this.props; pathProps.facecolor = "none"; pathProps.edgecolor = pathProps.color; delete pathProps.color; pathProps.edgewidth = pathProps.linewidth; delete pathProps.linewidth; this.defaultProps = mpld3_Path.prototype.defaultProps; mpld3_Path.call(this, ax, pathProps); this.datafunc = d3.svg.line().interpolate("linear"); } mpld3.Markers = mpld3_Markers; mpld3_Markers.prototype = Object.create(mpld3_PathCollection.prototype); mpld3_Markers.prototype.constructor = mpld3_Markers; mpld3_Markers.prototype.requiredProps = [ "data" ]; mpld3_Markers.prototype.defaultProps = { xindex: 0, yindex: 1, coordinates: "data", facecolor: "salmon", edgecolor: "black", edgewidth: 1, alpha: 1, markersize: 6, markername: "circle", markerpath: null, zorder: 3 }; function mpld3_Markers(ax, props) { mpld3_PlotElement.call(this, ax, props); if (this.props.markerpath !== null) { this.marker = this.props.markerpath[0].length == 0 ? null : mpld3.path().call(this.props.markerpath[0], this.props.markerpath[1]); } else { this.marker = this.props.markername === null ? null : d3.svg.symbol(this.props.markername).size(Math.pow(this.props.markersize, 2))(); } var PCprops = { paths: [ this.props.markerpath ], offsets: ax.fig.get_data(this.props.data), xindex: this.props.xindex, yindex: this.props.yindex, offsetcoordinates: this.props.coordinates, edgecolors: [ this.props.edgecolor ], edgewidths: [ this.props.edgewidth ], facecolors: [ this.props.facecolor ], alphas: [ this.props.alpha ], zorder: this.props.zorder, id: this.props.id }; this.requiredProps = mpld3_PathCollection.prototype.requiredProps; this.defaultProps = mpld3_PathCollection.prototype.defaultProps; mpld3_PathCollection.call(this, ax, PCprops); } mpld3_Markers.prototype.pathFunc = function(d, i) { return this.marker; }; mpld3.Image = mpld3_Image; mpld3_Image.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Image.prototype.constructor = mpld3_Image; mpld3_Image.prototype.requiredProps = [ "data", "extent" ]; mpld3_Image.prototype.defaultProps = { alpha: 1, coordinates: "data", zorder: 1 }; function mpld3_Image(ax, props) { mpld3_PlotElement.call(this, ax, props); this.coords = new mpld3_Coordinates(this.props.coordinates, this.ax); } mpld3_Image.prototype.draw = function() { this.image = this.ax.axes.append("svg:image").attr("class", "mpld3-image").attr("xlink:href", "data:image/png;base64," + this.props.data).style({ opacity: this.props.alpha }).attr("preserveAspectRatio", "none"); this.zoomed(); }; mpld3_Image.prototype.elements = function(d) { return d3.select(this.image); }; mpld3_Image.prototype.zoomed = function() { var extent = this.props.extent; this.image.attr("x", this.coords.x(extent[0])).attr("y", this.coords.y(extent[3])).attr("width", this.coords.x(extent[1]) - this.coords.x(extent[0])).attr("height", this.coords.y(extent[2]) - this.coords.y(extent[3])); }; mpld3.Text = mpld3_Text; mpld3_Text.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Text.prototype.constructor = mpld3_Text; mpld3_Text.prototype.requiredProps = [ "text", "position" ]; mpld3_Text.prototype.defaultProps = { coordinates: "data", h_anchor: "start", v_baseline: "auto", rotation: 0, fontsize: 11, color: "black", alpha: 1, zorder: 3 }; function mpld3_Text(ax, props) { mpld3_PlotElement.call(this, ax, props); this.text = this.props.text; this.position = this.props.position; this.coords = new mpld3_Coordinates(this.props.coordinates, this.ax); } mpld3_Text.prototype.draw = function() { if (this.props.coordinates == "data") { this.obj = this.ax.axes.append("text"); } else { this.obj = this.ax.baseaxes.append("text"); } this.obj.attr("class", "mpld3-text").text(this.text).style("text-anchor", this.props.h_anchor).style("dominant-baseline", this.props.v_baseline).style("font-size", this.props.fontsize).style("fill", this.props.color).style("opacity", this.props.alpha); this.applyTransform(); }; mpld3_Text.prototype.elements = function(d) { return d3.select(this.obj); }; mpld3_Text.prototype.applyTransform = function() { var pos = this.coords.xy(this.position); this.obj.attr("x", pos[0]).attr("y", pos[1]); if (this.props.rotation) this.obj.attr("transform", "rotate(" + this.props.rotation + "," + pos + ")"); }; mpld3_Text.prototype.zoomed = function() { if (this.coords.zoomable) this.applyTransform(); }; mpld3.Axes = mpld3_Axes; mpld3_Axes.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Axes.prototype.constructor = mpld3_Axes; mpld3_Axes.prototype.requiredProps = [ "xlim", "ylim" ]; mpld3_Axes.prototype.defaultProps = { bbox: [ .1, .1, .8, .8 ], axesbg: "#FFFFFF", axesbgalpha: 1, gridOn: false, xdomain: null, ydomain: null, xscale: "linear", yscale: "linear", zoomable: true, axes: [ { position: "left" }, { position: "bottom" } ], lines: [], paths: [], markers: [], texts: [], collections: [], sharex: [], sharey: [], images: [] }; function mpld3_Axes(fig, props) { mpld3_PlotElement.call(this, fig, props); this.axnum = this.fig.axes.length; this.axid = this.fig.figid + "_ax" + (this.axnum + 1); this.clipid = this.axid + "_clip"; this.props.xdomain = this.props.xdomain || this.props.xlim; this.props.ydomain = this.props.ydomain || this.props.ylim; this.sharex = []; this.sharey = []; this.elements = []; var bbox = this.props.bbox; this.position = [ bbox[0] * this.fig.width, (1 - bbox[1] - bbox[3]) * this.fig.height ]; this.width = bbox[2] * this.fig.width; this.height = bbox[3] * this.fig.height; function buildDate(d) { return new Date(d[0], d[1], d[2], d[3], d[4], d[5]); } function setDomain(scale, domain) { return scale !== "date" ? domain : [ buildDate(domain[0]), buildDate(domain[1]) ]; } this.props.xdomain = setDomain(this.props.xscale, this.props.xdomain); this.props.ydomain = setDomain(this.props.yscale, this.props.ydomain); function build_scale(scale, domain, range) { var dom = scale === "date" ? d3.time.scale() : scale === "log" ? d3.scale.log() : d3.scale.linear(); return dom.domain(domain).range(range); } this.x = this.xdom = build_scale(this.props.xscale, this.props.xdomain, [ 0, this.width ]); this.y = this.ydom = build_scale(this.props.yscale, this.props.ydomain, [ this.height, 0 ]); if (this.props.xscale === "date") { this.x = mpld3.multiscale(d3.scale.linear().domain(this.props.xlim).range(this.props.xdomain.map(Number)), this.xdom); } if (this.props.yscale === "date") { this.x = mpld3.multiscale(d3.scale.linear().domain(this.props.ylim).range(this.props.ydomain.map(Number)), this.ydom); } var axes = this.props.axes; for (var i = 0; i < axes.length; i++) { var axis = new mpld3.Axis(this, axes[i]); this.elements.push(axis); if (this.props.gridOn || axis.props.grid.gridOn) { this.elements.push(axis.getGrid()); } } var paths = this.props.paths; for (var i = 0; i < paths.length; i++) { this.elements.push(new mpld3.Path(this, paths[i])); } var lines = this.props.lines; for (var i = 0; i < lines.length; i++) { this.elements.push(new mpld3.Line(this, lines[i])); } var markers = this.props.markers; for (var i = 0; i < markers.length; i++) { this.elements.push(new mpld3.Markers(this, markers[i])); } var texts = this.props.texts; for (var i = 0; i < texts.length; i++) { this.elements.push(new mpld3.Text(this, texts[i])); } var collections = this.props.collections; for (var i = 0; i < collections.length; i++) { this.elements.push(new mpld3.PathCollection(this, collections[i])); } var images = this.props.images; for (var i = 0; i < images.length; i++) { this.elements.push(new mpld3.Image(this, images[i])); } this.elements.sort(function(a, b) { return a.props.zorder - b.props.zorder; }); } mpld3_Axes.prototype.draw = function() { for (var i = 0; i < this.props.sharex.length; i++) { this.sharex.push(mpld3.get_element(this.props.sharex[i])); } for (var i = 0; i < this.props.sharey.length; i++) { this.sharey.push(mpld3.get_element(this.props.sharey[i])); } this.zoom = d3.behavior.zoom(); this.zoom.last_t = this.zoom.translate(); this.zoom.last_s = this.zoom.scale(); this.zoom_x = d3.behavior.zoom().x(this.xdom); this.zoom_y = d3.behavior.zoom().y(this.ydom); this.baseaxes = this.fig.canvas.append("g").attr("transform", "translate(" + this.position[0] + "," + this.position[1] + ")").attr("width", this.width).attr("height", this.height).attr("class", "mpld3-baseaxes"); this.clip = this.baseaxes.append("svg:clipPath").attr("id", this.clipid).append("svg:rect").attr("x", 0).attr("y", 0).attr("width", this.width).attr("height", this.height); this.axes = this.baseaxes.append("g").attr("class", "mpld3-axes").attr("clip-path", "url(#" + this.clipid + ")"); this.axesbg = this.axes.append("svg:rect").attr("width", this.width).attr("height", this.height).attr("class", "mpld3-axesbg").style("fill", this.props.axesbg).style("fill-opacity", this.props.axesbgalpha); for (var i = 0; i < this.elements.length; i++) { this.elements[i].draw(); } }; mpld3_Axes.prototype.enable_zoom = function() { if (this.props.zoomable) { this.zoom.on("zoom", this.zoomed.bind(this, true)); this.axes.call(this.zoom); this.axes.style("cursor", "move"); } }; mpld3_Axes.prototype.disable_zoom = function() { if (this.props.zoomable) { this.zoom.on("zoom", null); this.axes.on(".zoom", null); this.axes.style("cursor", null); } }; mpld3_Axes.prototype.zoomed = function(propagate) { propagate = typeof propagate == "undefined" ? true : propagate; if (propagate) { var dt0 = this.zoom.translate()[0] - this.zoom.last_t[0]; var dt1 = this.zoom.translate()[1] - this.zoom.last_t[1]; var ds = this.zoom.scale() / this.zoom.last_s; this.zoom_x.translate([ this.zoom_x.translate()[0] + dt0, 0 ]); this.zoom_x.scale(this.zoom_x.scale() * ds); this.zoom_y.translate([ 0, this.zoom_y.translate()[1] + dt1 ]); this.zoom_y.scale(this.zoom_y.scale() * ds); this.zoom.last_t = this.zoom.translate(); this.zoom.last_s = this.zoom.scale(); this.sharex.forEach(function(ax) { ax.zoom_x.translate(this.zoom_x.translate()).scale(this.zoom_x.scale()); }.bind(this)); this.sharey.forEach(function(ax) { ax.zoom_y.translate(this.zoom_y.translate()).scale(this.zoom_y.scale()); }.bind(this)); this.sharex.forEach(function(ax) { ax.zoomed(false); }); this.sharey.forEach(function(ax) { ax.zoomed(false); }); } for (var i = 0; i < this.elements.length; i++) { this.elements[i].zoomed(); } }; mpld3_Axes.prototype.reset = function(duration, propagate) { this.set_axlim(this.props.xdomain, this.props.ydomain, duration, propagate); }; mpld3_Axes.prototype.set_axlim = function(xlim, ylim, duration, propagate) { xlim = isUndefinedOrNull(xlim) ? this.xdom.domain() : xlim; ylim = isUndefinedOrNull(ylim) ? this.ydom.domain() : ylim; duration = isUndefinedOrNull(duration) ? 750 : duration; propagate = isUndefined(propagate) ? true : propagate; var interpX = this.props.xscale === "date" ? mpld3.interpolateDates(this.xdom.domain(), xlim) : d3.interpolate(this.xdom.domain(), xlim); var interpY = this.props.yscale === "date" ? mpld3.interpolateDates(this.ydom.domain(), ylim) : d3.interpolate(this.ydom.domain(), ylim); var transition = function(t) { this.zoom_x.x(this.xdom.domain(interpX(t))); this.zoom_y.y(this.ydom.domain(interpY(t))); this.zoomed(false); }.bind(this); d3.select({}).transition().duration(duration).tween("zoom", function() { return transition; }); if (propagate) { this.sharex.forEach(function(ax) { ax.set_axlim(xlim, null, duration, false); }); this.sharey.forEach(function(ax) { ax.set_axlim(null, ylim, duration, false); }); } this.zoom.scale(1).translate([ 0, 0 ]); this.zoom.last_t = this.zoom.translate(); this.zoom.last_s = this.zoom.scale(); this.zoom_x.scale(1).translate([ 0, 0 ]); this.zoom_y.scale(1).translate([ 0, 0 ]); }; mpld3.Toolbar = mpld3_Toolbar; mpld3_Toolbar.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Toolbar.prototype.constructor = mpld3_Toolbar; mpld3_Toolbar.prototype.defaultProps = { buttons: [ "reset", "move" ] }; function mpld3_Toolbar(fig, props) { mpld3_PlotElement.call(this, fig, props); this.buttons = []; this.props.buttons.forEach(this.addButton.bind(this)); } mpld3_Toolbar.prototype.addButton = function(button) { this.buttons.push(new button(this)); }; mpld3_Toolbar.prototype.draw = function() { mpld3.insert_css("div#" + this.fig.figid + " .mpld3-toolbar image", { cursor: "pointer", opacity: .2, display: "inline-block", margin: "0px" }); mpld3.insert_css("div#" + this.fig.figid + " .mpld3-toolbar image.active", { opacity: .4 }); mpld3.insert_css("div#" + this.fig.figid + " .mpld3-toolbar image.pressed", { opacity: .6 }); function showButtons() { this.buttonsobj.transition(750).attr("y", 0); } function hideButtons() { this.buttonsobj.transition(750).delay(250).attr("y", 16); } this.fig.canvas.on("mouseenter", showButtons.bind(this)).on("mouseleave", hideButtons.bind(this)).on("touchenter", showButtons.bind(this)).on("touchstart", showButtons.bind(this)); this.toolbar = this.fig.canvas.append("svg:svg").attr("width", 16 * this.buttons.length).attr("height", 16).attr("x", 2).attr("y", this.fig.height - 16 - 2).attr("class", "mpld3-toolbar"); this.buttonsobj = this.toolbar.append("svg:g").selectAll("buttons").data(this.buttons).enter().append("svg:image").attr("class", function(d) { return d.cssclass; }).attr("xlink:href", function(d) { return d.icon(); }).attr("width", 16).attr("height", 16).attr("x", function(d, i) { return i * 16; }).attr("y", 16).on("click", function(d) { d.click(); }).on("mouseenter", function() { d3.select(this).classed({ active: 1 }); }).on("mouseleave", function() { d3.select(this).classed({ active: 0 }); }); for (var i = 0; i < this.buttons.length; i++) this.buttons[i].onDraw(); }; mpld3_Toolbar.prototype.deactivate_all = function() { this.buttons.forEach(function(b) { b.deactivate(); }); }; mpld3_Toolbar.prototype.deactivate_by_action = function(actions) { function filt(e) { return actions.indexOf(e) !== -1; } if (actions.length > 0) { this.buttons.forEach(function(button) { if (button.actions.filter(filt).length > 0) button.deactivate(); }); } }; mpld3.Button = mpld3_Button; mpld3_Button.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Button.prototype.constructor = mpld3_Button; function mpld3_Button(toolbar, key) { mpld3_PlotElement.call(this, toolbar); this.toolbar = toolbar; this.fig = this.toolbar.fig; this.cssclass = "mpld3-" + key + "button"; this.active = false; } mpld3_Button.prototype.setState = function(state) { state ? this.activate() : this.deactivate(); }; mpld3_Button.prototype.click = function() { this.active ? this.deactivate() : this.activate(); }; mpld3_Button.prototype.activate = function() { this.toolbar.deactivate_by_action(this.actions); this.onActivate(); this.active = true; this.toolbar.toolbar.select("." + this.cssclass).classed({ pressed: true }); if (!this.sticky) this.deactivate(); }; mpld3_Button.prototype.deactivate = function() { this.onDeactivate(); this.active = false; this.toolbar.toolbar.select("." + this.cssclass).classed({ pressed: false }); }; mpld3_Button.prototype.sticky = false; mpld3_Button.prototype.actions = []; mpld3_Button.prototype.icon = function() { return ""; }; mpld3_Button.prototype.onActivate = function() {}; mpld3_Button.prototype.onDeactivate = function() {}; mpld3_Button.prototype.onDraw = function() {}; mpld3.ButtonFactory = function(members) { if (typeof members.buttonID !== "string") { throw "ButtonFactory: buttonID must be present and be a string"; } function B(toolbar) { mpld3_Button.call(this, toolbar, this.buttonID); } B.prototype = Object.create(mpld3_Button.prototype); B.prototype.constructor = B; for (var key in members) { B.prototype[key] = members[key]; } return B; }; mpld3.Plugin = mpld3_Plugin; mpld3_Plugin.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Plugin.prototype.constructor = mpld3_Plugin; mpld3_Plugin.prototype.requiredProps = []; mpld3_Plugin.prototype.defaultProps = {}; function mpld3_Plugin(fig, props) { mpld3_PlotElement.call(this, fig, props); } mpld3_Plugin.prototype.draw = function() {}; mpld3.ResetPlugin = mpld3_ResetPlugin; mpld3.register_plugin("reset", mpld3_ResetPlugin); mpld3_ResetPlugin.prototype = Object.create(mpld3_Plugin.prototype); mpld3_ResetPlugin.prototype.constructor = mpld3_ResetPlugin; mpld3_ResetPlugin.prototype.requiredProps = []; mpld3_ResetPlugin.prototype.defaultProps = {}; function mpld3_ResetPlugin(fig, props) { mpld3_Plugin.call(this, fig, props); var ResetButton = mpld3.ButtonFactory({ buttonID: "reset", sticky: false, onActivate: function() { this.toolbar.fig.reset(); }, icon: function() { return mpld3.icons["reset"]; } }); this.fig.buttons.push(ResetButton); } mpld3.ZoomPlugin = mpld3_ZoomPlugin; mpld3.register_plugin("zoom", mpld3_ZoomPlugin); mpld3_ZoomPlugin.prototype = Object.create(mpld3_Plugin.prototype); mpld3_ZoomPlugin.prototype.constructor = mpld3_ZoomPlugin; mpld3_ZoomPlugin.prototype.requiredProps = []; mpld3_ZoomPlugin.prototype.defaultProps = { button: true, enabled: null }; function mpld3_ZoomPlugin(fig, props) { mpld3_Plugin.call(this, fig, props); if (this.props.enabled === null) { this.props.enabled = !this.props.button; } var enabled = this.props.enabled; if (this.props.button) { var ZoomButton = mpld3.ButtonFactory({ buttonID: "zoom", sticky: true, actions: [ "scroll", "drag" ], onActivate: this.activate.bind(this), onDeactivate: this.deactivate.bind(this), onDraw: function() { this.setState(enabled); }, icon: function() { return mpld3.icons["move"]; } }); this.fig.buttons.push(ZoomButton); } } mpld3_ZoomPlugin.prototype.activate = function() { this.fig.enable_zoom(); }; mpld3_ZoomPlugin.prototype.deactivate = function() { this.fig.disable_zoom(); }; mpld3_ZoomPlugin.prototype.draw = function() { if (this.props.enabled) this.fig.enable_zoom(); else this.fig.disable_zoom(); }; mpld3.BoxZoomPlugin = mpld3_BoxZoomPlugin; mpld3.register_plugin("boxzoom", mpld3_BoxZoomPlugin); mpld3_BoxZoomPlugin.prototype = Object.create(mpld3_Plugin.prototype); mpld3_BoxZoomPlugin.prototype.constructor = mpld3_BoxZoomPlugin; mpld3_BoxZoomPlugin.prototype.requiredProps = []; mpld3_BoxZoomPlugin.prototype.defaultProps = { button: true, enabled: null }; function mpld3_BoxZoomPlugin(fig, props) { mpld3_Plugin.call(this, fig, props); if (this.props.enabled === null) { this.props.enabled = !this.props.button; } var enabled = this.props.enabled; if (this.props.button) { var BoxZoomButton = mpld3.ButtonFactory({ buttonID: "boxzoom", sticky: true, actions: [ "drag" ], onActivate: this.activate.bind(this), onDeactivate: this.deactivate.bind(this), onDraw: function() { this.setState(enabled); }, icon: function() { return mpld3.icons["zoom"]; } }); this.fig.buttons.push(BoxZoomButton); } this.extentClass = "boxzoombrush"; } mpld3_BoxZoomPlugin.prototype.activate = function() { if (this.enable) this.enable(); }; mpld3_BoxZoomPlugin.prototype.deactivate = function() { if (this.disable) this.disable(); }; mpld3_BoxZoomPlugin.prototype.draw = function() { mpld3.insert_css("#" + this.fig.figid + " rect.extent." + this.extentClass, { fill: "#fff", "fill-opacity": 0, stroke: "#999" }); var brush = this.fig.getBrush(); this.enable = function() { this.fig.showBrush(this.extentClass); brush.on("brushend", brushend.bind(this)); this.enabled = true; }; this.disable = function() { this.fig.hideBrush(this.extentClass); this.enabled = false; }; this.toggle = function() { this.enabled ? this.disable() : this.enable(); }; function brushend(d) { if (this.enabled) { var extent = brush.extent(); if (!brush.empty()) { d.set_axlim([ extent[0][0], extent[1][0] ], [ extent[0][1], extent[1][1] ]); } } d.axes.call(brush.clear()); } this.disable(); }; mpld3.TooltipPlugin = mpld3_TooltipPlugin; mpld3.register_plugin("tooltip", mpld3_TooltipPlugin); mpld3_TooltipPlugin.prototype = Object.create(mpld3_Plugin.prototype); mpld3_TooltipPlugin.prototype.constructor = mpld3_TooltipPlugin; mpld3_TooltipPlugin.prototype.requiredProps = [ "id" ]; mpld3_TooltipPlugin.prototype.defaultProps = { labels: null, hoffset: 0, voffset: 10, location: "mouse" }; function mpld3_TooltipPlugin(fig, props) { mpld3_Plugin.call(this, fig, props); } mpld3_TooltipPlugin.prototype.draw = function() { var obj = mpld3.get_element(this.props.id, this.fig); var labels = this.props.labels; var loc = this.props.location; this.tooltip = this.fig.canvas.append("text").attr("class", "mpld3-tooltip-text").attr("x", 0).attr("y", 0).text("").style("visibility", "hidden"); if (loc == "bottom left" || loc == "top left") { this.x = obj.ax.position[0] + 5 + this.props.hoffset; this.tooltip.style("text-anchor", "beginning"); } else if (loc == "bottom right" || loc == "top right") { this.x = obj.ax.position[0] + obj.ax.width - 5 + this.props.hoffset; this.tooltip.style("text-anchor", "end"); } else { this.tooltip.style("text-anchor", "middle"); } if (loc == "bottom left" || loc == "bottom right") { this.y = obj.ax.position[1] + obj.ax.height - 5 + this.props.voffset; } else if (loc == "top left" || loc == "top right") { this.y = obj.ax.position[1] + 5 + this.props.voffset; } function mouseover(d, i) { this.tooltip.style("visibility", "visible").text(labels === null ? "(" + d + ")" : getMod(labels, i)); } function mousemove(d, i) { if (loc === "mouse") { var pos = d3.mouse(this.fig.canvas.node()); this.x = pos[0] + this.props.hoffset; this.y = pos[1] - this.props.voffset; } this.tooltip.attr("x", this.x).attr("y", this.y); } function mouseout(d, i) { this.tooltip.style("visibility", "hidden"); } obj.elements().on("mouseover", mouseover.bind(this)).on("mousemove", mousemove.bind(this)).on("mouseout", mouseout.bind(this)); }; mpld3.LinkedBrushPlugin = mpld3_LinkedBrushPlugin; mpld3.register_plugin("linkedbrush", mpld3_LinkedBrushPlugin); mpld3_LinkedBrushPlugin.prototype = Object.create(mpld3.Plugin.prototype); mpld3_LinkedBrushPlugin.prototype.constructor = mpld3_LinkedBrushPlugin; mpld3_LinkedBrushPlugin.prototype.requiredProps = [ "id" ]; mpld3_LinkedBrushPlugin.prototype.defaultProps = { button: true, enabled: null }; function mpld3_LinkedBrushPlugin(fig, props) { mpld3.Plugin.call(this, fig, props); if (this.props.enabled === null) { this.props.enabled = !this.props.button; } var enabled = this.props.enabled; if (this.props.button) { var BrushButton = mpld3.ButtonFactory({ buttonID: "linkedbrush", sticky: true, actions: [ "drag" ], onActivate: this.activate.bind(this), onDeactivate: this.deactivate.bind(this), onDraw: function() { this.setState(enabled); }, icon: function() { return mpld3.icons["brush"]; } }); this.fig.buttons.push(BrushButton); } this.extentClass = "linkedbrush"; } mpld3_LinkedBrushPlugin.prototype.activate = function() { if (this.enable) this.enable(); }; mpld3_LinkedBrushPlugin.prototype.deactivate = function() { if (this.disable) this.disable(); }; mpld3_LinkedBrushPlugin.prototype.draw = function() { var obj = mpld3.get_element(this.props.id); if (obj === null) { throw "LinkedBrush: no object with id='" + this.props.id + "' was found"; } var fig = this.fig; if (!("offsets" in obj.props)) { throw "Plot object with id='" + this.props.id + "' is not a scatter plot"; } var dataKey = "offsets" in obj.props ? "offsets" : "data"; mpld3.insert_css("#" + fig.figid + " rect.extent." + this.extentClass, { fill: "#000", "fill-opacity": .125, stroke: "#fff" }); mpld3.insert_css("#" + fig.figid + " path.mpld3-hidden", { stroke: "#ccc !important", fill: "#ccc !important" }); var dataClass = "mpld3data-" + obj.props[dataKey]; var brush = fig.getBrush(); var dataByAx = []; fig.axes.forEach(function(ax) { var axData = []; ax.elements.forEach(function(el) { if (el.props[dataKey] === obj.props[dataKey]) { el.group.classed(dataClass, true); axData.push(el); } }); dataByAx.push(axData); }); var allData = []; var dataToBrush = fig.canvas.selectAll("." + dataClass); var currentAxes; function brushstart(d) { if (currentAxes != this) { d3.select(currentAxes).call(brush.clear()); currentAxes = this; brush.x(d.xdom).y(d.ydom); } } function brushmove(d) { var data = dataByAx[d.axnum]; if (data.length > 0) { var ix = data[0].props.xindex; var iy = data[0].props.yindex; var e = brush.extent(); if (brush.empty()) { dataToBrush.selectAll("path").classed("mpld3-hidden", false); } else { dataToBrush.selectAll("path").classed("mpld3-hidden", function(p) { return e[0][0] > p[ix] || e[1][0] < p[ix] || e[0][1] > p[iy] || e[1][1] < p[iy]; }); } } } function brushend(d) { if (brush.empty()) { dataToBrush.selectAll("path").classed("mpld3-hidden", false); } } this.enable = function() { this.fig.showBrush(this.extentClass); brush.on("brushstart", brushstart).on("brush", brushmove).on("brushend", brushend); this.enabled = true; }; this.disable = function() { d3.select(currentAxes).call(brush.clear()); this.fig.hideBrush(this.extentClass); this.enabled = false; }; this.disable(); }; mpld3.register_plugin("mouseposition", MousePositionPlugin); MousePositionPlugin.prototype = Object.create(mpld3.Plugin.prototype); MousePositionPlugin.prototype.constructor = MousePositionPlugin; MousePositionPlugin.prototype.requiredProps = []; MousePositionPlugin.prototype.defaultProps = { fontsize: 12, fmt: ".3g" }; function MousePositionPlugin(fig, props) { mpld3.Plugin.call(this, fig, props); } MousePositionPlugin.prototype.draw = function() { var fig = this.fig; var fmt = d3.format(this.props.fmt); var coords = fig.canvas.append("text").attr("class", "mpld3-coordinates").style("text-anchor", "end").style("font-size", this.props.fontsize).attr("x", this.fig.width - 5).attr("y", this.fig.height - 5); for (var i = 0; i < this.fig.axes.length; i++) { var update_coords = function() { var ax = fig.axes[i]; return function() { var pos = d3.mouse(this), x = ax.x.invert(pos[0]), y = ax.y.invert(pos[1]); coords.text("(" + fmt(x) + ", " + fmt(y) + ")"); }; }(); fig.axes[i].baseaxes.on("mousemove", update_coords).on("mouseout", function() { coords.text(""); }); } }; mpld3.Figure = mpld3_Figure; mpld3_Figure.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Figure.prototype.constructor = mpld3_Figure; mpld3_Figure.prototype.requiredProps = [ "width", "height" ]; mpld3_Figure.prototype.defaultProps = { data: {}, axes: [], plugins: [ { type: "reset" }, { type: "zoom" }, { type: "boxzoom" } ] }; function mpld3_Figure(figid, props) { mpld3_PlotElement.call(this, null, props); this.figid = figid; this.width = this.props.width; this.height = this.props.height; this.data = this.props.data; this.buttons = []; this.root = d3.select("#" + figid).append("div").style("position", "relative"); this.axes = []; for (var i = 0; i < this.props.axes.length; i++) this.axes.push(new mpld3_Axes(this, this.props.axes[i])); this.plugins = []; for (var i = 0; i < this.props.plugins.length; i++) this.add_plugin(this.props.plugins[i]); this.toolbar = new mpld3.Toolbar(this, { buttons: this.buttons }); } mpld3_Figure.prototype.getBrush = function() { if (typeof this._brush === "undefined") { var brush = d3.svg.brush().x(d3.scale.linear()).y(d3.scale.linear()); this.root.selectAll(".mpld3-axes").data(this.axes).call(brush); this.axes.forEach(function(ax) { brush.x(ax.xdom).y(ax.ydom); ax.axes.call(brush); }); this._brush = brush; this.hideBrush(); } return this._brush; }; mpld3_Figure.prototype.showBrush = function(extentClass) { extentClass = typeof extentClass === "undefined" ? "" : extentClass; var brush = this.getBrush(); brush.on("brushstart", function(d) { brush.x(d.xdom).y(d.ydom); }); this.canvas.selectAll("rect.background").style("cursor", "crosshair").style("pointer-events", null); this.canvas.selectAll("rect.extent, rect.resize").style("display", null).classed(extentClass, true); }; mpld3_Figure.prototype.hideBrush = function(extentClass) { extentClass = typeof extentClass === "undefined" ? "" : extentClass; var brush = this.getBrush(); brush.on("brushstart", null).on("brush", null).on("brushend", function(d) { d.axes.call(brush.clear()); }); this.canvas.selectAll("rect.background").style("cursor", null).style("pointer-events", "visible"); this.canvas.selectAll("rect.extent, rect.resize").style("display", "none").classed(extentClass, false); }; mpld3_Figure.prototype.add_plugin = function(props) { var plug = props.type; if (typeof plug === "undefined") { console.warn("unspecified plugin type. Skipping this"); return; } props = mpld3_cloneObj(props); delete props.type; if (plug in mpld3.plugin_map) plug = mpld3.plugin_map[plug]; if (typeof plug !== "function") { console.warn("Skipping unrecognized plugin: " + plug); return; } if (props.clear_toolbar) { this.props.toolbar = []; } if ("buttons" in props) { if (typeof props.buttons === "string") { this.props.toolbar.push(props.buttons); } else { for (var i = 0; i < props.buttons.length; i++) { this.props.toolbar.push(props.buttons[i]); } } } this.plugins.push(new plug(this, props)); }; mpld3_Figure.prototype.draw = function() { this.canvas = this.root.append("svg:svg").attr("class", "mpld3-figure").attr("width", this.width).attr("height", this.height); for (var i = 0; i < this.axes.length; i++) { this.axes[i].draw(); } this.disable_zoom(); for (var i = 0; i < this.plugins.length; i++) { this.plugins[i].draw(); } this.toolbar.draw(); }; mpld3_Figure.prototype.reset = function(duration) { this.axes.forEach(function(ax) { ax.reset(duration, false); }); }; mpld3_Figure.prototype.enable_zoom = function() { for (var i = 0; i < this.axes.length; i++) { this.axes[i].enable_zoom(); } this.zoom_on = true; }; mpld3_Figure.prototype.disable_zoom = function() { for (var i = 0; i < this.axes.length; i++) { this.axes[i].disable_zoom(); } this.zoom_on = false; }; mpld3_Figure.prototype.toggle_zoom = function() { if (this.zoom_on) { this.disable_zoom(); } else { this.enable_zoom(); } }; mpld3_Figure.prototype.get_data = function(data) { if (data === null || typeof data === "undefined") { return null; } else if (typeof data === "string") { return this.data[data]; } else { return data; } }; mpld3.PlotElement = mpld3_PlotElement; function mpld3_PlotElement(parent, props) { this.parent = isUndefinedOrNull(parent) ? null : parent; this.props = isUndefinedOrNull(props) ? {} : this.processProps(props); this.fig = parent instanceof mpld3_Figure ? parent : parent && "fig" in parent ? parent.fig : null; this.ax = parent instanceof mpld3_Axes ? parent : parent && "ax" in parent ? parent.ax : null; } mpld3_PlotElement.prototype.requiredProps = []; mpld3_PlotElement.prototype.defaultProps = {}; mpld3_PlotElement.prototype.processProps = function(props) { props = mpld3_cloneObj(props); var finalProps = {}; var this_name = this.name(); this.requiredProps.forEach(function(p) { if (!(p in props)) { throw "property '" + p + "' " + "must be specified for " + this_name; } finalProps[p] = props[p]; delete props[p]; }); for (var p in this.defaultProps) { if (p in props) { finalProps[p] = props[p]; delete props[p]; } else { finalProps[p] = this.defaultProps[p]; } } if ("id" in props) { finalProps.id = props.id; delete props.id; } else if (!("id" in finalProps)) { finalProps.id = mpld3.generateId(); } for (var p in props) { console.warn("Unrecognized property '" + p + "' " + "for object " + this.name() + " (value = " + props[p] + ")."); } return finalProps; }; mpld3_PlotElement.prototype.name = function() { var funcNameRegex = /function (.{1,})\(/; var results = funcNameRegex.exec(this.constructor.toString()); return results && results.length > 1 ? results[1] : ""; }; if (typeof module === "object" && module.exports) { module.exports = mpld3; } else { this.mpld3 = mpld3; } console.log("Loaded mpld3 version " + mpld3.version); }(d3);python-mpld3/mpld3/mpld3renderer.py0000644000175500017550000002402612410130733017303 0ustar debacledebacle""" mpld3 renderer ============== This is the renderer class which implements the mplexporter framework for mpld3 """ __all__ = ["MPLD3Renderer"] import random import json import jinja2 import itertools import numpy as np from .mplexporter.utils import color_to_hex from .mplexporter.exporter import Exporter from .mplexporter.renderers import Renderer from .utils import get_id from .plugins import get_plugins class MPLD3Renderer(Renderer): """Renderer class for mpld3 This renderer class plugs into the ``mplexporter`` package in order to convert matplotlib figures into a JSON-serializable dictionary representation which can be read by mpld3.js. """ def __init__(self): self.figure_json = None self.axes_json = None self.finished_figures = [] @staticmethod def datalabel(i): return "data{0:02d}".format(i) def add_data(self, data, key="data"): """Add a dataset to the current figure If the dataset matches any already added data, we use that instead. Parameters ---------- data : array_like a shape [N,2] array of data key : string (optional) the key to use for the data Returns ------- datadict : dictionary datadict has the keys "data", "xindex", "yindex", which will be passed to the mpld3 JSON object. """ # Check if any column of the data exists elsewhere # If so, we'll use that dataset rather than duplicating it. data = np.asarray(data) if data.ndim != 2 and data.shape[1] != 2: raise ValueError("Data is expected to be of size [N, 2]") for (i, d) in enumerate(self.datasets): if data.shape[0] != d.shape[0]: continue matches = np.array([np.all(col == d.T, axis=1) for col in data.T]) if not np.any(matches): continue # If we get here, we've found a dataset with a matching column # we'll update this data with additional columns if necessary new_data = list(self.datasets[i].T) indices = [] for j in range(data.shape[1]): whr = np.where(matches[j])[0] if len(whr): indices.append(whr[0]) else: # append a new column to the data new_data.append(data[:, j]) indices.append(len(new_data) - 1) self.datasets[i] = np.asarray(new_data).T datalabel = self.datalabel(i + 1) xindex, yindex = map(int, indices) break else: # else here can be thought of as "if no break" # if we get here, then there were no matching datasets self.datasets.append(data) datalabel = self.datalabel(len(self.datasets)) xindex = 0 yindex = 1 self.datalabels.append(datalabel) return {key: datalabel, "xindex": xindex, "yindex": yindex} def open_figure(self, fig, props): self.datasets = [] self.datalabels = [] self.figure_json = dict(width=props['figwidth'] * props['dpi'], height=props['figheight'] * props['dpi'], axes=[], data={}, id=get_id(fig)) def close_figure(self, fig): additional_css = [] additional_js = [] for i, dataset in enumerate(self.datasets): datalabel = self.datalabel(i + 1) self.figure_json['data'][datalabel] = np.asarray(dataset).tolist() self.figure_json["plugins"] = [] for plugin in get_plugins(fig): self.figure_json["plugins"].append(plugin.get_dict()) additional_css.append(plugin.css()) additional_js.append(plugin.javascript()) self.finished_figures.append((fig, self.figure_json, "".join(additional_css), "".join(additional_js))) def open_axes(self, ax, props): self.axes_json = dict(bbox=props['bounds'], xlim=props['xlim'], ylim=props['ylim'], xdomain=props['xdomain'], ydomain=props['ydomain'], xscale=props['xscale'], yscale=props['yscale'], axes=props['axes'], axesbg=props['axesbg'], axesbgalpha=props['axesbgalpha'], zoomable=bool(props['dynamic']), id=get_id(ax), lines=[], paths=[], markers=[], texts=[], collections=[], images=[]) self.figure_json['axes'].append(self.axes_json) # Get shared axes info xsib = ax.get_shared_x_axes().get_siblings(ax) ysib = ax.get_shared_y_axes().get_siblings(ax) self.axes_json['sharex'] = [get_id(axi) for axi in xsib if axi is not ax] self.axes_json['sharey'] = [get_id(axi) for axi in ysib if axi is not ax] def close_axes(self, ax): self.axes_json = None # If draw_line() is not implemented, it will be delegated to draw_path # Should we get rid of this? There's not really any advantage here def draw_line(self, data, coordinates, style, label, mplobj=None): line = self.add_data(data) line['coordinates'] = coordinates line['id'] = get_id(mplobj) for key in ['color', 'linewidth', 'dasharray', 'alpha', 'zorder']: line[key] = style[key] # Some browsers do not accept dasharray="10,0" # This should probably be addressed in mplexporter. if line['dasharray'] == "10,0": line['dasharray'] = "none" self.axes_json['lines'].append(line) def draw_path(self, data, coordinates, pathcodes, style, offset=None, offset_coordinates="data", mplobj=None): path = self.add_data(data) path['coordinates'] = coordinates path['pathcodes'] = pathcodes path['id'] = get_id(mplobj) if offset is not None: path['offset'] = list(offset) path['offsetcoordinates'] = offset_coordinates for key in ['dasharray', 'alpha', 'facecolor', 'edgecolor', 'edgewidth', 'zorder']: path[key] = style[key] # Some browsers do not accept dasharray="10,0" # This should probably be addressed in mplexporter. if path['dasharray'] == "10,0": path['dasharray'] = "none" self.axes_json['paths'].append(path) # If draw_markers is not implemented, it will be delegated to draw_path def draw_markers(self, data, coordinates, style, label, mplobj=None): markers = self.add_data(data) markers["coordinates"] = coordinates markers['id'] = get_id(mplobj, 'pts') for key in ['facecolor', 'edgecolor', 'edgewidth', 'alpha', 'zorder']: markers[key] = style[key] if style.get('markerpath'): vertices, codes = style['markerpath'] markers['markerpath'] = (vertices.tolist(), codes) self.axes_json['markers'].append(markers) # If draw_path_collection is not implemented, # it will be delegated to draw_path def draw_path_collection(self, paths, path_coordinates, path_transforms, offsets, offset_coordinates, offset_order, styles, mplobj=None): if len(paths) != 0: styles = dict(alphas=[styles['alpha']], edgecolors=[color_to_hex(ec) for ec in styles['edgecolor']], facecolors=[color_to_hex(fc) for fc in styles['facecolor']], edgewidths=styles['linewidth'], offsetcoordinates=offset_coordinates, pathcoordinates=path_coordinates, zorder=styles['zorder']) pathsdict = self.add_data(offsets, "offsets") pathsdict['paths'] = [(v.tolist(), p) for (v, p) in paths] pathsdict['pathtransforms'] = [(t[0, :2].tolist() + t[1, :2].tolist() + t[2, :2].tolist()) for t in path_transforms] pathsdict.update(styles) pathsdict['id'] = get_id(mplobj) self.axes_json['collections'].append(pathsdict) def draw_text(self, text, position, coordinates, style, text_type=None, mplobj=None): text = dict(text=text, position=tuple(position), coordinates=coordinates, h_anchor=TEXT_HA_DICT[style['halign']], v_baseline=TEXT_VA_DICT[style['valign']], rotation=-style['rotation'], fontsize=style['fontsize'], color=style['color'], alpha=style['alpha'], zorder=style['zorder'], id=get_id(mplobj)) self.axes_json['texts'].append(text) def draw_image(self, imdata, extent, coordinates, style, mplobj=None): image = dict(data=imdata, extent=extent, coordinates=coordinates) image.update(style) image['id'] = get_id(mplobj) self.axes_json['images'].append(image) TEXT_VA_DICT = {'bottom': 'auto', 'baseline': 'auto', 'center': 'central', 'top': 'hanging'} TEXT_HA_DICT = {'left': 'start', 'center': 'middle', 'right': 'end'} python-mpld3/mpld3/_display.py0000644000175500017550000004041012410130733016334 0ustar debacledebacleimport warnings import random import json import jinja2 import numpy import re import os from ._server import serve_and_open from .utils import deprecated, get_id, write_ipynb_local_js from .mplexporter import Exporter from .mpld3renderer import MPLD3Renderer from . import urls __all__ = ["fig_to_html", "fig_to_dict", "fig_to_d3", "display_d3", "display", "show_d3", "show", "enable_notebook", "disable_notebook", "save_html", "save_json"] # Simple HTML template. This works in standalone web pages for single figures, # but will not work within the IPython notebook due to the presence of # requirejs SIMPLE_HTML = jinja2.Template("""
""") # RequireJS template. If requirejs and jquery are not defined, this will # result in an error. This is suitable for use within the IPython notebook. REQUIREJS_HTML = jinja2.Template("""
""") # General HTML template. This should work correctly whether or not requirejs # is defined, and whether it's embedded in a notebook or in a standalone # HTML page. GENERAL_HTML = jinja2.Template("""
""") TEMPLATE_DICT = {"simple": SIMPLE_HTML, "notebook": REQUIREJS_HTML, "general": GENERAL_HTML} class NumpyEncoder(json.JSONEncoder): """ Special json encoder for numpy types """ def default(self, obj): if isinstance(obj, (numpy.int_, numpy.intc, numpy.intp, numpy.int8, numpy.int16, numpy.int32, numpy.int64, numpy.uint8, numpy.uint16,numpy.uint32, numpy.uint64)): return int(obj) elif isinstance(obj, (numpy.float_, numpy.float16, numpy.float32, numpy.float64)): return float(obj) return json.JSONEncoder.default(self, obj) def fig_to_dict(fig, **kwargs): """Output json-serializable dictionary representation of the figure Parameters ---------- fig : matplotlib figure The figure to display **kwargs : Additional keyword arguments passed to mplexporter.Exporter Returns ------- fig_dict : dict the Python dictionary representation of the figure, which is directly convertible to json using the standard json package. See Also -------- :func:`save_json`: save json representation of a figure to file :func:`save_html` : save html representation of a figure to file :func:`fig_to_html` : output html representation of the figure :func:`show` : launch a local server and show a figure in a browser :func:`display` : embed figure within the IPython notebook :func:`enable_notebook` : automatically embed figures in IPython notebook """ renderer = MPLD3Renderer() Exporter(renderer, close_mpl=False, **kwargs).run(fig) fig, figure_dict, extra_css, extra_js = renderer.finished_figures[0] return figure_dict def fig_to_html(fig, d3_url=None, mpld3_url=None, no_extras=False, template_type="general", figid=None, use_http=False, **kwargs): """Output html representation of the figure Parameters ---------- fig : matplotlib figure The figure to display d3_url : string (optional) The URL of the d3 library. If not specified, a standard web path will be used. mpld3_url : string (optional) The URL of the mpld3 library. If not specified, a standard web path will be used. no_extras : boolean If true, remove any extra javascript or CSS. The output will be similar to that if the representation output by fig_to_json is embedded in a web page. template_type : string string specifying the type of HTML template to use. Options are: ``"simple"`` suitable for a simple html page with one figure. Will fail if require.js is available on the page. ``"notebook"`` assumes require.js and jquery are available. ``"general"`` more complicated, but works both in and out of the notebook, whether or not require.js and jquery are available figid : string (optional) The html/css id of the figure div, which must not contain spaces. If not specified, a random id will be generated. use_http : boolean (optional) If true, use http:// instead of https:// for d3_url and mpld3_url. **kwargs : Additional keyword arguments passed to mplexporter.Exporter Returns ------- fig_html : string the HTML representation of the figure See Also -------- :func:`save_json`: save json representation of a figure to file :func:`save_html` : save html representation of a figure to file :func:`fig_to_dict` : output dictionary representation of the figure :func:`show` : launch a local server and show a figure in a browser :func:`display` : embed figure within the IPython notebook :func:`enable_notebook` : automatically embed figures in IPython notebook """ template = TEMPLATE_DICT[template_type] # TODO: allow fig to be a list of figures? d3_url = d3_url or urls.D3_URL mpld3_url = mpld3_url or urls.MPLD3_URL if use_http: d3_url = d3_url.replace('https://', 'http://') mpld3_url = mpld3_url.replace('https://', 'http://') if figid is None: figid = 'fig_' + get_id(fig) + str(int(random.random() * 1E10)) elif re.search('\s', figid): raise ValueError("figid must not contain spaces") renderer = MPLD3Renderer() Exporter(renderer, close_mpl=False, **kwargs).run(fig) fig, figure_json, extra_css, extra_js = renderer.finished_figures[0] if no_extras: extra_css = "" extra_js = "" return template.render(figid=json.dumps(figid), d3_url=d3_url, mpld3_url=mpld3_url, figure_json=json.dumps(figure_json, cls=NumpyEncoder), extra_css=extra_css, extra_js=extra_js) def display(fig=None, closefig=True, local=False, **kwargs): """Display figure in IPython notebook via the HTML display hook Parameters ---------- fig : matplotlib figure The figure to display (grabs current figure if missing) closefig : boolean (default: True) If true, close the figure so that the IPython matplotlib mode will not display the png version of the figure. local : boolean (optional, default=False) if True, then copy the d3 & mpld3 libraries to a location visible to the notebook server, and source them from there. See Notes below. **kwargs : additional keyword arguments are passed through to :func:`fig_to_html`. Returns ------- fig_d3 : IPython.display.HTML object the IPython HTML rich display of the figure. Notes ----- Known issues: using ``local=True`` may not work correctly in certain cases: - In IPython < 2.0, ``local=True`` may fail if the current working directory is changed within the notebook (e.g. with the %cd command). - In IPython 2.0+, ``local=True`` may fail if a url prefix is added (e.g. by setting NotebookApp.base_url). See Also -------- :func:`show` : launch a local server and show a figure in a browser :func:`enable_notebook` : automatically embed figures in IPython notebook """ # import here, in case users don't have requirements installed from IPython.display import HTML import matplotlib.pyplot as plt if local: if 'mpld3_url' in kwargs or 'd3_url' in kwargs: warnings.warn( "display: specified urls are ignored when local=True") kwargs['d3_url'], kwargs['mpld3_url'] = write_ipynb_local_js() if fig is None: fig = plt.gcf() if closefig: plt.close(fig) return HTML(fig_to_html(fig, **kwargs)) def show(fig=None, ip='127.0.0.1', port=8888, n_retries=50, local=True, **kwargs): """Open figure in a web browser Similar behavior to plt.show(). This opens the D3 visualization of the specified figure in the web browser. On most platforms, the browser will open automatically. Parameters ---------- fig : matplotlib figure The figure to display. If not specified, the current active figure will be used. ip : string, default = '127.0.0.1' the ip address used for the local server port : int, default = 8888 the port number to use for the local server. If already in use, a nearby open port will be found (see n_retries) n_retries : int, default = 50 the maximum number of ports to try when locating an empty port. local : bool, default = True if True, use the local d3 & mpld3 javascript versions, within the js/ folder. If False, use the standard urls. **kwargs : additional keyword arguments are passed through to :func:`fig_to_html` See Also -------- :func:`display` : embed figure within the IPython notebook :func:`enable_notebook` : automatically embed figures in IPython notebook """ if local: kwargs['mpld3_url'] = '/mpld3.js' kwargs['d3_url'] = '/d3.js' files = {'/mpld3.js': ["text/javascript", open(urls.MPLD3_LOCAL, 'r').read()], '/d3.js': ["text/javascript", open(urls.D3_LOCAL, 'r').read()]} else: files = None if fig is None: # import here, in case matplotlib.use(...) is called by user import matplotlib.pyplot as plt fig = plt.gcf() html = fig_to_html(fig, **kwargs) serve_and_open(html, ip=ip, port=port, n_retries=n_retries, files=files) def enable_notebook(local=False, **kwargs): """Enable the automatic display of figures in the IPython Notebook. This function should be used with the inline Matplotlib backend that ships with IPython that can be enabled with `%pylab inline` or `%matplotlib inline`. This works by adding an HTML formatter for Figure objects; the existing SVG/PNG formatters will remain enabled. Parameters ---------- local : boolean (optional, default=False) if True, then copy the d3 & mpld3 libraries to a location visible to the notebook server, and source them from there. See Notes below. **kwargs : all keyword parameters are passed through to :func:`fig_to_html` Notes ----- Known issues: using ``local=True`` may not work correctly in certain cases: - In IPython < 2.0, ``local=True`` may fail if the current working directory is changed within the notebook (e.g. with the %cd command). - In IPython 2.0+, ``local=True`` may fail if a url prefix is added (e.g. by setting NotebookApp.base_url). See Also -------- :func:`disable_notebook` : undo the action of enable_notebook :func:`display` : embed figure within the IPython notebook :func:`show` : launch a local server and show a figure in a browser """ try: from IPython.core.getipython import get_ipython from matplotlib.figure import Figure except ImportError: raise ImportError('This feature requires IPython 1.0+ and Matplotlib') if local: if 'mpld3_url' in kwargs or 'd3_url' in kwargs: warnings.warn( "enable_notebook: specified urls are ignored when local=True") kwargs['d3_url'], kwargs['mpld3_url'] = write_ipynb_local_js() ip = get_ipython() formatter = ip.display_formatter.formatters['text/html'] formatter.for_type(Figure, lambda fig, kwds=kwargs: fig_to_html(fig, **kwds)) def disable_notebook(): """Disable the automatic display of figures in the IPython Notebook. See Also -------- :func:`enable_notebook` : automatically embed figures in IPython notebook """ try: from IPython.core.getipython import get_ipython from matplotlib.figure import Figure except ImportError: raise ImportError('This feature requires IPython 1.0+ and Matplotlib') ip = get_ipython() formatter = ip.display_formatter.formatters['text/html'] formatter.type_printers.pop(Figure, None) def save_html(fig, fileobj, **kwargs): """Save a matplotlib figure to an html file Parameters ---------- fig : matplotlib Figure instance The figure to write to file. fileobj : filename or file object The filename or file-like object in which to write the HTML representation of the figure. **kwargs : additional keyword arguments will be passed to :func:`fig_to_html` See Also -------- :func:`save_json`: save json representation of a figure to file :func:`fig_to_html` : output html representation of the figure :func:`fig_to_dict` : output dictionary representation of the figure """ if isinstance(fileobj, str): fileobj = open(fileobj, 'w') if not hasattr(fileobj, 'write'): raise ValueError("fileobj should be a filename or a writable file") fileobj.write(fig_to_html(fig, **kwargs)) def save_json(fig, fileobj, **kwargs): """Save a matplotlib figure to a json file. Note that any plugins which depend on generated HTML will not be included in the JSON encoding. Parameters ---------- fig : matplotlib Figure instance The figure to write to file. fileobj : filename or file object The filename or file-like object in which to write the HTML representation of the figure. **kwargs : additional keyword arguments will be passed to :func:`fig_to_dict` See Also -------- :func:`save_html` : save html representation of a figure to file :func:`fig_to_html` : output html representation of the figure :func:`fig_to_dict` : output dictionary representation of the figure """ if isinstance(fileobj, str): fileobj = open(fileobj, 'w') if not hasattr(fileobj, 'write'): raise ValueError("fileobj should be a filename or a writable file") json.dump(fig_to_dict(fig, **kwargs), fileobj) # Deprecated versions of these functions show_d3 = deprecated(show, "mpld3.show_d3", "mpld3.show") fig_to_d3 = deprecated(fig_to_html, "mpld3.fig_to_d3", "mpld3.fig_to_html") display_d3 = deprecated(display, "mpld3.display_d3", "mpld3.display") python-mpld3/mpld3/tests/0000755000175500017550000000000012410130733015321 5ustar debacledebaclepython-mpld3/mpld3/tests/test_plugin.py0000644000175500017550000000141012410130733020224 0ustar debacledebacle""" Test plugins """ import numpy as np import matplotlib.pyplot as plt from .. import fig_to_html, plugins from numpy.testing import assert_equal class FakePlugin(plugins.PluginBase): JAVASCRIPT = """TEST--this is the javascript--TEST""" def __init__(self, fig): self.fig = fig self.dict_ = {} self.css_ = """TEST--this is the css--TEST""" def test_plugins(): fig, ax = plt.subplots() ax.plot(np.arange(10), np.random.random(10), '--ok', alpha=0.3, zorder=10, lw=2) plug = FakePlugin(fig) plugins.connect(fig, plug) for template_type in ["simple", "notebook", "general"]: html = fig_to_html(fig, template_type=template_type) assert plug.JAVASCRIPT in html assert plug.css_ in html python-mpld3/mpld3/tests/__init__.py0000644000175500017550000000036612410130733017437 0ustar debacledebacle""" mpld3 tests """ # import matplotlib and set the backend to Agg. This needs to be done before # pyplot is imported: we set it here so that we don't have to set it in any # of the individual test files. import matplotlib matplotlib.use('Agg') python-mpld3/mpld3/tests/test_html.py0000644000175500017550000000152412410130733017700 0ustar debacledebacle""" Test html output """ import numpy as np import matplotlib.pyplot as plt from .. import fig_to_html, urls from numpy.testing import assert_equal def test_html(): fig, ax = plt.subplots() ax.plot(np.arange(10), np.random.random(10), '--ok', alpha=0.3, zorder=10, lw=2) d3_url = "http://this.is.a.test/d3.js" mpld3_url = "http://this.is.a.test/mpld3.js" for template_type in ["simple", "notebook", "general"]: html1 = fig_to_html(fig, template_type=template_type) html2 = fig_to_html(fig, d3_url, mpld3_url, template_type=template_type) # use [:-3] to strip .js from the end (it's not used in require) assert urls.D3_URL[:-3] in html1 assert urls.MPLD3_URL[:-3] in html1 assert d3_url[:-3] in html2 assert mpld3_url[:-3] in html2 python-mpld3/mpld3/tests/test_empty_collections.py0000644000175500017550000000151312410130733022466 0ustar debacledebacleimport unittest import numpy as np import matplotlib.pyplot as plt import mpld3 class empty_collection_tests(unittest.TestCase): """ Ensure that mpld3renderer filters out empty line collections. """ def test_extra_contour(self): """ Create an empty line collection by requesting invalid contours, and check that a collection with length(paths) === 0 is not passed to the JavaScript. """ fig, ax = plt.subplots() X, Y = np.mgrid[0:5, 0:5] Z = X**2 - Y**2 ax.contour(X, Y, Z, range(-15, 18, 2)) # last contour level is 17 # but Z.max() is 16 jsondict = mpld3.fig_to_dict(fig) for collection in jsondict["axes"][0]["collections"]: self.assertTrue(len(collection["paths"]) != 0) return python-mpld3/mpld3/tests/test_js_libs.py0000644000175500017550000000030012410130733020350 0ustar debacledebacleimport os from ..urls import MPLD3_LOCAL, MPLD3MIN_LOCAL, D3_LOCAL def test_js_libs_exist(): for jsfile in [MPLD3_LOCAL, MPLD3MIN_LOCAL, D3_LOCAL]: assert os.path.exists(jsfile) python-mpld3/mpld3/tests/test_figure.py0000644000175500017550000000302012410130733020206 0ustar debacledebacle""" Test creation of a figure """ import matplotlib.pyplot as plt from .. import fig_to_dict from numpy.testing import assert_equal def test_basic_figure(): size = (8, 6) dpi = 80 fig = plt.figure(figsize=size, dpi=dpi) rep = fig_to_dict(fig) plt.close(fig) assert_equal(list(sorted(rep.keys())), ['axes', 'data', 'height', 'id', 'plugins', 'width']) assert_equal(rep['width'], size[0] * dpi) assert_equal(rep['height'], size[1] * dpi) assert_equal(rep['data'], {}) assert_equal(rep['axes'], []) def test_axes(): bbox = [0.1, 0.1, 0.8, 0.8] xlim = [-10, 10] ylim = [-20, 20] fig = plt.figure() ax = fig.add_axes(bbox) ax.set_xlim(xlim) ax.set_ylim(ylim) rep = fig_to_dict(fig) axrep = rep['axes'][0] assert_equal(list(sorted(axrep.keys())), ['axes', 'axesbg', 'axesbgalpha', 'bbox', 'collections', 'id', 'images', 'lines', 'markers', 'paths', 'sharex', 'sharey', 'texts', 'xdomain', 'xlim', 'xscale', 'ydomain', 'ylim', 'yscale', 'zoomable']) for key in ['collections', 'images', 'lines', 'markers', 'paths', 'texts']: assert_equal(axrep[key], []) for key in ['xlim', 'xdomain']: assert_equal(axrep[key], xlim) for key in ['ylim', 'ydomain']: assert_equal(axrep[key], ylim) for key in ['xscale', 'yscale']: assert_equal(axrep[key], 'linear') assert_equal(axrep['zoomable'], True) assert_equal(axrep['bbox'], bbox) python-mpld3/mpld3/tests/test_elements.py0000644000175500017550000001303212410130733020545 0ustar debacledebacle""" Test creation of basic plot elements """ import numpy as np import matplotlib.pyplot as plt from .. import fig_to_dict, fig_to_html from numpy.testing import assert_equal def test_line(): fig, ax = plt.subplots() ax.plot(np.arange(10), np.random.random(10), '--k', alpha=0.3, zorder=10, lw=2) rep = fig_to_dict(fig) axrep = rep['axes'][0] line = axrep['lines'][0] assert_equal(list(sorted(line.keys())), ['alpha', 'color', 'coordinates', 'dasharray', 'data', 'id', 'linewidth', 'xindex', 'yindex', 'zorder']) assert_equal(line['alpha'], 0.3) assert_equal(line['color'], "#000000") assert_equal(line['coordinates'], 'data') assert_equal(line['dasharray'], '6,6') assert_equal(line['zorder'], 10) assert_equal(line['linewidth'], 2) def test_markers(): fig, ax = plt.subplots() ax.plot(np.arange(10), np.random.random(10), '^k', alpha=0.3, zorder=10, mec='r', mew=2, c='b') rep = fig_to_dict(fig) axrep = rep['axes'][0] markers = axrep['markers'][0] assert_equal(list(sorted(markers.keys())), ['alpha', 'coordinates', 'data', 'edgecolor', 'edgewidth', 'facecolor', 'id', 'markerpath', 'xindex', 'yindex', 'zorder']) assert_equal(markers['alpha'], 0.3) assert_equal(markers['zorder'], 10) assert_equal(markers['coordinates'], 'data') assert_equal(markers['edgecolor'], '#FF0000') assert_equal(markers['edgewidth'], 2) assert_equal(markers['facecolor'], '#0000FF') assert_equal(markers['markerpath'][0], [[0.0, -3.0], [-3.0, 3.0], [3.0, 3.0]]) assert_equal(markers['markerpath'][1], ['M', 'L', 'L', 'Z']) def test_scatter(): fig, ax = plt.subplots() ax.scatter(np.arange(10), np.random.random(10), c='r', s=30, marker='^', alpha=0.3, lw=2, edgecolors='b', zorder=10) rep = fig_to_dict(fig) axrep = rep['axes'][0] points = axrep['collections'][0] assert_equal(list(sorted(points.keys())), ['alphas', 'edgecolors', 'edgewidths', 'facecolors', 'id', 'offsetcoordinates', 'offsets', 'pathcoordinates', 'paths', 'pathtransforms', 'xindex', 'yindex', 'zorder']) assert_equal(points['alphas'], [0.3]) assert_equal(points['zorder'], 10) assert_equal(points['edgecolors'], ['#0000FF']) assert_equal(points['facecolors'], ['#FF0000']) assert_equal(points['edgewidths'], (2.0,)) assert_equal(points['paths'][0][0], [[0.0, 0.5], [-0.5, -0.5], [0.5, -0.5]]) assert_equal(points['paths'][0][1], ['M', 'L', 'L', 'Z']) assert_equal(points['pathtransforms'], [[6.085806194501846, 0.0, 0.0, 6.085806194501846, 0.0, 0.0]]) def test_patch(): fig, ax = plt.subplots() ax.add_patch(plt.Rectangle((0, 0), 1, 2, alpha=0.2, linewidth=2, edgecolor='green', facecolor='red', zorder=3)) rep = fig_to_dict(fig) axrep = rep['axes'][0] path = axrep['paths'][0] assert_equal(list(sorted(path.keys())), ['alpha', 'coordinates', 'dasharray', 'data', 'edgecolor', 'edgewidth', 'facecolor', 'id', 'pathcodes', 'xindex', 'yindex', 'zorder']) assert_equal(path['alpha'], 0.2) assert_equal(path['edgecolor'], "#008000") assert_equal(path['facecolor'], "#FF0000") assert_equal(path['edgewidth'], 2) assert_equal(path['zorder'], 3) def test_text(): fig, ax = plt.subplots() ax.text(0.1, 0.1, "abcde", size=14, color='red', alpha=0.7, rotation=15, ha='center', va='center') rep = fig_to_dict(fig) axrep = rep['axes'][0] text = axrep['texts'][0] assert_equal(list(sorted(text.keys())), ['alpha', 'color', 'coordinates', 'fontsize', 'h_anchor', 'id', 'position', 'rotation', 'text', 'v_baseline', 'zorder']) assert_equal(text['alpha'], 0.7) assert_equal(text['color'], "#FF0000") assert_equal(text['text'], "abcde") assert_equal(text['rotation'], -15) assert_equal(text['fontsize'], 14) assert_equal(text['position'], [0.1, 0.1]) assert_equal(text['h_anchor'], 'middle') assert_equal(text['v_baseline'], 'central') assert_equal(text['zorder'], 3) assert_equal(text['coordinates'], "data") def test_image(): fig, ax = plt.subplots() ax.imshow(np.random.random((20, 20)), cmap=plt.cm.binary, alpha=0.2, zorder=4, extent=(2, 4, 3, 5)) rep = fig_to_dict(fig) axrep = rep['axes'][0] image = axrep['images'][0] # TODO: how to test data? assert_equal(list(sorted(image.keys())), ['alpha', 'coordinates', 'data', 'extent', 'id', 'zorder']) assert_equal(image['alpha'], 0.2) assert_equal(image['extent'], (2, 4, 3, 5)) assert_equal(image['zorder'], 4) assert_equal(image['coordinates'], "data") def test_ticks(): plt.xticks([1,2,3]) rep = fig_to_html(plt.gcf()) # TODO: use casperjs here if available to confirm that the xticks # are rendeder as expected # pandas tslib generates ticks with unusual dtypes # test that they are converted to html successfully plt.xticks(np.array([1,2,3], dtype=np.int32)) rep = fig_to_html(plt.gcf()) # custom ticks should appear in the correct place, with the # correct text positions, labels = [0, 1, 10], ['A','B','C'] rep = fig_to_html(plt.gcf()) # TODO: use casperjs here if available to confirm that the xticks # are rendeder as expected python-mpld3/mpld3/plugins.py0000644000175500017550000005534212410130733016223 0ustar debacledebacle""" Plugins to add behavior to mpld3 charts ======================================= Plugins are means of adding additional javascript features to D3-rendered matplotlib plots. A number of plugins are defined here; it is also possible to create nearly any imaginable behavior by defining your own custom plugin. """ __all__ = ['connect', 'clear', 'get_plugins', 'PluginBase', 'Reset', 'Zoom', 'BoxZoom', 'PointLabelTooltip', 'PointHTMLTooltip', 'LineLabelTooltip', 'MousePosition'] import collections import json import uuid import matplotlib from .utils import get_id def get_plugins(fig): """Get the list of plugins in the figure""" connect(fig) return fig.mpld3_plugins def connect(fig, *plugins): """Connect one or more plugins to a figure Parameters ---------- fig : matplotlib Figure instance The figure to which the plugins will be connected *plugins : Additional arguments should be plugins which will be connected to the figure. Examples -------- >>> import matplotlib.pyplot as plt >>> from mpld3 import plugins >>> fig, ax = plt.subplots() >>> lines = ax.plot(range(10), '-k') >>> plugins.connect(fig, plugins.LineLabelTooltip(lines[0])) """ if not isinstance(fig, matplotlib.figure.Figure): raise ValueError("plugins.connect: first argument must be a figure") if not hasattr(fig, 'mpld3_plugins'): fig.mpld3_plugins = DEFAULT_PLUGINS[:] for plugin in plugins: fig.mpld3_plugins.append(plugin) def clear(fig): """Clear all plugins from the figure, including defaults""" fig.mpld3_plugins = [] class PluginBase(object): def get_dict(self): return self.dict_ def javascript(self): if hasattr(self, "JAVASCRIPT"): if hasattr(self, "js_args_"): return self.JAVASCRIPT.render(self.js_args_) else: return self.JAVASCRIPT else: return "" def css(self): if hasattr(self, "css_"): return self.css_ else: return "" class Reset(PluginBase): """A Plugin to add a reset button""" dict_ = {"type": "reset"} class MousePosition(PluginBase): """A Plugin to display coordinates for the current mouse position Example ------- >>> import matplotlib.pyplot as plt >>> from mpld3 import fig_to_html, plugins >>> fig, ax = plt.subplots() >>> points = ax.plot(range(10), 'o') >>> plugins.connect(fig, plugins.MousePosition()) >>> fig_to_html(fig) """ def __init__(self, fontsize=12, fmt=".3g"): self.dict_ = {"type": "mouseposition", "fontsize": fontsize, "fmt": fmt} class Zoom(PluginBase): """A Plugin to add zoom behavior to the plot Parameters ---------- button : boolean, optional if True (default), then add a button to enable/disable zoom behavior enabled : boolean, optional specify whether the zoom should be enabled by default. By default, zoom is enabled if button == False, and disabled if button == True. Notes ----- Even if ``enabled`` is specified, other plugins may modify this state. """ def __init__(self, button=True, enabled=None): if enabled is None: enabled = not button self.dict_ = {"type": "zoom", "button": button, "enabled": enabled} class BoxZoom(PluginBase): """A Plugin to add box-zoom behavior to the plot Parameters ---------- button : boolean, optional if True (default), then add a button to enable/disable zoom behavior enabled : boolean, optional specify whether the zoom should be enabled by default. By default, zoom is enabled if button == False, and disabled if button == True. Notes ----- Even if ``enabled`` is specified, other plugins may modify this state. """ def __init__(self, button=True, enabled=None): if enabled is None: enabled = not button self.dict_ = {"type": "boxzoom", "button": button, "enabled": enabled} class PointLabelTooltip(PluginBase): """A Plugin to enable a tooltip: text which hovers over points. Parameters ---------- points : matplotlib Collection or Line2D object The figure element to apply the tooltip to labels : array or None If supplied, specify the labels for each point in points. If not supplied, the (x, y) values will be used. hoffset, voffset : integer The number of pixels to offset the tooltip text. Default is hoffset = 0, voffset = 10 Examples -------- >>> import matplotlib.pyplot as plt >>> from mpld3 import fig_to_html, plugins >>> fig, ax = plt.subplots() >>> points = ax.plot(range(10), 'o') >>> plugins.connect(fig, PointLabelTooltip(points[0])) >>> fig_to_html(fig) """ def __init__(self, points, labels=None, hoffset=0, voffset=10, location="mouse"): if location not in ["bottom left", "top left", "bottom right", "top right", "mouse"]: raise ValueError("invalid location: {0}".format(location)) if isinstance(points, matplotlib.lines.Line2D): suffix = "pts" else: suffix = None self.dict_ = {"type": "tooltip", "id": get_id(points, suffix), "labels": labels, "hoffset": hoffset, "voffset": voffset, "location": location} class LineLabelTooltip(PluginBase): """A Plugin to enable a tooltip: text which hovers over a line. Parameters ---------- line : matplotlib Line2D object The figure element to apply the tooltip to label : string If supplied, specify the labels for each point in points. If not supplied, the (x, y) values will be used. hoffset, voffset : integer The number of pixels to offset the tooltip text. Default is hoffset = 0, voffset = 10 Examples -------- >>> import matplotlib.pyplot as plt >>> from mpld3 import fig_to_html, plugins >>> fig, ax = plt.subplots() >>> lines = ax.plot(range(10), 'o') >>> plugins.connect(fig, LineLabelTooltip(lines[0])) >>> fig_to_html(fig) """ def __init__(self, points, label=None, hoffset=0, voffset=10, location="mouse"): if location not in ["bottom left", "top left", "bottom right", "top right", "mouse"]: raise ValueError("invalid location: {0}".format(location)) self.dict_ = {"type": "tooltip", "id": get_id(points), "labels": label if label is None else [label], "hoffset": hoffset, "voffset": voffset, "location": location} class LinkedBrush(PluginBase): """A Plugin to enable linked brushing between plots Parameters ---------- points : matplotlib Collection or Line2D object A representative of the scatter plot elements to brush. button : boolean, optional if True (default), then add a button to enable/disable zoom behavior enabled : boolean, optional specify whether the zoom should be enabled by default. default=True. Examples -------- >>> import matplotlib.pyplot as plt >>> import numpy as np >>> from mpld3 import fig_to_html, plugins >>> X = np.random.random((3, 100)) >>> fig, ax = plt.subplots(3, 3) >>> for i in range(2): ... for j in range(2): ... points = ax[i, j].scatter(X[i], X[j]) >>> plugins.connect(fig, LinkedBrush(points)) >>> fig_to_html(fig) Notes ----- Notice that in the above example, only one of the four sets of points is passed to the plugin. This is all that is needed: for the sake of efficient data storage, mpld3 keeps track of which plot objects draw from the same data. Also note that for the linked brushing to work correctly, the data must not contain any NaNs. The presence of NaNs makes the different data views have different sizes, so that mpld3 is unable to link the related points. """ def __init__(self, points, button=True, enabled=True): if isinstance(points, matplotlib.lines.Line2D): suffix = "pts" else: suffix = None self.dict_ = {"type": "linkedbrush", "button": button, "enabled": enabled, "id": get_id(points, suffix)} class PointHTMLTooltip(PluginBase): """A Plugin to enable an HTML tooltip: formated text which hovers over points. Parameters ---------- points : matplotlib Collection or Line2D object The figure element to apply the tooltip to labels : list The labels for each point in points, as strings of unescaped HTML. hoffset, voffset : integer, optional The number of pixels to offset the tooltip text. Default is hoffset = 0, voffset = 10 css : str, optional css to be included, for styling the label html if desired Examples -------- >>> import matplotlib.pyplot as plt >>> from mpld3 import fig_to_html, plugins >>> fig, ax = plt.subplots() >>> points = ax.plot(range(10), 'o') >>> labels = ['

{title}

'.format(title=i) for i in range(10)] >>> plugins.connect(fig, PointHTMLTooltip(points[0], labels)) >>> fig_to_html(fig) """ JAVASCRIPT = """ mpld3.register_plugin("htmltooltip", HtmlTooltipPlugin); HtmlTooltipPlugin.prototype = Object.create(mpld3.Plugin.prototype); HtmlTooltipPlugin.prototype.constructor = HtmlTooltipPlugin; HtmlTooltipPlugin.prototype.requiredProps = ["id"]; HtmlTooltipPlugin.prototype.defaultProps = {labels:null, hoffset:0, voffset:10}; function HtmlTooltipPlugin(fig, props){ mpld3.Plugin.call(this, fig, props); }; HtmlTooltipPlugin.prototype.draw = function(){ var obj = mpld3.get_element(this.props.id); var labels = this.props.labels; var tooltip = d3.select("body").append("div") .attr("class", "mpld3-tooltip") .style("position", "absolute") .style("z-index", "10") .style("visibility", "hidden"); obj.elements() .on("mouseover", function(d, i){ tooltip.html(labels[i]) .style("visibility", "visible");}) .on("mousemove", function(d, i){ tooltip .style("top", d3.event.pageY + this.props.voffset + "px") .style("left",d3.event.pageX + this.props.hoffset + "px"); }.bind(this)) .on("mouseout", function(d, i){ tooltip.style("visibility", "hidden");}); }; """ def __init__(self, points, labels=None, hoffset=0, voffset=10, css=None): self.points = points self.labels = labels self.voffset = voffset self.hoffset = hoffset self.css_ = css or "" if isinstance(points, matplotlib.lines.Line2D): suffix = "pts" else: suffix = None self.dict_ = {"type": "htmltooltip", "id": get_id(points, suffix), "labels": labels, "hoffset": hoffset, "voffset": voffset} class LineHTMLTooltip(PluginBase): """A Plugin to enable an HTML tooltip: formated text which hovers over points. Parameters ---------- points : matplotlib Line2D object The figure element to apply the tooltip to label : string The label for the line, as strings of unescaped HTML. hoffset, voffset : integer, optional The number of pixels to offset the tooltip text. Default is hoffset = 0, voffset = 10 css : str, optional css to be included, for styling the label html if desired Examples -------- >>> import matplotlib.pyplot as plt >>> from mpld3 import fig_to_html, plugins >>> fig, ax = plt.subplots() >>> lines = ax.plot(range(10)) >>> label = '

line {title}

'.format(title='A') >>> plugins.connect(fig, LineHTMLTooltip(lines[0], label)) >>> fig_to_html(fig) """ JAVASCRIPT = """ mpld3.register_plugin("linehtmltooltip", LineHTMLTooltip); LineHTMLTooltip.prototype = Object.create(mpld3.Plugin.prototype); LineHTMLTooltip.prototype.constructor = LineHTMLTooltip; LineHTMLTooltip.prototype.requiredProps = ["id"]; LineHTMLTooltip.prototype.defaultProps = {label:null, hoffset:0, voffset:10}; function LineHTMLTooltip(fig, props){ mpld3.Plugin.call(this, fig, props); }; LineHTMLTooltip.prototype.draw = function(){ var obj = mpld3.get_element(this.props.id, this.fig); var label = this.props.label var tooltip = d3.select("body").append("div") .attr("class", "mpld3-tooltip") .style("position", "absolute") .style("z-index", "10") .style("visibility", "hidden"); obj.elements() .on("mouseover", function(d, i){ tooltip.html(label) .style("visibility", "visible"); }) .on("mousemove", function(d, i){ tooltip .style("top", d3.event.pageY + this.props.voffset + "px") .style("left",d3.event.pageX + this.props.hoffset + "px"); }.bind(this)) .on("mouseout", function(d, i){ tooltip.style("visibility", "hidden");}) }; """ def __init__(self, line, label=None, hoffset=0, voffset=10, css=None): self.line = line self.label = label self.voffset = voffset self.hoffset = hoffset self.css_ = css or "" self.dict_ = {"type": "linehtmltooltip", "id": get_id(line), "label": label, "hoffset": hoffset, "voffset": voffset} class InteractiveLegendPlugin(PluginBase): """A plugin for an interactive legends. Inspired by http://bl.ocks.org/simzou/6439398 Parameters ---------- plot_elements : iterable of matplotlib elements the elements to associate with a given legend items labels : iterable of strings The labels for each legend element ax : matplotlib axes instance, optional the ax to which the legend belongs. Default is the first axes. The legend will be plotted to the right of the specified axes alpha_sel : float, optional the alpha value to apply to the plot_element(s) associated with the legend item when the legend item is selected. Default is 1.0 alpha_unsel : float, optional the alpha value to apply to the plot_element(s) associated with the legend item when the legend item is unselected. Default is 0.2 Examples -------- >>> import matplotlib.pyplot as plt >>> from mpld3 import fig_to_html, plugins >>> N_paths = 5 >>> N_steps = 100 >>> x = np.linspace(0, 10, 100) >>> y = 0.1 * (np.random.random((N_paths, N_steps)) - 0.5) >>> y = y.cumsum(1) >>> fig, ax = plt.subplots() >>> labels = ["a", "b", "c", "d", "e"] >>> line_collections = ax.plot(x, y.T, lw=4, alpha=0.1) >>> interactive_legend = plugins.InteractiveLegendPlugin(line_collections, ... labels, ... alpha_unsel=0.1) >>> plugins.connect(fig, interactive_legend) >>> fig_to_html(fig) """ JAVASCRIPT = """ mpld3.register_plugin("interactive_legend", InteractiveLegend); InteractiveLegend.prototype = Object.create(mpld3.Plugin.prototype); InteractiveLegend.prototype.constructor = InteractiveLegend; InteractiveLegend.prototype.requiredProps = ["element_ids", "labels"]; InteractiveLegend.prototype.defaultProps = {"ax":null, "alpha_sel":1.0, "alpha_unsel":0} function InteractiveLegend(fig, props){ mpld3.Plugin.call(this, fig, props); }; InteractiveLegend.prototype.draw = function(){ var alpha_sel = this.props.alpha_sel; var alpha_unsel = this.props.alpha_unsel; var legendItems = new Array(); for(var i=0; i - License: BSD 3-clause This is an interactive D3js-based viewer which brings matplotlib graphics to the browser. Please visit [http://mpld3.github.io](http://mpld3.github.io) for documentation and examples. You may also see the [blog post](http://jakevdp.github.io/blog/2013/12/19/a-d3-viewer-for-matplotlib/), or the [IPython notebook examples](http://nbviewer.ipython.org/github/jakevdp/mpld3/tree/master/notebooks/) available in the ``notebooks`` directory of this repository. [![version status](https://pypip.in/v/mpld3/badge.png)](https://pypi.python.org/pypi/mpld3) [![downloads](https://pypip.in/d/mpld3/badge.png)](https://pypi.python.org/pypi/mpld3) [![build status](https://travis-ci.org/jakevdp/mpld3.png?branch=master)](https://travis-ci.org/jakevdp/mpld3) About ----- mpld3 provides a custom stand-alone javascript library built on D3, which parses JSON representations of plots. The mpld3 python module provides a set of routines which parses matplotlib plots (using the [mplexporter](http://github.com/mpld3/mplexporter) framework) and outputs the JSON description readable by mpld3.js. Installation ------------ mpld3 is compatible with python 2.6-2.7 and 3.3-3.4. It requires [matplotlib](http://matplotlib.org) version 1.3 and [jinja2](http://jinja.pocoo.org/) version 2.7+. Optionally, mpld3 can be used with [IPython](http://ipython.org) notebook, and requires IPython version 1.x or (preferably) version 2.0+. This package is based on the [mplexporter](http://github.com/mpld3/mplexporter) framework for crawling and exporting matplotlib images. mplexporter is bundled with the source distribution via git submodule. Within the git source directory, you can download the mplexporter dependency and copy it into the mpld3 source directory using the following command: [~]$ python setup.py submodule The submodule command is not necessary if you are installing from a distribution rather than from the git source. Once the submodule command has been run, you can build the package locally using [~]$ python setup.py build or install the package to the standard Python path using: [~]$ python setup.py install Or, to install to another location, use [~]$ python setup.py install --prefix=/path/to/location/ Then make sure your PYTHONPATH environment variable points to this location. Trying it out ------------- The package is pure python, and very light-weight. You can take a look at the notebooks in the examples directory, or run ``create_example.py``, which will create a set of plots and launch a browser window showing interactive views of these plots. For a more comprehensive set of examples, see the [IPython notebook examples](http://nbviewer.ipython.org/github/jakevdp/mpld3/tree/master/notebooks/) available in the ``notebooks`` directory. Test Plots ---------- To explore the comparison between D3 renderings and matplotlib renderings for various plot types, run the script ``visualize_tests.py``. This will generate an HTML page with the D3 renderings beside corresponding matplotlib renderings. Features -------- Many of the core features of matplotlib are already supported. And additionally there is some extra interactivity provided via the plugin framework. The following is a non-exhausive list of features that are yet to be supported: - tick specification & formatting - some legend features - blended transforms, such as those required by ``axvlines`` and ``axhlines`` - twin axes (i.e. multiple scales on one plot) tied together If any of these look like something you'd like to tackle, feel free to submit a pull request! python-mpld3/icons/0000755000175500017550000000000012410130733014253 5ustar debacledebaclepython-mpld3/icons/base64_conv.py0000644000175500017550000000141712410130733016741 0ustar debacledebacle""" Quick script to output JS code for including the listed icons in base64 Usage: python base64_conv.py """ import os import argparse import json def compute_base64_encoding(filename): base, suffix = os.path.splitext(filename) suffix = suffix.lstrip('.') with open(filename, 'rb') as f: data = f.read().encode("base64") return (base, "data:image/{0};base64,{1}".format(suffix, data)) def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("files", nargs='*', type=str) args = parser.parse_args() encodings = dict([compute_base64_encoding(filename) for filename in args.files]) print json.dumps(dict(encodings)) if __name__ == "__main__": main() python-mpld3/icons/brush-128.png0000644000175500017550000000672512410130733016426 0ustar debacledebacle‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYsD$D$@gÄTtEXtSoftwarewww.inkscape.org›î< RIDATxœíy¬UÇ?ó ¥@yÂ&&mQ‘Ŷ÷wR,ÒÒ$‚„„€ ʾj\ (È"P¶ˆ,AÄ+ˆX°.(±ïw ”–U”Åm…BYÒ×Àÿ8sÉëcf3÷ÎÜ7Ÿ¤iß;s–ôû½¿3sçœßñ|ß§bä²i·ÐkˆÈAÀwCUõn§}Ý@/ˆ/0 xHD¶íòÚRÀCÄüj2%0Ae„ˆß¢ð&¨ ‘ñ[Ú•2 "sˆ¿EaMP %ø¿¡½ø- i‚Ê)H!~‹Â™ 2€%ÄoQ(T°Àø- c‚Ê q(~‹B˜ 2@Dd6ÉÅ÷§6ÝuThC þ"’‹2 ÀvÑUTˆ!øªºPUߥ&¨ ¥øóTua뇲˜ 2@)Ä?YUoþË2˜ 2À0DdvwûóÂÄoQtTB þ"`ó„Uæ©êõí.*² *¤ÿ”$â·(ª *Züëlû)¢ F¼:%~‹¢™`D …ø§f¿E‘L0b "b/þµ®ú/Š F¤ñKrñOs)~‹"˜`Ä ¥ø×ä5žn›`D …ø§ç)~‹nš`Ä ¥ø rÒFtË#Â)Ä?£“â·è† zÞ"2;ñ¿¥ªWç8¤X:m¯—wâßGrñ©ê—rRbDd Œqg&¬ò0ËvCjÏF€â¿—×xléT$èÉ0$ìoaQíDU½)c¿»b>±ƒÀ}ªú¿,ímæ zÎ"²?ðvâ7UuUŠþ<àËÀ|à“CŠÖ¨ê¶íEô‘› zj ¨Õj3ßjYueJñ÷–w²±øÛ!3yN=c€Z­6Óó¼û€-éÀ_,ª'½O@Dv‘{?cVGájAn&è‰)`Ê”)öõõ Ôó¿û'hâm`{UŒ»HD&ßN }z7€íTÕé°ëé ô B|ä‘`+Œ°¡ˆÈ."r3ð€ªžOw"AWÞ$¦¥ˆqÉÂÄV·“‘àUî°=kl#Aá#@ñ¡ã‘à‡m¥Â6ÚYÅo¡ªçû¾YH‘K4_:h'36&(ìP«ÕòÐõz}z”øÀ’´â·ÈÑŸ‘MÒŽ+®¾Ñî¢ÂÑl6›žç= ìRØw û¹­ ¦NZÏÚ©ªžCçLð/U]gSAD®ÆøP|üxsØïbMÐl6—ÌÚ\ˆZÂËW3£Ä‡‚@U7¿)ê%ü=ÉE"ÒÜðÙŠÿTÜE…6@Àði E¯˜ m‘±À=ØÝðµÊa€%@ÔÙLô}ÿÉ2×&øQH‘ ¼W("㿇%lo5 Ň@U?þsI¿çybLàêÆðlò1ÁÇ£ Dä ˜Í§{'lk5æ†/‘øP´[Ùg‚­ n‚ÛEä€Ö"â‰È"2€Ùé¼cÂv¬Å‡‚¾ ŽˆLÂÄÎ:ß÷_ò”Ë6 E/šÀ™øP.<Ÿ²^¿çy<Ïë¬Á¡øP.43Ôí÷}¿#&ð}ÿª"Wûf¸Êe«L^!tÄFãÌLàü“ߢLp‘r­­ jµZ-k'ŽMÐ?Õª¡v”É®ŽI‰5çyȹŠå2À Ûjg‚"D‚ÜŇ’|,";a²yoæ¸éužç½äû~Ø×Æk}ߟÝh4Y;©ÕjWzžwFHQÔׯJDd3àÜ‹ñ‘`—‘Àó¼°Ô1a‘ câCÁ#€ˆlƒI‘wÚ•ŽD‚z½~•ïû§‡µ"ÁtP|(p‘‰˜õrȹÓïûþÂ×ç;‹£Fº;CÀv÷}F'Ň‚ X ñ(°{»íÆc™’¶ñiÓ¦m»aƇ€íBŠ×³†óçüvj ‘ÍK0kÞ½. cð20)¤l-&Õê2›‡ˆ?9¤x p ª&YðâœÂ@D¦·ŸîöXph‚"‹0€ˆÔï`²Z‰Ì&(ºøÐEˆÈ~áêÊ’‘Úeº`™~FG;Nµ Ê">tÈA®œÃ31™3ÊFb”I|ÈÙ"2ø*fKÓ„Ü:ê mM0zôèË$>äd€à¸´S1'qŽuÞ=«1â­Ãõ.°3æ‰Ã&»ç:àLò§á¬þ„}›XHñÁ±‚sv.¼¹+—Lÿ.Æœ•M|,°+F¸9Àl îÀÇ8„QXñÁ¡Dä4Œø[9i0;7bŽ_oS)H±:ótr8–u$© ->80€ˆŒ~ ãdDnx84ØXš Ù˜ ËÆywÛ™ ðâCFoë2o¼tÈÓÀ¾¶iWÚ<ÉŒ¹¯9 M´ J!>d0@ðž~1y[—”€ºª>–g'ÁKÇ`îu>ÁÆ&(øÒÁÿÌfŽW2(Ë Ï"^aI¤‚—=G$hã~ÌÑnãTušªŽvάÞÅ[P}úwrè!˜´¥Q¼¯ª92]UW—ŠÈ=ÀÝ„/“J˘Ô鈛Ú-ð¸$Lü¡¨êsÀÑÀ íÀb¸ úô»#ÔAøÿbL½•À÷“t$0žo?´PÇl¯pDT˜D|R¦{£YFà꛺s«O¿[¢ ¶®}(¶+n^ úÔ¤ü4“¶G:i ðºM'Á§v­Ma¬ÂrìTd$Êa'v%é&À‡;„ÆÛÔÆIªº:CýŠ¢ Ðn7í uÒ'|¸XU–²nEÒîÞ9ZDöMr¡ˆŒÂÎãMÂ=À·SÖ­H@ZlÜl«jÇÀgSôñÌ»þê®?G¢¾ |?AÝÝ€å"r‚ª.^("ÛדîeÒTµúäw€( IÒ¢í<,"uV`vÛNÆ|•–+Ž07|7YÖ«HI”¾ž° ³eêàŒcy˜«ªgl§Â‚¨{€%˜ì•âV`¯Jüι$LDî$ÿ¿¯_SÕûsî§"‚¸§€y˜ yð6&—À•øÝ%vQ¨ˆŒ9¿ÖUÖÎwkËUõ GmVd ɪà0sôÄ ý<‡y®¿QU×dh§Â1I7†ŒÅ|›wÉÏîYy |‡ª.M;ÀŠ|±Ú¤ƒù&‘’°ñrñ·0 6SÕÝ ³"/þºaÆÚ>¿¡IEND®B`‚python-mpld3/icons/move-128.png0000644000175500017550000000313312410130733016237 0ustar debacledebacle‰PNG  IHDR€€Ã>aËbKGDÿÿÿ ½§“ pHYs  šœtIMEÞ.:ÍZ1jèIDATxÚí[ˆUUÆ3gF›ÑlpÊJJR§™³TdEEô–‘Ñ…$ Œ"(B",cÀ‡$0º@¤ÝÈ@´ìa¨è‚™–Ó-J‘n6åe¦¼ÌœÖÞtΙ9û¾ÖÞßþ/3sÎYûû¾Ù{­½ÖY»„xhvJŠbÑì™^öêIRNT˜ï×RI“æÇª˜ï×’(¿Ü4Šñ•õ ¤Ê+ê4߯G$Y~x) ù~=.éÜçÓæûõ„$t“IÀþˆæûõ¤ät‹À0SÊÀS’Õ ®Ñô‘µRòÚÍòÍ÷ëÉl'kR0߯U’Û.¶¤h¾_«%{¶4ã20߯Ùg‡24߯5²"}.†,0߯çdIzÜe‘ñ•µVÖ$ÏJKÍ÷k,JŽõ–›ï×˲*^Ú€=Ž˜ï×k® £\  h÷„ sŒÀ«_÷†÷Ú&¯š½WQ ÕXQ%ï÷›eúÿÍž9!þƒ‹ LcAæÌq’ ¡@(B €P„ ¡@(B €P„ð?K$mqYüjY›f|IX«Eí?³ÆÐz–yâíÉAZ,jÿ `»íæß[!Þ÷:ÄÊÙ^›¶Øjþȯj}§$€2°Á6óï¨"Þ7º$«¾ƒx[ ñútH4eàÙ¬uË(âíR@¦»–-C¼¯€TPJ»1 ëï+ µ”»ÓjÈuЧ¤€2pkÒ¸!€x;s€ÇP® úÆõÎ\l¢X48Øæ÷€KâÀ|`kÀ† !²â3 ;®\ô†hĉYv¸í}À9Qp1ðqÈä! Ž·ÿ[`ÊXÇQ+ŸGøð<Àuš1SÉ0ø"â‡Z&Æ€ãÇp8äë&?ë=ÍG<·qbžÉgËi´É;á‹ú%àô}™~`*æQy5Ð…}³x">~¦ µ è”ù¹ç,ªÌÒ6³°o‡H†.àË‘xÓñ1¯ÆùÀ•}€VàìšüÉó6°Èïv{¥IáxÑïî®”…cviÄ0a?°@º‚>`^iÄ·{}Ë¥O®Ùí(UùåV¯§x®tÊ%{™þÈo´[µ»0·†E>(¿{þã•ÃÀZ4yÃö¶ØaÑÁO#ø:ú;±gaËd¢=•ÌŸèþ úÁ'¾žÎ¶Žd…ÖªaÏü ÕÞx¬Aý^ Lâ„ÂÌ „ €ßX\Ðk¦ëö̯¹ž ÞUÁo+ ×—„ zæí‚l³ xAgT'8ê™ÿ÷Xg² {->Ô%Àj†0+‚Ôs a6‰š¹e¬K€¡ÄŸ°»„uÿêLk˜•À$€A/iº1÷øI#eÌòUÒÝ æb¾BZðéî—þ™r¾ŽÇN¡Ï=dÂDüO\[Å> ¼«Q@ª\|õMâÜ+xöí–WböÀ¦ÌŽè(‹q½YÜ8Ž™zÖ% ‘0ÞŽ™—q}=@'ð°l,nCO )8 € ¡@(B €P„ ¡@(Bp›Y]&Ú8³@#Љ“C¼fá·ˆiÀ¬üM‹ÎÕ„ß%«êÚe]|t9dþnªo¿'"2³ÚØfó·É¦d™ŽYzn£ù½²'ÎÀìug“ù›eKºCºv¯—mƒùdI6!hfÜ/X++² Á$ௌBÐ# ì`"ðgÊ!xZ²ÛE+f'ì4ÌLrÛÉ8Ì^øIšŸd¶›’w'. ó—H^wè‹Ùü›%©{ìˆÉ|=MÍa¶E4ÿBIè>Ÿ„4¿[Òå‡÷ 3é$rÆ;u˜˜"©òËzj?Xé f~AësÎ+T_Âu²¤)ë*Ìߌ/ªE]»¶8Í3¾›Š'iÿ“ù¡¨KçîIEND®B`‚python-mpld3/icons/home.png0000644000175500017550000000041312410130733015707 0ustar debacledebacle‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÞ#(ó³#˜IDAT8Ëc` 1à Ô€Û {ÈÕ|‹á?ï¥D3Ɇ`ÓL´!ø44„Í0Œ°ÌÐÐÆ¦p9ÃfB.±‚ T¢)0A²$M®JË#»ÂIÁK,^D6@ª‡ *ù—IñOÍ Õ7€lÀ„f* p«ÙÙl bP?þe``x¦I*Ç £ßTÉ®iÎM¡¬\] IEND®B`‚python-mpld3/icons/home-128.png0000644000175500017550000000213212410130733016217 0ustar debacledebacle‰PNG  IHDR€€Ã>aËbKGDÿÿÿ ½§“ pHYs  šœtIMEÞ.†^å-çIDATxÚíKKUQ†_-°Û ‘A!]Ñ(*Š,»§e*I(šá%/QBs© º‚~‚4lÖhذ(ˆ„$)M*OÏ/ûœ³÷Zk¯õ<ðÍÜ—õ½ïÞçÝ·¥(khA¼ I*HºH+⣣(¾©´$š‰oj/­ Ÿ®eÄ/Hš“TO‹ÂedñV­ Á„â†áÑ^¢ø¦ŽÓºp_Ò"æ˜î Å7Á°VæÑÄ_Xghi~HY|Sh­ÿ´e$¾©c´Ø_Z2ßÔZí=–Ä7Áð -7ð%­³´Þ=ýŽÄ'z@«cñMEŠpÁÐCz=ßÃCHnàKZç(;ny.¾©óH•>Ws"¾©#H–Wr&>Á0Eúr*¾©ÃHnà#räc~óù9ˆ:í #¼Îç‘ÀÇÍ¢4éL|‚áZ"ßTÔZ#ßaËbKGDÿÿÿ ½§“ pHYs  šœtIMEÞ!0[ûµ<FIDATxÚíhVUÇ?ï¬Ít˜Í,â$­EK쇨E…¡TR"D "¡ý1Åè YEѬŒ±AP™ý0Ñ™3Ô Zn«•Nêæ´¶þ8wð6tí}Ÿsß{Ï9Ïž¿ä¸û}¾Ï9÷½÷žûÜ J.ÌnfÓiÀå@PýÀY 8t@+°ØœÖTºÁ|`=p°]@°¸XÓœ.nÞ·løÿE#° ¥éO† PÍÌ„ã൤0/¥ÀôóÅNàµ(>jSjüÐø*ú±©Xâà„#ægǵNNƒƒÆgÇñèRTÉ‘*à”ãægÇ‹jéÈYå‘ñÙ±¸HížMžšŸ}J˜¤6ŸŸo=70úÙj÷i Äüì¨RÛ »40r^ 2ž™¿XT ¿µ؇yÊ÷p è‹þm æ)áôÈ”¹Z¦€rà÷gþ+1Ï®6`p½àçuÄûÌáDˆWŘИçÿ¶™|Ó1ï Éüi1%q=f“GÜL6Çpüu¡@§åÄ} ŒK@ÇUÀAËZæùnþË–ö` 4ÕXÔãõÖ³™õ 0!EÚ*žè&T[½¯pÈ’ùß§Tß Ý’Fïv=l)1[ÐÚlAç¾@7vvÚ¸B›½wùbþc’Ñì˜æà¤Ps‹/ð‡0}ÑùÕ5®¶Pø ]7ÿn I¸Õaý+-ÜãpšíÂlò`”>í¼ÌUác…ÂÏyr œ,ÌÃZW…?%þ„GWA¯ òpÄUÑ{¢»=» .N† × ~ÿ¨䣯5± ÀG*ùØéšØ7b·à/C™-¡‹<.€gy¹Î%¡ºüÛ? Tƒy?>íÌÞ4ñ™ 7ϱs\)ɳìøÏ7yŽ«t¥f Æî  %+« 0U0öP¯Æ)®À•‚±í@›d° 0^0öTpT0v¬ p J\E^âBhŒáùG0¶Ø…8§ËhÁس.@¯`lQP&{Æ…u%t é =.ÀŸ‚±3(‘F @r-Bßœ|û w¸R? Æ. &ׂRNþÀ½Øéø\@çýà;Ÿ®[*‚•–´zõÚØëœæ"xšp:¢æÌv‹E°&…úê-ê»ÂÇÝVñŸ¤DW)ð£E]Ïã1«-Á_Àm êY†ñÎwË…c–‹`øÙ;‰¹R‰Ù a[Ç ßÍ+†¤eÇæ˜“x#ðELǾZÍ·û1Ïßm|Dª xó­Á¸Ž÷35?¾8€ùVÑRF¶ßp6ðð&f+vÜÇ×ê»ùo'hþ…âoÌ ,QMè8º‘½+˜zÞI¡ùi‰îîêÌOKœ&©ùaFWtS,£Ë~xq·7¸¨ù‚xWí‡ËÔüÜbðMØZÇoÂ|m\ÍÏ!ù4Ù×G’Šj nó³Yœà ›\âUÂèu˲?’Ä­ˆîâ¥ÍøzdM2ƒ¾·8Ysæ•é¤oè¬%°æ˜i0?›‰˜}‚-4þ=àNd£åD¶Y>_ŽÃ|¬º8añ8w/7%m@&aó·øÿµc6oôÇxÌ£1›8ª¢¿UÙp9³—¯Óºõ f{Ù1à×è÷H3°awo½Ãwá|M«š¯¨ùŠš¯¨ùŠš¯¨ùŠš¯¨ùŠš¯¨ùŠš¯¨ùŠš¯¨ùŠš¯¨ùŠš¯¨ùŠš¯¨ùŠš¯¨ùŠš¯¨ùj¾š¯æ«ùáQÈæ JʨUóÃ¥\Í›×IOs%~Ò™6çtæ‡M¯Îü°iRóÃ¥ø8ϱm˜>9šF·)Ö™¯,Vó•¥#0·šï7—bú÷õ 1~/°DÓ¥Л>tþïY«$æàØIEND®B`‚python-mpld3/icons/brush.png0000644000175500017550000000073612410130733016112 0ustar debacledebacle‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYsD$D$@gÄTtIMEÞ$ ÖkIDAT8ËÒ½jUQ†ágïM$ñ/­"6""8¥à‚‚hˆ…`+ñ"l¼ K i Ño`¬-ÔFAÔ¢ F娅kËæ˜ãÉ4‹ÅÌû­™Y#""Ú³“Quóõ(83EÄ2ãvvEêMÀO°%3à ÞwEªðÆ3óh'7‡[˜ÄJõø)ŽãöâZfùg„?Âu¬`7q¯Ss—ñªÞ ƒsËÌå~¿¿«ø…#q?"v”Òi|¶ƒŸXÌ̳±/1&3«ˆ¸«˜&°ˆSx\D&ðÛ°Žo؃õz#Ó` NGÄBf®•qÞâS gætÀ]1åÞàLD,4M³†×Ø×ÂPw¾íA1Éù?Ã!Ìà;>à$¾¶ð_#EÄ]̬bªXW ´u£ŠˆÝxƒK¸ƒqô2ó¢MDcxž™½2ÂgÌuö2R` Û#â–¯ú2Øê°ø Rºsë„üIEND®B`‚python-mpld3/icons/move.png0000644000175500017550000000051112410130733015724 0ustar debacledebacle‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÞ$ |±Á5ÖIDAT8ËÓ±JAà/‰¢”Zûâk¤ ˜FR§òADŸÄN)´°byE´HlF8ŽÛ»ä†]þùùwvþ]ÊãjÆÖ‘Ï)R3÷qŒw|à×uºxÃK¡Y!Шâd‹ã-:ëÿovb}Jœ´ŠÌÇG¸m`Šn k™Zá$\Xà [Qèá7²}ìá0êß9ü»Ùî®p_Ðê,á ypP@œãµ¿ÙtÚ)ßAʅʸŒ{~á3Ü9ÛVd’ùL£º?òçe„?@7-§YÓ ýIEND®B`‚python-mpld3/version.py0000644000175500017550000000025212410130733015176 0ustar debacledebacle""" Short script which prints the mpld3 version to stdout This is used within the Javascript build system. """ from _mpld3_setup import get_version print(get_version()) python-mpld3/AUTHORS.md0000644000175500017550000000154412410130733014613 0ustar debacledebacle# Authors This package was started by Jake Vanderplas in December 2013, but its current state is largely due to enthusiastic contributions from a number of developers ## Maintainers - [Jake Vanderplas](http://github.com/jakevdp) - [Abraham Flaxman](https://github.com/aflaxman) - [Dan Allan](http://github.com/danielballan) ## Authors - [Rob Story](http://github.com/wrobstory): packaging help - [jmeppley](http://github.com/jmeppley): various line markers - [Michael Waskom](http://github.com/mwaskom): API design - [Renaud Richardet](http://github.com/renaud): various bug fixes - [Jason Furtney](http://github.com/jkfurtney): time & log support for axes - [Brian Granger](http://github.com/ellisonbg): IPython notebook interaction - [Justin Goodwin](http://github.com/jgbos): Refactor to D3 node/smash style - [Dirk Loss](https://github.com/dloss): Logo designpython-mpld3/test/0000755000175500017550000000000012410130733014117 5ustar debacledebaclepython-mpld3/test/utils/0000755000175500017550000000000012410130733015257 5ustar debacledebaclepython-mpld3/test/utils/path-test.js0000644000175500017550000000212112410130733017522 0ustar debacledebaclevar vows = require("vows"), load = require("../load"), assert = require("assert"); var suite = vows.describe('mpld3.path') suite.addBatch({ "path": { topic: load("utils/util").document(), "A simple straight line path": { topic: function(mpld3) { var data = [[0, 1], [1, 2], [2, 3]]; return mpld3.path().call(data); }, "returns the correct SVG codes": function(path){ assert.equal(path, "M 0 1 L 1 2 L 2 3"); } }, "A simple quadratic path": { topic: function(mpld3) { var data = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]; var pathcodes = ['M', 'Q', 'Q'] return mpld3.path().call(data, pathcodes); }, "returns the correct SVG codes": function(path){ assert.equal(path, "M 0 1 Q 1 2 2 3 Q 3 4 4 5"); } }, "A simple closed path": { topic: function(mpld3) { var data = [[0, 0], [1, 0], [0, 1]]; var pathcodes = ['M', 'L', 'L', 'Z']; return mpld3.path().call(data, pathcodes); }, "returns the correct SVG codes": function(path){ assert.equal(path, "M 0 0 L 1 0 L 0 1 Z"); } } } }); suite.export(module); python-mpld3/test/utils/multiscale-test.js0000644000175500017550000000377012410130733020743 0ustar debacledebaclevar vows = require("vows"), d3 = require("d3"), load = require("../load"), assert = require("assert"); var suite = vows.describe('mpld3.path') suite.addBatch({ "multiscale": { topic: load("utils/util").document(), "A multiscale object": { topic: function(mpld3) { return mpld3.multiscale(d3.scale.linear() .domain([0, 1]) .range([10, 20]), d3.scale.linear() .domain([10, 20]) .range([100, 200])); }, "has the expected domain": function(m){ assert.deepEqual(m.domain(), [0, 1]); }, "has the expected range": function(m){ assert.deepEqual(m.range(), [100, 200]); }, "converts from domain to range as expected": function(m){ assert.equal(m(0.5), 150); } }, "A modified multiscale object": { topic: function(mpld3) { var scale1 = d3.scale.linear() .domain([0, 1]) .range([10, 20]); var scale2 = d3.scale.linear() .domain([10, 20]) .range([100, 200]); return [scale1, scale2, mpld3.multiscale(scale1, scale2)]; }, "has the expected domain": function(tup){ var s1 = tup[0], s2 = tup[1], m = tup[2]; assert.deepEqual(m.domain(), s1.domain()); }, "has the expected range": function(tup){ var s1 = tup[0], s2 = tup[1], m = tup[2]; assert.deepEqual(m.range(), s2.range()); }, "correctly behaves when domain/range are modified": function(tup){ var s1 = tup[0], s2 = tup[1], m = tup[2]; // modify domain and range m.domain([-1, 1]); assert.deepEqual(m.domain(), s1.domain()); m.range([8, 16]); assert.deepEqual(m.range(), s2.range()); // check the new multiscale mapping assert.deepEqual(m(3.14), s2(s1(3.14))); } } } }); suite.export(module); python-mpld3/test/core/0000755000175500017550000000000012410130733015047 5ustar debacledebaclepython-mpld3/test/core/coords-test.js0000644000175500017550000000527012410130733017657 0ustar debacledebaclevar vows = require("vows"), load = require("../load"), assert = require("assert"); var suite = vows.describe('mpld3.Coordinates') suite.addBatch({ "Coordinates": { topic: load("core/figure", "core/axes", "core/coordinates").document(), "A Coordinates('display') object": { topic: function(mpld3) { var fig_props = { width: 400, height: 300, axes: [{xlim: [0, 1], ylim: [0, 1]}] }; var fig = new mpld3.Figure("chart", fig_props); fig.draw(); return new mpld3.Coordinates("display", fig.axes[0]); }, "transforms to the correct display coordinates": function(coords){ assert.equal(coords.xy([100, 100])[0], 100); assert.equal(coords.xy([100, 100])[1], 100); } }, "A Coordinates('data') object": { topic: function(mpld3) { var fig_props = { width: 400, height: 300, axes: [{xlim: [-1, 1], ylim: [-1, 1]}] }; var fig = new mpld3.Figure("chart", fig_props); fig.draw(); return new mpld3.Coordinates("data", fig.axes[0]); }, "transforms to the correct display coordinates": function(coords){ assert.equal(coords.xy([0.3, 0.4])[0], 208); assert.equal(coords.xy([0.3, 0.4])[1], 72); } }, "A Coordinates('axes') object": { topic: function(mpld3) { var fig_props = { width: 400, height: 300, axes: [{xlim: [-1, 1], ylim: [-1, 1]}] }; var fig = new mpld3.Figure("chart", fig_props); fig.draw(); return new mpld3.Coordinates("axes", fig.axes[0]); }, "transforms to the correct display coordinates": function(coords){ assert.equal(coords.xy([0.3, 0.4])[0], 96); assert.equal(coords.xy([0.3, 0.4])[1], 144); } }, "A Coordinates('figure') object": { topic: function(mpld3) { var fig_props = { width: 400, height: 300, axes: [{xlim: [-1, 1], ylim: [-1, 1]}] }; var fig = new mpld3.Figure("chart", fig_props); fig.draw(); return new mpld3.Coordinates("figure", fig.axes[0]); }, "transforms to the correct display coordinates": function(coords){ assert.equal(coords.xy([0.3, 0.4])[0], 80); assert.equal(coords.xy([0.3, 0.4])[1], 150); } } } }); suite.export(module); python-mpld3/test/core/axes-test.js0000644000175500017550000000217212410130733017324 0ustar debacledebaclevar vows = require("vows"), load = require("../load"), assert = require("assert"); var suite = vows.describe("mpld3.Axes"); suite.addBatch({ "Axes": { topic: load("core/figure", "core/axes").document(), "A simple axes": { topic: function(mpld3) { var ax_props = { xlim: [0, 1], ylim: [0, 1], bbox: [0.1, 0.1, 0.8, 0.8], axes: [] }; var fig_props = { width: 400, height: 300, plugins: [], axes: [ax_props] }; var fig = new mpld3.Figure("chart", fig_props); fig.draw(); return fig.axes[0]; }, "has the expected axnum": function(ax) { assert.equal(ax.axnum, 0); }, "has the expected dimensions": function(ax) { assert.equal(ax.width, 400 * 0.8); assert.equal(ax.height, 300 * 0.8); } } } }); suite.export(module); python-mpld3/test/core/figure-test.js0000644000175500017550000000163412410130733017647 0ustar debacledebaclevar vows = require("vows"), load = require("../load"), assert = require("assert"); var suite = vows.describe("mpld3.Figure"); suite.addBatch({ "Figure": { topic: load("core/figure").document(), "A simple figure": { topic: function(mpld3) { var props = { width: 400, height: 300, plugins: [] }; var figure = new mpld3.Figure("chart", props); figure.draw(); return figure; }, "has the expected id": function(figure){ assert.equal(figure.figid, "chart"); }, "has the expected width and height": function(figure){ assert.equal(figure.props.width, 400); assert.equal(figure.props.height, 300); } } } }); suite.export(module); python-mpld3/test/core/element-test.js0000644000175500017550000000367112410130733020022 0ustar debacledebaclevar vows = require("vows"), load = require("../load"), assert = require("assert"); var suite = vows.describe("mpld3.Element"); suite.addBatch({ "Element": { topic: load("core/element").document(), "A generic plot element ": { topic: function(mpld3) { return new mpld3.PlotElement(null); }, "has the expected parent": function(element) { assert.equal(element.parent, null); }, "has the expected figure reference": function(element) { assert.equal(element.fig, null); }, "has the expected axes reference": function(element) { assert.equal(element.ax, null); } }, "A generic plot element attached to an axes": { topic: function(mpld3) { MyEl.prototype = Object.create(mpld3.PlotElement.prototype); MyEl.constructor = MyEl; MyEl.prototype.requiredProps = ["A"]; MyEl.prototype.defaultProps = {B:1, C:4}; function MyEl(parent, props){ mpld3.PlotElement.call(this, parent, props); } return new MyEl(new mpld3.Figure("fig01", {width:400, height:300}), {A:3, B:10}); }, "has the expected parent figure reference": function(element) { assert.equal(element.fig, element.parent); }, "has the expected axes reference": function(element) { assert.equal(element.ax, null); }, "has the expected properties and values": function(element) { assert.equal(element.props.A, 3); assert.equal(element.props.B, 10); assert.equal(element.props.C, 4); } } } }); suite.export(module); python-mpld3/test/elements/0000755000175500017550000000000012410130733015733 5ustar debacledebaclepython-mpld3/test/elements/text-test.js0000644000175500017550000000270112410130733020232 0ustar debacledebaclevar vows = require("vows"), load = require("../load"), assert = require("assert"); var suite = vows.describe("mpld3.Text"); suite.addBatch({ "Text": { topic: load("elements/path").document(), "A simple Text object": { topic: function(mpld3) { var fig_props = { width: 400, height: 300 }; var ax_props = { xlim: [0, 4], ylim: [0, 4] }; var text_props = { text: "hello world", position: [1, 3] }; var fig = new mpld3.Figure("chart", fig_props); var ax = new mpld3.Axes(fig, ax_props); var text = new mpld3.Text(ax, text_props); ax.elements.push(text); fig.axes.push(ax); fig.draw(); return text; }, "contains the expected text": function(text) { assert.equal(text.text, "hello world"); }, "has the expected coordinate transform": function(text) { assert.equal(text.props.coordinates, "data"); }, "has the expected position": function(text) { assert.equal(text.position[0], 1); assert.equal(text.position[1], 3); } } } }); suite.export(module); python-mpld3/test/elements/image-test.js0000644000175500017550000000323312410130733020331 0ustar debacledebaclevar vows = require("vows"), load = require("../load"), assert = require("assert"); var suite = vows.describe("mpld3.Text"); suite.addBatch({ "Image": { topic: load("elements/path").document(), "A simple Image": { topic: function(mpld3) { var fig_props = { width: 400, height: 300 }; var ax_props = { xlim: [0, 4], ylim: [0, 4] }; var img_props = { data: "NdxDRpYZ6D9YTVL09/fjP8zDz+GgeOM/nlErkxBJ6D8=", extent: [0, 0, 1, 2], alpha: 0.5 }; var fig = new mpld3.Figure("chart", fig_props); var ax = new mpld3.Axes(fig, ax_props); var img = new mpld3.Image(ax, img_props); ax.elements.push(img); fig.axes.push(ax); fig.draw(); return img; }, "contains the expected data": function(img) { assert.equal(img.props.data, "NdxDRpYZ6D9YTVL09/fjP8zDz+GgeOM/nlErkxBJ6D8="); }, "has the expected extent": function(img) { assert.equal(img.props.extent[0], 0); assert.equal(img.props.extent[1], 0); assert.equal(img.props.extent[2], 1); assert.equal(img.props.extent[3], 2); }, "has the expected transparency": function(img) { assert.equal(img.props.alpha, 0.5); } } } }); suite.export(module); python-mpld3/test/elements/path-test.js0000644000175500017550000000241412410130733020203 0ustar debacledebaclevar vows = require("vows"), load = require("../load"), assert = require("assert"); var suite = vows.describe("mpld3.Line"); suite.addBatch({ "Path": { topic: load("elements/path").document(), "A simple Path": { topic: function(mpld3) { var fig_props = { width: 400, height: 300 }; var ax_props = { xlim: [0, 4], ylim: [0, 4] }; var path_props = { data: [[0, 1], [1, 2], [2, 3], [3, 2], [4, 1]], pathcodes: ['M', 'L', 'L', 'L', 'L', 'Z'] }; var fig = new mpld3.Figure("chart", fig_props); var ax = new mpld3.Axes(fig, ax_props); var path = new mpld3.Path(ax, path_props); ax.elements.push(path); fig.axes.push(ax); fig.draw(); return path; }, "has the expected SVG path.": function(path) { assert.equal(path.datafunc(path.data, path.pathcodes), "M 0 180 L 80 120 L 160 60 L 240 120 L 320 180 Z"); } } } }); suite.export(module); python-mpld3/test/elements/line-test.js0000644000175500017550000000222712410130733020200 0ustar debacledebaclevar vows = require("vows"), load = require("../load"), assert = require("assert"); var suite = vows.describe("mpld3.Line"); suite.addBatch({ "Line": { topic: load("elements/line").document(), "A simple Line": { topic: function(mpld3) { var fig_props = { width: 400, height: 300 }; var ax_props = { xlim: [0, 1], ylim: [2, 3] }; var line_props = { data: [[0, 2], [1, 3], [2, 4]] }; var fig = new mpld3.Figure("chart", fig_props); var ax = new mpld3.Axes(fig, ax_props); var line = new mpld3.Line(ax, line_props); ax.elements.push(line); fig.axes.push(ax); fig.draw(); return line; }, "returns the expected SVG path": function(line) { assert.equal(line.datafunc(line.data, line.pathcodes), "M0,240L320,0L640,-240") } } } }); suite.export(module); python-mpld3/test/elements/path_collection-test.js0000644000175500017550000000354512410130733022424 0ustar debacledebaclevar vows = require("vows"), load = require("../load"), assert = require("assert"); var suite = vows.describe("mpld3.PathCollection"); suite.addBatch({ "Path Collections": { topic: load("elements/path").document(), "A simple Path collection": { topic: function(mpld3) { var fig_props = { width: 400, height: 300 }; var ax_props = { xlim: [0, 4], ylim: [0, 4] }; var coll_props = { paths: [[[[0, 1], [1, 2], [2, 3], [3, 2], [4, 1]], ['M', 'L', 'L', 'L', 'L', 'Z']]], offsets: null, alphas: [0, 0.25, 0.5, 0.75, 1.0] }; var fig = new mpld3.Figure("chart", fig_props); var ax = new mpld3.Axes(fig, ax_props); var coll = new mpld3.PathCollection(ax, coll_props); ax.elements.push(coll); fig.axes.push(ax); fig.draw(); return coll; }, "has the expected number of offsets.": function(coll) { assert.equal(coll.offsets.length, 1); }, "has the expected transform.": function(coll) { assert.equal(coll.transformFunc([0, 0], 0), "translate(0,240)"); }, "has the expected path.": function(coll) { assert.equal(coll.pathFunc([0, 0], 0), "M 0 1 L 1 2 L 2 3 L 3 2 L 4 1 Z"); }, "has the expected style.": function(coll) { assert.equal(coll.styleFunc([0, 0], 0), "stroke:#000000;stroke-width:1;stroke-opacity:0;fill:#0000FF;fill-opacity:0;"); } } } }); suite.export(module); python-mpld3/test/elements/marker-test.js0000644000175500017550000000565612410130733020543 0ustar debacledebaclevar vows = require("vows"), load = require("../load"), assert = require("assert"); var suite = vows.describe("mpld3.Markers"); suite.addBatch({ "Markers": { topic: load("elements/markers").document(), "A simple set of circle markers": { topic: function(mpld3) { var fig_props = { width: 400, height: 300, }; var ax_props = { xlim: [0, 1], ylim: [2, 3], }; var marker_props = { markername: "circle", data: [[0, 2], [1, 3]] }; var fig = new mpld3.Figure("fig01", fig_props); var ax = new mpld3.Axes(fig, ax_props); var markers = new mpld3.Markers(ax, marker_props); ax.elements.push(markers); fig.axes.push(ax); fig.draw(); return markers; }, "has the expected marker path": function(markers) { assert.equal(markers.marker, "M0,3.385137501286538A3.385137501286538,3.385137501286538 0 1,1 0,-3.385137501286538A3.385137501286538,3.385137501286538 0 1,1 0,3.385137501286538Z"); }, "has the expected offsets": function(markers) { assert.equal(markers.offsets[0][0], 0); assert.equal(markers.offsets[0][1], 2); assert.equal(markers.offsets[1][0], 1); assert.equal(markers.offsets[1][1], 3); } }, "A set of markers with custom paths": { topic: function(mpld3) { var fig_props = { width: 100, height: 200 }; var ax_props = { xlim: [0, 1], ylim: [2, 3] }; var marker_props = { markerpath: [[[0, 0], [1, 0], [1, 1], [0, 1]], ["M", "L", "L", "L", "Z"]], data: [[0, 1], [2, 3]] }; var fig = new mpld3.Figure("fig01", fig_props); var ax = new mpld3.Axes(fig, ax_props); var markers = new mpld3.Markers(ax, marker_props); ax.elements.push(markers); fig.axes.push(ax); fig.draw(); return markers; }, "has the expected SVG output": function(markers) { assert.equal(markers.marker, "M 0 0 L 1 0 L 1 1 L 0 1 Z"); }, "has the expected offsets": function(markers) { assert.equal(markers.offsets[0][0], 0); assert.equal(markers.offsets[0][1], 1); assert.equal(markers.offsets[1][0], 2); assert.equal(markers.offsets[1][1], 3); } } } }); suite.export(module); python-mpld3/test/load.js0000644000175500017550000000206512410130733015377 0ustar debacledebaclevar smash = require("smash"), d3 = require("d3"), jsdom = require("jsdom"); module.exports = function() { var files = [].slice.call(arguments).map(function(d) { return "src/" + d; }), expression = "mpld3", sandbox = {console: console, d3: d3}; files.unshift("src/start"); files.push("src/version"); files.push("src/end"); function topic() { var callback = this.callback; smash.load(files, expression, sandbox, function(error, result) { if (error) console.trace(error.stack); callback(error, result); }); } topic.expression = function(_) { expression = _; return topic; }; topic.sandbox = function(_) { sandbox = _; return topic; }; topic.document = function(_) { var document = jsdom.jsdom(""); sandbox = { d3 : d3, console: console, document: document, window: document.createWindow() }; return topic; }; return topic; }; process.on("uncaughtException", function(e) { console.trace(e.stack); }); python-mpld3/setup.cfg0000644000175500017550000000004712410130733014762 0ustar debacledebacle[metadata] description-file = README.mdpython-mpld3/setup.py0000644000175500017550000000361012410130733014652 0ustar debacledebacleimport os import sys try: from setuptools import setup except ImportError: from distutils.core import setup from _mpld3_setup import (require_clean_submodules, UpdateSubmodules, check_js_build_status, BuildJavascript, get_version) DESCRIPTION = "D3 Viewer for Matplotlib" LONG_DESCRIPTION = open('README.md').read() NAME = "mpld3" AUTHOR = "Jake VanderPlas" AUTHOR_EMAIL = "jakevdp@cs.washington.edu" MAINTAINER = "Jake VanderPlas" MAINTAINER_EMAIL = "jakevdp@cs.washington.edu" URL = 'http://mpld3.github.com' DOWNLOAD_URL = 'http://github.com/jakevdp/mpld3' LICENSE = 'BSD 3-clause' VERSION = get_version() # Make sure submodules are updated and synced root_dir = os.path.abspath(os.path.dirname(__file__)) require_clean_submodules(root_dir, sys.argv) # Warn if it looks like JS libs need to be built if 'buildjs' not in sys.argv: check_js_build_status(VERSION, root_dir) setup(name=NAME, version=VERSION, description=DESCRIPTION, long_description=LONG_DESCRIPTION, author=AUTHOR, author_email=AUTHOR_EMAIL, maintainer=MAINTAINER, maintainer_email=MAINTAINER_EMAIL, url=URL, download_url=DOWNLOAD_URL, license=LICENSE, cmdclass={'submodule': UpdateSubmodules, 'buildjs': BuildJavascript}, packages=['mpld3', 'mpld3/mplexporter', 'mpld3/mplexporter/renderers'], package_data={'mpld3': ['js/*.js']}, classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Console', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: BSD License', 'Natural Language :: English', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4'], ) python-mpld3/notebooks/0000755000175500017550000000000012410130733015143 5ustar debacledebaclepython-mpld3/notebooks/sliderPlugin.ipynb0000755000175500017550000072060412410130733020663 0ustar debacledebacle{ "metadata": { "name": "", "signature": "sha256:5b76069e0e751e9e0117b297530db92683d26f33bad3f8fc2b9ba3e41f085293" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Adding HTML elements to figures" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This notebook contains examples how to add HTML elements to figures and create interaction between Javascript and Python code.\n", "\n", "**Note**: this notebook makes interactive calculation when slider position is changed, so you need to download this notebook to see any changes in plot." ] }, { "cell_type": "code", "collapsed": false, "input": [ "%matplotlib inline\n", "import matplotlib.pylab as plt\n", "import mpld3\n", "mpld3.enable_notebook()" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Simple example: slider plugin" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We add a simple slider HTML element ```` to our figure. When slider position is changed, we call ``kernel.execute()`` and pass updated value to Python function ``runCalculation()``. In this simple example we just update the frequency $\\omega$ of $\\sin(\\omega x)$." ] }, { "cell_type": "code", "collapsed": false, "input": [ "class SliderView(mpld3.plugins.PluginBase):\n", " \"\"\" Add slider and JavaScript / Python interaction. \"\"\"\n", "\n", " JAVASCRIPT = \"\"\"\n", " mpld3.register_plugin(\"sliderview\", SliderViewPlugin);\n", " SliderViewPlugin.prototype = Object.create(mpld3.Plugin.prototype);\n", " SliderViewPlugin.prototype.constructor = SliderViewPlugin;\n", " SliderViewPlugin.prototype.requiredProps = [\"idline\", \"callback_func\"];\n", " SliderViewPlugin.prototype.defaultProps = {}\n", "\n", " function SliderViewPlugin(fig, props){\n", " mpld3.Plugin.call(this, fig, props);\n", " };\n", "\n", " SliderViewPlugin.prototype.draw = function(){\n", " var line = mpld3.get_element(this.props.idline);\n", " var callback_func = this.props.callback_func;\n", "\n", " var div = d3.select(\"#\" + this.fig.figid);\n", "\n", " // Create slider\n", " div.append(\"input\").attr(\"type\", \"range\").attr(\"min\", 0).attr(\"max\", 10).attr(\"step\", 0.1).attr(\"value\", 1)\n", " .on(\"change\", function() {\n", " var command = callback_func + \"(\" + this.value + \")\";\n", " console.log(\"running \"+command);\n", " var callbacks = { 'iopub' : {'output' : handle_output}};\n", " var kernel = IPython.notebook.kernel;\n", " kernel.execute(command, callbacks, {silent:false});\n", " });\n", "\n", " function handle_output(out){\n", " //console.log(out);\n", " var res = null;\n", " // if output is a print statement\n", " if (out.msg_type == \"stream\"){\n", " res = out.content.data;\n", " }\n", " // if output is a python object\n", " else if(out.msg_type === \"pyout\"){\n", " res = out.content.data[\"text/plain\"];\n", " }\n", " // if output is a python error\n", " else if(out.msg_type == \"pyerr\"){\n", " res = out.content.ename + \": \" + out.content.evalue;\n", " alert(res);\n", " }\n", " // if output is something we haven't thought of\n", " else{\n", " res = \"[out type not implemented]\"; \n", " }\n", "\n", " // Update line data\n", " line.data = JSON.parse(res);\n", " line.elements()\n", " .attr(\"d\", line.datafunc(line.data))\n", " .style(\"stroke\", \"black\");\n", "\n", " }\n", "\n", " };\n", " \"\"\"\n", "\n", " def __init__(self, line, callback_func):\n", " self.dict_ = {\"type\": \"sliderview\",\n", " \"idline\": mpld3.utils.get_id(line),\n", " \"callback_func\": callback_func}" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "import numpy as np\n", "\n", "def updateSlider(val1):\n", " t = np.linspace(0, 10, 500)\n", " y = np.sin(val1*t)\n", " return map(list, list(zip(list(t), list(y))))\n", "\n", "fig, ax = plt.subplots(figsize=(8, 4))\n", "\n", "t = np.linspace(0, 10, 500)\n", "y = np.sin(t)\n", "ax.set_xlabel('Time')\n", "ax.set_ylabel('Amplitude')\n", "\n", "# create the line object\n", "line, = ax.plot(t, y, '-k', lw=3, alpha=0.5)\n", "ax.set_ylim(-1.2, 1.2)\n", "ax.set_title(\"Slider demo\")\n", "\n", "mpld3.plugins.connect(fig, SliderView(line, callback_func=\"updateSlider\"))" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "display_data", "png": "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\ngAAbAAAAAElFTkSuQmCC\n", "text": [ "" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Note**: this notebook makes interactive calculation when slider position is changed, so you need to download this notebook to see any changes in plot." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Complex example: beam deflection" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When creating more interaction between Javascript and Python, things get easily quite complicated. Therefore one should consider using e.g. Backbone or similar to get more structured code in Javascript side. IPython notebook seems to be using Backbone internally already.\n", "\n", "In the next example we add more inputs and use Backbone to handle syncronizing Python and Javascript. In this example we calculate the deflection line $v(x)$ for simple supported Euler Bernoulli beam and update visualization when user changes force location $x \\in [0, 1]$. The formula for deflection $v(x)$ is \n", "\n", "\\begin{equation}\n", "v(x) = \\frac{FL^2}{6EI}\\left[ \\frac{ab}{L^2}(L+b)\\frac{x}{L} - b\\left(\\frac{x}{L}\\right)^3 + \\frac{1}{L^2}^3 \\right],\n", "\\end{equation}\n", "where\n", "\\begin{equation}\n", "=\\begin{cases}\n", "0 & ,x\n", "

Tools

\n", "

Force location

\n", " \n", " \n", "

Boundary conditions

\n", " \n", "

Young's modulus (GPa)

\n", " \n", "

Other options

\n", "
\n", " \n", "
\n", "\n", "\"\"\")" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n" ], "metadata": {}, "output_type": "pyout", "prompt_number": 4, "text": [ "" ] } ], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Our plugin code comes next. Note that we have now Backbone model LineModel to handle Python-Javascript-interaction and Backbone views ToolsView and CanvasView to take care of visualization when data is changed.\n", "\n", "Note that not all input elements are \"connected\" to the visualization, they are more like placeholders ready for your own coding experiments. They are not implemented on purpose to keep lines of code as low as possible. To get them work, modify ``this.notImplemented`` $\\rightarrow$ ``this.modelChanged`` in ``initialize`` function and change ``var command = ... `` in ``modelChanged`` to pass more parameters to notebook server. Don't forget to change Python side function accordingly." ] }, { "cell_type": "code", "collapsed": false, "input": [ "class MyUserInterface(mpld3.plugins.PluginBase):\n", " \"\"\" Here we use Backbone to create more structured Javascript. \"\"\"\n", "\n", " JAVASCRIPT = \"\"\"\n", "\n", "var LineModel = Backbone.Model.extend({\n", "\n", " initialize: function(options) {\n", " this.options = options || {};\n", " this.on(\"change:sliderPosition\", this.modelChanged);\n", " this.on(\"change:boundaryCondition\", this.notImplemented);\n", " this.on(\"change:youngsModulus\", this.notImplemented);\n", " this.on(\"change:useFEM\", this.notImplemented);\n", " },\n", "\n", " /**\n", " This example should be quite easy to extend to use more inputs. You\n", " just have to pass more model.get('...') things to kernel execute command below.\n", " */\n", " notImplemented: function(model) {\n", " alert(\"This function is not implemented in the example on purpose.\");\n", " },\n", "\n", " /**\n", " Model changed, execute notebook kernel and update model data.\n", " */\n", " modelChanged: function(model) {\n", " var command = this.options.callback_func + \"(\" + model.get('sliderPosition') + \")\";\n", " console.log(\"IPython kernel execute \"+command);\n", " var callbacks = {\n", " 'iopub' : {\n", " 'output' : function(out) {\n", " //console.log(out);\n", " var res = null;\n", " // if output is a print statement\n", " if (out.msg_type == \"stream\"){\n", " res = out.content.data;\n", " }\n", " // if output is a python object\n", " else if(out.msg_type === \"pyout\"){\n", " res = out.content.data[\"text/plain\"];\n", " }\n", " // if output is a python error\n", " else if(out.msg_type == \"pyerr\"){\n", " res = out.content.ename + \": \" + out.content.evalue;\n", " alert(res);\n", " }\n", " // if output is something we haven't thought of\n", " else{\n", " res = \"[out type not implemented]\";\n", " alert(res);\n", " }\n", " model.set(\"line\", JSON.parse(res));\n", " }\n", " }\n", " };\n", " IPython.notebook.kernel.execute(command, callbacks, {silent:false});\n", " }\n", "\n", "});\n", "\n", "\n", "var ToolsView = Backbone.View.extend({\n", "\n", " /**\n", " This view renders toolbar with slider and other html elements.\n", " */\n", " initialize: function(options) {\n", " this.options = options || {};\n", " _.bindAll(this, 'render');\n", " },\n", "\n", " render: function() {\n", " var template = _.template($(\"#tools-template\").html(), {});\n", " $(this.el).append(template);\n", " return this;\n", " },\n", "\n", " /**\n", " Listen event changes.\n", " */\n", " events: {\n", " \"change #slider1\": \"changeSlider1\",\n", " \"change #boundary_conditions\": \"changeBoundaryConditions\",\n", " \"change #young\": \"changeModulus\",\n", " \"change #useFEM\": \"changeUseFEM\"\n", " },\n", "\n", " changeSlider1: function(ev) {\n", " var sliderPosition = $(ev.currentTarget).val();\n", " this.model.set('sliderPosition', sliderPosition);\n", " $(this.el).find(\"#slider1label\").text(parseFloat(sliderPosition).toFixed(2));\n", " },\n", "\n", " changeBoundaryConditions: function(ev) {\n", " this.model.set('boundaryCondition', $(ev.currentTarget).val());\n", " },\n", "\n", " changeModulus: function(ev) {\n", " this.model.set('youngsModulus', $(ev.currentTarget).val());\n", " },\n", "\n", " changeUseFEM: function(ev) {\n", " var isChecked = $(ev.currentTarget).is(\":checked\");\n", " this.model.set('useFEM', isChecked);\n", " }\n", "\n", "});\n", "\n", "var CanvasView = Backbone.View.extend({\n", "\n", " initialize: function(options) {\n", " this.options = options || {};\n", " this.line = mpld3.get_element(this.options.props.idline);\n", " _.bindAll(this, 'render');\n", " this.model.bind('change:line', this.render);\n", " },\n", "\n", " /**\n", " Update line when model changes, f.e. new data is calculated\n", " inside notebook and updated to Backbone model.\n", " */\n", " render: function() {\n", " this.line.elements().transition()\n", " .attr(\"d\", this.line.datafunc(this.model.get('line')))\n", " .style(\"stroke\", \"black\");\n", " }\n", "\n", "});\n", "\n", "// PLUGIN START\n", "\n", "mpld3.register_plugin(\"myuserinterface\", MyUserInterfacePlugin);\n", "MyUserInterfacePlugin.prototype = Object.create(mpld3.Plugin.prototype);\n", "MyUserInterfacePlugin.prototype.constructor = MyUserInterfacePlugin;\n", "MyUserInterfacePlugin.prototype.requiredProps = [\"idline\", \"callback_func\"];\n", "MyUserInterfacePlugin.prototype.defaultProps = {}\n", "\n", "function MyUserInterfacePlugin(fig, props){\n", " mpld3.Plugin.call(this, fig, props);\n", "};\n", "\n", "MyUserInterfacePlugin.prototype.draw = function() {\n", "\n", " // Some hacking to get proper layout.\n", " var div = $(\"#\" + this.fig.figid).attr(\"style\", \"border: 1px solid;\");\n", " var figdiv = div.find(\"div\");\n", " figdiv.attr(\"style\", \"display: inline;\");\n", "\n", " // Create LineModel\n", " var lineModel = new LineModel({\n", " callback_func: this.props.callback_func\n", " });\n", "\n", " // Create tools view\n", " var myel = $('
');\n", " div.append(myel);\n", " var toolsView = new ToolsView({\n", " el: myel,\n", " model: lineModel\n", " });\n", " toolsView.render();\n", "\n", " // Create canvas view which updates line visualization when the model is changed\n", " var canvasView = new CanvasView({\n", " el: figdiv,\n", " model: lineModel,\n", " props: this.props\n", " });\n", "\n", "};\n", "\"\"\"\n", "\n", " def __init__(self, line, callback_func):\n", " self.dict_ = {\"type\": \"myuserinterface\",\n", " \"idline\": mpld3.utils.get_id(line),\n", " \"callback_func\": callback_func}" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next we do the actual calculation of the deflection using Python and display results:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import numpy as np\n", "\n", "L = 1.0\n", "F = 3.0\n", "E = 100.0\n", "I = 0.1\n", "\n", "def v_(x, a):\n", " b = L - a\n", " v = a*b/L**2*(L+b)*x/L - b*(x/L)**3\n", " if x-a > 0.0:\n", " v += 1.0/L**2*(x-a)**3\n", " v *= F*L**2/(6.0*E*I)\n", " return v\n", "\n", "v = np.vectorize(v_)\n", "\n", "def runCalculation(a):\n", " \"\"\" \n", " \"\"\"\n", " x = np.linspace(0, L, 500)\n", " y = -v(x, a)*1000.0\n", " return map(list, list(zip(list(x), list(y))))\n", "\n", "fig, ax = plt.subplots(figsize=(8, 4))\n", "\n", "t = np.linspace(0, 1, 200)\n", "y = np.sin(t)\n", "ax.set_xlabel('x [m]')\n", "ax.set_ylabel('Deflection [mm]')\n", "ax.set_title('Euler-Bernoulli beam deflection line')\n", "\n", "# create the line object\n", "initial_data = np.array(runCalculation(0.5))\n", "line, = ax.plot(initial_data[:, 0], initial_data[:, 1], '-k', lw=3, alpha=0.5)\n", "ax.plot([0.975, 1.025, 1.00, 0.975], [-1, -1, 0, -1], '-k', lw=1)\n", "ax.plot([-0.025, 0.025, 0.000, -0.025], [-1, -1, 0, -1], '-k', lw=1)\n", "ax.set_ylim(-10, 5)\n", "ax.grid(lw=0.1, alpha=0.2)\n", "\n", "mpld3.plugins.connect(fig, MyUserInterface(line, callback_func=\"runCalculation\"))" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "display_data", "png": "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\nYII=\n", "text": [ "" ] } ], "prompt_number": 6 }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Note**: this notebook makes interactive calculation when slider position is changed, so you need to download this notebook to see any changes in plot." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Note 2**: The line is updated only when force location is changed, but it should be trivial to extend this example use more tools. " ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 6 } ], "metadata": {} } ] }python-mpld3/notebooks/interactive_legend.ipynb0000644000175500017550000212074512410130733022054 0ustar debacledebacle{ "metadata": { "name": "", "signature": "sha256:818a4a74de89f7d6535437da31fe5b3add5fd9d0e11a4539fd2cfbbd1e8039e4" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Simple legend example\n", "\n", "This is the simplest use case for the plugin. We plot a few lines, instantiate the InteractiveLegendPlugin, and connect it to the figure. Note that we pass the labels for each of the lines explicitly. At the moment the label information of matplotlib is not passed along to D3. The plugin creates a legend to the right of the axes starting at the top. Each of the rectangles is clickable. When a legend item is selected, the rectangle is filled. \n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import mpld3\n", "from mpld3 import plugins\n", "from mpld3.utils import get_id\n", "import collections\n", "\n", "N_paths = 5\n", "N_steps = 100\n", "\n", "x = np.linspace(0, 10, 100)\n", "y = 0.1 * (np.random.random((N_paths, N_steps)) - 0.5)\n", "y = y.cumsum(1)\n", "\n", "fig, ax = plt.subplots()\n", "labels = [\"a\", \"b\", \"c\", \"d\", \"e\"]\n", "line_collections = ax.plot(x, y.T, lw=4, alpha=0.2)\n", "interactive_legend = plugins.InteractiveLegendPlugin(line_collections, labels)\n", "plugins.connect(fig, interactive_legend)\n", "\n", "mpld3.display()" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "pyout", "prompt_number": 1, "text": [ "" ] } ], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## We can link multiple elements to a single legend item\n", "\n", "There is the possibility to link more than one matplotlib element (e.g. a line) to a single item in the legend. As demonstrated by the example below. The plugin needs a list of matplotlib items, a list of lists, or a hybrid. Thus, it is possible to link one legend item to several elements in the plot, while another legend item is linked only to a single item. In case of multiple items being associated with a single legend item, the box takes on the color of the first item in the list. " ] }, { "cell_type": "code", "collapsed": false, "input": [ "N_paths = 5\n", "N_steps = 100\n", "\n", "x1 = np.linspace(0, 10, 100)\n", "y = 0.1 * (np.random.random((N_paths, N_steps)) - 0.5)\n", "y1 = y.cumsum(1)\n", "\n", "x2 = np.linspace(0, 10, 100)\n", "y = 0.1 * (np.random.random((N_paths, N_steps)) - 0.5)\n", "y2 = y.cumsum(1)\n", "\n", "fig, ax = plt.subplots()\n", "labels = [\"a\", \"b\",]\n", "l1 = ax.plot(x1, y1.T, lw=4, alpha=0.1, c='b', label='a')\n", "l2 = ax.plot(x2, y2.T, lw=4, alpha=0.2, c='r', label='b')\n", "\n", "line_collections = [l1,l2]\n", "plugins.connect(fig, plugins.InteractiveLegendPlugin(line_collections, labels))\n", "\n", "mpld3.display()" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "pyout", "prompt_number": 2, "text": [ "" ] } ], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Legends for different axes\n", "\n", "By default, the legend is shown to the right of the first axes. However, through the use of the optional keyword argument 'ax', we can specify the axes to the right of which the legend will be shown." ] }, { "cell_type": "code", "collapsed": false, "input": [ "N_paths = 5\n", "N_steps = 100\n", "\n", "x = np.linspace(0, 10, 100)\n", "y = 0.1 * (np.random.random((N_paths, N_steps)) - 0.5)\n", "y = y.cumsum(1)\n", "\n", "fig = plt.figure()\n", "ax1 = fig.add_subplot(2,1,1)\n", "ax2 = fig.add_subplot(2,1,2)\n", "\n", "labels = [\"a\", \"b\", \"c\", \"d\", \"e\"]\n", "l1 = ax1.plot(x, y.T, lw=4, alpha=0.1)\n", "s1 = []\n", "for i in range(N_paths):\n", " s = ax2.scatter(x,y[i, :], c=next(ax2._get_lines.color_cycle), alpha=0.1)\n", " s1.append(s)\n", " \n", "plugins.connect(fig, plugins.InteractiveLegendPlugin(l1, labels, ax=ax1))\n", "plugins.connect(fig, plugins.InteractiveLegendPlugin(s1, labels, ax=ax2))\n", "mpld3.display()" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "pyout", "prompt_number": 3, "text": [ "" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## single legend for different axes\n", "\n", "We can link multiple matplotlib elements to a single item in the legend. This functionality works even when the elements belong to different axes as shown below. " ] }, { "cell_type": "code", "collapsed": false, "input": [ "N_paths = 5\n", "N_steps = 100\n", "\n", "x = np.linspace(0, 10, 100)\n", "y = 0.1 * (np.random.random((N_paths, N_steps)) - 0.5)\n", "y = y.cumsum(1)\n", "\n", "\n", "fig = plt.figure()\n", "ax1 = fig.add_subplot(2,1,1)\n", "ax2 = fig.add_subplot(2,1,2)\n", "\n", "labels = [\"a\", \"b\", \"c\", \"d\", \"e\"]\n", "l1 = ax1.plot(x, y.T, lw=4, alpha=0.1)\n", "s1 = []\n", "for i in range(N_paths):\n", " s = ax2.scatter(x,y[i, :], c=next(ax2._get_lines.color_cycle), alpha=0.1)\n", " s1.append(s)\n", " \n", "plugins.connect(fig, plugins.InteractiveLegendPlugin(zip(l1, s1), labels))\n", "mpld3.display()" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "pyout", "prompt_number": 4, "text": [ "" ] } ], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## scatterplot demo" ] }, { "cell_type": "code", "collapsed": false, "input": [ "nr_elements = 5\n", "\n", "fig, ax = plt.subplots()\n", "elements = []\n", "for i in range(nr_elements):\n", " x = np.random.rand(100)\n", " y = np.random.rand(100)\n", " \n", " element = ax.scatter(x,y, color=next(ax2._get_lines.color_cycle), alpha=0.2, marker='+')\n", " elements.append([element])\n", "\n", "labels = [\"{}\".format(i) for i in range(nr_elements)]\n", "plugins.connect(fig, plugins.InteractiveLegendPlugin(elements, labels))\n", "mpld3.display()" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "pyout", "prompt_number": 5, "text": [ "" ] } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Markers and Lines in case of Line2D instances\n", "A Line2d instance can have both a line, as well as markers at each vertex. In D3 these are two distinct things. The interactive legend can handle both as demonstrated by the example below. See the code and comments there on how this is achieved for details. \n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "N_paths = 5\n", "N_steps = 100\n", "\n", "x = np.linspace(0, 10, 100)\n", "y = 0.1 * (np.random.random((N_paths, N_steps)) - 0.5)\n", "y = y.cumsum(1)\n", "\n", "\n", "fig = plt.figure()\n", "ax1 = fig.add_subplot(2,1,1)\n", "ax2 = fig.add_subplot(2,1,2)\n", "\n", "labels = [\"a\", \"b\", \"c\", \"d\", \"e\"]\n", "l1 = ax1.plot(x, y.T, marker='x',lw=2, alpha=0.1)\n", "s1 = ax2.plot(x, y.T, 'o', ms=8, alpha=0.1)\n", " \n", "plugins.connect(fig, plugins.InteractiveLegendPlugin(zip(l1, s1), labels))\n", "mpld3.display()" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "pyout", "prompt_number": 6, "text": [ "" ] } ], "prompt_number": 6 } ], "metadata": {} } ] }python-mpld3/notebooks/mpld3_demo.ipynb0000644000175500017550000312203012410130733020232 0ustar debacledebacle{ "metadata": { "name": "", "signature": "sha256:19f55359179ddd946d4097b419e880518a9dc2826c6835632320d8d5822eda66" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Demo of mpld3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This notebook gives a brief overview of [mpld3](http://mpld3.github.io), a package which allows seamless visualization of matplotlib plots using HTML, Javascript, and the [D3js](http://d3js.org/) package.\n", "\n", "One of the nicest parts of the IPython notebook is the ability to embed figures inline with code. For example, we can quickly create a scatter plot as so:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "import numpy as np" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "code", "collapsed": false, "input": [ "# Scatter points\n", "fig, ax = plt.subplots()\n", "np.random.seed(0)\n", "x, y = np.random.normal(size=(2, 200))\n", "color, size = np.random.random((2, 200))\n", "\n", "ax.scatter(x, y, c=color, s=500 * size, alpha=0.3)\n", "ax.grid(color='lightgray', alpha=0.7)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "display_data", "png": "iVBORw0KGgoAAAANSUhEUgAAAXAAAAEACAYAAACqOy3+AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzsvVlsHGl27/mLyIzc92QuzOSSJLVQJCVSUlVpKUnV1V1d\n3dWb7bZn5hoYL20/G/DLPBgwYMAvfjFg2IAfBpiX6ztA33s99m2799qkUklVkkoStVDc9yWZydz3\nNSLmgdpFSqRISaQqf4AeUhn84nyZkf84cb7znSOoqqrSoEGDBg12HeKrNqBBgwYNGjwfDQFv0KBB\ng11KQ8AbNGjQYJfSEPAGDRo02KU0BLxBgwYNdikNAW/QoEGDXcqWBLxcLnPs2DEGBgbo6enhr/7q\nr7bLrgYNGjRo8AyEreaBF4tFTCYT9XqdU6dO8fd///ecOnVqu+xr0KBBgwbrsOUQislkAqBarSLL\nMi6Xa8tGNWjQoEGDZ7NlAVcUhYGBAXw+H++++y49PT3bYVeDBg0aNHgGWxZwURS5ceMGi4uLnD9/\nnnPnzm2DWQ0aNGjQ4Flot2sgu93O97//fa5evco3vvGN+/+/Z88epqamtus0DRo0aPC1oKuri8nJ\nyacesyUPPB6Pk06nASiVSnz00UccPnz4kWOmpqZQVfW1/fc3f/M3r9yGxvwa8/u6ze3rML+NOL5b\n8sCXl5f5kz/5ExRFQVEU/uiP/ohvfetbWxly11Gv11+1CS+Uxvx2L6/z3OD1n99G2JKAHzx4kOvX\nr2+XLQ0aNGjQYBM0dmJukffee+9Vm/BCacxv9/I6zw1e//lthC1v5HnmCQSBF3yKBg0aNHjt2Ih2\nNjzwLVIul1+1CS+Uxvx2L6/z3OD1n99GaAh4gwYNGuxSGiGUBg0aNNiBNEIoDRo0aPAa0xDwLfK6\nx+Ea84NCoUAsFmNlZYVUKoUsyy/Bsq3T+O5ef7ZtK32DBq8TqVSKydkJ5qKzIKnozFoQBOSqTDVf\nw2Vxs6+tm2AwiFbb+Bk1eDU0YuANGjxEpVJh8PZ1FjKzuDuc+IJedHrdI8coikI6kSY6F0dJCRw/\neAK/3/+KLH69kGWZbDZLtVpFEATMZjNms/lVm/VK2Ih2NgS8QYO7pNNpzl75BHObgfZ9rYjisyOM\n6WSGmRvz7Pf20N/X/xKsfP1QFIVwOMzt2UnC2TSi1YSo14GqIueLSDWFA80t7A11YrfbX7W5L42G\ngL8EyuUyBoPhVZvxwvi6zC+bzfLxpd8SGPDi9ro39LeKrFCv16nVa0xcnWafe2eJ+G747pLJJOdv\nXiNp0mAPteLwND1x46xWKsQXlijPLjHgbaG/pw+tVrsr5rcVNqKdjeBdg689sixz8doFPL2uDYl3\nNptlcWmFxUgGBS0gIMtlxi7+CkEROHjwIIIgvHjDdzmzc7N8Oj6E/eA+Ovy+dY/T6fUE9nQih9oY\nGh5j8fOzvH/8VOMzpuGBN2jA8OgwU4URuo/uf+px1UqVW0MTxHIqksmHxeZGo1n1FhVVJbowx8z5\nIU73H+GD945js9lehvm7kqWlJX4zeoPAiSMY7rZl3CiR6VlMcyt879Q3kCTpBVn46mnkgTdo8Axk\nWWZk7g6hnvanHlepVLh8bYRUrYmmYB92p+e+eAOIgkBzW4jmg/tYyjv5919dul8rv8GjlEolzt4Z\nxPfmoU2LN4C/M0TGY2Vw6NYLsG530RDwLfK656K+rvOr1+vMz8/z6UcfMTE/xO2rV7l64SLDN2+x\nuLhIsVC8f6yqqNy4PUFF24zDvf6jPkBTq4diLYHo7OdXn3xFtVp90VNZl5363Q0ODyF0BDBv4Qkl\ncGAfk9kEyWRyGy3bfTRi4A2+VtRqNYaHhhgfHERfrZItF/D5tbjvPq5WEglWlsPMKipWj4eO/fuo\n1eokChKegPeZ41ucDuarC9jsbiJZHzMzc+zfv/clzGx3UC6XGYsv09r/9pbG0Wg0GFv8jM5McdLl\n2ibrdh8NAd8ir/MqOLxe84vH41z8+GO06TTdXi86SeLL8Rs0NTnR61ZzvQ16PXYsqKpKNpfj5ucX\nyCJh8B3d0DkEQUBn1VEsZHF6QgzeucK+fXteyYLbTvzulpeXEfxuNNuw+cnaHmR8/ALHZBmNRrMN\n1u0+GiGUBl8LIpEIn/77v+OTZfYEg+juLn5V5Tpa6UkxEQQBu8VCwGolOjZDOrqIrCgbOpdGJ1Kv\n1zBZbKTKBuLx+LbOZTcTTScxuhzbMpZGq0U1G8jlctsy3m6kIeBbZKfGGbeL12F+mUyG87/4BZ02\nG87H4q5mqx2estKvKAoeRxNyfJHowsTGTqhy3+MWJSulUum5bd8KO/G7i+ezGC2WbRlLU64iWs3k\n8/ltGW830hDwBq81iqLw5blzNEsS1jW2ZBu0ekqlyvoDqAog0GR1kV+cIp99dmZJtVBDb7ibXSGI\nKBv03L8OKKqKIG5jOEkUvtafb0PAt8hOjDNuJ7t9fvPz85SWlvCus9BlrAsUcsU13wMQRQ0gI4ga\nXEYLkemhpzns1Ks15LKKwXj3ZiFXX1mu8k787vRaLfVqbVvGkg06qNZf61zwZ9FYxGzwWjMyOEjz\nU+pneBxOpsOLtIbWfl+v1yOJdeR6FYPeiJqJU8insVjXjuMmoyu47R0IgoBcryNUY7jdvdswk62j\nqiqRSISRkWni8RyKomI26+nubqWtrQ29Xv/CbfDbXQxlczg8TdsyXj2Tw9779amP8jgND3yL7MQ4\n43aym+eXz+fJRaNPxL0fxup0YqmbSCYya74viCK+Jhulwur7ZlFLNhFd81hVVUnOpfD7V9MGE7FF\nevd4Xpkn/PB3Fw6H+elPf8XPfnaL+Xkb0I1W20su18onn0T4l3/5Ndeu3Xjh4Qifu4lKdHsWdWuJ\nNFZVxPQcm4FeF7Ys4AsLC7z77rv09vbS19fHP/3TP22HXQ0abJl0Oo1xA8ft94dYGo0i19du1OB0\nOhBqWZR6Db3eQCm79uaRyOwCVk0LVruLer1GJT1F977Q809gm5ienuFnP7uKIHTT0nIUt7sZo9GC\nXm/CanUSDB6gqekYly4lOHv24gsVca/Xi6lQpbgNmSOpcIRD7V3bYNXuZcsCLkkS//AP/8CdO3e4\ndOkS//zP/8zIyMh22LYr2Ilxxu1kN88vl82if0ZJWKFWw2W306r1Mz26uGbtCUmS6Ghzk08vohEE\nKoXsE8dkk0nS0yU6u96gXq+xNHGFUwPNuN0bq2z4IjAYDMRiMT788BZe72EslvVDDVqtRFtbP2Nj\nNa5du/nCbBJFkTe69hMZGt3SOPlMhvpyjI720PYYtkvZsoD7/X4GBgYAsFgsHDhwgHA4vGXDGjTY\nKvVaDXGDG2j2t4WwpE1M3plf0xN3OBx0tTgoZ5YoF7LUH2qrllqJsXQjQveeb5DPpVieuMipQw4O\nHezZtrk8LzdujGIwdKHXb+RZBAKBXgYH519o6mNXRyetskR4cvq5/r5eqxEdvMM7PQMvJW6/k9nW\nGPjs7CyDg4McO3ZsO4fd0ezmGPFG2M3zk/T6Z26+Ue9mMIiiyEDXfjwFJ8OXp9aMiTtdTvZ3ebEb\nymSXb7E8N8GtC18weX4ah76VXPg6fmmGH3+7m4H+V79wmUwmmZpK4XQ+uwTAPTQaDYriZnp69oXZ\nJQgCp4++hWFuhcgmz1OrVpm7fJ2jTS00NW3PQuhuZtuyUPL5PH/wB3/AP/7jP2J5LFH/r//6r+/3\nDTx58iRnzpy5/2h+TyB26+tKpbKj7HnV88vlchSLRbRaLVqtFkmSEEXxldhvs9lQTCZUSUKoraau\n3RPs+6/vXpdCrYYoinTv3U9zPsjwnRHC2hV8Hc2YzEZEqY4oCNSrEq3eEFa9jpXJJd72dtIy0ILF\nYsTv73sipe1Vfn8rKyuYTF70eplabdVXk6TVeddq0rqv/f5mhocn6O098MLsMxqNfO/kGS5ev8py\n/AbOvn0YTCY05dXiX7JhtbTBvdd1vUQ8vEx9bI4TgXZ6u1dte9W/j+18fe7cOT7++GOADfdZ3ZZ6\n4LVajR/84Ad88MEH/OVf/uWjJ2jUA9+xyLJMOBymUChQKlXR6yWMRgOBQGBTj6bFYpHJqVlGppZJ\n52sgWRAEEVWpIcoF/E1WDnW30dLS8lJrVhSLRf7zv/5XBoLB56pFksnniaWSpCo5irUSCiq5XIFg\n72FOnTxDIBDY0Q2Nr1+/yfXrMj5f26b+rl6vkclc4U//9HdekGUPUFWVialJrkyNUXOaMfo9mO02\ndHo9qqpSyhcopNJUFiIEdGZOHBzA4dierfg7nZfSkUdVVf78z/+cnp6eJ8S7wc4kn88zMTHNzZuz\nlEpmRNGCKGpRlDKKEkOjuUlvb4Du7q6nLsLJssyd4TEu3V5ENbXi9B4jEHr06UtRFDLpBL+6Moft\n6jjfevvgS2sAbDKZ8IZCxGMxPE7npv/ebrFgf+xp8ubiIu+9/z1cu6AC3vM6T6qqvrTiW4IgsG/P\nXro6OgmHw4QTMSIzE6SqFQRBwGm2sMfuovXo218b4d4MW/bAL1y4wJkzZzh06ND9L/3v/u7v+O53\nv7t6gtfcA98pffkURaFYLCLLMlqtdt1O3mNjE5w7N4wg+HC5gmsubslynUQiTLUa5sgRP2++eeSJ\nPoXlcpkPz15iKW/DF+pDknRPjPM4+WyK1PwNjvc2cXig76WIxNLSEpf+4z/obWlZ83wPh1eexUoy\nSdHp5Ds/+tF2m/lCmJyc5KOPwrS0bG4xNZtNYrUu8KMffesFWbY97JTf3ovipXjgp06d+lrXInjV\nFItFZmYmWZy/iSQV0WigWlURNW7aQ4dpa2tDd7dU6o0bt7l4cQG//yg63foXvkajxettQ1FaGBkZ\nIZ+/yLvvvn1fxKvVKr/++EsStNKyd8+GbbXYnBi7T/PF6BVgiCOHD25p7hshGAzi3rePpbk5Wrwb\nX8x7nGqtRrhU4ts//OE2Wvdi8Xq9aLVDyHIdjWbjP/VsdomTJztfoGUNtoudG8DbJbxKD2B2dpax\nkY9oDSicOuHGZHrwiJlO55md+5izE2beeOt7pNMZLlyYIxg8ila7sdoRoijidvcyNnYLs/k6x4+/\nAcCVa7eIVr0EOzcu3vfQaLW07H2LL+98TrN/mebm5k2PsVneOnmS34TDGNNp3I89hm/E+5ZlmfHl\nZfrOnNkVoZN72Gw2enuD3LmzgN/fseYx9bpMNpslXyxQqBSpVspUSkPU6y1kMhnsTylD8Kp5nb3v\njdJoarxLmZ2dZWriVxx/04vJtP6CYzye5avrBaZnrfj9b6PXb37bsaIohMOX+cM/PE25XObfPxkl\neODME2GVzZDPppBXvuK//O43X8pCYCqV4tOf/xx3vU6zx7PhvytVKkxGo3QeO8aRN954gRa+GPL5\nPP/2b2fRavdhsz1Yz6hUKsyHF1lMxhCterRmPaJWQ2rlDgdPNuF2OanEs7g1Jg51dtPa2voKZ7E5\nZHn1plQoFFAUBUmSsNls64YVdyob0c6GgG+RFxWHy2azTE1MMDcyQrVUQhAETDYbew4dwuP1cuXS\nv3H6pPOp4n2Pq9cm+G8/lXnvvT/ddNxZkmrUahLR6CwHDwqk8hWiSgcuz9Y958WJa3zwpptQKLTl\nsTZCPp/n0vnz5GZnCTqd2C2WdWPgtXqdSCJBEjjyzjvs2bv72qLduzYTiQQ///kXyHIQtztIPB5n\nZGkGyWfH6W1CI2kp5tLkUhP0nwqwt3///THS8QTR0VlaNXaO9R/dUXVHHv/txeNxRkZnGR2PoShm\nEK2ACGoV1CwWk8xAfxudne0YjRvb2PQqaQj4S2C7BbxcLnP588+JTU3RJIr4XS50koSqqhTKZaKZ\nDHeiy+wfqPCd7xxHEJ7tBf+v/xjixi07XXu+jcu1uWyMewJeq1UJhz9DsDloPfjdbVmAzKYTWEt3\n+NEHZ7Y81kZRVZWZmRmGr12jnEhgN5nQyTKSVouiqpQrFYqKQkkU6ejro+fgwSf2NewWHr42c7kc\n168P8eEn11gqavB27UFvNFCvVZHrKzi9Ir1vdeFrDT4xjqqqhKfnkKfjfOfYO9i20Ix4O7k3v0ql\nwldf3ebWcA6DqROXO7hmzL9UypNKzKHTLPHO6b10dq4dVtopvJRFzK872ynexWKRT3/+c6y5HEcD\ngSdE0mY2YzEaWY6PYCnmGb51iwMHD96tWb02uVyRaFShs93NSnR+0wL+YIOHjmxWg6CXniretXqN\nWrWGqqrodLqn1mq22l1ElgrU6/WXlk8tCAKdnZ10dnaSSCRIpVIkolEqpdJq5UG3G1dTEx6P5/7i\n727l4WvTarXi8TsIvdNMr89NMVtBUQsYTTp8bYewu9eP7QuCQLArRMxo4MPLn/GD09/eEfFng2G1\nndovfnmJXLmVYNuT2VIPYzRaMLb0Ui6H+M3HNzjUk+Dkyaf/zU6nIeA7BFmWOf/b3+IsFgn6fOse\nV65WMRhq7GtpZmEpzKRez77uA+seX6nUEUU9NruZ2fmtlfEslusYNE8+QheLRaKRMNlUmHq1iF4L\nCFCtqQhaIzanH5+/5QlPVhAEVI2FXC6H8znytLeK2+3G7XazZ8/mF2N3G6lUiqtzoxz4xhtIz3lj\n8gT8LOSLfHXrOqffOrnNFm6eUqnEz395iZraQ3PgySeH9TAYzATbTnBz+BoazQ1OnDjyAq18seze\nW88OYbtqhSwuLiJHIgSfUd+hLsvc28wYdLuIz8w+tfCQLMuABlEUUJS1y6U+jXtbrQFqdQWBB95+\nrVZjYmyY8dufoa9Nsr9F5OgBF317XfTtcXHkgJueNgmzOs/UnfOMDt+kUn2sfZlGR22Dedgvgt1c\n6+VZPDy3y7ev4+oLPbd43yO4J8RMKU4kEtmqeVvm8pVbFCoduNwbF+97iKJIS9tRrt/KsbS09AKs\nezk0BHyHMDo4SPMGYouSVkutthoXEwURiygQWV6/+qNWu9oSrF6X0WwwfXA9REG9/7iZy+UYunER\nozLPoX1OAj4XBv2T4qDXS/g9Dg7td2PTRBkevEA6/aCvpIDy0nb9fR1ZzSAKM5+PYXM5trxnQxRF\nnHtaGJ2d3CYLn4+lpSVm52V8/uevBy6KIm7vAJ+eu3PX0dl9NEIoW2Q7YoHpdJpCJML+4LM9CaNe\njyrbSOdKOKxG3FYb8zOzhDo61lzQNJsNQJFEPIvdEdq0bfdi4AAmg4xWqJEv5JkcvkxnQIPdurG8\naAGBgM+BzVJiYuwSnd0nsNvtqNX8K10k3Amx3BdBKpViYnaSqcgMc5ElUqY68c/zCLJAS7CNYCiE\n2fp8n3tTs4+JocuvdCfk4I1pNPr9W775m812FhMuFhcXaW9v3ybrXh4NAd8BFAoFTJu4EIPuTuaX\nbuDoNiJptajVKvVafc3HY4NBx769Zn712ziHj5x6bhuLxTxer566VGVq9AYhv4jduvm8WovZyJ4W\nmBwfZO+BIxglZVekdO0WkskkV4aukapncISa2N93iNKYlmDIjdFiplqukJiPMn/5M5wmFwcOHcJk\n2dz3KIoiWoeZTCbzSgQ8n8+zGK4QaNt4Pv/TsNrauTM8visFvBFC2SLbEUNVFIXN+BHNTR5WVgzE\nUwVgdTFQeUq6kckooigy1ufwuO7FwFOpRU6fHiAXHUenrOC0P7/XbDUbabKUGR68SN/ewHOPsx28\nTjHw5eVlfnv1U/T7rPR98zAtgSCSJJEr5dHfvUnqDHqa97Wx71v9iEGJy198TiaZ2vS5tDYj2eyT\nnYleBul0GkQXOqny7IM3gMXqZDmS3ZXpzg0B3wFIkkR9M8drtfSG3uDGUJ1YMo+sqndj3U8yORkl\nV2rhjTf3k0qt3Yz3WZRKebTaBK2tLTilOEZh6z9cX5OFzPwXBAPPX5+kwQPi8Tjnbl8gdHwPTf4H\nnqmiqKiAqHn0py4IAk3tzXgOt3D96mUK2c31qBQlLdX6q1l8TqdziJrty0XXaLTUZT2FQmHbxnxZ\nNAR8i2zHI6TL5aKo0VDdRDaGw2qlL3SCi1/VGJtXiUQyVKs1ZFmmXK4yPR3l088WicRbOHX6h3zw\nwSnq9Sny+fSzB3+IQkEmFrvF++8fJplMcni/HY8UIZvZ3DiPE1ua5e1ukUx6897fdvI6xMDr9Tqf\nXf+c1jc6sdisD94wiAgCoKrrepd2jxNXr49b165u6pyKLKN9yv6DF0mtJiOIGmr1bfzuBO2uXMhs\nxMB3ADqdjlBfH9E7d2jdRMU8u8VCoLmH5rfeYiGSYWhkEVmuodUa8Pj6OPLG/vv51QaDgR/+8AS/\n+MWXVKuduFzPrsldKGRJpe7w/vs9tLW1MXj1C5qbjHQE7fzb+dtIuqMYjZvfWh2PLdOkWeTEQIiF\n2ALs7970GI8jyzJLS0vMzUWoVGpIkoaWFg9tbW1P3Uy001BVlWw2S7W62onmXh2Pp202WVpaQnVJ\n2F1P1ssWBAGzwUSlVMZgWnutwRX0kpyKkoolcHo21oRZzpWxNL+axWdJ0qAqm3lm3QBq/aU2G9ku\nGgK+RbZrJX5vdzcf37iBr1ZDt0HByeTzyDYbhw8fXvPiK5fLLC0tUbvbLsxisfDjH7/D2bNXWFiY\nQ69vxu0OPLLtWFVVUqkoxWIYm63G97/fT1vbakeXTDJCV5cZm9XE996q8qsr17A2H8K2wYp1qqoS\nXZ7HVpvigzNdaDQidxa2lk+sqirDw2NcvTpBsWjGYPCg1dqR5TojI0tI0hCHD4fo7+9b9zPaCV54\nuVxmdm6e69Nz5DQ60OlBEKBawVwrc7ijjc7Qag0PVVWJRqNEl+dJJ5e4dO1z9EEz2dgkZpcXmzeA\nr8WPJGvAIOIwW0gXCusKOIA95GFhdmbDAl5LF3AceDUNFhwOK6qygqQtb4sXLst1tJrKrit2BQ0B\n3zE4HA56Tp/mztmz9AYCzxTxbKHARCbDmR//+AlhSiQSTIyMsDg8jElV0agqqiBQVBRMfj8Dhw9z\n8qSJiYlZhocvoSh6BEGDqipAhVDIycGDffj9/vueIECtWkInrf5g2lo8/L5BxydXrrOYCtLka8Xw\nlGySTDpFJjrFAX+Zk4f3YjDoUFWVWvX5u5+rqsrFi1e4eTOLz3cEl+vx8zdTq1W5fHmcePwC3/rW\nqR3pZQ2PjnFhYgbFG8TZf5yA1frI+6V8nguLc1z8+DwdZh1CJYpRmyLolWjyC9TfkAgdClIp18hl\nF1lZmOL6bS2BziMEDnTgc3lYXp7C6Vl/k5gr6GFy5DblUump3yNAKpbALZlfmeA5HA5UeXTbFh1z\nuSQBv21X7kdoCPgW2U7vrae3F1VRuP355wSMRnwu1xOPztVajeVEgrgo8vbv/A7ex0IuoyMj3D53\njma9nn6vF+1jgpXKZrn9q19hCoU4/d57vPnmAKVSiXp99RFSr9c/ktb38PwE8dHiOp4mO7//bTNj\nU8sMTnxJQrWDzoneaEYQROr1GvVyHspxAo463zjmpiXwoCypoigIwvML6u3bw9y6laOl5fC6IQZJ\n0tHS0sfU1BBm8zXefvutR95/1d73tZu3uLSSpfnkN9fdJWm0WNDt7WYqE+OLmz/nu4fcvHV4taNR\nLBbD5DCi0YiYzHpMZj2+ZthXqTE+foXrn0xx4PhJ9FUo5vOY1sm512g06OwGSvniMwU8Pr3I6dD6\n5RteNBaLhbYWA7F4Fqdz6ymohdw87xzfPeVyH6Yh4DuM3oMH8fh8jA8NcX1iApuqIt1NE6wCBUmi\nc2CAI93dWB/z1CbGxxn+9FMONjejX8eDd9psOG02phcXOf/RR3zjO9/ZcNF+s9VNvhDDaHxQwlaS\ntPR1t9KzTyGeyJLOZohnYsiyglGvoclhwOnwY7c96a3lC2XM1uergVKr1fjqq0n8/rc2VIwoEOjh\n9u0vGBgo7JhH5ZGxcS6tZAm+eeKpTwbVWpWJLz/Gq5nk+I/fJj47xezCAh1tbdTrdUStiKqqFIsl\nMukYlUoBVVGwWXVImhK3z35Ia/9bjM+EMfbuQVjn8xK1AnL96bHllaVlXGXNK68P3n+og5/9YhyH\nw7slz7lQyGAxJAkGD2+jdS+PhoBvkRcRQ/V6vXi/+U0Kx44RjUapVCpoNBoMBgPNzc1rLsrl83lu\nnD3LQb9/XfF+mM7mZkbm5hgbHaW3r2/d4x6en90VIJWdw9P0pOCLoojX48DrcbBvg/NMpfPYXc/X\nVm1hYYFq1YEkPbse+j37BMHL5OQM/f0P5rtd31+pVCISiRCJpInF89TrCkajhN9nw+t14vf7HxHp\nSqXChfFpmk+8u654FwoFVpbDjH32Ic3CMKa9HmbvpNDbnNycWyLg8yGIIolYhunZeXKZHHqdFotJ\ni8OlwaD1orfGSScXGblUpuXwEaKzi/g71+5SryrquuIOkM9kydyZ44fHvvnKK/gFg0H6DiwxMTuF\nz/98xchkWSaxMsjv/qB3R4bWNkJDwHcwZrOZzs6N9SacnpzEBeg3Uawo5PUyNjjIgZ6eDf0gmwMt\nDH4us2+b2iUuxmrsPRJ6rr+dnAxjNq9ftXEtHA4/4+Njjwj4Vsnn81y/PsLoeBKFZnSGJoyGEKKo\noZStshjJIteWMOqHOHqknQMH9qLRaJidm0f2BJD0a9+AFhfmiY3ewVzKEZJnOHm0jcXlJLOxJLn6\nLOlkmrk7C+h0fq6OLBNob8Ns3oNGoyGiKMj1EhaLikqF7h4tqdRNErM+HG3NRKbm8YZansgNl8t1\nJN3aN/9MIknk2jjvHzqxY9qs9R/aRzj8FcmEcdMFrRRFYWn+Gkf77QQ3UMJip9IQ8C3yMmKo+Xye\n8ekJJsIzVGoVrEYL3a176OroQqfTIcsykzducMC9sQyCexj1erSxGOFwmJaWljWPeXh+TqcTrbmF\nyEoKv3dr5V+TqRwV3E/E8DdKuVzdsPd9D0nSUyg8mmv/+PenKAqRSIRCoUClVkHSSPeffB6vDz41\nNcPZ8+MI4l68gSNrenE2exPQSaVc5MKlMcbGP+Ob7x5mcHoO58G3njgeILy4SHr4NiG9hrHhYZpN\nKT45u0g7nkLmAAAgAElEQVTKrifQ00bQbKAyneS3X0RwZXK0Bvbg8/rRGXQ8fh8ulzxc+XIZi7XC\n8uJv+c7A/4WpkGV+aAJHezMWx+qGmGI2j6YqYnU8Ks7VSoXwxCzaSIEPDp/Cs4l2dC8ah8PBD75/\nnF/++jLhpSz+5v0bckRKpTyxyA0OHzRy7NjAS7D0xdEQ8B3OysoKn974HHOHi9A3etAb9BRyeYZn\n5hk7P8W3T7y7GgetVDBsUsAB7Fot8ZWVdQX8cXoHTjJ44V9xO61I0vNdPrIsc3M8Tc8bv/fc8UtJ\n0m66PK6iyEjS2o/KpVKJmbkZxueH0dgUTA49ok5AVaCSrHFlpELIt4c9ob04nU6Ghkb57EIUX/Np\n9IZn58LrDSaCrYdJJpb56X8/T6kJ9q1RfbJULjF89kN8+TAr5SSu9B1CNhMxocyhA53ki1EmRitk\nyk6sra1EMlO4KjZmlxOYzAasRh02sxGNdlXIDEYDzcEOslk3ycXLXPzwU37vj/4LTakmJhdnWZqP\noHdbic9EafeEqJTL1Ks18pksxXgGeSVHT7CTg++8vSPz6a1WKz/+3TNcuXKLW8Pn0Bs7cTe1rNmR\np1jMkU7NodOE+f539hMK7b7aJ4/TEPAt8iLziCuVCmcHLxB4qwub84FnZLZa6Dq0j+W5JT6/+gVv\n9h1BfE4h1Gq1VJ9SD+Tx+bndbpo7j3P9zhe8eSi46VioqqrcHAlj9x/eUkf6YNDN/Hwcm23jXeIz\nmTjd3e77dpRKJYrFIvFEnJtT13C1m9lzMoDZ8qQg12o1IgsrfHJ9AmPVwcysiUDr20jS5upru9zN\nlEqHGBr8Fe3vlO7XKAEoZDJc/9W/0hIf5HCnH6VmROuxIkoiHpsZq0VHMlEn6GrBrSokU2mqzSrl\nch6zxoHZY6FUqlJIZPC5bNisFkrl1TRNm81GZ+dbfPnhHU68G8Hf4udN5wC5XJ6VlRXCN6PoOj3E\n4yPotDqa7S587r0EDgZ2pHDDg2tTp9Nx6tQbHDiQYHR0luHRYRT10Z6YqpLBZoXTx9ro7DzzyrOP\ntostC/if/dmf8ctf/hKv18vt27e3w6YGd5mdn0NqNj8i3g/T3B5keGaQbDb71GJWT0OWZUybvJh7\n+vq5Xipy+eYghw/4MRg2JmK1Wp2bI8vUDd28dfTY85h7n66uEF988QmKsmfDN5FKJUx7+yGGR0e5\nMTdLQRQpFwsMLwzR1mrHrKwfkpEkidbOIC6vg//n7z/Bbf6Atuesr261uamrXYx+dZP+M8cBSEUj\nRL78JaHaNAcPtKKXJFaWE9gMImUZ5JpMNFpEll3URTCaDbhlIzqXhtzQOAW9hGjU4vDbqWhFVpJZ\nbI+lDDqdFvRSBxd/e4cf/bEbSZIwm01Uonn+92/+Ln0Heu8fqygKy8vLXPhykGy+sppVZJDoaG0i\nFGrbkQLodrt5+203J04o5HI58vn8I13pd1JD5u1iywL+k5/8hL/4i7/gj//4j7fDnl3Hi7yQ51cW\ncXU/PeZoCTrJ5rMoOh2VanVTi5gA6VqN0FPimmvNTxAEjrx5gvExB+evX2Bfq4bWgHvdlXxFUVha\nTjA6VyXQdZIDvYe2nMVgNpvp7vYwMTGNfwNZCLHYIqoQ4ze3b6EGmnEdexO1VmN2/iaH3/9d1LrM\nnYVlbl28Q6/PRt+hvWvaOD0Wpqn1OJVCienZabo6Nt9QQKvVYrUGWJpKEuqJIQgikS/+kzc6bSxP\n6ZE0GkrlMol4DI05i04nsTSeRNvZjdkGgl5EFATqtRqs5Dm2x81KLcbigoCAgN1nJVeskUhlMJke\nXA+SToNeqyOX9jN1Z4Y9fZ1MXhslpA/cF29FURgZGWfwzjy5qg2jow2D0YwgCJRqVeZuLiN+9Rk9\nnW4G+rt3ZC13URSx2+07ZrH1RbJlAT99+jSzs7PbYEqDx5EVGcMz0ps0Wg2qAJ39/SxdvUrnJsIS\npUqFutlMILD5kq6CILC/uwd/c5Dh29e48MsvsRuKWPQyZrMRSdJjMFoo17TEMgJ2z16OnhnA5dp4\nyONZnDhxhETiHNHoND7f+qkxicQSkdgFTAOdtJw6eT/zY+jWZZq7mlZDBJKEd18HSlcbt68PsfLx\nZbr3t6MqKlpJi81hRW/QMXIridvbh6jRMn1rgUApsOl65kajERMKOfzMDk8iFRcYaDVhsZoplkrM\np7PUahqKJS0ahw2TyYinVmByNEehQ4/FbSFVypAanuGIXoPRoKcvaKU4EaOadZKs1NGYtOSK5UcE\nHBVkBRxNHVz65FOqsSy9/v309/UDq2Gizz7/irFlHZ7ASVpMT4qzzdGEXD/AaHSe6V98wQ/ef2Nb\nv9MGm6MRA98iLzIG7rY6WUlmsDrWL51ZTORwetpxuVxMXLlCsFbbUB44wFwsxt6330YQBDKZDJVK\nBUEQMJlM9ze7PG1+6XSa2ekxMqlp9nRaUWSJYqFANF2gUsuQymVpau7l0MBxOjs7t2WrsizLZLNZ\narUagiDw7rtvcvnyLWZmLqHXB3A6/Wi1ErJcJ51eoVwOI2rimPpDdL1zGo129ZLPZDLI2ipNWg/3\nNvPX63USsRRLZSNXBkvc/GIKv78dQSijKnPY3RVSKSuuZh2CIGD1GInGIoTaOjY1B0EQ6PJ7uZkp\nMPrldd4fELE7AiwuhomnVQxaExajhaqxSr2ap6KtYZIcHBR9TI9GyZsyCKUKB0QJm01ClDRoNRp6\ngiZuRCP4/X0kk1nqdYWUmkPSaRAEkVyuRD4PmZkUYsVLf3MvfXf3ACiKwmcXrjKxYqVtz9Nz8zVa\nLb5gJ5mUlf/87VV+/P3j2DbQDnC72Sl1bF4lL0XA//qv/xrt3R/OyZMnOXPmwSLCvYL6u/V1pVJ5\nYePvae9i/tYFFJ8f0XxXlMt3exoaRIr5AlJGxd3txmKxcPCdd5i8dIk9Hg/6uzFx5a6Yi3dL1d57\nPTs/T8ZkwpqL8dtP/gcaXQmdQUQjGCmXZMolmaB/P35vCy6X6xH7VFVlemqcyPyXtAWtvP2GH6t5\n9Xzl6ur4Bl2NRDLL0FCUyx//N85VTBw58Q1aQh1YrdZNfR71ep14PM6tWzNksxVU1UixKAIqRmMV\nvV5l714TipIinV6mWKxTrSqEQk3s39/H1fExKgd7kRWFUiSKrMjcnptCdNURizWMSMTrRW5fXcJa\nd+MydaI5vpfCF1/Q1tqJRqOlUFEZH7pKJqnDbFjE096My2MnNx9Go/Eiy6s3PEm7av+9IkvrvfZ5\nPQjzCzjlFG2+/SwtRYhE6rR0HIbkIigyks6ELHmoa0VQ81iNRno9+9Gb9cQnR3AaJao6EzqjEVWt\n4rAaaa1rEAwSXr8LMSvjtJqoyTL5bJ7cQoHDXW/y1tF+lpf9qGrt/ue9uLjE6KJI1/49CJSpqXft\nFe7av8Zru9NDkf1cvHyLD759atuv/xfxulQqIQjCjrHn4dfnzp3j448/Brivl89CULehIszs7Cw/\n/OEP11zEFARhV3a62Clcu3md8cICHYf3YTA+8DayqQwL1yc5tfdN2tsepEMN37nD8Gef0Www4HO5\nnohLZ/J5xpeWWKLAgTd8dO5z4vU5nziuUqmytJhgcaZMc9MhDvYevp+NMHjtEuX0Nd4YCKyZSphM\n5hj6aoR6LE6bQYNVL7EUTbOUNKJr78Hc2snBE29vKEYZiUT45JMb5HI2rNZWrFb3E558tVommVxC\nlhc4csTP4cN9921dWVnhXy5fQtMaJLu0hFVVERWF6YVJnK0OCqKI4LSxFJGx2nswmh+EDVLDt+lW\nLHj8qymWk6MjRKNB6rKKw52h70iIhYkI+/19OBybz4u/cfMyS0P/N9/6nT5WUhI2WwBQiS+O4BdV\nJFFDevk6TkuN6EozFrODeC5OITmHtVrEqNWSVlQUs5n2Lh/uJjvxVJ7RohubM4hT0eBrWq0YmEjm\nuTWu0HP0x/h8PtLpFZqbZ3nvveOoqsr//NmnKNajWKybrzC4OHaW/+MH/dsWSimXy+Tz+ftVNCVJ\nwuFwPNe6SbFYZH5mhsT8LNloFLlaBVHE2tSEI9hKS2cn7udIv30ZbEQ7GyGUHc6RQ4cxjRu5dX4E\nwS6hNUhUc2WMVS3f6D7xxC6ynt5ePF4vE8PDDI6OYlFVNACCQEFRiNfrlMw53nirmY49zdhs5jVD\nG3q9js6uZtpDMuMjw5w9v8SpE99hfm6aYuoax48G11y0jK6kuPnRFQ5ZJfyhB9XvfE4L3uUkmVIC\nW9bE5f/8d45+70dYrVYW5udZnh+lVi0iiBrM1ibaOrtZWopy6dIyTuchgsH1BVKnM+D3dyHLIQYH\nx5ibO8sHH5xEp9Pxr//fv7Kil9gjaWi9KwL1ep1C1kKzx0mtVufGV9OosoOMZxZdx340d7NLDMEW\nwrdH7wu4qqgggMMVIBVTmB4LYzRI1GrPV5vaYQKj08Dk9Vv4ur8Nqooi1zA7AiyvzODTaRH1PrLZ\nSQRBpFwuUJkbpVmUcbscVFWBJoOFXDHH3PA00sA+bGYDlUicmujG2eKlVK6QSlfIl4xYHAGamlYX\nrDUaLZXKqt2xWIxEXkdr4PnKw0rWEGMTc5w49nwCXiqVKBQKxONxFpZnSZZWsDj1aCQRVVGpVWTU\nkpa9bb10tHdsaM2hWq1y5/p1YkM3aRGh22bB5nUiabUoikKuVCI5cpPbN64iBlrpP3V6Vy56btkD\n/8M//EM+++wzEokEXq+Xv/3bv+UnP/nJgxO85h74y4rDybJMLBajVqthNBpxu5/0RB+nVCoRi8Uo\nl8skEgluTc9wKzpGW68Po1GPUqlgVyr0d7hoa/ei1z+ZwVIta9EZ6szNrjA7IkA5xfunfege2nKd\nz5eo1WSKpQo3Pr3K201GHJa1P5PRyThNwbdQRS3/a2wGf0cTbR6RFq8Vg0FCVVUy2SLnv5rixohA\nd/8f4/FsbJPRPRKJRURxBLdUYOrOEPbTb2N9KEZbq9WYXByjuaOJeqbK6GQJi9VNopAjrjfg2XsI\nrSQh16oUL37Bib63AZibGmN+vgmbsw1FUcmm79DWYaTTeeC5dpSODf4MT/kLCpkVcqKKaqxjsFnR\n6iSqlRqFdBpRNiCvTGAU26inI7TIdURBQDXrMNmciHe74sQzccoeGy5vExduRfAF3qSlvZVCDuwO\nH+FYDU/wDXz+1UYemUwMr3ea998/weWvbnB70YEvENr0HADq9RrJmY/48//zexv+m2w2e7eccYRE\nosT0QoSaUMbq1uBwijT5dbibREw2M4oqrH4XmSJCxUBnczdHDh2lVqut+dtLpVJc/e2vCZZy7Pf7\nnlnnZDGeYLhUZe83vkVH1+azil4UL8UD/+lPf7rVIRqwurGkUCis7qoURcxm8yMXnkajwe9/ehcd\nVVVJp9NUKhVUVUWSJKxWK1+NTRCW9Mw5jQy89x72hxoSF7N5zs8toftkhG8fbsHf/OTjZKFQRBWK\njMx8iSYXxW7bi6IoZNJ14rkKktmIzWVhaW4FZSlCk+xlj+LEbXsy79bnMbC4OE1OlGiWR+gNHqez\n60EGiaIqxONRhGKOo3v8jI78v1Qqv0dLy/4Nf5YORzOXz37MQWEGf4uHymM3OlEQQFFBVUklSugN\nq+LuNlsRCjli08P49vaBIKAqyv2/s9isKPXM6hiigIqLZDTK3qZHi1RFo1EWFmJUKjX0eonWVg8+\nnw/9Y3VP0okFSslrdHS1sSfoRNSopKt56hoVQaOl7rWRXkmwuFwkubxAq17EbPOg0emp1SpU8yVE\nvRZRo8FqMJOIxGiyNxNwNONvO4TH68br0bKwlERjaL0v3gClUhafb7WaZaFYRad//rKsWq1EXRao\n1+vPjN3WajUGB+9w/XoMURNCqz3ESm6cUH8rDpedQr7IcjjOzfNRymIek3uZQLcTUSOi5Gs4yJMq\nXiQWj3LmxLtPjJ/JZPjq5//BgEGDN7ix7KqWJjfuSoUvP/oN8N0dJeLPohFC2SJb8b7vbZYYnZ8i\nko6j6DSIOi2KrKAWK7jNdvYFQ7S3tT9Rh+NhqtUqc/Nz3JybIqcF0WQAASq5AoNXb+Hp7sfqcuH3\nFx8RbwCTzYLp4H6KmQC/vH6D76kqzYHV0Ec+n2dqboJCPYPVrcfuKRLslDB49AxPRdE2ifh7jWg1\noFSK2PIyR7u7SCSLfDYXpjlq4K3OAJqHiiY57GY+vHKHtpCDb/e3MbI0h9IZol6rE4kuE4tOEl6a\npMntRq8vYTHWOXf170gk/jc6O09gtT77MT2ZDBOoVNBip5LLUXus16hGq0UrSGTSOSLJClbbg6cJ\nl9lKKZsin05iNJqRHtqsY7E6UJUhVFVdbVVmcbMwOc67b67eqFZWVrhxYxJFsWA2ezEYtMhyneHh\nFKOjiwwM7LnvqYfDY0STX/FWh5b9B7u4d4+xq25qtcpqmQADdNi99LXv47MPhyiGk6DRodWu/lNk\nmVq1jKLKaNCgrYp4HR4SlTJmkxFV1jC/lCBXdbO/58EmHQBZTuF2B+5eh+o2ZAg921vM5/P8+teX\nSaZ8+Ju/Sblc5tb4Nfx7HFisZpYWooxHCmiafDQd3Us5nyA2+CkTV8/T2WXG4fcQr1ZZMugYWvyK\nSqnC7/zgx/dj47Isc+3Tj+mTwOvYXDjIqNdzIujj83Of4Gpq2jXhlIaAvyLi8Tif3/yKglnA1dFM\nyB1C+1D6n6Io5NIZri0s8NXZOxzfd4jOjidznecX5jl75wY0u3AfPUDT3WJEqqpy5dZt7L//fUql\nMrcvfsLB/R6UVhfiGo+UJrsVjh7mo6tX+T2riVQ6xmJ8Fk+bjWZXK8l4Dq9LwGGT+OzSEG9+0IPD\n/cDDjsey1Isx8kWZZr+bgN/G+Hici5OLnNrbiiiuCkShVANNgk6XG4NOhy6dJxaLEV4aw+koEmxR\nUBQ3NttqPntTk4woVvl06L/zZfILDIZj9O57A6fTv+6iVnzmFntNVnSig9LKLQrRFRyPLbC5HU0s\nJuYQhCdznV0GI/PRRVSzgxbzg9i73mDC49WRzkWx2PzUKjIa1YxOpyORSHD16hQ2Wzs63QNPW6uV\n0OuNVKsVrl6d4tgxDbVahmTpC7whM1abhYe1UxAEdLpHnQKdDoJtLiLZMuF4Eq/DhtloQtRo0GtW\ns19kpY6mbkKj0VCsqRgrCjOLCQy2EN29+9FqH3zntVoFnS6Bz7daA9tk1FHLrl9O4VnIsowgyE/d\ncl8qlfj5z7+kUj1AINCCqqqMTg3R1G7BYjUzPxtmIqXg2NuNRtKSTy6Tv/YhXUYr+tDbFGITGDwq\nvW0tpFMZ5ioqvxi7jdvp4czpdwCYGBnBmYgRaHu+6oJGvZ4eo46bFz7nzPd/8FxjvGwaXem3yL00\noM0wPDbKL298juFgC3uP9+P2ex8Rb7i7m8zlpKP/AIFTB7m4PMpnly8+0jl7cnqKjyZu4z11hPb+\nPiwPVZLLZDIkEHG1BDH6/TR/a4CUQcvwldso63TfNtks1ANtnLtwhUhhjlBfMzazH0GASrmGTlK4\nM5PG2qpQrxWIR2Mk42kqpdV65W63BUWqEEtEUVHYv7+JnFNhZCl+/xxz0SRdfi2KstqqTa3XmJy4\nRmuwRlubi2ymiE6y3Z1DgrnoHLJNwtRkJHS8nZxhlI/HrvL5zbOkUtEn5pDPpyG+hMNsx2S0oJOt\n1Ofmn/DCbTYHlXwd+xoLYkadAW0uQ2FiHK/nUTFo7WilWppAUWTymRIOqwtZlhkZmcFsDjwi3g+j\n0+kxmwPcGLxNJHme9m4ndq+RurwxH6q1w41os2JwWIhnZVZSZXK5EuVShVq1RiKfRTE4CK+kmVmu\nE0076Op5g737eh4Rb4BYbJr+/gc1TtpbvVRy4Q3ZsRbJeJh9oafvGL5wYZBCsRO3e3U9I5PJUNeU\ncbjsxKIJJpJ1nF1daCQtilwnc/tzWi0OjEYLokaD2bWX8GiWci6P0+WgXa8n0Bzgf375BclkElmW\nmbtxjf3e9dvGbYSWJjdKeIFkMrmlcV4WDQF/yYyMj3ElMk7XmSO4NnixGc0m9p4YYNlQ4fMrX9wv\neXpueoTWk0cxrrGdeT4SRbq7Rb5UKWIwa/Ed7iZl0jF5a2zdcylmicGlKC1d/vuV+xRFJbGSYmJo\nFlWXx+MuIdZXMGmSaOVlEuEpVsJhiqUKZqsZ0aAST8ZAgM49LsYyKWR5NZa8GF+h3WtEuRtbDiej\nBPw1XG4rqqqQy5XQ6UwkUzFWqmUkbwizy09H0Ey9qvDGyb2YrGnk0CEuzd4hHJ5gYvI2Fy+d5+z5\nT/jNh//B/PwSE5EFStUSktZBOwIrc/OPzFOr1eIwO6gUi2t+Dtp0EkMqg/Gx3Yg2h5v2kJHIwk3E\nqhaTSU8+nyebVTAan97px2g0sxyZxeZRqFfDHH+7l1hh9XOo1+vEV+JMj88zPjLL1Ngcy+EIlfLq\nPgOHy4E/ZCWpAVVfR9J7UDR+clULC+kKi7KTCm1k6y7aDnxAX/9b2O1Pbq4pFDIYjYv09XXf/7/m\n5masuiylYv6p9q9HOTNLT3do3ffn5uYYn1Dxeh88QS6vLGH3mVFVlamFJNbW9vtPhvnEMtZqGb3u\nwc1V1GjQGUMsjoRRVRWny4m+UKLa7OP8pSusrKzgqJQwGTZXYngt2vUSC1NTWx7nZdAQ8C2ymRh4\nMpnkytwwXccPrdv/cD0EQSB0qJsFMc/Y5ASXR4fwHO5Bt8b5ZVlmPh5H0mipV6tUqyV0d/O1Pf37\nCKeyFLNP/lhLpRLZahrznk5S8dX3FW2O6dFxyskJcqUiPQMuHE4DRpMWu92I22Wmvc1Ci18llU+R\niMYxmg3IQoV8Po/RIKFzS4STOVRVpS7X0EsCokZDvlSioGZpabl7oymVqZRlMtkYkVwSyeJEEFYv\nUZNBg1wtozcaCPqrZKKzrJRU/sdvPmIqbEDRH0XvOIPG+Cai8S1GUz4+Hl1iKBLHJAs0hZdZWVh4\nZL4tLW0kkmly2UdFPJdKop+YJmhb+wbr8jQjlmfRksDpNN7dHPLsQklyvUqdRerqMj37HXT37CWj\nSIwMjXPr6gSzk0VyWTOVsoNC3kp4XuH29VkmR2eplMrsOdCCudlC3uVmuhRjRa2Q1OkRW4/Rsuc7\nuFweiqKN1o57W+MfvTYqlRLJ5FXee+/gIwuqoihyuLeNRGTzopVNx2myVJ9aJ/zq1WmczgP34+yV\naoVkfgWny0YmlaWkNaIzPRDrSjKMdY1a7zqTlXLOSDG9upAsF3K4Ag4uToyzvLiIW7M9cuayWkgv\nLTz7wB1AIwb+nNTr9fvtzgB0Oh1er3fdxUZVVbl48ys8BzvRrdOF5VkIgkB7fzfnfvE5WO0ccLso\nF4vkkinqtTqCIKDIMnMzS9y+OYU5AlRLiMYKHScCgBFRFNG3+4nOhek4+Gjzs0gsjN3z/7P3XkFy\nnWl65nNceu9dmSyHqoIhCAIgCdpmd5OtmememB7tarSSNlYzdxuKvdiIvdONInQze7chxV7sjbQb\nq5UUMdpQj9RGI/bQNUkQlgAKhfImqzKr0ntz8ri9SKCAgqFpjlbdM3zvTlUekyf/857//773ez8X\nnb6HodrCMEy27q3hd9QJTAW4u6TgD9molPpgHr+2gN9B+kSI3n4dsQK+UIBGuYbL5SKSdFPY6pCJ\n+LAsUIcmis3Ban6fzFSQZqtFqdmgrfYomwM0U0X1OhiqJay2jk10oA7kI0WI2zEgd/PnuLL/I/bx\naQTJg90+UlRIkozT5sHn9GJaY1Tr+/xy5QZ/560Y2zt77HW6hMYyuD0enE4nkxNx9vMqLcPEZpfo\nVEs4d/Z4zhej+JjboGEY1MoN2gcqP3z7v+XatZ/itCdQVRdfJQd4eHAbT2iX+bmTTGbH6bR7dA0f\nl28d8PKZU0+0M7M73ECITrvD8u09ZheSLJ5Nsna3SsXI4I2cxWZ3ISDQ7TawZA3DvYjP96SSqNNp\nUK9f5+23p57qfTM3N83GzscU85vE01+swjBNk16vR61apr73Ce+8PkexWMTv9z+h0a7VapRKApmx\nhzmIfq+P3S0jihL7h3WUcOrxEzwzqSrbo1Tzh7iDAQTA7XVT8PpZXb7LW86/Gjmv1+mkvf9keO43\nEd8S+NfEqDvONrdyBQbeIB63i64pwLCOdHOJU6k481OTBIPHC09KpRINRWcu8et1oHkAu8NBVRii\naR3U9z9jb/UQ8GAhow9VNtZX0UJj6OlZItMvINkUCks3Wf/gLs//8AKSLOMfT7D//nXG5rNHsfd+\nf8DA6BH0RngwN89v5/DLImPjflpNFet+RxtDtxCdT8524mkPO4dtvPTotmQUp0Kv10NRJDrmyGdF\nlmWKNZWJSRdr1XXSaSd7WgdXKkxAiNKUqmiqiScQP9LB6v0uxeU8NdWJp2CjVe/jDSWQnCFE2UW5\nvEcwOLqvomzHuN/oQRRE3M4gHs8LfLha5K0FPzOawa3rN9nzeJCiYYJOmc1ugfJWg35ul5gkEovG\nqKhNDEHEMAyGQ416uUm3ohL2Rjk7fwpRtDh7NsFLL03zs19cpVYxcTgu4nD4j7TZALqu0uvV0AY5\nLOs6p06HmZnJMhio/Oef3SGZvsjN3GeUG01ioacVKwk4XV50zcb68gHzpzMsnolxo7tBs+UjFJxF\nlh30BmXaTg/zM68e7akoA7pdqFS2cLny/MEfnHmmB7uiKLz91ov84t3LFHZU4pm5I9+YB+h0OhTz\neSq7uwxbVcTGEq9Pe+FGh7UbN2hZFs54nOnnnyeTySDLMvV6HVE8Pjs3DANRHhF0rT3AO3Y81CN5\nQ/TyGzzN59Dm9NCpjNxrbG4vis+L7O9zuL+HmPxmXaIeQBRFMI0jtdFvMr4l8K+B/f19fvH5MlZq\nktCLbxBxOFCGAwL3VQO6pnE3v8+tT67z5uwE83OzR/uu723jn/h6PRyfBm04ZGV5i2rTzqmFGMH4\ncyDrHQUAACAASURBVEexw8PcFsrYBfzxKVY31+l37xA9kSAws0B1pURj95DwdAbZbgOPi36rizc8\nklu12k1cfttoJtkfPSCdWoGJuQmggSgKBMIeylUdyQB75MmhY7eDI2ljfaVMQG/hD4XpGxpudwyJ\n0YPgtXnZa+hsbeboBL34p5L4gqNH1TRMTFMD0XZE3pqmYQgShaEPZSrCxuYdgu7z2GwSuqkjKw5U\n42GC0u7y0TFNHjzKpqHh93nx+lN8uHKFP3gxzR8mk5QbDbZyefb1IcLuHfzhCU688xaablDqNCmU\nCzRX77Kda5IMjjM1fpLFk3HsdhuGoZPPX+btt08wOztDNjvBP/tn/5Jq/SbNmo5lOrAQwNKx2Q2i\nIQ9jmRT5wwmCoR2CgSB3bm3RbHhIppLMnH6Ozz+/xXm5TcjnPfoulmliYSIKIrJiRzGi5LYOWDgz\nw/SJBJ0SdLorFEt91mttFl/5Y4bDPoNBh8GgjcPRxDBqXLiQ4uTJN5/QoT8Op9PJ777zClev3+Hu\nxi8xbSkCkXFkxc7+7i6llXvY+k38VBnzGbx0dpHwYyZW1VaLvZ/9jNVIhHPf+Q7FYgvF9lgoSgCs\n0UzeMHli5eGNjVFevULENI69DAFEScYwZNr1Bpo/SCgaRpbrGKKEZvx6FbGPQzcMRJvtN5684VsC\n/8rI5/P8+a0VIi9cOpY01B6RfMmKQnwyi5ZM8csbn2FZFgsnRmGKg3qZ2MmTTxz360AbDvnk559S\nLznxTZ/A7Q8ekwSWqzUc6fPIio1oNEFbtlFereLr9sGbpLyzTXh6pAIQbArGIyXgvUEXZ8SGNhhi\na1dBcBAOguJsAOBwyrgcCoVDjURAeqI1Wb8/oNeokfBLOOfDbCzVaZd72LUWpqEyTZxio829wwG3\nqhrf+bsnSDlMBLF1dAxRErHbJFpdHXUwYKj1USSLVr2P4fZhVzSEzByN6j7tlgtXSAaso25ElgVu\nd4C6bEMzNBRJwULF6QxhtzmQHNOs5XOcn5lgq1ZhzWHhnpjgh6+eYXunQKdjJ+oJE7dSWOPjXFh4\nlW61TC+3T29YRFHSqGqfYvE6ly5FmZ0d+ZA7nU5+9KO3+OUv10gmT6HrQyzLQpIk7PcLZAzD4O5K\nnpemkpiWyd1bRcKRUSJxYnKMdrvPje0dZnsVol4bvX4PXTMAAUGwcLqcuJxuOp1RwZdljcJ2RjvP\nRu0u4wsnsYb/nlLBhdsbZXp2jvn5ORKJc1/ZGAlGx3zl5Rd44fkBOzs5rt3+hKufXsPebjMZDjKV\ncjGbShDyep+6f9jnI+zzUWk2ufpnf0bZGUWWj8/6ZUnG0J4dJlHsLuzTz5Nfu0o6lHiCxHXdYrvW\nYPy1lzF0A1mScQeDNPtNvr4x8pNodrv4419cNPebgm8J/Cug1+vx85tLhM9deqri43EodjvJcy/y\nwZVfEYuE8Xq99AwNx9f0jX4UlmVx4/1r1A4VfOEUlt2Gqg6PxdMNwzzy8fC73bSbbVyhDK39PQR/\nj75/+PCApnls5jMY9vDbg1Q385wZc9CqHHBi+mFiTpZFJtJelvbqyKZMVjdR5IcFFN1GHY+iIIgi\nkYiM96UIyxtDWmWFlV8VGEz7WdYcaCfeJOIU6MsqPrdBp1nG6394nkDQTa6Yxy4reJw21IHOZt4i\nspih1+3jC4ep63DQLDKp9xkOBjh1i/XtHO2eiiUIDFUFW6tIOhhFktSjTiwhX5ylvRWaxj3KcR8T\n84tHWvKZmXH29w6pVHeo98E+fgrFbieQyuBLpNi+eYXC5X/FyekYb7+9cETeDzA/f4Jut8enn36O\nLIcIBKLI8khtU68X6fUKnDmdJhLxcpCvoA5chCOjfImiyCyenOGOYfHJ3XUC5iHZiJtwIIB0//pG\nfiFVJBF2NnJUi3nanWUEn5P/+X/5MfNzkwB0uwMazS750irLnxfg7Jtfud/po3A4HExOjpO7c4s/\nPpNhPPL15HkRv5+LLhf/4sNrGIlJgsGHhOjxeND6ApqmY5MljKGGZDuebwhNnqSGxebGTQIIuOxO\nLMukM+xz0O/w8ne+S3gsRfGgjMfuIxERKO01WPja3/RJlNodQvPP/RUc6b88viXwr4CtnV2M+Biu\np8w6lOHg2Cz86O92O7aJGZY3tzl/+iTiM5rpflXUShX2N9rExk5zUL5LX9OfaKMW8HmoNCvI0Qx2\nhwNHs8VwMMDmS1FefpfgeR3TNBFFEaM3QLE/fGgM00TrDRD3d8lcipJf28Hp9GOoQSR7fXR8v4P6\nJwYLP5hgdb3E7JQTu12iP+hj4/hS2O6QCfoMRNXOS7NZdJud9Ml3yFkCF9+4wM6Nq2jlu3iHBvG0\nhSiNZmOiKGKng2h5abcsljYGOGYWkWxA34coinRbBtrUBfb3foXR9BB0xvF4IriDo2Rivxtj/e57\ntLdWOXcyiK5rIIjIksR2XaeVlTi/OApvKYKMZumIksT4ZJpgpMP1wiGSq0WtdgsQsSydsed8KFND\nFkPxJ8gbRtWwisOGFdZYKa1SXrqGrA4Yc7l45aUzPP/8iwyHQ9YPPsAUdGy242Np5LonEU7N0O3o\n3G40cNaqeG0WfjsoEhimRS6fZ2jkmJkOcuHSS/ytt1861hXH43Hi8TjJpKFc11m+/RMO889x7sKl\nr+3md+OTT4g2Gox/iYXDo+ipKrphIAAuu51L2QT/5upNxidO4PU+SDRLJMNpauUSqbCbXL2OP348\nNyQIAuHsabTkNO3iDu1WBQQRJZggbEVIzc/g0AxapT5RQ+T8yQU2em1qreNhqK8LwzDYM+DVqWc3\nCPlNwrcE/iUwDIOb23uEz7/65R9+DKFUmnsfr3BmOMTUv14H9cexfXcbm3M0yGPhICvFQ8THsvex\nZJrivQ00bxDF4SYWDLC6vYOqq5h7W+hTce7dWiOVCOPmfvXlfWjdAfWr63zvOT9Op43Hn/Xh0CC/\nM+C5qSy9mk44nWF5/YCg38Qh9fHKT76g2i2V259UmJPnGNhiTPrCOOMeHC4Xc5deY/26i+s/3yJ/\ncIcTcz5sNpFms45lmFy9vMswME305Bm8YR+1YglR8aH2BuSLNqLzz7H13oeE1HEic8fVNA6XD2ns\nFDvL/wFzpUG50kZRFIZah/3gkGh47Kn3WB0O2ev3ufCDtwmHwxj6/ReeJCHL8qhg5/1PWWw0CAQC\nWJaFZVmoqsrPfvUJJX+U5Pd+l0mXC90w6HU6NPZzNOvFIw/0z+9J6HIbUTpOMuVyFd1wMTkZRFWH\ntFsh6vU4jaFBeTjEUHU69SIBV5ygt82P/+A7vHjx0hfGab0eJ69dzHBz6TZXLxtcfPn1rxzX3d3d\npXvvHqfGnn6vHsA0TYr1Oit7NfKVPqpmQxAUwESgjyyp0NG5d+Ma51974+glkoglubm6S3Imws69\nQ6xY9KnXpjhchCYWj7YHnQaKPT+SoTZa2CwHYb1FKpVCuPgiSz/9c17zen7t+PXqYZHI4unfmv6Z\n3xL4l6BWq9Fzegg84wd92uz7ASRZxggnqNfr2JFQBwPsv4Z3Sr/bY2+9QihxBoBQNIJ28y7y4vGf\nz+X1MzeZZnPzU/qeOPW2iqecx9Ys4A1HcFU0HC2F5aXP+M65UTy+3+5S381j3LnLq29FSKSD6LrB\nAw8nyV6n39e5dbVGKjbOzGyc6zd2Ke+2GZsdp99XWV/fxMMAn1dGEi103aJ4MOT9n5dJCnO8+uYP\nWGm3Wa8UmTh/gmajQWF7E7VdYfHiJdY+0xgadVwugXanjy/oJjIBTdnAEgaYpgfLNNGGGqtLPdTQ\n6xjdJjafAw/Hw1KGaXKQz1OvbhM98yqVwga+Xo9sKkWt0UAPxNjcPiATcBGLx9AsHcs0qXc6FDSN\niQsXiNwPFzxeHStJEo7xFL/67DIet0W1cYAgwMpmDn3sHPNnLmK/P05kScLn9+Pzn6a85+fdy1f4\n/e9+h2zmJNfu/RzTeDieTMOkWGzgdo2S3Ha7DXvURijkYzjUMEyTeqVKJtAgk8qS3ynicvq/lKQc\nigaInDud4fKNJTY3kszMzn3hPg+wdvUqc8HgF56j3Gjw4e196h0/TvsUfrcfWXrEDsIy6fTbVNu3\n2bn8CYrPxpkzLyFJEk6nk5A7TrPaIOwQaNUaeMJfriLpt/JMvBpF0zV28g38qo2zkxkkSSKTyZCf\nX2R5c5WTma8fDS81GuSdXt44f/5r7/tfC98S+JdAVVVw/Pqxa9HuRFVVkoEIrVqDaOrrJ0ea1RqW\n5RmFPnQDVVVxqia1QpHE5Pgxs6hgLMHZYJhKYQ85t8ZELIxn6hy94ZCNvc+xJ50MP1nj81IHbW+P\nhM3itWyY4WuzSL5RQYssSyDZ6PWG1EoDtteGTGenyE6N5GDnX5hkc6PExrUyklckHE/QLhRpNhVa\nDZVGvocbhTOTC6Rss8iShOFwIIb97O1s09nbJOOzE0yFRtr22I9Zu3MFj79CZsrJRMaPphvc2SiS\n27lJXnRRKVvsHqbp+y7hMXWE4YBYZpbBvcMjuZdpmuzv7tBp75JdnMYTiDKIpllf+oBuvUTDKhMO\nn0UWNTa3i/QGAxSvhzrgTSaZn5o6WuY/DaqqctA64M7mR/x3P3yB069M0+v2aARqmN4Oa5/9GbHs\nKySnRuEZCxiqKp5IlJ3NNSqVClOTM1y+7qDZrBKJjQi71+9jmvITHjWiJOFwSgzVIdagwmQ2SPHw\nkGgwQrPZf/zynglBEDi7GOej6x+RSme+dHZZqVSgXCb0jNi5ZVnc3trjysoAn/s06cjTjaNEQcTn\n8vNcdp6bW3DjswLq4H2ef/5l7A4Xs1MnuH3vc7x2lUYxh+pwYHc/+1nThwNk+QB/6jl2Vw/waC5m\n6DD/SEjr3KVX+KTd5u5+gcV08ivPxA+qNe5oFhd++HtfaBz3m4ZvCfwb4lkx8AewGMWpZzKTvJe7\n82sReLfTpVZt0FaXMY0BvWaDpG9IY/kK5doOvkgcnzdCwB9EVmRkRcHuC5GOpQh4RzIvn6KQ9vnJ\n7BX5u/PPsSIIxIjidIxaTCmCk/zOPjabnV5XpVaz89PrO5xaOMtLF914vA+/oyAIzMzGmZqOUiq2\nyRfqlA8NnDJMuV1kLiUoHHTZzAWIixE2azUCc7MsHewybbo5lQodi8c63U4Wz11id2uHy599wL3V\nApK9j8Nh4jCG5Dcb7LYiGMEsEZ8Ln99Ho91HEp0Ibjv6sI0g2insrdBq5chMT2F3juLCDpcX39gC\nDrMCYRs1WWIoCkiuALvlJt9ZWOT0zNSXVtTqmsbdlZuE0iaul2bBGt2HcrWKI5UmlEwRG1dZ+uQD\nGs0mPctJrdbF0CVAoHXYpXbz3/DGpXOcO/ka/+f/86+Ixsbx+T0j58EvKIpu1GrEAjAcqDQrdb7z\ngxdQh/UvHTcDTbk/Cwen004mqrO7s8XC4qkv3K9cKhH+Ag/tmxu7XFuTSIVfQBK/nEIy0RC5cp79\nfpJWO8WVq7/i4sXXsNudnDpxhuW1JaJKkcLGPczsLM5nxLBbpSXGzvrIb1Zx9RQW5T7ff+XFY/JI\nRVG49M4PuPHJx3y0cpdT4eAXxsT7qspKsUw9FOPF3/neb40L4QN8S+BfArvdDoOvPtt5AoM+9lCA\nZDKJ697nNKs1/OGv1rnEMAxyuW021j8DYUAqNYUkuijeqXDh5SyiIHBjrUDPLDMcdtnZ3SfgzxAK\nRxAFgUej7t12l8bOPv/w9VOkIxHwennjhz+kUqlQrpSoNQ5YvbJJozYgHI2RTGYxGnYWFsewO5/u\nFyKKIomkn0TSz8JCjL21dZyGjiAYbOY0mhWNeshi7pWXuHbtMuGoyERs/KnHUmwKiYkMG6UkjliP\noFtGFgRiNomFczLL200+3q7i9QVpNBo02k40KYopazTKdzDMLqq2R/ZEAsWep1PfwzIDeMNTIAiY\nlo4vnkBwGsxOnMfvD9Fs1rCQvpIdwkGxgMPXJ5qIkm+0UNURMQ51Hcl+vz+qrmH5NK68/0syp/8e\nXs/E0YtKMf3IfQ+5XIh+P4/PGefyezeZOZnBMIdUKhWGgyF2uwuH04WsPJwFdmqHBMIapX2TyUwc\nuwKDfpdqrYrH7flSffcDBP0KP3nvP7BX7iCKAmGfm+ns+BMNiWv5PMlnKKZypTLXVk3SkTNH8r5q\nu02rO8Buk4g/opw5+m1liTNTIXI3dpHEU/R6JktLVzl37jUUReHUwhny+X2M7hq7168jhMN402k8\nwSCIYOgmB5u3ke3bqLVJYnqTM8kwl86ePZbAPTqfovDiG2+yPz3DrSufIe7uE5ME/E4HNlnBMA3a\n/QFVw6RhczL+4qu8sbj4pY0ffhPxLYF/CcLhMK7+TQbdLg73k2ZFXzT7NnQdoXpI4tw8oijyyunz\n/OLWp7hff+FLtbn9Xp+Vtev4fG1OngnRzlewKTKHW0UmQx7crtF5LyyOsblbopBv4Qr4aDXXaLUq\nJOLjtDQDqVTGqLbwGRYnPT5mUinuFYukL14EIBKJ3I/5LpJOTvN57lecPjfyrdAGXTY21zl56sur\nR10uF1MnF2nUG9y4vMlu28nc1Hm++/t/SKVYRGkekDix+Mz9h5rGRn6T+XkvQZeI33ucQF44aWev\n3kLwDUgl3Fy/vYvo8uESFZxCG39CxBCzuD2j5bxlWfRabYq5WwiqDcEtYVk6NrGN1zvSJXu9Adb2\nd0jPTn6hvYFpmhyWd5mcHxGdIEto2kiS6bAp6KrKwUGRfL6DwznGeLaI1msj+h6+qHW1j8fhJhxO\n0Wgo9IVD1tob7OXsuFIRWlE3Xrcdqd+F8iF+Q8Zn99Btm7SKTQxHFMPI4Qk5uV3OE0t7uFqoQ3eX\ntN9DdiyFx32czB7MvjvdDktrO1T7JoW+hU1Ko9jsbFcbfLZ2hamoi1cvnj0KrfSbTZxPuR+D4ZAP\n7xSJ+F84Iu9cqcrygYFij6ANu8QbBzw3mTqyD36AoMfD4rjCYX2JSPQMh4cVDg62SKWmkUSJ8bEJ\n0ukMtVqN1Y1ldm/eJa/qWJKC2isQj9d46eIiL2czzE9NfqX+m5lMhkwmQ7VapVqpUCgeovUHiIqM\nNxpjLBzmfPzLO/b8JuNbAv8SiKLI89kxPt7bITX/9Qpxqvl9TsYjRzO8eDzO6VKWu1fvMH3xzDMH\nTr/f597qZ2QyBuFQGG2oIUk7FHMlPP0h4wsPlQE2RWZhJsW0plMqN8nXWhQrBVZur+JzRxgUS8z5\n/Ch2AZsscDOXQ89muTA5+cR5JycmWd9a4daVZbInxsnOz3D3apPVlTIn5r/YLhRGM596XUBznuLi\nhRl+77s/RtM0cjc+5kwqzvJQe+a+++US0YhKIhKlUtaQeypu1yO+2qLIc1mRa7sNXB43U9kouZoK\n6hB/xIY/FqLVfFiYJAgCbr+PUKJM7d4B7vAk1fY+E9kYoiiiaUPUQZ9OR6VcLpP+Aq10t9tFsg1x\nOEekYenGQ3OwcITSBx/T8Uzh86URBIFQ0sPu+g4kHjabNg/2CMdnWd26ybbVwHXxOV574yWW7n5E\nKJzENdA5LDexuaKYDoNau4mZOyDc9hBw+am0Nsi+kMQ/ewJ1WCd7Kovdbsc0DQ7rNQ6W1rkw96SF\nQ7vd5vKdDcTwBNFkiFT7AJvdgT8chUgMa2KWvfwO//4/f8zvf+8Sbrf7mY0ZtgpF1GGasHdE9KZp\nsXbYJRQ8eX8shyhXN2j1ugSeMjMO+bykT6TI5TbRdQ9LS0skEtmjVYokSkQjUaKRN7hkmhwe7tBu\n3+X0qdOcO3cav9//a8Wnw+HwqHHxia/e1em3Bd8S+FfAdHaSz375Ib3UGK7HlpvPioEPBwO03Q0W\nXz539Lder4fX4YLrRX569V8Smx/HGwriDobwBgIEg6PZ4/r6bVJJjXDoYTzOLvXp5Q4489Lpp+p5\nbYpMJhUmkxoZGeVyFfIFO/3pLJfLJeqHG8w+56eRDBJX4ObSbeay0/j9fgzDIJ/Ps3P7c7T9XQq7\nq5T9n+KKBvBk51jN9Wi1CkxP+wmFR6sQ0zAxTANBEJBEkXq9z9Z2m2LTj1vO8OaLb2Oz2dhYXWHM\nYeF3+rjTfLpdqW7oNLolzoy7kSSRcCRJtXJIX+3hccko98ky4heQ1D0OD/3MzJ+i3t5jZ2uNs99/\nh95AhcfyVZZloggDAn7odVsIyh4u5wT5nVX61RJ2wCnorF5ucJBMkp6aIpFIPJH4MnQd+REdv9nq\n4kiP7nO/30ct9RFkE8E/2k+2KZiGevT5Rn6TkGawfrhKMxUgNnUJUZIwDJ0TJy6ytfkpPp8bm6zj\ntCVwubxYQZNhYprKxjU6967z9hsvkDmxSKtVJpn0HYVNRFHCF4pQt+C9G7c5Nz2Bx+PBZrMh2gJc\nu7uBEp3GdT8XIorWMYIWBIFYJktZlHj3V1f50dtvoDidDFsPK2RhtAq5td0k5H1oD2FhYVkcq5QU\nRIVnNebREQiFQoyNjVMoHHDtWpF7y39OMDiLrHgQENCNIZbZBKrMzPg4c+alZzod/v/Vj/Y3Gd8S\n+FeA0+nkb507zZ/fvALPv/jUgp5HMRwMOLzxGd+bGy31Op0Od65epb62RsKyeMXh4LQU5NrlFYZx\nL2LYR9flYMfpBK8Ht7dCNBpl0FMp58r0cxW+u5DgVr9zZK/6RcjlK2xUWhxaLeLjz3Py+ROo/QTf\n//t/C0mS0IZD1nP73L72EUFdwFapEVc7LAS8ROcm0bJplteWUNUWYrWEXm+w1/ZQ74kYg01sUoeh\nNkq8aUOTQklHcUUJRTKEHWO8+eL3j5a4e8u3eC0RRgCM/fxRIdGjqDbbBPwm8n01jSzLxOJp+v0B\nnW4DvT0iQ1lx8/r5EO/eOWCozpAKyGxXDwETURSOPMYBtOGAYatCxKFQc3URultENJ388g1iDgdR\njxdREDH6DWTNoLO1y9XVddKL8zx/8eKxa5Rk+X5ZO6h9FbneJv7CLKZhcuv2FrPj58nXCtQGPSRv\niFazS6PpxshtoVcOiLfbYJdpTyQIT0zTbtVo13cxBzWcCox5RGSpSHjSwdLaR3TbAYKRMZLJBOn0\nG6z6ihQHJr7mIbGYk9T9RLiuazSaTUqtGros0Hc50fMbxBNRzP4QoylSGcD42EPVyVAD71M650RT\n4+zf3qVcLhNKpWgdHBwrl2/3+/RUJ4FHVCKSKJIKyOw39vG6IwyGPRxiE4/z6R1xBli4XG5kWWJ8\nPIOivM7UVJFs1kG93sQwLFwuhVAoQTC48IRa5mlj5286viXwr4hUKsUPLYtf3PiUZnKc0NgEdqfz\n2OxbGw6p7e+h72/x/bksc7MzbG1usvr++2Qti7OJh23A0uEw08kke5Uy97bK1E0N0S5ya/ceodkA\ng9UoPkXmRDrM1KUFPB4nsrDJjRs7pNPZp8qjLCzWNg/JaRbRM9N4dYO9XBFLP+SVH507CtkoNhup\nmSl68SjX/sX/xalqlYXzF45iqIqicGbxLPlCntzuJpMhGSOf4/OcA3/2NLoqYVMUBEA3BWQvVPJt\nGjsKjnkf7XaHcDhMt9tFHvZwOUYriym7g1KpSjRxfEY1UAe4vce/jyAIuFxOXK4nk2kX52tsNlbp\n5LrEXR78Zpt+q0W/0QeHD/QhdsEkapMwBjUY3Obk3CU2bq5jCyn4QlFMy6RQLNAY9Bj3nkBx23AO\nhyxdXaLa6vK97755JOtzu90YQxuDvkpt95CFTARJkiiVSgwGTmRZwNJtDGtV2gcFcrtVSrUZ/LU+\nEVuA/VaLXkRgwjVNfvsaHhpMeB14og901iFarT0WF9O89cIU27kCd7d2aDc7DC0ZLRqjLDbxlg8R\nHSna6zs4JIsuGpLXiSsdGfmiJCIM1peI3NdFX//4Ji1XlM7OBuOROH5fgE5fION5stEDgD0yyfL6\nDrOTaTZ0nclH/tfq9cB6cuIyl44z3N2jVM/jsovMJsPITwkNdgcqisd7tJoC8HqD9HpFpp/RRNgw\nDPb391nbXabaKiMIIIs2JpPTTE/OEviafS//OuJbAv8aSKfT/B2/n42dXW5d+ZCKJ4DgdHG/5xhS\no8LpdIL5Vy/i9/tZWV5m/733eCkex/WUpJBNUZhOpphOphhqGlu5HPMBB8rAoFhp8dYfvoLH85DA\nzl/I0h+ssXx3i1Rq8okY+uZOiZ2hhRL1s7ZXpdcfUNxbZ/aVRZbKBeragEw8caQ62HzvQ15OBHCn\nQ9xYv8eLC2eOluaCIJBJZ4hFY1z+7Bq1DRNZbbLXKJGamUPtWww6GqLpIuTOMnViBpfLR6/X4qc/\nvcErr3SIx0P4HhlhJ5NxNjZyhKKhY9duWl9vZhX22BA9EpG9AqqzilrfYiI0jlotQl9DkRUEo4Zd\nbjA56+JAjmGqAxZ8YTYKFfRUika7QW1gkZ48wVDX6A66hMNxsu5Flje3WBnbYnFhFC4QRZFEdIKD\n3ApC7pDsKyMZ3uZmgWJVZ+CoYY9FSU2OMxyotEsFTn3n91EcLgxtyJ21jzBnxtnc+oi5gEImmXqi\nf6Qoeqk3GqSSSU7MZJmdGid3UOWjjTqyHMWeSnO4ss10NEutXKDWL5KejBCOPfT+lhQFQ7YzHKjY\nnXaGpkh8ehJd09gtlHGVasiemWfmXvzhKPm1FV576QVuulz0VfUomTkYDoHRuLGskevgdmGfUi2P\nKA5QFNCGEkv7u9wreJmKTpKJRo8UKZVOh/jZ4/4iNpuTdvvpCq9qtcqvrr+HLWSSWIwwGz6FIAgM\nhxqHe4f88voqaf80F56/+FudhPym+JbAvyY8Hg9nT53k9MI8pVKJXq+HKIrYbEGi0TNHSZZ8Ps/e\n++/zUjKJ7QuavT6ATVFA6zA7GSQY8LBfaXHl3c9544cPB6goirz++gm83h2uX7uHZfkJBqM4nQ6K\nxTqXdyqQSaB1+ohiH2diyIu/ex53/AzRaJxKtUY+t4HXFIjb3TjLhySyo4q1xlBjeWud5xeOtRTD\nJQAAIABJREFUa4S3ynXarQhnFl9iUdf4ZSFPwv4qiuLAmfCgPNY5xeXykUq9wq9+dZmFhTLhR3g5\nGvRzulxhdTPH2Fz26O+ypDDUHusQ8QWwLJP63U3+8PWTjHsHqEqX5PgB8dCAlXsbxGJJojEvwfAc\nuxsHeB1p2ltbZMNxzHqRjeUV2l4XrkCMdCjIen4LRANd03DYncS8QZbWdpiZnjj6PWOROJ//p7/g\n0qSC2+2k2+ly7e4a9tQFfKEQCKCpQzZv5fHHL6E4Rsv/RiWPGnDg6m+TPZHG1DT2K2VS4TD2R/pn\n2mwOWq0aqfvGfaIoMZmO8fl2gdVhBNVScCUT7K6tIUcVYrMnaLUreHs9jKF25CzZa7XRVBWb3YbT\nNgpjyYpCIBPns/98m+jUa8+8r4IgohsmkiSRff55Nj/+mFMPkrv3A9uVZou93R0a5X3iPp2Xk068\nzhGx66ZFb6hT7VVZ3T5ks5Dg5cWzIAi0bQrT0a/mhV+r1fjg+l+QPRcnFDmelLXZFManM2SyKTZv\n7XP52idcuvjqb4X1638JfOOA0i9+8Qvm5+eZnZ3lT//0T/8qrum3ApIkkUwmSafTZLNZ0un00cOu\nqiq3//IvORMMfiXyfoBur4bbPQrJZCI+3Ac17i3tHvuMIAicO5fl7/+D53j1VRdDbYut7dv85C/f\no+7ug7NOeGzA6d/LcP7vvUh8NsNAbSNKEr5wGOdYkoJL5ic//XN6B/vUaqN+lf5YlLLap9vtHp2r\nWquS2x0QDk8jCiI2xU7WaWeo9vH5wk+Q9wPIskIqdZErVw7odI9ryJ/PjuPLVzjcOzj6W8DrpVZ/\nRubrMRiGyf7tXeY9EoYBJ0+9wrnF76P1BV44P83v//gsoaiJKAmsL+/TKPiJhsdxYSKJIhPhJO6t\nIpWNbeKxIJIkEY2kCPpSOO5bv7ptdgYatO4n8oaqyt7VW/z41Gv4xGk++2iVn3/4CWYgjCccYqiq\nFHcKLF/OI9lfJBiffHgPGweYZp2JiAvFpmB3uxADPg6qVXT9oWpGVmz0eiqPwy5YxENu9ssausvB\nTuUATyKGrmn06m1yN+4w2NzF3Mtj7O4x3Nom98k19u6uoqsDzPvnaNXa9IPzHAwHTzR4foCh2sft\nGI3hE4uLtCMRyo2RnbAoCOwUtiitr+Julzg7LrMwHiTodiCLIrIo4pAlQi47sxEv35kIEDNKvPfZ\nr1guHDB++vSx8AnAcDjA4zmehLQsi09ufMjk80+S96MQRZHs/Dg1a5+t7a1nfu6vO77RDNwwDP7R\nP/pHvPvuu6TTaS5cuMCPfvQjFhb+KkwdfzvwtCz41sYGsU6HwNew8TQMA8MYYFMeas1PxkN8dHWd\nuYUxbI/ZbTqddhZPjjE+EeH//o/Xib89wcyPXkW2K8fKke2iwHDYp1KpUGg00Ox25HAQxa7Qku3c\nLRXxVivEfT6UiJ988ZBwIECj0eL2rXV6/SiaX8Tni2C3O4m53NwrbULqSUe+R6Eoduz2Ga6vXCbk\ndFBtDTFMcCgiJwJ+bi5tkuv1Sc9M4HU5ESwP9UYPc6ihDfUjP21vwIXzvpyw31UpLO2Q7da58Po5\nlpZ1XnxlBp/PR+Qgxvr2XSqNBr2ywM7mNg45y/j4LINBn6Gq0mhU0fUWc3EPsirTurlCbyyKP5HE\n5XysvNyCfrtD7rCMkS/zSvYEC3MnMAyDP/uP/4H1Wofde7vsrW+h9oaYRHEHxjEMg16riut+W7PS\n4SrjFxPHPHAUhwPVY1Cp10ncV1iIgohljlYXjyaqg047HmOA4Q2ze7hByIBht0t/dwe3oRNw2Ql4\nR7mLTrNONuhhMhyiU66Sy5doCBKh9DjLGwNiz79Du9GlWC6SST05NpvFPV67vyKTZZkX3nqLT//d\nv+OkKLK+tYmr1SDjPUPPYRDwfXE5viyKnBwLoK8XOSyXWJCfnMh0uw1mZ4+T9OHhIZarTzg68cTn\nnziHEyZOpFi9eZfpqS9uA/fXFd+IwK9cucLMzAyT9zXFf/RHf8RPfvKTv1EE/jgsy2Ln5k0uhp/s\nS/goOp0OjUYDw9RQZDt+v/+oMcED2BSJqG6yu1Nidu7pmf0Prm/RCgVJTqRwh56enCrXmjTtIdyZ\nNE5FwbIshopMeGqK7l4BfzTGfquNkdtnaeWQqcQspmVne0fA7XLQatXB2iMQ8OLyBTDFLy431jSV\nXG6Nzc0DNj4H2fLgdvgQBRHd0NCMNrreY5Bbo7S6TXRxhn69x1/cXWJqzovdM+oMZA4M1ncGOGUH\niiXiazX57piHrj9MvtDBF3z+KJ6fTCZJJpMYxsNWWPl8ntXVbUqlDodKh0wmTCYziSiKmDc38Sbm\nKZXK5HZuoYc8SB4nyBL1epWWOkBTBF5aOEX29bNHvR7L5TKNgIdL3/0HlP63/5cBXoiZOBMBkAX6\nep3awQ5ywUbAO47ePyTon6PXaKJ2u+hDHUEUUBx2egMVn9uNy+W6r7DgCZVRIuJne6eJ7vRzIEfp\nFD5nZmmZTDSMrvYwdZ1qpYrW69DeWUehz2apgNPnI26XuHrlMnfDJqELfxtXIIhod7C7licSCtGu\nVWnVGwx6Krqmo5Xu4Jj5LrquI8sy4XCY8z/6Ef/qf/1TzrVqZAMK5VaJZPrLV5WmadIaDIiNRwiZ\nbnLXr+F45VXc7ofEr+tlksnJY/tt5taITYQwDZOhNkQUhC8ssvIHfWzLBSqVypEJ2d8kfCMCz+fz\njD1iN5nJZPjss8++8UX9NuFxLWqr1ULpdvE8w1Oh2+2ytXOPoV4hGBaRbRJd1WB/xeSgcMDiSS/2\nR2bbCbeD3E7xqQReLjcpCTKSz47rGeRdKDZp2xxMpVJHOmlBEDAFEUGWUMIBGuUyaqFJ48BEGXjx\n+dPUak1czjHCE2kGlT4WFp1Oi73iOsWEzuwz+gXWagfcunULVU3i830HX0RAU3uE4w+VJ6YVo9VN\notaTrH74AbfvXCe0GMCb8FI3VVJuG3a7gqBLOBSdTqGMWOsTc7oI+kLcWKkTkCd57fVXnjj/owmt\n8fFxxsdHpfvv+hTCjcYR4ce8MvVOi+lslnQnRbPdRGsM0Q2DW7kKv/Pmef6HH/34ieTq3e0t3NOT\nHO5s0xQLJJ//Lq5gEKzRWOgO+sguL2qnzY2P/pxBbovlD5JY+LEEH4LoGL1g6KIPOhSFA06encAb\n8R+Fzx5FLBJgotplpbgNopuWEWJzS2dYz+FTeqR9ThyChVrKkzVaRFxuDH2I2GlwqMfYvX7Ilr/A\nW6/fJ05dY3N1leL1PZyOcUQxgCD4aBQ2mQrP8Rd/UcJmW+W551KcOjVPv9fjTCZFoGHH19pgVbWY\nsj979WVZFv2hRtc0cEeihP1+cttNkpLF1tIdTl64iCgKDAZd3O7WEz06D8t5vG6TwvYtZNHANC1E\nu5dYeop4InHMc94YgOQAV8BGt9v9lsC/Lr5q4uAf/+N/fFQ6funSJV5//fUj0hsMBgC/tdsPutI/\n2K7Vavgf8ZFQ78fA7ZpGt9tl9XCNWFYh6holdIbKiFDSmQZDPcfSTp2FhSlcxqjoxR2K02s8zNQP\nBsr982ms7JQIj0/RL1Qx78cX3YMRgXUdBrphoDZMpsJjtNttBr0egd4Q0zCoGAb5nT2S4Ri1zRIS\nYUITE2i2Q1RFoN8bIisB7IH737vSx+n0owcV9iw7Gxs3mZ09h6KM7oemOTg42GJ3d4dw+AyDwYiw\nsyem6Gi3j66/J/TYqhxSqJQoNjaJnfSQSb1IyLvH/ISNatNGeaVOz8yTDHuYTC8SyGSwqHHr8wP+\n958dMnf6HV57feQa9+jvUa1W2dzdpFQ/pNNvAgJel59EKElyaoqN99/HFw4jiSKLJ6a48vkKw6Eb\nxeEiKAbRtSHF+j4Lp7L80Y9/D1EUjx1/OByydXhAp93g1vY9AhMR3FoXpW9jvdlGFxUSHheCZXFQ\nKFJp2hjznyUQPEVPCKAoNmKe0TNT6ljAPN5Bmfp+l43lO1z6XhrZGP1+ujTSnfvsPs5OQr9zl42N\nLcYGHRTfGHduHZBxdnFmFAJiB2+zhCE7qZCi2TPYu7PNqecy/E+/s8iHa7v85f/xzwg8dxGf4cNl\nZHF55wgEgshGEb1dYWZ2iqnsOIoyQNeHXLuW586dv8Rn5nnzxBx+wULw+li5uULLLiA0eiiShCs2\n8kXvFOvoloUS8aN4QkRMGZuiYPM58CUM/JKLZr1Kr1ckGAyyt7fM9743w3A4PLq/tVqNwtYaz8cC\nzIy7Rx7suou+OqCQu0mjmmJm6iyCJCDdf9cZA1BE21ENwH9tPvgm2++//z7vvvsuwFdug/eNCDyd\nTrO3t3e0vbe399T2Tf/0n/7TZx7j8Rjyb9v24+5luq5j73bhfkmz/ZGE0frmHZIZlZDroZ7Wpt2v\neJNExiczlA/XOVjXmJ4azbjdZge1UTsqYnA4Rsfr91U2a30y59x08ntY9wdw1/HQwqpe77A2VBEb\nNbyDLnZJYWiTEEUJ/+mTND75GH1jn1YBvO4eittPu9WlpBUwdRFRkGhuPHS9syyLe/kWtpnfY3V1\ni0AgSjQ6dv9ch9y8uYHf/xKDwSMvMDVMvm0j5Wlhl2Uub9/FmzDwRJtIWZGpMynabZX8YZigv8u5\neRfFmsX6ZpC19RpL9z4hHAqTiMZxeyaxTWt4IpEjGZ7D4eDw8JDPV27QpUV0MsDUyTQ22+To/AOV\nUqHM9k6disOkc+cOF6encTmdvHxukf39A7YPqqi6RaPTwDM9zh//w//+yCTpwe+dz+f5T//pU967\nm6epu/DNzjMs9Li59Am2VJjEuQU8yTB1Xad4c4l2yYs3egG1usVOtYPL58ahG5SO+ZcLVDUnliOE\nIVrcu3qAx7FPavLhrFSXDFxBNwuzGZY3t5D2V3mumyMZDyPiR2kZ2GUPxVqMiirjKls4FBsnwhNM\n2AVQ27yR9FC6vcaVf29yOPYmkrNPVFiDmp10yMNsevxoHGuaA3CQSvnY3VVY/uRjXnhHJBSPMp2d\n5EJzlbvFQ8KRKYbDIYPWqAJWCYZwOWzYbI5RQdb9hdCwNaBT6RJICCRcLnaWc/QmB0xO6szOzhxN\nAjVN49oHPyPtGuB1Gcjy6D5Jcg+PDHPuKNv5A/YOPGRnRvLOByTe7fZwhB3Hfq8H+G3afvPNN3nz\nzTePtv/JP/knfBm+EYGfP3+e9fV1dnZ2SKVS/Nt/+2/51//6X3+TQ/71wFNWJs1mE8QGodCzpVR+\nX4BWy0G9UabTC9NRdTr9IXuHVTY3DwgEPAQCbhRFplbrIEYCoyYDNpn2YHjsWOpQ4+7KAYbiI5H0\nHfWvfABPKkpesxivDvHHJzBqLZrlCqZuUO/3CNl8mNZxaV+j32TgTuN3BYBJNjfvEY2OoWlDbt26\nhdt9FkU5XnhjWSbpqVn2a3s0iqs4kwOSaT+re5tMLWQQJRF/wMmw72P3ELqdXTy6xpjTxnQmSVsd\nstfoYqmgudy8/qNLFFZLHBwckEql2Nza4MbWFSbPZpiNPNk9xuF0MD6dYWwqTaVY5eovbvDB3h4Z\npxO/ouD0uZlwKFQMg1MLb3D+0qUnHrLV1XV++cs1NC2DIxhEt6mExiY5LJexj53G0rwcfLpL9NyQ\nQaVJpxLBnVxgsLuKz+2k3O8ihCQGhgWDPs5H/eUliX6/TTASxO1Lcfn961x4Q2MsO8YxbwBBpLlZ\n4Pd9Nt557klPj1TAzUG+gmFJYGrEow+TgwfNPs16mh+cf5OtxgAt6ONMJM7YWOYLvUXUZp+Z6Ev8\n/NoK/81rdnxOJ1G3j/PzA25tFklHZp5wHnwcumFiaBKyIuO32fh8Z5XkdJ033njr2Ap+L5cjausw\nPTXFRn6fYOhJL5XxRJCb25uMTUweNdsY9AeoDYid/2oSxb9u+EYELssy//yf/3PeeecdDMPgT/7k\nT/7GJTAfj4E7nU5qT/lcrVYmFPni5I/D6aCrOlk53CTf7pCJO3EpBgmPjrZ/m40NaPVFYuMTyHYH\nwn0dcTwRpLhfwp8axQCHms7uWh6jpxL4/9h7kyC58uvc73fnnOepsjJrBgpVKBTmngc2KYpsUqRI\nSrKfHfZb2OEIbxwOR3jhpcJre+OIF+FwOOyNHGFLsh6lR1LSE7vZ3ewJQGMqTIVCzZWVlfOceTPz\nTl4kGg00xu4mKeq5vyWQd6h/3Pvd8z/nO9/Jhh8ibwBRlmlGkmxcLbPotxBFAdW06La79NwOSV8Q\nq2XgGnfTr+h0B11u9i2Ch0beLh5PhGp1m3a7RrV6gK4niT7CJteyBkQiAVrKODevv8N3zszQbjXx\nJFRU12fk4fKp9Dpe7qwP+d6SB/XuPWuyC48i8d7GBhNnJzgejTLIDnnv43fxqkGu719h8cU5unoX\n78DzWGtVQRCIp2K8/qevcOv9dWKxeSRGxbYxn4/nJyfxPsJtslgs8tZbt0mlzlCp1OgWCrhSMdqd\nNl1BIjk/Q/l2Hsm7xO5bbyH7JwjOjd4BR1LR3C7Eah1T7+IKROjrPVTTRJJlwGHY17H7RYJ+LwO9\ni6Al+OAfz3PytQrx1ATBYAhJkilXmrg3t3ju5VMP3SOAS3ORzSYZDgdIsjJaB1+YXrXIxS2HiHcO\nRVKYi2lc3Mnhm1p6qjFUt1Zl0hdEHy7y9pUVfvLyEYL+DKlAAVVu8MnaCmHfIXzuh9ftU7RbOgFf\nDBybXHWDqOs2r7zy+kNrvb95k4W4n6Dfw5Xzm/TnhrjcKg4O3U6XZqVMr16nVWnzTrnD1JEF4olJ\nSqUShzILX7qZp9FosJ3b5aBRpdpujOyBRYmIz89YKMZkOvNYL5bfB3zlRp4333yTN9988zdxL/9B\nIBgMcvMR/25aQ1zK45fbMC1u7uSp91pkg32OTidIJvzUO33cUT/zh0eqFsOw2DvY5dyVBoXELONL\n00TTUaRbewx7fRSPxv52EdfQBFvG/ZiXyzZNBi3oH3uVG+tXmB4OUUSTVChMPZ/HNZ7BshpYdoJS\np8KaIeKZ+RYu12cpI0mKk89vkMtVCAReevgatoPjlPH5pimUVxlfmGC/a9Ku7DP1/OdVOg56d4hb\nilPt1BgLjaLUjj6k1LNITyQRlAbnzl2g2TBYOb8HlsbiawsUiiq5fIcbN/ZJj/mZnEwTfEybtdfn\n4fALU2yd2+KH3/oxpmk+0RDp0qVVfL45FEVDkiQsY4gky1Q7PdRQdBRZZsPUNgr0Km7c6mcvu+Dx\nY9Qh5tYoFYu4AlFEVaNvDHHj0GtUsAclJjMe4vFPI043dekovdImRsBhu7pHPDnD3vlrHNc7eB7j\n0w2jhp3Pj4FbL7RxnEPIsoYgCrhkmVivgzF4WHN+PyzLwh700fweNCVCrhInV6mSSma4s7XL8cUo\nYV+dv33nbUrVCCF/mqlsCv99ncOGaVEsd/EHNIr1LZ477EHVRvJAx3EoFAqsredotvvc/OQTlHmN\nQ1NpjmenWbm0xcKpFNX8PjQbBBWZMb8Xt+ngaB60Yp6b13coFAVe/C+/+8S/5VFoNBp8fO0yBaON\nZyKJf3GcbODIvdmnvXaHrXqD67fOE7wm8eLiCVJfYLjz7wpfd2J+RXz+5ff7/RAO0+h0HrDUlCUV\nwzA/fzgwipjP31on6mnxzeUwO5tD6rU+sZif2mBIKPXZdlhRJGYmQrgUh7+6eJP18yHmnjvKZCbG\nznYBORXBbHSxhiIRb2RkwvSIQMsaDHEsGW96krrqorZylej+LsvREOKwz52tOzQtjYs3ReTkMp7Q\nFIOBQaezhySJeDwBFMVDuZxjOAzh9z+sC+52a4yNeajUCiTGRFTfGEP3gP2GSV9UEPtDXKqMJIro\n7SGqJOITA+TrVbzqgEbfwnK5SB4ex6602Dvo0mkXWVp4kWC6i+hIxJKfzT607TF2d/NcePeXROgT\nCQXwxMNkjh0imU7cU5QEQgHU6AG5XO6eBPZRaLVa7Oy0SaePAaPdlTg00fUeQ0XG82nhOBahe7CL\nIyXRq0PMgY6suZG9XpoHDuNBD+3tBnq1ijsaod8dYDWLeD0DwjGNUOhBj5FgLM1BbovFkxrhgMgH\n779N8M4amXgMvdt95rmqRrPCelEg4ApTGQyRZYVuq83hZIrK7jbj2cxjhQi27Txg7hjwZLiycZU/\nfmmBeOQIK5cvU610ORqNMBN2uLN/mwuXL5POJgkGApiWSalQIpvI8tKyh9mxGbwuF7dzOfb2cpy/\nskVz4MUdnERze7G8++RbFWrXyrhlnZjs5pd/9THTKZGFySTy3R2ZYTk4A5NudYAv7/C8O8LKxx/z\n/BtvPLMdw43btzi/c5vw0RkOjT88nWjUfxDEHwrC9CSNSpVfrJxnqTDOmeWTv1eGWl8T+G8BM6dP\ns/VP/8TJ+wg8EomzubdO8nMfccdxuHRnmzF/h/lMENO0EQQf4UiCze09GkGJudjDEsFoxMfCWINC\n9Q47KyrjhyfZ+fUKm4U6XtlDKJDELytstlrwiDmDjnV/w4gCWhL/8SPcrBWZSsWoOSLeQ3PY5TBd\nw83qpRVaLQPD6GLbQ5CH+HwOqUSbUOB7hMPWA7aitu2g6wf4/R52ctc4ejzKuC/O1VtreINeguk4\nvY5Ou6PTrrSg6yALEqX2AEe0iWd9hMfDeDwuer0+q1st0ktH0TSZbq9H1ywznjzywN/UqtepfHyZ\ntGmiCj3GJQE3sPd375A/PMX0iXkO9soMdBPLGnD51sUnEnitVgNC90jO4/HiEWUKBxWYnURvNunU\nm+itJtVL1xCF4wxrZapXikjuCKLbh912UJtF4sEMlb19Gt0WktglGhdJpkPYne5oBul9EEUJR0xT\nPqghGCaJ3U2SdoXo0VNUDvIEI+FncqVs9fpYdgTDMHFFwoiSiNnsks5M06l16PX0B3TZ90OSJGxG\ncz0FIOAJkq85DA2DicwU166tUSxYxJMKiaCbTDzKYDCgXNtietKh0xSYPfkKk5kH6xI7ByU+bgSZ\nP/VHD5hqxafO0C78ksz0EQYDnd21cxyq6YSEKJf393EHFGwBVrbaLMZjHI1PMnUkgSLLfHxnldyh\nQ/cko0/CxZUrXGsfMPX6mSfqy+9HKBbF//pzrF65Qe/8h7z23Eu/NyT+NYF/RTzKk3hqaorNWIxy\ns0n8bnU/GAwi7ISo1dpEIp9FXFsHVWSnynxmtOWv1zv4fQnGUmnym316ikih0CSZ8CPfl4LRNIW0\nT0UNatzYXKUVj+Dz+yn/fIXYH76B3+/HcRy0dotBf4DmevBhFRUZx7GwDJPOjXUO++OEYwm0WoMj\ns7P0+n0akgvH2efyNdBcEsm0gD8QRxRFOp0B+VKF7eIdxuQt+jmHsCdLLJLFtm22Nj4iQI7qZQWx\nv8e+XsTyuYlFApTzBvWDLqIs4pgKyWSaaCSIMTTZv5NDswfExry4NAXDMLl0NY8rMkk4EqXd6lEt\n7yO6bFz32Y32dZ38Bx+y4HbhdbuxbZti8YD5kJ+FZJS/+dsPeeeXecZnTiIrXkxDZ+fWJSKeFK++\n+uIDL6RhGFiWdVfi9hm5SpLIQnaSm5c+wBLBkWRkQyeAydDlxRUZo7G9DdUyjuRlaMt02gqNssBY\nqkA4KeEulxCDIh53Bts0cSvKw2TsOAwNlVu/WuXHix7qHiDoJzUWZ7tSpX5QJpJOPv3Z1AI4jo+u\nZRGORakflIh7g2iqileCXq/7WAIXRQHV76d/n6EVToBmt0fI50ES3CzMH6HRqHOwV8KyRxYMelcl\nMH+I42dmHvB6ASiVy3yy3WTiJ9/A8zlHxFhqgrUtD+l2m4DPh2qCT/BwKODmhD9Juz/gRq7GK4nT\nvLZ8EkEQ6MsKgmkwFwpy6+qVpxL4+uYGK808sy+d+sI5c0mSmDl1jK1L17h8fYXTyye+0PG/LXxN\n4L8FyLLMqTfe4MJf/zXPaxreuwR/aPYYq2vncOwWkagf23bYOtjj1Xkftm1Tq3Xpdz1MZJLk63V8\nhw5x4uhR8vk9rl3bwh+w8XpHbfSiKOB3ydzeyhPxRTj/i2skj7/Kayc0Krf3KHf7BDMpssEgG6Uy\nQjKBqn2WS7Esi0G7Suv2RWJ9AU/Sy8G16yz5fUiigCqJvPPux8ycfJXIeIuAYhC5r7s0oqkM9AO6\nzjTdnsDkYpBu84D69j56cY8j3h5nFg/RatYh4Ccc8dHpD9nbKqIqEuOxOAigasq9CNTt0RDnJ1i7\nvsd+rYVbUdjIldntaKQ8LrZWNnEcKNZ00IwHtLKV3D4Jy8J7N0c8klxGyO9XKPUErOEsEhHCsfS9\n4Qx6S+LatSZe7wrHjx8ll8txdXudYrvBwDBolauUN924XAnC4TCiKBDweGmWOjiuIlOTIfwRH2a/\nR9n2UtvWMfQgsdlpVFlDdmzCHYOh6kEVh6DFMKs3mArVcO3tUh3YRBNJzICFKIk4lo3d07HbXaJW\nj0mPxHOHYvyb9+/wH51doFhtcPjUKTbPn0MQIZSMPzESH5gOXd3AnwnRa7YIoTGWGG0BXQIM7mqQ\nh8Mh9Xqd4dBAFAXcbg+hUAhfNE4rt/0ZgQsaQ9NEFEUEcTTIIx5PEI8nsO2Rl029vk0mk32IvB0c\nrt/exYxMEQw/XBRUFJXs8ve4fPXvyHhKePQukfgkuYNdJjQ3u9UeknuKF5eOP5T2iYeCXN3bp9Pp\nPHJGJowa6D66c52JV0986YKnIAhMHF/k2rsXmCiP/14UN78m8K+IxxXAYrEYi2++yfm//3tOBIOE\nfT68Xi8L8y+wuX2Lg/0KPTooZpNu00uxDV53lOz4GAetFu1wiMXlZRRFYWbmEBMT0zSbTTqdFuVy\nE8e2EcQwnn4RfzrLXExiYIE/FmMyPU4xf8DeRytYYT/xaID86hotvx+r12ewvY2wvkUwV6J4DerS\nGPXbLSaDcbY7Ajv5DYbDErqhInlThDxdIiHQ9Tqi4EKSVIaDAbZQYKCLtBt97JuXcPsobm4YAAAg\nAElEQVQ0usVtpts9ji6+gqZqGOYAt2v0wvhcKvOaQmFtl4OdPLNHZx5aN82l4I/6KEoG+e0q5X2D\noHuSVt3ELZsEVAGpWqHYbFD3FdC8Xnw+H+3dXTKfe3k1zc1efo+9RoBsKovZaNNutQlHR7sdSZbx\neGZ5771L3DzYwEyGqRpDikVw7DBDQ2a9fJneZpIxd4CFqVlu7h+QjMbolwoQ1hACfvqtNs0DC1ck\ngcw2mi8IiNR38wQskcnDs1TzeTq7BSKxJLWKyOGxMqfTAVTVpNOtYNkOkijg02R8WQ+i4KJVlfho\ntUYwNU4iFsI0GkjeEDNnn2P70kUMfR9PNIjX53ugQxFGH+j81gZdaZkwIjHZSzqRekDhqvf73Fxd\nZ7fYwtHCCLKG4zg4gwIecYdkxE3HMPks1ncQhNHos2wmxu5umUh09EEQRYFWq0EopD00mxOgXq+z\nWxsSPHES+RG+KACBUAz59J+ytvIr+puf0IhKNOtDsnqLpcMnOJFOP0C+LvOzHgu3INxrCnoUrq/d\nQptNPbBr+zKQZZnI0Rku3Frhe/FvfaVz/SbwNYH/FjE5OYn2ox9x5a23SObzzMRieDwelhZP0+12\n+fXV82SCBi4lRHzCT88YstZs4pmcZHH+MMp9D/qn3hTRz3msTE7onFu9TlBRuFOpEgr4UDWV7PQk\n45NZ6uUq5YMaWqfD5o338Op1xqI+Ij6VfHeAW5DJhmJYiDTsAS45Q7HmUNH7dHoWg34fQYRwKEDA\nb9JotClXivTMNtGMB7Pjxhm6sTWYfjFN51yDCSnK+bUrHEnPIArWA6QhCgKLySznL60zszCNcHf4\nrWXaFIpNCnWdniWQdGJMZSMoWPj9o+Yw0zCoDgbs1fdwDd3EcSjfXsWcmcWxrLvSPDAti2qjSWmg\nc3m9QmfgI2cUaHV04nd2mdAHxOMRbMthMDBY2W5x9qUZBm2D/EaASOos0t21rxcF9vaKeE9F+dW5\nD6kZsBx3U/FEaTUMqo0dDrbKYGcxek00v0y31MTqDvFoPjRp5OcRS6cpDA2K+3lScR8He13OTPsI\neF18vgHcsh32S232SwNe/8HzWGwwMCw8bpmOobN4bBmX28PqpUt0t4o0lCLuUABRlbFtm0a3R8uy\nsWSZdMjP/NjEQ2ZdnX6f66s7eNNLhCam7w2vGGGcQV9ns7yH1dJJay1igQDQwesa0fncoRla7etU\nKjvYtkKzWcHolZjOxPn47beQVY1wMklqPI3X42Vvv0xO9DE9/fjB1gAeX4DJ+efpFvaZiETRwy2S\nnhqHsw9r/O+HLfDYvPRwOGS1mGNq6bknnuNZEU0luXNzk3q9/tAM0t81vibwr4inzeVLpVJ888/+\njNs3bvDBlSsEBgNCoohP0+jbfYKhAG3bId9sIkejZJeXiUaebIR1P9xuN2cOL1D9+Dy1hs3YfX7e\noigSTcYJRSNsnD/Hn83FGI/PUSoUufHBBif98xxZcrhd6pDyZQkO+lzfvYw7nsVLgnpPgn4ZJIWe\nPsQY9NEtg2Dah8eoMHkoi9oOoJX7iGIURzdIe91EIgFcfg87+Qpy1yBk2AQMC1mSCHo1kqEI8ppD\ncb9IKptC7w3Y3GtiaCFsj4RrIDATDtBptUD4LO3zqUTO6PkQNRebjR4Zr0p9cwPb5aLVbNI3DDYG\nXZxUFE88hSqqhIwp4tlxBvUWwlSa3f6AzevrOKUOypSMe3KSYd9kb80knnnwJZ9dfoFK7qc06lXy\nAx2t1WTy2BxySUQxTOq6jthP0C9uIYh9FJcXW26gaCqm200LG0GU8UfDhKIRmu0C1bqFHEpzdW2f\no7MhVEXCcaA/NOn2Leo6mLLGi68uMzOdplas0SwVcIki5sBkZ2eTRmOLqSN+ajUo5lsMuhaqJYGi\nMDZ9hNNjaeRIgr/75f5D5G0YBjd3S2jHTxOOP1oap7ncxDKHyA8GXNi9zBvzGrLUw383RaUqKseP\nL3DtylWK22tkVZlsOnMv3WJZNs2tTVY21vHE43yyV0Ze+jGB4NOfbY83SEGScWsaqhhC7xQf+bu+\nrOAyDQZDg66oPDZ9UiqVkOKBhySWXwXaeJyDYuFrAv//A1RV5djJkywcO0a5XKZerVKqVinnrmNP\nxwhEI4z5/Y9sJHkSyuUyq7tbnD26zAuLx7jxD2tsv3eO4dI8kXTyntysWioR65UJhjQqGzuU7+SZ\n88+RiCSwHRvdyrNXzRFwJYmIbXr0sdFQXBFMw42kGmxuF/GHRbSgjNHfZnZxgkrLRerIEST3Jvk7\nNRw9hutuPtvj91CSGxQxMJt9JiM+JNvCzlWY8GhMeLLsXCmgaCq5qoUSGcPn0thdO8fydABVkTAt\nG+E+MZtj2+yu7uC153BLDo7Lz67eZUy1qTsO7+3uEp6fJDQ1g3T3PlwehWa5T08fIIcChJMjAmkH\n/RS6+2zWy7iiAfROH1Gc5vPQ3D6Ov/4G1z/8S9ptjYAs4wDRQIB6scz+xTsMD2zcwx3igSTuvgP0\nkXo9nGYdS5Jw9B7lchlwiGkirnCc9GSafNUgaqgwsAABzR3CO+ZlMeijWt3j8MyoEzaSilHe3iXl\nkigUD0jFBiwfDaPIMhCj2+2zvtUhO/0CkfBnzVS6KBMJDOjobXzuzwrn5WqdpujncDzNkyAIAmMz\nS2zV83y8cYMfnXHdi3K7vS43LlzANxgwNTWNJD0Y/SoyuDSVhONwM7fPud0iCy89W2CiudyoE0co\nFdaJep88fxZgt1YlvXzqsf4hlUYNNfz083wR+EIBDraqPHk/8dvH1wT+FfFFpmLLsnzP9hSgWtlg\nZj7ykIzsWaEoCj63G1EU0TSNs8snaW8XCNf63Nq6zFAWERSFvetXOekd4O8FmNBcmEqcUGDUeiwK\nIsvjaWQhz8U7FzHwU8tvYSppbDFEpelnqK+jixKtWhF3t0VmbpJCJ0xoZhq3340v6kfavApSAvvu\n5JZipUHJJeHPZHGsPqIM8XgQy7TZyVWwqzYp7zzv/fwK2ZeP4XVpNOtl3EqHeGRqtF6SiMPofKZh\nkF/L0d/zkU4cxbLatMpbpGYy7Oa3yBW26R+fA8FE7lRQZRkB0Hwm1Vtr9LxexjOHsS0bURLptQcE\n0mM0VSis/YrZ4ycfu85uf5jDp2bZuPgWLtlPLjegVe+xdXWF/kGTOc8pkDN0BYuQNpId2o6NaZkM\n9A5Gp0wwEsCRFYayQDBkgyMQDKQYSyuEQw9GjrZtYxs5xsdGqopMOsrbjoRx0EWwLWansw+kC7xe\nF5MZi+vXLzA2Nos5HCJIIh6vj6UpL+9c3cHnHu3MbMdhba+Af/LsvY/ckyCKAsHMAq2DFZqCQEfX\nkUWB6+fPE3McQk+IQG3bYb3eoBCK8q1Ihosf/SOR2BiR2Nhjj/kUiZkl1nduotIi4Xp05OwyDVrd\nHluOyIuHDz/2XLVuG0/iNxspe/w+6t3d3+g5vwy+JvB/RngDETpdnVDw0Vu/pyEUCnHybsdht9dg\nLLOEPRAYsyzmM1mGpkmr02HVv843Z6aQJJFitQZi4F5e2jBNqtUGLkNmNuKjKzmU8tuUOgY9Wpg7\nVXT9JgvfPMrU8stonuDIT1xv0C19TO+gQb9dIJWtsX9HYNCP4dIU9vU+qSNZ9E4fGR8dvYGv28fr\ndZPIxrhYa6M0HQKxb1C5laO6fQPHlePkfOyeykBRFfqdGu2iTiev4xXH8Xvjo52K42Env0431mKr\nVGU4HiUzn0KToFao4DFHueeuW8I3b+J169jDKuViG0X1I5oyliiCUWLqe0cptOoMBxaOM/uQyqFd\nOyAzH2ew4+LUy8us/vI8nlKOFwJe7rS8jAfSKJrDrXYRRZ5EFD99rVS8iopp+mk3G/iDNj7NTb3c\nQI1E0dwSpjUyH7Mdm2azx9AwqFaLTMY7qOroPKqqEJoc5/LVi3z7TOxByaNpks9X2d8qcrBRx922\n0DQNx7FpGSZdAZyuwH4xwHhygk63y/5AJJN98kCO+2GaJSaPhDj2J9/hg3d+RX/lEtOWSegx9q2O\n41DsdFjv9lGyU5w5fJhOq0Xxwh5bH/0DgTf/s8cWMj+FPxhBf+67fPiz/5V/dWKUd98uHGBaBnPj\nE6NOznqda70Bx77/g1ED3WPgOM4j/Ym+CgRRxLatp//wt4yvCfwr4mk58CchGB2n3ryK3+emXq/T\n7rZp9VpYtoUkSvjcPgLeAOFw+Kn2kvW2QfhwimAkwbVf/IITXi+aoqAqCl5NubfFtSwbgVGecjgc\nki/WcOQAilclgEQq5EF3BAjM4wpnEXqwtlNlcvkE4bEU9YNthrWLpFIWyVM+JNGDKIrMvXCK9/9u\nm4s/LXLpRgR5agpRlhAlCVV00TVUGh0dr9dNpz/ENZFgozhg8eU5jH6a0t67CAOZ/KUCDV8NQRAw\nBhbFmyUinhfIRtO020NkJYx0t2Eooi1w8d//FNfzScJzM1jmgPhEGnssht7t4zgOwUGdl39yhM1z\nu5R31hn0fOTyAzJjM7T1HY79wWGiry5TW99mWLpCZf86kdQRJHk0+KJVO0B17TA+e5iWz8X1c1fp\nXStxNnWKUnOdaEAk4tOwbIu07JDTNwi4P4sGHcvEpyh41AStYR9dGOJWLMoHVbIzLkzTYnu/zHat\ny9DjxpYEur11fOkwf/H+LRZjvlEnosdPKzpLo1O679kbcu3KBk6zS9LvwQr6iASD95waLV+QRKuO\nbFb42c2/w7Z+SGMAQnIGt+fZ0nWN6hbheJ2xdIbJqSm0777J/7N2h16vQ65cJQR4FRlREBhYJk3L\noWqDlkgysTRN4m6ErobDRH279LpNyoVdxjJPn6ATiqaInjlBKalR3Mkhterg2AwdibwN3pk5Tp88\n+VBh//PQZJmO+ZslW3NooClP9pL5XeBrAv9nRDw1zjv/7m/JV+4g+WU0v4Y77EKURGzLoa23qLTK\nDHcNxiJjTGYmH5pmDmCaFoWWyEIqhaZp7B4+zM72NlOpFLIkcf+8YEkScTCxLZuDYg3UEJrmYtAf\nIMoitmXRchzSCycJxjOU1z5BKsPWVpFhr4pfWmH5pRiSLNJrVZG0IrNn0mguhdd/MoMqr/PuX2wg\nO0FarRCaLCEg4PGEaJfz1Ns96pKEJxaiUe/Squ7jOOu8/MdHKOeSTJqjlnrHsZEkmaTngLXbAsOh\nhTFQiCRGO47hcEi300L1REGLMBwaDBjJykRRwuv3MhwO8HgVAiEvR795mN3VPPmVPEuzMdrDNRLR\nSRKLUziSROTQNP2dA8aULvmNd7EtHzh94lmNY6+cwTItBEFg4607/GD2NPWDMmk/VC0TGxNFVsgE\nU3Tre3QNH14ljWFaGLaI5YiIDsiomKaEZbUZ1BoU/Q5Xd0WkTIrAkRQ+WaC6d4nXfjxPZm4cY2iw\nlivyzlsrTKhT/OBf/xf8w//+PzI9qePVFFYurePSh0QiAfr9IYLgecS0e5HJRII/0Zr8b+//Xxjj\n3yOYfrCD9VGwLZN65SahaI2jp88glC8DcLC/z5npaTLxOI12m1a3S6nbwbEdZE0j4Pcz4fPh+VxQ\nI4giR2bTlC/vUrj5yVMJ3LIsijuX+PZrJzm6OE+9XqdcLmMOBiguF88lk6iq+kzBUzwQZq9ZhbGn\nNz89K7qtNsnAP28BE74m8K+MLxt9VyoVLty8QA6bQyk/Y+mHnfx8AS8kR9vk2kGVC9dLLEwtPFT5\n3tork8gu3XPie/7VV3m72WSnVGIiHsdSvbT0PgG3C7/XAxTp9lwYuPBoo/t3cLBsi3JnQC86QSw2\nhiCKVPt9pp9XMYbX6O3f5ujrUwx6u4hSl7E5L7HsBIo2Ig1Zlnj1J/M0O+e5fnWF3b0CPtcMsVAS\nt8tHeSjRqPdYODnJ1SvrmIMDoimD+bNLuL0eqsU2jjFEu6/hKDUW5/r1m3Q7PsbH5hAFAdt2qFeL\nyDTwzmTwBado5CuUugXifjeBiA9JEmi1q0xlVXKbFQYNg7FQnDM/OoJ2t8Pzg4s5dg4OyESD9Ls9\nnFgQUbf5zr9+nX63R6/VxjQMmpUaoiRwdaXKguBFQ8ToNkikPczS5na9SsSVQhQkDoXGuVVfZ38w\nRHVNoPm9SKKI6cBwMERwbEy9h6I6bG6vMfm9NwmGAwx6XSp711g+q5KZG3nBi5KIoXmwj7xErWWj\nuTQOfeNP+OuL/5Ypq0tEHxAJ+UamUSWdSPzBPLDUaQIwNC0KPYOTZ+fYGWyxUx4geT0EI1kk6UHC\nN4Y6nVYO29phbinJzPxrVAp7LKYjOI7D1tWrnIhGkSWJWChE7DGmYY9CaizJ6V6ff3v5PNWTrxCN\nP3pM4KCvU9i5xNl5D0cXR9a54XD4Sys+IuEIxtrWlzr2cehWG4yFn966/9vG1wT+z4BCocC7K+8y\ncSpL4sQfsfrePxKLWyjKo4tKiiyTzCbpRXpcu3ONI+YREvFREbLV7rFVVXj1O58V4VwuF298//t8\n+KtfsbK1RSSZZadwk2PjLjwuF5GAwNpmFdU3eoEc26HX16lZQ6xYBDV2GklSMI0hQ6PC0reO09+/\nydx4kPljbiRVxuVNPLYIdvKVWbTDJgPH4cK/u4JhJlCHYaSUhNjuUSxsIfsbvPDKGZaeO37vOF80\nQKPWIHB3tJhpWTQbAyaz4+zvNUYeLCi0Wg00eUDL6aHG0iiyhssdJyB6kRoW3c6QRqtIOiXi7nqJ\n+f3EFgMP3K+iyCzNhfm/f3WJYknHEQKYfZHVjy/SKOhYYgshrOFOBrEti70LqxxsVfnj8WmMRh2v\nZCAJAmNeN7dqORwngSCIOI6MX00w0Mp0nR42h1Ck8CivLmk4okR3aNDTc2SXEmzvNtFyu4S8e5x6\ndYzERJJ2p0el1qPelghFpzhxdlSYfPv9c/zpq3/AOVnlL//N/8RJj8VERccne4nGZwkEHhwu0jdM\n8q022wOH2Mwi35iYYPPggMOah5vla3Saa1imhuNoCAI49HC5HGYWUoxPvoCiaujdNrWdKyTnlmk2\nmziGgfYV5Hgzs5OcbDWo7byL3pzDG57E5faOWuP1Lp3aLi6hyjfPTLO4cJjhcEi5XMa2bQKBwEMD\nVJ4FsVgM91WbXruDx//l6k33wzQMrIM66SMvfOVzfVV8TeBfEV80B95qtXhv5T1mnp/GHxwVXsKH\nT3Dp+iVOH0s8UZHi8XoYP5Lm9uoqLs2FrGhcWK1x9Lkf3hu6+yncbjfffPNN1u/c4fKvf8123QAj\nx2wySjLk4aK+iU+Log8H6IAYCoPtJSf68SVG29tO/YCZKRvF5cLl7xJIpZBcKt5HOA/ej2Q2xO07\nW4y/cJie7SY79TrRWJRaoUTK9GAPDf7y//i3mGKYcqmBx+fCpalEE0FuXrcItjr0exa9rkAoMMbx\n5QST2QqffHKDbi+N3u6RirspVPu43V4coGc7eEJBBBq4JDhxNsvsdOJeQdK2bPr6cOTxoSnYls3u\nQYeEPM5+1c/YkUNIsoRxp8r1mzW0SZOTz08TSyexbZvN9QKRpST7FZ1ZdxC5B2aviyLJTPu7bDQ2\niWpT1HoGSijAnDuBbrQpd2/Q7EggxrAFH6Lioi9WGRo3Sfon6ZnrzL80hzscp4lNY8dBVjyEo4c4\ndihxLyUiKwpkx9jdz5HJzvDmt36MaNsUCvsIepdq38FXqiICBtC0gEgCTyrB0bE0vrsdiMlQiHav\nx+Gsh8DMyAPGGI6sZTWXB83lplkrc7BxmWHlNla3SFxtUbhVYrUzZH39NhOqSjIc/tIt6WPJOK99\n92VEUeTm2ibNxqheEfe7eO3lccbHTyAIAp98ssLlq3ksJwbIOPYaExmVV185TiAQeOZ3TxAElifn\nOHd7g9kzx5/6+6fhYGOHI8nMY73nf5cQHOeu7uu3dQFB4Ld8iX9WfBECt22bX77/S7QZlWTmwXzc\n2spNeptXOXYoQDD4ZIJsNdpsXz5AcB1m8ez3mHyCox6M8onr6+u887d/TaS1R0iCW5sHdM0IqncG\nXyhFU+/w3m6F+As/QNY8dBo53N4SoYRFPw6HM3k0t8lEWsL/DKqZaqHFpZUyDVElknqRmaVjlPby\nhMomve0SraaXydNvUGuU6XRrDAYdHAfKuQLZgclEYoyAP/AASXS7HW7cvMX2+jp+b4b1To7Yqy/R\nN0zaooOitllK9nnu1ASRu7pfy7LZz5eo1IookoVpOaiqn4GhUmzGiPvjXC84DNwutEiQyoe/JhR2\nkT59nG71Jouns7TKFa78YpUlWaZ27hrLLZmg0yEqC2BZDC2bK5UWO+0JhsosgUSU+6fpDM0+faNL\nvd+hZbZAWCc2ofHqi7P0F06y9MMfPnU9AfrdLu0PLhBu68SHQwJ3G1cM06TT69Hr93FsG1mW8Xk8\neAIBRPNhC+OV/X2WXn+dd6/k8GdPEgiP1CSdZp3da2/jtYtkYgqKMyQs1TlzfAFVVTEtk7//f/8O\nxXDRGLiZzR4lnfjik3Cu5/Oc+NGPSCYfn5N+993z3LgtMzZ+7J5ixXEcqpUcsnCLn/zo5dE0qi/w\n7v38vbewD6eIpb+8r3en2aJ27iY/ef0Pf+sE/izc+XUE/hXxRaLv/f192kqbiczD8v/Dy4uUYjHO\nf/IxCa1AdsxHMOh5oEHCNC0qlTa7xT53Om6+tfjcU8kbRk5q8/PzTP23/z2bd9ZYu/gR3fYqgUiG\nYqHI5Z1r2KElhGiEenmVYBRmj4+TnHqJWysfMWwe4DriwrFaiMKzPTLRVIDjls3Ku9sc3PoEqWJQ\nvr3NZHqRVxbO8OvN+iPzmvqSzupHHyHKwkMRntfrIzueZHZs9OEsr7ZRtCI9TeDQXBpFVDnkadM4\nKFHPF4kmY+xXKni0OkuHfajq6Hz1ps6/f2+bQGwMQ1XQRJ2pZIZKo8advS0CsQW61QadmsjWry8x\nl06RjmQImy3sQxPsvX2dsUyYTrM5UmCIAmfGIqhSjgv9DmZ3Bo+aRJU0EISRosbuI8v7LKZFgqEE\neiKNJDk4vd4zrSeAy+ul7FapbefI3Ke8UGSZcCBAOPA52+FHkDeAIgjEYjF+8q0ov75wjdy+iO64\naW29z9KEgk8VoZ8nE/czf2jxs12AJJPOpIgZBg4iFzcv0B8eYybz7Llgy7LoAIHP3+t9KJfL3FjV\nyUy+9oCkUxAEYvEsB/kB166t8cILj9fufx6iKPLqibP87Px7qC6NQOSL59P7vR75C9f57rHnfi+i\nb/iawH+nWN1eJTX/+KgjkU4Q+d73KOaKXF9fQ1+r4FEcJNHBsGBgyfgSY6ROzpF+UeXgch7HcR5r\nyv95aJrGwtIx5uaPsG/9FDlxisPeAEdVF329Q6NeZb28yZHnl+7li4OBOHuFVRDCYOho7mfvaBMx\nefnlY2yuh5hbPsFuS+JH3/k+AO9ef+uRx7hdbubOnmX9wgXG6g3igcADH7G+3iES9RAKBYiVCwyi\nQZYXpvG4XWxf+JicvcXUQhgEgU8+uoUvqHL05Qc7LGUZJiZC7Je2CYWiiKKNLEtMpDPkPT7mYmn8\nnhCO24+jC8TCCbbUBpgtQtEoe4is1vJ0hQpBQUBVBUwDel6HCb+GS9nioLlBtefgOKDKEPPZRJMJ\nxjMT7FQ2kDU3er8FX3R3qqpYlvUb2dUmEgn+5PsJ7ty5w9s/+wuem1MI+j0EfG5SyaOPJKn09DSF\nK1eYiEZ56XCEj9ZWUGSV7DNOqynUaqSPHHko5Xc/1tb2cHmmHvtcxxOT3Lj5FmfPWl8ojRMKhfjO\nyRf5x08+Ql+YIJl9dBH1UaiXK1SurPHN+RP3GvF+H/A1gX9FPGsKZTAYUO1VyMSfnIOTZZnxqXHG\np8axbRu9q2NZFpIs4fF6HhwEK+7RbrefGM08Coqi8NrzS3xwp48ohdm8vUqv02dsIkEqPEG90iCW\nGkV40+kM6zd1ug2ZdEJ5wJP8Sei2e4hDBZfbjebx0m20OJqZvTeHMeZz0W018QYeLkr5fX6OvPgi\nuc1N8rk9oiIENRVRFGl1uqBAAxEhHCESD+JxuzBNk9buKt/+j2fwhUca586wRfV2CcuafOAjYNsO\nmqoRCVpIehdZErEtG6OvE1ZCyI5wb01rPQAHSZKpNltU7lwhfdgkEhpwIhxENIb4ZAlZFCm3eqw0\nClSqGhGCLHnSqIpKezCgJ8rIaoh6o4Ou95GkUR5e+oL2CVgW3kCA/nCI6xEEawyHDO6OS1N8PrRH\nkODQce6Rs+M47K5d4cevz5GIPV1REo/H2ZIlDNNEVWTOzoX54PZVYuHwZ7azT0BxMOD5p8zNbTR1\nXE8IFGRZwbQU2u02oS+ggvn0/n/4wjf44MonrOdLJA5NPTEa77U7FDd28FR1vn/ipd8LC9n78S+W\nwE3TJJfLUWuWcRwHr9vPRHYSz1e0i/xtodFooAVdzxwtw2jb5/U//gXXQi6azeYXJnCA2Zkp3vn4\nF7zz0Rou9wkUzcvVc1uMTxnoA3B73Xj9Hlw+H17XBLtXPmLpP302E3tjYNApdZhOz7KzVscdWKCz\nXuDoi39w7zfHZjP8ancHb2D5kedwu9wcWjzKYG6OcrFIqVHHMkxyHh8LU0EW03FSpRKrzTZkoVkq\nEw9yj7wBBNnBExDpdwd4A59FfIos4thDPG4NUx/i4AIBOuUis8kFWjtlhmNjIAq4XAqaptCplagV\nznF6Fp7LLlDO7+B12fQ6LaqdFpJhItoOGb/CzFSAcr3Hjeu38ToT+MMJQoFR0c80LVoNA1+zgZKQ\nUcee7EdyP2zbxun0mF9eZueDDwjd7T7UdZ18oUCuVqMPCJoGAnhcbob1GmPBEJlkEn8gQKPdxheP\n33tmisUiLrtCIpZ5pnuQZZnxuUPs37rFZDSKR1PIhG1yxQMOTUw98ditQgHv5CSJp+TN/T6NUq2H\n3/+wtBZGaRhBGD61ue1xCAQCfOeVb7C7u8vKyhrrzm3kSAA14EVWFGzLYtDuYiEhS1cAACAASURB\nVNY7uAcOZyZmmVua/dLX+23i9++OngG3bt/g9tZlAnEIx92IgkClNWD11+dIRWY5dfz5p07c/hTd\nbpedjQ2quW3M4WBkg5nOMjk798T23E/xrDnwXq+H6vvNdm4pXoVur/uljnW73UwlA5z7uEdgJozb\n68ftDlPYe4tTry5zZ32D2EyEoSqRDPup7w0x+kPcXjfm0GCgD0a+IqKI6tbuacGH/SH1fINMPIss\ny+Rz4Pe1eWH66APrOTU5gXr9Hfq9WVxP6ArUVI1MdgKyozyro9jEol00TSGWSuBcvMhwboDTqxHy\neOh3B7i8dx3xTId+x8bleXDd3W4NVW7TbKgMbBvDGO1K6nt5jk8+h663uX3+E8ygxelTEcp7+/Tz\n/8Rk1GQpMYMiybi8QWyrSTSZpKm5qZRrgIWpD2l3dNwhD4vPi9xe7RDxTN/b6huWjWKF6eRydJLp\nZ049ANQOCswEI8zPz3Pz3DkGgwH7BwfcqVYREzF8C/P4PhcFK5k0+VqNnc0NJjxeHFXl5B/90b3/\n375zg2z8iz2XE1NT9Lpddnd3yUYiTMT9fLi+xWxm4rGWrjulEu1wmG9+6+ke2ocOjXP91ibEH/1R\nqVVzLMzHH+s++CwQRZGpqSmmpqZoNBo0Gg1q7SZD00CRZMK+cYJjQSKRyBcKun7X+BdH4JevfkKx\ne53T35jA9bkxYXNHLDZu53j3wybfePk7j+xa/BSDwYArH39Ic+s2E26RpaAfxSdhWl1Ka5/w8ZVz\n+CbmOPHiy0/M1z0rRrnqr3yaByAIIw33l72ffn9IQO1w/f2/YGCrhBNZ3L46suAwFR3n6ru/wuMt\n890fLLO3+Qdc+uk/ETgUB5cb3B4EUQLHxtHLKNj4XAKa4mFqfBq/38fq1RztssoL41mOHHqwyUTT\nNF4/foh/vHWV7PGHJ9o/Dl5/hG63RsA36jqcjiW48tF5zp5I4I8vcfv8LVKzfgRBoLiqEwzFHtKr\nCwiMxTUu36wzPulBHGq08jmipgd/III/EAEHdjZ+ju21KG5/xOkpL2H/CfrtXYJAIBimUuwh6kMG\nfZNwJIUgiIQdh1qnS1/UiEXdKMf73Lh8hyl1CWNoUi51iIgRaq19NjpxTqSfPZ/a2dphce4oqqoy\nMT/Pz//mb/BkM0SWFu95oX8esiwTSiSwYzHW1tep7B7witfLzs4Oa7fOc/X9n/LaUoDirkQgmCIx\nNkkoGHwiaQmCwPziIhuKwsbGBhFFIaAMKdXrpD7X1l5pNMi328jZLG98+9vPVPxLpVLMTG2wk7vB\n2PjiA/fSalZwzNssLz//jKv2dIRCIUKhEFO/sTP+7vAvisDz+Tz55jVOvzz7yOKFJEkcXpxg1d5h\n5cZlTp94tIG7rut8+A8/J2vUOTs39lDUEPL7OOQ4bB3s8P7Pyrz0vR8+1ur1WXPgqqpiNh6tCviy\nsIc2quuLR/WWZfHOOx+zutql2fSzfPQNdL3P+uY1GvvX2DxX5+zZY3z7P3mdWqvGhY/OcbvZpNKd\nYjrpEBkfwxcNIMoypmEyHAzpNLr0Wn1C3SG6v8POrTw33h/wJ3/4n3N86dgj72NmZpojByVur66Q\nOfLoVMrnEQrH2Luzeq8r2utSie2uET6TIDGRxuPzUNovgOOwtPwihUaJSq1HLPJZas00bWoNh8l0\nBL2exzDHGGxXOHPkWwwHfWqVXWR7m//mv/ozCsUcJxa7DI0ue7tuSg2RsGWiSjKR+Bj5vU3svkVA\nGZGMIAhEfF46ep9OpYFLVXB7G+ysbyLqMolghlAkSHH/GiVdQtf1Z4ok92+tMi2oJJPJUZv5cED1\n0CyKID6WvF2qSv/ulBpd1+n4/cReeIH/+f/8X/jBqQTZuIL3RJDnjkWxLJt6o8zB9j57RDh85MQT\nn2tRFDk0P08ileJgb4/m/g3KOzv0+n0EQcB0HBqOg298nKOvv874+PgzFxwFQeBb33ye99+/xO07\nvwQxDYKMY1WIhHR+9MPTBIPBr+RD9B8KvrQO/K/+6q/48z//c1ZXV7lw4QKnTp169AV+gzrwdz/4\nJ6KzOsnUk81rhkODC2/v8r1v/quHUimO4/De3/+MbK/ETPrpGta9YoU7YoDX/+hHj3wAn/Uharfb\n/MMnf8+xNx5NZl8GNz64yevzrxN7jCvc4/D+++e5ds1ifPwoW1u7rK+XsSyJYFBieXmWen2d06c9\nPPfcSS5dXeHX+2VIZWh0G2xd+iXh0D7uqIwa8uDye/F4fXg8HgSgdVBl89c3cNWi/Hf/9f/A+PiT\nK/2mafL2++dY77sYO7z8TKb7K5c/ZCLWp1+vEOps8crRFG/fzqEemyP6/7H3psFxpOeB5pOVdd+F\nQqFQKNz3SYBX82azu8WW1LqvXUnr3fCMfsz6x0zMTIRCnpD9wxFjjcaOidixI8YTMQ5JniN2LUuW\naUvqVt/N7maz2bwPACRA3FcBhULdd2bujyJBgrgPEmR1PhEdXUlkZb5vfZlvfvl+7/HItZFKZRga\nGUWSotitAnkJojGBUrcPf0UZl89PM9kbxI8XZ0kZBp3CnnY/zc11GI1GXn/rf3HseQe5bIYPPhgC\nxY1m6hq1rlI0gsDo6ASJeAZByWLWg9GgRbw3IZBkmVgixWQwye1rLrqrX8BgMDEyfZlojRvBXYq+\nw8pzX/48hlXe8qR8num+fspCcV4+chy9Xs+1mzc5n0pQ3tFO79vvIA0P43E4sdmXuvyMej3ReJzg\nfIioTkv5kSOEY8M4WKAlPkdHjYfJWxc40LbU1zwXjDAxq6et49CGDWTvwCgT+Qaqa+qQJQm9wYDb\n7d52w4NYLEYgEFjMxPR6vYsz8mI34I81Dryrq4tf/epX/It/8S+2eohNkUwmWUhM0OZtWndfvV6H\nwysyNTVF7SNx0jMzM+iC49Q3rt2i6T5V3lJmhiaYnJxcsev1Ri8gq9WKmBNJJpKYV+kEvhmy2SxS\nLL/pVfh4PM7Nm3NUVBxHEATq62uorq4kn88t6mIydXLt2gcoosKlaJbaYy8sPrz2dOxjevg24Ylr\nGGNBrOTJR7MkckmiCxrSGQ9NR35Adj7EuQsX6WgMoRFFzFYrFRUVyxaCtFotL504TFlvP+evvoe+\nopmS8tVna4qiYLe5ufj2z/lqj5kjxxoxGvV80Wzg9auDjAUj+NtqFr9vMhnoaGsmkUiRTGURBIHa\najMajcD7b18leifFN4+9iM/nw2azLTEQo6OjuNxpjEYPRqOepiY7d+7kyJTUcXf2Nmadhon4GHqD\nFSQNqYwBQ1ZGUAqV7wSNiKh3U1tbRTAcQwamgkOMm/K8cOIr5PNZ0sl+Fs6eJ+t2YK+pwnRvNp5N\np4lMTMLULG1lPg4eO4lWqyUej3NhYpzyk8fR6fV0nv4MwfFxJq9eY2piEqsAokZT6PCjyKQNBsoP\nHsBfXcXQ3cu01JsxmVwMfBTBOx9FWsEF5yl1AFEGbl+lq3tj6eJaUUeNv46W1vULZW0Gm8226lpU\nMRvvjbJlA966wwO1HplMBoNZu+EFBZNFQzqTXvbvI703qV0n0/FRal02+m5cXdGAbxRBEGipamVs\ndJS69uWdXzbLzNgM9eWbXxkfGRlDEMqXuI20WnFJCr8oikSjJl69fJO93/o/lhhTnV5PdUsXlU0d\nhGcDJKNhyKcxWIzUVDsRtTrmeq8hj/QzMnAD6UMRjdZIJCcT1proPHGY48+/sOSmFEWRnq4Oqv0+\nrvcPcvtiH4rNg2hxYrjXDiw0P0dsfgYlMkdNiYmX93TitM5gvOdCctgtfPVIO1f7x7j+9kW0lV5c\nFR7MtkLDC4vFhNlsJBaOc+2T21x7u4/UuInjz32L3l47vb0JFGWUioo+enrqqaysZCEcoLTsgc+2\nvr6aubkbDNydRzLGcRlDlNfLWO7V9Y5EI8RCYMeHw7T0wVpSInDj2jWmxDjPnf4ysdgCsixRWenj\nc595nomJCXrvjBJNp5FkGYtez1Gfn9rn9ywxVHdHRhCq/OjuvVmKooi3thZvbS3R+XlioQXymTQa\nrY5Si5kSnw9Rq2ViYgy3U8JsLhzLWlfNYN8NnJmVrxNPqZ1AMEgkEtlQ/ZFUTsGhGtQnzjPjA9do\nCiVWN4okKcsWr7LZLJHxIcobN5dK63E5uHZnkkQiscwXvpnXuPraevre7yVRncBi3WT870Nk0hkW\nhsIcObLxxb/7RCJJDIb1o2uGpsKUN1VjlPPkVrhMNBoNJeU+SsofLMLNjo4QfOsMXiVNMiWTcjcz\nPzVDZ/1efKJIMhVn5LXz/Ph353jl21/n6NGDSx7IJSUlnDr6HIdSKYLBIMGFCLfv3mJyqB9zLkqH\n24jLZQbRSCCh4+acQi4/yv6uSkRRRKfTcrCrno5khrsTswxd6WM0nUXQ60AQSITj3O2fJxdy4TWd\n4NDXvojdriGXe2Cko9Egv/nNMPX1o9gdWZxlD3SXZQW9IUFl3Qw6vQeNWM1Y/xWQ0lj1Biq8NnJu\nmcnJSRYSEi6zm7yUJ5SY506onwHByle/chinsx9Zvs3EZIR0ysqdeh/l5eUc7ezGaDSuudDXPz2F\n6+D+Ff9md7uxP5yhmc6Q02pRFIW5wBBt9Q+uOZe3hKkbIhbRwkIkhcux3IXjLdURmBlf14AXyhmL\ntGwiomYnKHYXykZY04CfPn2amZmZZf/+ox/9iC996UsbPskf/dEfLc4Ujx49ysmTJxd/+HS6MEte\nb9tqtSJndMTCeYxGPTpjoch1Ll2YST66vRDI0tpVsuR42WwWs9lMVmvAKBdqR6c1BZ/rutuiQCaT\nWZyN3pfvftLERvQxmUzsbdjHreu3aDzcgEajQUkXHkqCsWDI1tuWUzLjN8bZU7MHm8224d/v/rbB\nIKLT5RbHRqcrLHLlcvrF7Xg8TkSWafV40OYK+uX0he/rsukVtwOhBSJnf0ujw8xCxIDeZMNsNyAZ\nzShGAYPGhMFgosRfQdXCPP/wP39HIpnm+LEDaDSaJfIKgkBVVRXxSBi/EuSFow14bYVxSFP4f1c2\nSe/IFH3jIrH0PF0Neso8TtI5HRqdjq5mA13NkMiI5LIS6VSIX/1miGrbKfS+KsrKOzGZjGi1sXv6\nF4ym223D7d7D2NgwydTbfMHnI5PWYTDmuDvcj7PUTEPpYcKxESYnQzi8e0hnNcTTYwjZJDZDGQ6/\nlcE7dxkLptCZHSiWFDXdZo6//Dx1dYVOOIqcQkMEvS7DO7/6r6TCGupqm9Da7ZRWVdHQ2orX6112\n/eaAEq2O+yOoS98bn3sRWSttp9NpdGIGo9GCLqu5N36Aw4bbWMrI/BiuezY6rRQ+GIUILqeV8fk0\naUmHUbx3P0j374cH25OBGKWV7RiNxk1fj+r2g+13332XN998E2DDb9Zr7vXGG29s6CDr8e///b9f\n9W+PPkHX2q6r7GB66hbN7Q9cGfcN98Pb88EwBtzLOnUIgkA+nVw0zsCSz2ttK7DE0Nzn0dnJevo0\nNDQwH5mn/5N+Wg60IBofCXEzCqtuK4rCQP8gLtlFS1PLhs736HZlpY8LF25it9cADwz3fXI5PWMT\nERRLFneFj5RlqX73DffD24qiMP3RO9QbYGIigd3hL4QYAlnByOzUJLWVhTBCJZGjVG9nv8fD2fdH\ncTkdHDz4IDv1vryTk5MEbpzlWGsFuoeyP433TZdex97mGkwj0wzlHfRN6rh1d4KKUg1Ou4m8uZA0\nlcnmCEfi/PyfBglGumlqPUi5z49GU/hdU6mlbyP3DbnP18qFC9cYGrpNde0BMukM0cQ0HY0eBE0c\nr6UUl8vBxMQkN25OojeWoCgWInIORZAxV9uZGIxS7Ymzp9PL6LAZs86EIqdQFIX+viHGr17hZFcT\nXU1OxidCpOMhmnw+5oaG+PDWLfw9PRw8fHjR3ZVKpUhptYvGGVjy+dHt+5+TuSxazf3xenC/aMwW\nnJY8A6NR0n4LRoMWoxBZ/LtWK5JPBReNNbDkM4BeyDA+E6br5GeXjN+j4/k4tleafT/J8+/09qlT\npzh16tTi9p/8yZ+wHitH3W+SJ1VtsLG+mfCklpmp4Kr7JBIpbl+dpav14LK/GY1GsoKWbC63wjdX\nR5IkkrKwI/HgAAf3HqTaUMOt93uJhqMb+k4iluDmB7fw5D0cO3hs1YSJ9fB6vXg8MgsLgVX3GZke\nobzOtuR1fC0WAjPYEwtEwlmsNt+i8QbQm6zEMsuTjSpLyrBkM1y4PEUisfzvgzcu0lnpXGK8V6Kl\nphx9co6eg6foPvq/ozhOMBzy8cltgY/7FHonbIzF6pENRznxwjep8FcuGu/VUBSFVCqF09nKhx+M\nEZoPMT09QYlHi/DQd/UGHXV1tTTUe6iosOH3m6mstFBdbae9vRZPeYLOjgqMJjNzcwr2e1UcB26P\nMnP5FsebK6jyliCKGmpq3CjSJJFIBF9pKd1+P3NXrvDJ+fNLhdtCMoFGo2G1dAGdTktjexsXekNI\n0tLJkCTJaIS1r7Prt6ewlHet29ZM5fGwZR/4r371K/7Vv/pXBINBvvCFL7B3715effXVnZRtGUaj\nkROHPsv7H/+O0NwwlbWexZsik8kyMTpLYCRDT+uLlK/gjxNFkfKWTsZHb9Dg33h7pcm5ECX1LSv6\nJrfihxMEgQM9B/BP+zl/4TxTzinc1W6cbueS5KN8Pk90IcrcWJBcMMehtkPbWki9f+7Tp5/jzJkP\nCQRSlJZWLbqFJCnP3NwYqdwtXnz5/wYKLpJHZ92PEhrow6vJE5ZMmB5pVivqDCRlCVmW0Dxs2HU6\nysUcgaSBwcERurs7Fv92584d+q68S8IDeTmPVqOlxFpKXXkVZW7nsgp15WaZy59coLmtHYfTha/C\nj81mW3zIvfPOx/h89Ssabp0uszjrjsXizM5MEJ6fQKfNo9fKTAymufTRq6SySSoaDJjNGuwOO5p7\ntVUEDdTV+envH8Nk9qC7p38iEcPtLljN2UAcq6kco0FPJJpg7Gof7V49FQ+VNRUQKPcamZkZwe12\no9FoaKus5NrVqwQaGvB6vRiNRpRUas2xWKJbOkPOaMBoMpHOFuqX6B56NZdTaYzlNqqrPCQTKT66\neYfn2koWqzZGogksttUbF1/rnySur+PIc5tfi9kJVB/4Ngz41772Nb72ta/tpCwbwm63c/r5rzA6\nNsLtT66TlaYRNKBIOmorWnnxSPOaKfC1zS1c6r1MrbSxSmayLDMcTdN+YnkJ2O3i8/n4ctmXmZqa\n4u7wXfqu9INeQRA1KJIMWXDbS+n2d1PZXbljtRicTidf//pJLl/u5fbtD1CUwu8lCDE6Orzk7C2Y\nNlFfJReZJ5WQ0BtXWexaZdZo12mImpxcuzlBd3cHkUiETy69RSTaT1vHAvvbqtBqNeTzMrPz8/SN\nTnF9yMbB1m6MBj0jkwFG+ocJz82TyPWiuztUaO4ApEWR8qYmalpaGBiYo6xs9UShXC7HyN07JGOj\nlLu11LTa0d73OXCM+dm36eqxYXOlSMeGCAV1eMprF+OuLVYLTU1+BgenyGvtGI1m0qkgNqsORZEZ\nH8vjL/MhyxK3b/VRpk/T2tq+aOwfjIuF0fFZUqkUJlMheqbcZGKwtxev14vBYMCi0ZBOJjFuouaP\nqNFQ4qljLniXivJCXLaiKBCN4LAXHiJ7upvoN+h573ovdR4NVT4bs8EMZf6aJceSJInJmRDDM2lM\n3k6OHDq25cYO67GwsEAymUSr1VJaWvrYzvMs88xEoTyMXq+nqbGZpsZCyyVZltHr9RtyKzidTkra\n93G5/yL76yvX/I6iKFwbmcTc2LVqFbLtzgBEUaSqqoqqqqrFV3dJktBoNIXkmMdUh8Fms/H884d4\n7rkUsVhhIc9ut2M0Ghl7LUI+k0E0m9edfQMgyaQzOaym5W8oiiQhKiCs8CouIKDV6kgm5UKP0Mu/\noa1Tg1b0kRqZXpwJ6vUilT47lT4IzMY48+6r6OeN1Ou17LFbEUpLGEsbaa94UBgqL0lM373LJ1eu\ncGcYXK6TKxqAcFjiTu95PI40DS3uZbN0f3kNdwY1NDTKOMs0eNwW0uksgcBtkslKvN5yEMDusNPW\npmNqapZwZJpkcgE5JzExFiYRcaC4YywsTCHH5zlyoB2DYfnvKiBgNhUWy++768pcLq4MDJA5ehSD\nwUBruY9r09OUN6zf1f1hf3iZt4LbNwfwuPPodFoiwTAVZi0Gw4OHSGtrDT5fKaMjU5w510cuLvOc\nLU08NYskyyRSeaYiGkr8rbQfb39slfkCgQA3+j4mxzxmu5Z8ViZ5VaShupvWlo7Fe/bTPvuGZ9SA\nP8xGi1Y9TPeBg1zO5zh/5ypt5W5c9uWpzJF4gv7peZSaNg5uIVxvKwiC8MSrKZpMpmW+fZ/TwUgk\njGGDsogmM9lVmgdk0wksBtOKD6K0JKHVm5CSMh9f+C179ot4vS7CC2FCKyxTyJJEaCGI3zLD/KSB\nBm8nBp2WuVAEvWnpq75WFKnyeHDbbFy4dJMbH3xA04EDSxKfUqk0d3rPU+sDl3PljEG9Tk+Fp5nx\noUmywgIlbgtGo56qCi1TMxPMBqDsnrvOZDbR0FhDJpPh0ifTTIxnyCcFnjtQQ2WlB6u1ieREYlnH\n9ofRCIW3vsXfVhTR3XuwGwwGGmtrufjxeaTa2k3NSM0mE+WVe7h99yrN9U6iQ+OcqF7ut3Y4LPgr\nvUwELfgPHyYnakjlMohaHaZyCyf9/h1bC1qJqakpLt16jba9btyl9Yv/nkpl6L/xCfHLUQ7uP/pU\nF5h6kjzzBnwraDQa9h85xkh5BVeuXUYbmMCrF9BpCwkZs1mFjLWEmqMv09DYuObFUox+uBpvKf2T\nM+Cr2JAP3NbQxsTFj3FKEqKoRZLyCAhoRJFsPEyJaCQajZLP55BlBa0ootPrmUgrVDvLuDv1Lgee\ny+P1FrJjHQ4HIxoT6Uxmsea1LEv03RlBG1zgYHUpN3NRxucjNJa5mYvn8NetnLKv1+nwOAyYRZGB\n8x/TfOQwDocDRVG4O3CDploR6xoGKZPN4PPaObivif/+q7/FbAnR1Owkl8uj0SqMjPWRSGfwecsx\nLr6BiAzfkdBlm/k/v/MKVmvh+Mlkhodbra14vpyyYhG2+9egw+Ggp9TD9f7b+DvWduvd94Hfx+er\nQEDg3Ptv0TA/hrtraTx5OBxndDJCYN7Mc8e/sekSDZtBlmUURVnyEJIkiUs33mXPkXLs9qV5EiaT\nge4DdVz88DbT03VUVFQU5b23WT6VBhwKN0RdfT119fXMzc0Rmp8nlckg6vU0lZRQVlb2qX3KV1ZW\noly+zsxUOWZBJqXRotXqMJvNK86+SququWO3E16YQSPnUNIRZCCLiczQICZDGVntAiIF8yUDgUSU\nQdFL4sZlLMYJauoeFPkXNAJl1Q2Mj16nyV8KgsDEdBBhLkT1vYDlap+Jy+MzlIR15I1O7Kskm2hF\nkfpyI+NzCWpMNgYuX6b7+HGCc3PolDlczjJyGXnF7wLEYjM8t89OudfFV176Iq++8zofnR/BUa2h\noqUUXUUJQ9F55kbTmPJa8ikbt3sThGYO8NlT/kXjDWAwaFG0ItmchF63fPacSmXI5cxLiltJkkQO\nlvzu+7q6GH/vXebGx/FUbawkxH0sBgP1Qgk9HV/k/U8GMehDiBrI5hTQuKipf4lT+2q29Ga7HrJc\nSHK6dneYiXAUBAGLTqS7porGujqCwSDWktwy430fjUZDVYODu6O9VFRsvI56MfOpNeAP4/F4tuzP\nK6YZQC6XY3R0jKt3RpmeDDI4dw5Xx0EQJJDiKJkJzKJMnc9Dubds8SbX6fX4D53g1s/+ihN1DRit\nBoJzc0wMnEcbk8nXOsnkJZwmCzajmXQuS39CR0d1F8O9byNW9xILe3DYzYvRHb4KP3cW5hmansJj\nNzM7PEHLQ8Wa7GYdWXGBm3NZDhw5subDtq26lMHJSdz2vThCIYYHBkmmgjRX2dY03rl8Dq12lpqq\nQsx9S1MlN+92ci4wjCRbiPQlQckTCmUw2kvIRNI48wqdDZ/nW188yScf/6LQTeneLFMUReo6a5i+\nPkyNd7nLJjAXx1PWtUSXmVCIqvb2JQZVp9Px+SNHefWjc0wlk5Q3Na24lvNojPjc+DjK7QG+eewE\npaWlSNIRkskkkiSh1WqxWCyPbdKSzWZ589x5RgQdtpoWKg54CnH6ySQfjY9y8Z33qbVoKKlZu9xs\nqcfJ4PVpoLjuva2iGnAVoFDk6+1PbhDVl+Ko2sf+9lMoH79PWJZxVj2o3ZJJJ+mdn2Ng4hZdDZWU\nlRUefM76JrIVfi4O3Ean0RAW85jrSsnrTYy4XCBDbnoOQ2CCVFygvPVlFCVLs0/A7/cQ7usjGgrR\n1t2NqBURNAJN7V2M3jVx9pNzVMSTZHRasoJANi8RSUmkdAba6nswr9OWzON0UuqcIhQP4nOWcKm/\nD2elDrN57VDS2dlR9u6xoNcXXBrxeIoFk5nj3/gWgfFJIrNjWGzg1KWZDRlwV3WSmUxz5LnPYLPZ\nKCvv5tqNK+zredCYoKGpgjevDFKRl9A9VOohHI4TDpvo3PNAJkmSmM1kOLFC3SGLxcKXTpzkk+vX\nuXH2A0z1tbhXKNmqKAoLgQCx4VFqFIUTx44vRmmJorihpiXbRVEU3j7/MeP2UqpalrZTM5jNVLS0\nkSiv4Oxvfskpu0xN3eo10mVZXnFB/NOKasC3STH44W719vNe/xTOxv34nQ9Ki3bvfY6BGxeYlCSc\nNQ0IgoDBaMbgryGT9vDJ0DCN0SjNDfVIeQlLqYvr4Sm0Vgt1eplGp4uFTB6j046kCMTNZiaTOYSU\nnkRggDZ3jiMdtUym5qkuLWVqbpa+a9fo2LsXQSOgETX4qqsZuHKTlKjn2nQSkLBazVRUeKnI5jdU\nS1sQBF7oqeOfPuojluzAnE6TTaUALzqDhlxGRpblJbPYmcAo/opZ9vc80wmQDwAAIABJREFUaEQx\nORNC9HuxuWzYXK3ksg2k4iny+TyxoSR7X/wK47f6mJ2dxWaz0d19kI8/TnDpym26OsrR63U4nVZa\nj7TT+8Et2n0laLUa5oMxxqc0NLccWPR/S5JE7+QktYcOrfp2aDAYOH7wIC1zc/QOD3Ontx/FYkG4\n1zvVmM2RDIepcjh4ob6BioqKXXELBgIBhnIsM94PY3E4cPY8x8eXfkn3vuZV95udWaDMXciFKIZ7\nb7uoBvxTTl//Hd69M4tvz/HFCnf3MRhNdHZ0k+vtZWo+gLWxHZPDde9vZtx1rQyODSLcHSYVnOJG\neI7Ww50YgrNocwK3k3nmsiIlFj2i3oKpzEMZkMvMk7cPYFUEHBYLd+YKWX8VJW5GZmaYHB+nxFPG\nnTsBzn8yQ+CugVJ7PWgMgALxBPJYmJnxeWz7wjgtlnUjMuxmM184VMvrF28Ri2UQw4U492gswpWr\ng0QiGRx2A36/Ew1JamsivHSycUmVxnROQmt7yJWh16ErKRhcxwKk0mk0Rj3ZXKG+jCiKHD78Ardu\nlfD2e5fwevL4KyxUVXuIdNXy1ns3ICJQUVpHW3sXJpOJXD7PzPw8c7kc9YcP07NKnf2H8Xg8PO/x\ncFySiEajJJNJoOAzLi0tXbMz1ZPg1tAw5ur1K3DWtrbz1tlfMzo8veIsPJfLM343zqE9T7YS6tPM\nlhs6bPgEO9jQQWVnCYVC/PydS5R1P7/MeD9KYHyUwdG7REUtONzobA40Wi1SLsvIh6+TjNyhzOeg\ngjQNJSZS2Sx3F3LkdOUYDPbC6qWSw+vQUllqw2G1MjkwREMoA1IKb8MsleUOcvk8b10fZDrXgMbc\niKA3Yg5HKLEtTSwKRZJMDgm4DQJl+jlOtFdRsgF3QDqb5Y333uaDmQD1nYe4ciOOUd+B0WghmZ5C\nr7/JH/yzerraa5Y9FIZHZ3gnIVPdvbwmfd9AiMrGYyzcuctnPNXLMmZzuRxjY2MEZgbJ5VKIog4E\nK3JOZnZ4GCGXA0VBEkVqOzpobG2lpGTlpr7PGn/zm9ewHX1h3WsMYODDs5TO32DPYQ/+qtLF5LXg\nXJjB3jlqyg7R3rZzTVGeZh5rQweVnUWSpMIKfd8oM3NRZEXBatbT2eSnob5mWw1cV0JRFN67cA1z\nTdeGbixvVQ3eqhqiC/PEIwuEw7Pk8nm0okg4n0BvFvn6/r3kJIlIIoFVEHi+xYZGEMjfixHXiuKS\nbFJffS0DUxc5XupnZHgUsy7PO+cnuDDswFxXhctTSnxqGnsyhOhVsFotiFotCgqzczmqy1pwWayE\nY/P8w6WbvNxRSqVn7dA3o15Ps9+LXJLA2pAkmyvHaRfR6rJYzH7SGRupdGDFGb3f54YPesm21Cxr\nZScrkEul0AbDVKzQBEGn09HQ0EDDCgk40smTZDIZFEXBYDA8ld3Pt0OhH+zGXDcWi4VDNaeJhIKc\nuz2AwQS5rIxZ76Gr4XNUVq7c6Hij5HI5JiYmyOVylJSUPNZQySdBcV0pu8BO+OFCoRCvvnORmOzC\n6m7F01aCRqMhm07x8fAYH904x+FOP9172rftw8zlckxPTzMxMUH/dJj21rXbyumkNDnxgX52lxu7\ny839IK7owjy9o5fx6iqIx+I4XU5Mj9SM0a7i3hC1ImKFh/B8jOEbeT68PErOtIfGpnbmpBw2azlS\nRkLMKgTnZUILQcq9dmbDObQ5N87SwuKl0+bGqD/I725e4ks9ImXrtPEymuzkonksZjMNDZWYH6qP\nLklpkklpxe/p9TqO1ng4e+EWvv2tmCyF0D5FUYiEUuhCfXy2uX3TBlgUxceSwPW0+IjdVguRcBjH\nBiK95FiE8s4mWhwtZLMHSafTaLXaFX+fzeqXzWb57W/fYmoqi0ajR1Gu8PLLB2loqF//y08pqgHf\nZUKhEL/63UWM5fvwu5bOBgwmM76aVvK5Bj7svYgk3WD/vo01/12JyclJbrz9Oh45TXB0FIPsoPe3\nKWqOfw6bc2uv6zNTowg2Ay6TjZlQGKdrcy3ebN5SXn3zdWq1bQxPOfE2VJGXQJQkcvksGq0eBQGT\n2UEiqeP8pSlKzNXsqatGeCgpxmgwY3fv4d2+S3z1oBX9Gn5fk8VGPCfQVO/i3XNzGHWWQm12RSEW\nn6KhbvU6MK0NFWjFGT4+d5VZuw3RbCIxHyHbH+OVb/0zamtqN6X/p4E9dTX8ZmxkXQMemZvDb9Au\nlmjW6/U7Go9+584A09MyVVUFH3omk+addz6hpqb6mX3rUeNxtsl2ZjiKovDG2cvovT3YXau/yml1\nOvzNz/FxX2jFBhsbIRwO0/vGbzhWamZ/bSUWvYnDLS3sM8iMvfdrcpmVe2s9PPteiUQmjiLnsNoc\nJDN5ZGnl2etqzM9HCGdNjMXz1FWdRpNqZGhAYXI0zsz0NPFElplwnLsjEUaGRHSpPRDTgbI8fttq\ncRATqukdn1rznIJWS1bnxOd10VgbYWrmEpPTg0xOX2JPe5bqyrUNTWNtOd8+0cErFQ5esGjoROa7\nn//mU2e8n4bZNxQSw9zJCKGpyVX3yWWzRG/fZH9z44aPu1n9otEEBsODkFODwUg+Lyw2ZXkWeTYf\nO0VCIBAglDZTWbu2GwPuvWZ7mui9Pbpiqdz1GOrrpdGkwWY2k8lmyCoCNp0Ol8NBZXySuYkRKhpa\nNn3cfD4HslzwGev0hUJMG3QHZDMZQqEciqAjKtnwmFxYgBJcjAYnWQjWYTKZCEwlaHV4KXfaEBCI\nRWeIRKIrLvKVuqq4MTFKZ420qusmlE5T23WYkfF5jh9upKM1Tiyewmb143JubK1BFEV85SVkszn6\nhyXq6jdueHaLfD7P5OQk0ViIXD6DTmvAYXfjXyF+fCcRRZHPHznEr8+dZyoeo7S6Fv094yvLMguB\nGZKD/bxQV4nfv3JJhJ2grKyEK1cmkWUvGo2GaHQBm033WGu7PG5UA75NtuNn7L09iqmkZv0d7+Eq\n9THQd4sj98qNboaFyTFa7r2a5vN5hIdKmbotZoKzk7CCAX/UB/4oep3hQfElQbukENO6Mi1EURQr\n0XgSn+NBSriAgMlgRl9SgdPphZyEMj+16DIxGB3MBGZwlbiWuFHuy5PVlDEbDlOxQpMBWZaZURRO\nnf4clz76NW63RKnLumHD/SjX+2aobjrxVBqB+9dmIpFg8G4/49M3cZXmcZbosGhF8nmJ0UCOG316\naiq7aKhveWx62O12vvb8CfoHB7l2/j0yBjOCKCIn4tQ7bXTv7cTr3XiN/of12ygNDQ10dwe5ceMG\noqjHaJR45ZXnt9wc5WlANeC7SDCcwFK2cZ+xRqNB0NtIJBKbvtG0egPZfBoLBQPJQ+FJ+XweQbc1\nX6PL5kaayJHJbv41dGEhgZQ3omS1mIxLQwCzgOVeES1nWQ2zs6PYZAlRI6LXm4hFCwuy+hXk1ugc\nzMcCKxrwu7OzlHV24na76dj7GW7deoNDXbbF7vabYXA4QEKuYl9rx/o77xLBYJALl1+lolbm6KlS\nDIaletbWFWqwjI5c5d0P+jh84HO41lkE3iomk4m9XV10tbURi8WQZRmTyfTEKnAKgsDx44fp6moj\nm83icDgeS82XJ8mz++h5StiOn1GWlWUzyPVQ2FpcfUVLO6PzYaCQwUc+i6IoKIrCeDyNq3plF8B6\nPnBvZS1COEMqmQQpu6mkkXxeJjk5gxkbet2Dm1hBIQ0YDIV/MxmtGP0tjC3MEE5GmI0GCSZiTAfn\niSYT5KSlpWxNBivBWHbZ+RbicaYNBroPFtrt+f1+KuuPce5ygHAkvmG5ZVnmVv8k4/NuDh09/dTO\n4FKpFB9f/jWd+800NVcsM973MZkMtLb5ae0W+eiTXy/Wh39caLVaXC4Xbrd7W8Z7q/eew+HA4/E8\n88YbVAO+qzhtJpLJjd8siqKg5DY/+waora9nwVlO79gUkixjNeqIRiP0TUyQqmzB6dnc6+t9DEYT\n1f4mpgIzaOT8pm6KXDaDMBvFbFrqvkikE+gdHrSijryUIzg/SSARpler41ImxajFwYTdS69g4+NQ\nmvdGpuidniGaup+BKJKTlj7kIokE16NRDnz2s0ta4zU0NtG696tcuJmn9/YUqdTqbxKKojATWODs\nx5OkxE6OPf+FbT7AN+5u2sqxL1x6k/YeM273xrorlZW5aOrQceHS249NLpWdRXWhbJPt+MDbmysZ\n+XgMl3tjxjOyMEelW7+lpB6dTsfRz71C/43rvHXrOlPJLAMLk9Sc/AINjavHl6/nAwfo2necm//1\nTeoPNGy46W4+nycxMkaNUM5dcijKgyJFoWwKV103sdg8w7NjZK1OTFVtVNb3EJodIRWdx2Kz4vb6\nEAUNkiwxE4swEQhQa4xRYhTQGx7MTUbn5hhRFA585SvL/KzpdJqKigrc7v+Ngdu9nL10DYd5HqcN\nrGY9giCQzeWIxCSCETDZamjd9/KWFpIfJhgM8o9vXaDS4+DlF49t61grMTMzg9mWpaxs/QXyh6nw\nuxkZHCEYDD71SS5PS5z7bqIa8F3E7/djUvpIxqOYrWvPkhRFIRoY5NTx2i2fz2Aw0H3gIF379rOw\nsMDP37mIr7F92xEIdmcJ7XVtTN+8SU2lH7tzbV2ymSyT1/o46SolFJWxZ3RkskmMBiuRZBTZ7iGe\nijGRimH2N2M3Pgj9cnvrmRMgmUuykEhgN5nQi1ocjhJkm5OR+RnuDl+jrUtiMhhkPJVCX1/PqePH\n13zwGQwGOvfspa1jD8FgkEg4zFxsHkVR0OlNlNSU0lhSsmMZseFwmIjsQAlElpSc3SnujtykvGpr\n7onKWjNDI/2Ulh7fUZlUdh7VgG+T7cwARFHkM8c6OfPOBYT6w5jMKxsHRVGYHLpOW4Vm26nEUFgM\ndbvd7K0p49pQPxVNqy/CrTf7BpgdH+alg3vIBj1ceesczqZa7JXlOEuWLtAm4wlCUzPIk3Mccnpp\naPfx/vw1bAkDU5kwgqgjqMjorE4mMknsVe0ImkcNm4zRpKGlZx/pZJrp2QCkUugBEZBNNqbI8YvB\nUb7Z2cGevXvXbM7x6PiJoojX68Xr9RKLxRgaGiMcSyMT29HFvbq6Or4gKzidTTtuvLPZLOHoGHsr\nq9fdV5KkezXBZTQaAYPBgL/SzTu3biPLR59a/z48PXHuu4lqwHcZv9/PF0/KvP7hORZMVbjLazEY\nCz5uWZZZCE6TnB+ivVLP8SMHdrQc6L7uDoZ/9x4Lc6W4tugDT0QjCIE7HP/scXS6g+g0GhK3b5NZ\nGGJEIyEaDSAIyNkclozEXmcpVU2dGO4tdnZ0VDEdvEMs2EcIE5bqNsYSEWzVHcuMt6IoRKMBfOVG\nbFY7NqsdT1kZuVyOTCaDJEvk03FanC207fkcgpjYdGjafa5evcX5i1NodNXojT6y6RgffXKewwcq\n6OnZftSJKIo0Ny8virUTZLNZ9AbWvFZSyRTTs9NMhyYRjYXSvYqikEvlcZpKSMQVstmsaiSfclQD\nvk12wg9XXV3Fd9wl3B0a5UrfWebzWhA0IGVoqnLR/kITXq93x2s56/V6Pn/iIP/wzgUWlD24ypb7\nddfygccjC0TvfMJXjnVjuddU4cUvfpELTieRvj46rVYMen3BDSGKWEzLmxvbnU6qGqy8OTWI1fkC\nwUQYo7cejbj00sxLWZLxWcrKBCr8S+XU6XSL0S/B0AAde1vxNzRy6+L7NE1OrpkcstL4DQ0N8+GF\nBfy1LyA+JEc+X8+HFz7Gbh+mvn798qi7iSAIZNNa9MalETqKojA6NspEaAxbmZmqTh86/YPIIVmW\niSxEGZ6/yxtnX+czJ04/lTHuoPrAYZvlZL///e/z61//Gr1eT0NDAz/96U8X6xgsnqDIy8nu9EUk\nyzLpdBpZlne8FsRqhMNhXv/wEiG9B299G9qHQgFXMuCyLDM7MoAhPMpnj3SvOMsdHR3lxocfoo1E\nKNXrsZvNBQMOZPJ5YokEoVSKBY2Gqj17MNls/Pj/OcOQsA9X7SFErR4BAUnKk5ei6HUZKiqcuEtK\nVn2QxeYnsGrucvDFE2g0GiLBOewzfXz5pZOr6v7o+CmKws9/+TaK7gAW6/I+m/F4GDF3iW9948Wn\ntmdqJpPh9Xf+O8eeb8BgWlraYGBogLnMDFVNFavW/5Akmfd/N0N9y0ESw1k+c+zlp9KIF7sB34jt\n3JYBf+ONN3jppZfQaDT84R/+IQA//vGPNy2Eyu6Tz+e5dqOXS3enkB1+bB4fZptj0ZhL+TzJeJRY\nMICyME6nv4SDe7uWhOQ9iqIozMzMMD0+zvzkJPGFhULJVJMJl8+Hp7KSqqqqxZvwr//Xz3lzQMBQ\nfpC8pEVRQKvVUOKyYrFa0azRSisRnkWOXuXIZw5jfqh2+MTHb/Odk/twOjeWMJVMJvnv/+85/LWf\nWXWfyZE3+b++c/SJJaBshbMfvkplQxRv+YNyA9Mz0wyHBqluqUQUV/8tp8dDzE576H7uAONDk+TG\n4fTJzz61D6xi5bHXAz99+vTi50OHDvHLX/5yO4dT2UW0Wi379+6ho62ZkdExRqbvMHU3Qk4u3LRa\njUKZ00ZXuZv6Q8cWXSZrIQgCPp8Pn2/1Hof3kSQJ2Wjl+dNN3Lg8iKGkC6trff+1IsuEZwbQy6Mc\neuHgEuMNIDjLCIVCGzbgxUJD7R4GR19bNOCKojA6PUJ5S9maxhtgYiRFfUvBRVRV7+fGVKFN3FbX\nE1QeHzvmA//JT37Cd77znZ063DNDsb3GGY1GWluaaW0p9CWMx+OLTQYe5wwsGo2imGxUNjZhLynh\nxoVrBEdGMDpqsTg8CI9EQ0j5HPHQJLnYMNXVFpp7Ti4WSHoYg83J9Pws9auUfH50/MxmMy6HQDwe\nxmpdbvTj8TAlDuGpdCk8jM/no+9OCcFghNJSBwsLYTDKmMxrX6tzMxHyOQfusgdlCEprXQyM3H7q\nDHix3XtbYV0Dfvr06RVLmP7oRz/iS1/6EgB/+qd/il6v57vf/e6Kx/ijP/qjRX/b0aNHOXny5OIP\nn06nAZ7Z7fulKJ8WeXZ6W5IkJElaXCTcyvHy+TyxWIxcLgcUuq6479Upub9/JpMBvRFdPo3bbuHw\n6edZCEwTGr1LePY6obQRNAZKTICcIp5K4q8po/G5NiwOJzlt4Xy6fOF497ftepF0snDeleRbafwO\n7K3l1TdvYKw9jMlY8CHn8kby+Rzp6C1OHq1dfJjt9vistd3ZdoRr19+mrStLYGEKe5kVOV148GiM\nKYAl2wvzcUZ7dXR2Pbf4e8lp8Lg8XL/Vt3jsp0W/Ytt+9913efPNNwE2XJ982z0xf/azn/Hf/tt/\n46233lrxaaj6wD+9RKNRBobvMDQ9iLFEh2jQokgyyVAKt8lLS23rYoTIzMwMZ26OU9F1cNlxJEki\nFYuSy2UREDCYzRjNlg29EUTng5QGB/jsySObkv3q1VucvzSFRluN3mglm44j58c4vH9nwgifFIFA\ngIvXXiMm3aT5aCV2x3LXVzabZ2o0xPiwQOf+47jcy988br7fz6mu0586V9Ru8th94K+99hp//ud/\nznvvvfepf5VRWcrU1BTnbp7FVe+g48Vm9A+FqimKQjAwz/mB96mcqePg3oOFxdBsesVjiaKI1bm1\nJJpsJo3VuPpC62r09HTQ0FDN8PA4sVgAm81IXd1hbBtonPw04fV6OXnk6/z0/5tl4Z0glXVRHC49\nolZEyksszGeZDwh4fI3sP1aH2bLywqwgCo+1dovK1tiWAf+X//Jfks1mFxczjxw5wn/5L/9lRwR7\nVih2P9xW9JudneXDW+/RdKQOq235jE8QBDzlpbjLSui/NMClawL79uxHSBVKjO5k9l82HqG8Ynk4\n4H3W0s9ms7FnT/uOyfKkua+bzWajtXUP9mYDiXiCcCiMlM+j1emwO500d5avW0VSykpPXduxYr/3\nNsK2RmRgYGCn5FApEhRF4fz1c9Ttr1rReD+MRqOhZV8jN97vpzZUh7/ETmg+iNOzuQJMa8oTnsXd\ntXfHjvesUuGuYCo0Qn1bLbB+iv3DJOJJNDntjtWBUdk5nt5CB88IxT4D2Kx+gUAAyZTFWbL6rPdh\nRFHEW+9mYOQOexpriE+PbF7IVYgE56gwi2v6bYt5/B7Wra6mnvB4HGmTPUsBpkcCtFS3P3V1UYp5\n7DbK0zUiKs88A6O38dRursN9md/DRGgMt9uNKxclGprfthyKohAZ7mNfyyrxg58yLBYLFQ4/02Ob\na4qdSWeITiaora59PIKpbAvVgG+Th0OripHN6hdJRLA7N7fQJ4oieouWTCbDiwf2EL5zFSmfX/+L\naxAYHqDDZVi3emMxj9+juvV07GNhIM787MYekNlsjr4Lg+xt2P9Uxr0X89htFNWAq+wohcYMm0/4\nETSFKIeysjKO1Zczef3Clo343MQY9oUxDu/v3tL3ixWr1cqpgy8xdXWe8aGJNd0p4VCEWx/20+bp\npKmx+QlKqbIZnq5l5WeQYvfDbVY/o95EJp3FZN7cjC2Xyi0W7urp6kCWb3D+yoeUtPRgsW/Mny5J\nEoG7/ZTEZ3jl+SMbkr2Yx28l3VwuF6ePfpbrfde4NtCHo9KCy+tEp9MiSTKJaILg6AIm2cqRppM7\nUn/+cVHMY7dRtp3Is+4J1ESeTxUDgwMMJG7R3N2ALMksLCwQDAeJJKKksykUBQw6PXaLHZfNhafU\nQywaJ3gjxudPvbLkWBMTE7x9uZeUswJXZS0my8pREJIkEZqeJD05yF6fk/3dnUXRsPZxk0qlGB4d\nJhCaJpvPImpE7GYH9dUNT307tU8Dj70a4U4J8SxT7LGom9Uvm83yD2/9Ak+Hi/H5cQSzgNVtxWQx\noTcUekzmsjlSyRSJcIJMKEN6Isvpji/Q2Ni47HiZTIa7wyNcGRglrjGgmB0IRguCRoOczSAkIwjJ\nCK3lbtqb6jZteIp5/IpZNyh+/R57JqaKyqMoikJ8Ic2t989y6KsHV8zs0xv06A16HC4HU0wzdm2G\nG0M3KS0tXRbyZzAYaG9toa2lmWg0SiQSIZ5IIsk5TAY9dnsDTqdTnXGrfCpRZ+AqO0Ymk+Gtc2+B\nTyAWjxLKzVLfU43BtDyVXZIkZoYDREdSHDx8mGQ8yez1AC8dfGlHe0+qqDyrqC4UlSfKex+9R9KV\npLa1DkVRGL4zxPDIXXQukRK/A71BhyTJxObjRCbilDq9tHW1YzQVXoPnZ+cJXpvjledfUWfUKp96\nVAP+BCh2P9xG9RsZHeGT8U/oONa5JIxQkiRmp2aZDQTI5jJoNCIOuwN/TeWKkSpDt4bwZEp5bt9z\ny/72OCjm8Stm3aD49VN94CpPBEVRuHrnKrWH6pbFgIuiiK/Kh69q/a48ADWtNdx86wbt8Xa19oaK\nyjqoiTzbpJhnALAx/WZmZpAsMlb79g2uKIo4qh0MjQ5t+1gboZjHr5h1g+LXbyOoBlxl20zPTWP3\n2dffcYOUVngYn5vYseOpqBQrqgHfJsVej2Ej+s1F5rBtsv7JWlhsFmKp6JYq522WYh6/YtYNil+/\njaAacJVtE08lNp06vxaCIKAxiOoNqqKyDuoi5jYpdj/cp02/ZDLJzZv9DA7OYDLp2bOnjvr6+i0V\n6NptPm1j92lEnYGrbBuLwUwmndmx4ymKgpTJF/pkPkHS6TRnzrzD1as59PpOUqkaXnttkIsXrz5R\nOVRUNopqwLdJsb/mb0Q/t8NNNBzdsXMm40msBusT6cH4sH537gwSjbrw+RowGMzYbC78/h4uXx4j\nkUg8dll2GvXaLH5UA66ybSo8FcRmds6AB2eC+Ev9O3a8jTI5GcJqXVoMSxRFwE44HH7i8qiorIdq\nwLdJsfvhNqKfz+dDjigkE8ltn09RFMKjCzTUNGz7WBvhYf3sdhOZzPKZtiynnslxfhZl3gzFrt9G\nUA24yrbRaDR01XcycmNk28caGxijyl6Fw7GxJg47SVtbA9nsOMlkHCg8TAKBESorDbjd7icuj4rK\neqgGfJsUux9uo/o1NTThyNmZHJ7c8rkiCxESI3H279m/5WNslof1Kykp4ZVXeshmbzI19QlTU+eo\nqkrwmc8cfWLy7CTqtVn8bLmY1R//8R/zj//4jwiCgNvt5mc/+xlVVVXLT6AWs3qm2Yx+yWSSN869\ngbXRSkXt5nzY4VCYsYtjvNBzirKysq2IuiVW0k+WZaLRKDqdDovF8sRk2WnUa/PZ5rFWI4zFYths\nhey7v/zLv+TatWv89V//9ZaEUCkekskkZy+cJW1NU9dVj96wdllYWZYZuzNKcizJyb0n8Xg8T0hS\nFZWnm8dajfC+8QaIx+NqDz0VAMxmMy+ffJne273ceucWpnITbn8pVod1sca3JEnEo3EWAiEiYxFq\nSmp48fkXn3jct4rKs8626oH/8Ic/5H/8j/+B2Wzm/Pnzy9phQfHPwIv9NW47+mWzWcbGxxgLjDEf\nnSePhCCAIkGJzUWFu4K66rpdLRtbzONXzLpB8eu3bRfK6dOnmZmZWfbvP/rRj/jSl760uP3jH/+Y\n27dv89Of/nRFIX74wx8uJmUcPXqUkydPLv7w9xcintXtSCSCwWB4auR5mvXL5XKk02m0Wi0mk6no\n9Hvath9e5Hsa5FH1W3v73Xff5c033wRAq9XyJ3/yJ0+mI8/Y2BivvPIKN2/eXH6CIp+Bq6ioqDwO\nNmI7txxGODAwsPj5zJkz7N27d6uHUlFRUVHZAluegX/zm9/k9u3biKJIQ0MDf/VXf7Vi+Fexz8CL\n3Q+n6vfsUsy6QfHr91ijUH7xi19s9asqKioqKjuA2pVeRUVF5SnksfrAVVRUVFR2F9WAb5Nir8eg\n6vfsUsy6QfHrtxFUA66ioqLyjKL6wFVUVFSeQlQfuIqKikoRoxrwbVLsfjhVv2eXYtYNil+/jaAa\ncBUVFZVnFNUHrqKiovIUovrAVVRUVIoY1YBvk2L3w6n6PbsUs2655HJKAAAFr0lEQVRQ/PptBNWA\nq6ioqDyjqD5wFRUVlacQ1QeuoqKiUsSoBnybFLsfTtXv2aWYdYPi128jqAZcRUVF5RlF9YGrqKio\nPIWoPnAVFRWVIkY14Nuk2P1wqn7PLsWsGxS/fhtBNeAqKioqzyiqD1xFRUXlKUT1gauoqKgUMds2\n4P/pP/0nNBoNoVBoJ+R55ih2P5yq37NLMesGxa/fRtiWAR8fH+eNN96gpqZmp+R55jh79uxui/BY\nUfV7dilm3aD49dsI2zLg//bf/lv+7M/+bKdkeSY5d+7cbovwWFH1e3YpZt2g+PXbCFs24GfOnKGy\nspI9e/bspDwqKioqKhtEu9YfT58+zczMzLJ//9M//VP+w3/4D7z++uuL//ZpjTTJ5/O7LcJjRdXv\n2aWYdYPi128jbCmM8ObNm7z00kuYzWYAJiYm8Pv9XLhwgbKysiX7NjY2cvfu3Z2RVkVFReVTQkND\nA4ODg2vusyNx4HV1dVy6dImSkpLtHkpFRUVFZYPsSBy4IAg7cRgVFRUVlU3w2DMxVVRUVFQeD08k\nE/OP//iP6e7upqenh5deeonx8fEncdonxve//33a2tro7u7m61//OpFIZLdF2jH+7u/+jo6ODkRR\n5PLly7stzo7x2muv0draSlNTE//xP/7H3RZnR/nn//yf4/V66erq2m1RHgvj4+O88MILdHR00NnZ\nyV/8xV/stkg7Sjqd5tChQ/T09NDe3s6/+3f/bvWdlSdANBpd/PwXf/EXyve+970ncdonxuuvv65I\nkqQoiqL84Ac/UH7wgx/sskQ7R19fn3L79m3l1KlTyqVLl3ZbnB0hn88rDQ0NyvDwsJLNZpXu7m6l\nt7d3t8XaMc6ePatcvnxZ6ezs3G1RHgvT09PKlStXFEVRlFgspjQ3NxfV+CmKoiQSCUVRFCWXyymH\nDh1S3n///RX3eyIzcJvNtvg5Ho9TWlr6JE77xDh9+jQaTeGnPHToEBMTE7ss0c7R2tpKc3Pzboux\no1y4cIHGxkZqa2vR6XR8+9vf5syZM7st1o5x4sQJXC7Xbovx2CgvL6enpwcAq9VKW1sbU1NTuyzV\nznI/wi+bzSJJ0qoBIk+smNUPf/hDqqur+Zu/+Rv+8A//8Emd9onzk5/8hFdeeWW3xVBZg8nJSaqq\nqha3KysrmZyc3EWJVLbKyMgIV65c4dChQ7styo4iyzI9PT14vV5eeOEF2tvbV9xvxwz46dOn6erq\nWvbfP/3TPwGF5J+xsTF+//d/n3/zb/7NTp32ibGeflDQUa/X893vfncXJd08G9GtmFCjpoqDeDzO\nN7/5Tf7zf/7PWK3W3RZnR9FoNFy9epWJiQnOnj3Lu+++u+J+a2ZiboY33nhjQ/t997vffSZnqOvp\n97Of/Yzf/va3vPXWW09Iop1jo2NXLPj9/iUL6ePj41RWVu6iRCqbJZfL8Y1vfIPf+73f46tf/epu\ni/PYcDgcfOELX+DixYucOnVq2d+fiAtlYGBg8fOZM2fYu3fvkzjtE+O1117jz//8zzlz5gxGo3G3\nxXlsKEUScXrgwAEGBgYYGRkhm83yt3/7t3z5y1/ebbFUNoiiKHzve9+jvb2df/2v//Vui7PjBINB\nwuEwAKlUijfeeGN1m/kkVlS/8Y1vKJ2dnUp3d7fy9a9/XQkEAk/itE+MxsZGpbq6Wunp6VF6enqU\nP/iDP9htkXaMv//7v1cqKysVo9GoeL1e5XOf+9xui7Qj/Pa3v1Wam5uVhoYG5Uc/+tFui7OjfPvb\n31Z8Pp+i1+uVyspK5Sc/+clui7SjvP/++4ogCEp3d/fiPffqq6/utlg7xvXr15W9e/cq3d3dSldX\nl/Jnf/Znq+6rJvKoqKioPKOoLdVUVFRUnlFUA66ioqLyjKIacBUVlf+/nTogAQAAABD0/3U7Ah0h\nUwIHmBI4wJTAAaYEDjAlcICpAHrHmB6NaClTAAAAAElFTkSuQmCC\n", "text": [ "" ] } ], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "A weakness quickly becomes clear, however: the embedded figure is a simple static PNG image.\n", "\n", "This is where mpld3 comes in. Using the simple ``mpld3.display()`` command, we can create a fully interactive visualization of the same plot:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import mpld3\n", "mpld3.display(fig)" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "pyout", "prompt_number": 3, "text": [ "" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that as you hover over the plot, a toolbar appears in the lower left. This has tools to enable panning and zooming, and a button to reset the view once you've explored the plot.\n", "\n", "If you'd like to use mpld3 by default for every figure you generate, you can call the following command:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "mpld3.enable_notebook()" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 4 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Other Plot Types" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nearly any type of plot matplotlib can do, mpld3 can visualize as well. Below are some examples:" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "A Histogram" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Histogram with modified axes/grid\n", "fig = plt.figure()\n", "\n", "ax = fig.add_subplot(111, axisbg='#EEEEEE')\n", "ax.grid(color='white', linestyle='solid')\n", "\n", "x = np.random.normal(size=1000)\n", "ax.hist(x, 30, histtype='stepfilled', fc='lightblue', alpha=0.5);" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "display_data", "png": "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\nzyf/94I+cUZo9+7dXufaLen8J5VqvF6rfe//R7dzrV984XeH9WdBLfWxY8eqoqKi83FFRYWSk5Nv\nmRk/frz+68svBvPbAkBQvPnfi+yO0K3x48f7NeewgvhuZFtbmyZOnKgPPvhAY8aMUV5ent5+++3A\njqkDAHosqHvqTqdTP/vZz/TQQw+pvb1dK1asoNABIISCuqcOALCXLZfe/eEPf6js7Gzl5OSooKDg\nluPw4eD73/++MjIylJ2drccee0z19fV2R+qR3/72t8rKytKgQYN0/Phxu+P4pbS0VOnp6ZowYYJe\nf/11u+P02PLly+VyuTR58mS7o/RYRUWF5s6dq6ysLE2aNEmbNm2yO1KPNDc3a8aMGcrJyVFmZqZe\neeUVuyMFpL29Xbm5uVq4cKH3QcsGDQ0NnV9v2rTJWrFihR0xAvb+++9b7e3tlmVZ1po1a6w1a9bY\nnKhnTp8+bZ09e9aaM2eOdezYMbvj+NTW1maNHz/eunjxotXS0mJlZ2dbp06dsjtWj3g8Huv48ePW\npEmT7I7SY1VVVdaJEycsy7KsGzduWGlpaWH3829qarIsy7JaW1utGTNmWPv27bM5Uc+98cYb1rJl\ny6yFCxd6nbNlT3348OGdXzc2NmrkyJF2xAiY2+1WRMSXP7oZM2aosrLS5kQ9k56errS0NLtj+O2r\nJ7VFRkZ2ntQWTh544AHFxcXZHSMgSUlJysnJkSTFxMQoIyNDV65csTlVzwwdOlSS1NLSovb2dsXH\nx9ucqGcqKyu1c+dOPf/88z7PtLftzkc/+MEPNG7cOBUXF2vt2rV2xei1X/3qV1qwYIHdMYzW1Ult\nly9ftjHRwHXp0iWdOHFCM2bMsDtKj3R0dCgnJ0cul0tz585VZmZ43Wf1pZde0vr16zt3Jr3ps1J3\nu92aPHnybX/e+/93Pfnxj3+sTz75RN/85jf10ksv9VWMgPnKL3353zB48GAtW7bMxqRd8yd/uDDh\nhBATNDY2asmSJdq4caNiYnxfnqM/iYiI0MmTJ1VZWSmPx6M9e/bYHclvO3bsUGJionJzc/26Hlaf\nXQJx165dfs0tW7asX+7p+sr/61//Wjt37tQHH3wQokQ94+/PPxz4c1Ib+lZra6sef/xxPfPMM1q8\neLHdcQIWGxurRx55REePHtWcOXPsjuOXgwcPqqSkRDt37lRzc7MaGhr07LPP6je/+U2X87Ycfjl3\n7lzn19u3b1dubq4dMQJWWlqq9evXa/v27YqODu9rxfjzL7/dpk2bpnPnzunSpUtqaWnRu+++q0WL\nFtkda8CwLEsrVqxQZmamXnwx/M4Gv3btmurq6iRJn3/+uXbt2hVWnfPaa6+poqJCFy9e1DvvvKN5\n8+Z1W+iSTaX+yiuvaPLkycrJydGePXv0xhtv2BEjYN/5znfU2Ngot9ut3NxcrVy50u5IPfL73/9e\nKSkpOnTokB555BE9/PDDdkfy6qsntWVmZurJJ58Mu5PannrqKc2cOVPl5eVKSUnRW2+9ZXckvx04\ncEBbtmzRhx9+qNzcXOXm5qq0tNTuWH6rqqrSvHnzlJOToxkzZmjhwoUqKCiwO1bAfB2O5OQjADCI\nbZ9+AQAEH6UOAAah1AHAIJQ6ABiEUgcAg1DqAGAQSh0ADEKpA4BB/h/0N6WKnsTR9AAAAABJRU5E\nrkJggg==\n", "text": [ "" ] } ], "prompt_number": 5 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Line Plots with Legend" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Draw lines\n", "fig, ax = plt.subplots()\n", "x = np.linspace(-5, 15, 1000)\n", "for offset in np.linspace(0, 3, 4):\n", " ax.plot(x, 0.9 * np.sin(x - offset), lw=5, alpha=0.4,\n", " label=\"Offset: {0}\".format(offset))\n", "ax.set_xlim(0, 10)\n", "ax.set_ylim(-1.2, 1.0)\n", "ax.text(5, -1.1, \"Here are some curves\", size=18, ha='center')\n", "ax.grid(color='lightgray', alpha=0.7)\n", "ax.legend()" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 6, "text": [ "" ] }, { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "display_data", "png": "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\n", "text": [ "" ] } ], "prompt_number": 6 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Multiple Subplots with linked axes" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# multiple subplots, shared axes\n", "fig, ax = plt.subplots(2, 2, figsize=(8, 6),sharex='col', sharey='row')\n", "fig.subplots_adjust(hspace=0.3)\n", "\n", "np.random.seed(0)\n", "\n", "for axi in ax.flat:\n", " color = np.random.random(3)\n", " axi.plot(np.random.random(30), lw=2, c=color)\n", " axi.set_title(\"RGB = ({0:.2f}, {1:.2f}, {2:.2f})\".format(*color),\n", " size=14)\n", " axi.grid(color='lightgray', alpha=0.7)" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "display_data", "png": "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\ntmzZknO/973vfXj33XfTPjt9+jQWLlwIAFi0aBFaW1vx3HPPSesjkQheeeWVrONevHgR73nPewoe\nuwkR5nzOhtp8/q//+i987GMfQ01NjebjURQzn7XOBSPPZwCIx+PYuXMnenp68MILL6C5uVnxWFWb\nzxWXlhWJXbt2kQ996ENZn1999dXkYx/7mLT81FNPEbvdTrZv30727dtHzpw5Q9555x3yve99j9hs\nNvKLX/yCEJJSaz777LNkcHCQ9PX1kb1795L29nbygQ98oKy/5dFHHyUrVqxI+2xqaoq0traSO+64\ng/T09JDf/OY3xOv1ku9///vSNq+//jpZtmwZOXToECGEkLNnz5IHH3yQvPHGG+T8+fPk97//PVm+\nfDm5+uqriSAIhBBCDh48SL7//e+To0ePknPnzpEnnniCtLe3k9tuu62gMScSCbJ69Wry/ve/X0qh\naG9vJ5///OelbS5fvkyWLVtGfvvb36btGwwGidfrVVQy+v1+smnTJrJq1SrS29tLBgcHpb9YLFbQ\nGHfs2EFWr15NDh48SF599VXS3d1Nbr311rRtli1bRh555BFp+fDhw4RlWfLNb36T9Pb2kl/96lfE\n5/ORH/3oR9I2Dz/8MPH5fOTJJ58kx44dIzt37iTt7e1ZaWWbNm0y1dcaYc7n4uYzxcsvv5ylTi4E\nxc7nfHPB6PM5Ho+TD3/4w6S9vZ0cOXIkbXzhcDjt2NWazzPGKN91112KOWqPP/44sdlsaflkR44c\nITt37iTz5s0jLMuShoYGcsMNN5Bf/OIX0s1NJzH9s9lspLOzk9x9991kdHS0rL9laGiI2O120tvb\nm/b5sWPHyNatWwnHcaStrY3867/+a9r6F154gVgsFvLiiy8SQgjp6+sj1113HWloaCAOh4N0dXWR\nL37xi2RiYiLtXGzatInU1tYSp9NJli9fTh588MGsG3DBggXkrrvuUh33pUuXyIc+9CHicrlIQ0MD\n+cIXvpA20eg5/dnPfpa233//938TlmXJ4OBg1jFfeOEFwjAMsVgsaddD/jsJIeS6664j27ZtUx3f\nxMQE+dSnPkW8Xi/xer3k05/+NJmamkrbhmEY8uCDD6Z99vvf/56sWbOGcBxHli1bRn74wx9mHfsb\n3/gGmTdvHuE4jmzbto0cP348bf3Q0JCZp1wAzPlc3Hym2LVrF1m1alXOMZVzPqvNBaPPZ/qbMseX\n+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\nlyM5ORmbNm2Ki+AMBoPBYIw1OEK8AsIMBoPBYDASAuvoxWAwGAyGQmBKmcFgMBgMhcCUMoPBYDAY\nCoEpZQaDwWAwFAJTygwGg8FgKASmlBkMBoPBUAhMKTMYDAaDoRCYUmYwGAwGQyEwpcxgMBgMhkJg\nSpnBYDAYDIXAlDKDwWAwGAqBKWUGg8FgMBQCU8oMBoPBYCgEppQZDAaDwVAITCkzGAwGg6EQmFJm\nMBgMBkMhMKXMYDAYDIZCYEqZwWAwGAyFwJQyg8FgMBgKgSllBoPBYDAUAlPKDAaDwWAoBKaUGQwG\ng8FQCEwpMxgMBoOhEJhSThDnzp1Dbm4u+vv7Ey0KY4SYzWaUlJTg8OHDiRaFkSDYeB47JHo8jxql\nfPfdd4PnefA8D7VajeLiYtx1111obW31Wffw4cO47bbbUFRUBJ1Oh4kTJ+Laa6/F22+/DUIIAKC+\nvl7aH8/z0Ol0qKysxLPPPhuX3/OrX/0K9957L1JTU6Xvjh07hqVLlyIpKQnFxcX4zW9+E3I/Fy5c\nwO23346CggIkJydjzpw5eO2116Tl9fX1+P73v4/JkycjKSkJkydPxmOPPQaTyRS2zI2Njbj++uth\nMBiQk5ODhx56CFarNeg2b775JlauXInc3FzwPI+dO3f6rGM2m/Hggw8iJycHBoMBN9xwA1paWsKW\nr6enB3feeSfS09ORnp6O7373u+jr6wu6jc1mw2OPPYaysjLo9XqUlZXhl7/8Jex2u9/1161bB57n\nPe4TrVaLhx9+GI8//njYMo9X2Hj2j5yxEMl97o9IxjMAnDlzBjfddBMyMjKQnJyMefPm4fTp09Ly\nUM8kuUTyO3/7299iwYIFSEtLQ25uLtasWYMTJ054rON+n7j/PfDAAwAUMJ7JKOHuu+8mK1asIO3t\n7aSlpYVs376dlJSUkKuvvtpjvXfffZdoNBpy7bXXku3bt5Pz58+Tmpoa8uKLL5L58+eTlpYWQggh\n58+fJxzHke3bt5P29nbS2NhINm3aRNRqNdmyZUtMf0t7ezvRaDSkrq5O+q6vr4/k5eWRW2+9lZw4\ncYL861//IikpKeTZZ58Nuq/ly5eTBQsWkH379pHz58+TZ599lvA8T3bt2kUIIaS6uprcfffd0rl4\n//33SVFREbn33nvDktlms5EZM2aQ5cuXk0OHDpGPPvqIFBYWkgcffDDodq+88gp56qmnyCuvvEI4\n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\nRU5ErkJggg==\n", "text": [ "" ] } ], "prompt_number": 7 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Plugins" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One of the key features of mpld3 is the plugin framework. Plugins are a way to specify additional interactivity for your plots. A number of plugins are built-in, and it is also possible to define new, custom plugins for nearly limitless interactive behaviors. For example, here is the built-in Linked Brushing plugin that allows exploration of multi-dimensional datasets:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from mpld3 import plugins\n", "\n", "fig, ax = plt.subplots(3, 3, figsize=(6, 6))\n", "fig.subplots_adjust(hspace=0.1, wspace=0.1)\n", "ax = ax[::-1]\n", "\n", "X = np.random.normal(size=(3, 100))\n", "for i in range(3):\n", " for j in range(3):\n", " ax[i, j].xaxis.set_major_formatter(plt.NullFormatter())\n", " ax[i, j].yaxis.set_major_formatter(plt.NullFormatter())\n", " points = ax[i, j].scatter(X[j], X[i])\n", " \n", "plugins.connect(fig, plugins.LinkedBrush(points))" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "display_data", "png": "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\n", "text": [ "" ] } ], "prompt_number": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Selecting points with the brush lets you quickly explore the relationships between the points." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "For More Information" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "More examples, documentation, and information can be found on the [mpld3 website](http://mpld3.github.io). See especially the [Example Gallery](http://mpld3.github.io/examples/index.html) and the [Notebook Gallery](http://mpld3.github.io/notebooks/index.html). If you are interested in contributing, the source of mpld3 can be found on [GitHub](http://github.com/jakevdp/mpld3)." ] } ], "metadata": {} } ] }python-mpld3/notebooks/custom_plugins.ipynb0000644000175500017550000065203412410130733021273 0ustar debacledebacle{ "metadata": { "name": "", "signature": "sha256:9c0177def85f24a70b579bb05088f8eccb50700b55f738e3c0227de6dfec149f" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Plugins in mpld3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One of the most interesting features of mpld3 is the ability to add plugins to your plots. Plugins are objects which define new, interactive functionality for your visualizations. There are several built-in to the mpld3 package, and there is a well-defined API to create your own. We'll briefly walk through these below." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We'll start with the standard set of imports for working with mpld3" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%matplotlib inline\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import mpld3\n", "mpld3.enable_notebook()" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Just to make sure it's working, let's create a simple plot:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "np.random.seed(0)\n", "plt.plot(np.random.rand(10));" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "display_data", "png": "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\nQdL2tkUL6ZpYXS1//9lnMkq/7TZt49Ozbt2YxI0kNFS+v/fvd+91TORkCMHBstnn2DFg8mSgqkrq\niX/5iyR4okBgMjXtoAn+CJBhXHSRtGrdt09qvx07SsMtokDSlDo5EzkZStu2wIoVgNkMzJsXmEe4\nUfPWlBE5JzuJiHTEZpNj+w4ckIEKJzuJiAzGbJYVWXa7669hIici0pGm7PBsNJHn5OQgKioKkZGR\nyMjIuOB13377LYKCgvDxxx+7/nQiImrA3QZaThO5w+HA1KlTkZOTg8LCQmRlZaGoqOi8182cOROj\nRo1iHZyIyEPutrR1mshzc3MRERGBsLAwBAcHIzU1FdnZ2Q2ue/XVVzF+/Hh0797d7YCJiKi+2hG5\nq+Nip4ncbrcjNDS07nOz2Qz7ORV4u92O7Oxs3P//W8+ZuB6MiMgjISGy0c3V07KCnH3RlaT8yCOP\nYO7cuXVLZJyVVtLPaumVlJSEpKQk16IkImomrFYrrFYrOnSQ055c4TSRh4SEwGaz1X1us9lgNpvr\nXfPdd98h9f93LDp8+DBWrVqF4OBgjBkzpsH9zk7kRETUUO0gVynA4QCA2Y2+xmkiT0xMRHFxMUpL\nS9G7d28sX74cWVlZ9a7Zu3dv3Z8nTZqEG2+88bxJnIiIXDd4sLRxdoXTRB4UFITMzEykpKTA4XBg\nypQpiI6OxqJFiwAAaWlpHgdLREQNubNyhVv0iYh06pJLgP/9j1v0iYgMa9Ik167jiJyISMfYNIuI\nqBlgIiciMjgmciIig2MiJyIyOCZyIiKDYyInIjI4JnIiIoNjIiciMjgmciIig2MiJyIyOCZyIiKD\nYyInIjI4JnIiIoNjIiciMjgmciIig2MiJyIyOCZyIiKDYyInIjI4JnIiIoNjIiciMrhGE3lOTg6i\noqIQGRmJjIyMBl/Pzs5GfHw8LBYLBg8ejDVr1vgkUCIiOj+nidzhcGDq1KnIyclBYWEhsrKyUFRU\nVO+a5ORkbN26FQUFBXjnnXdw3333+TRgb7JarVqH0IAeYwL0GRdjcg1jcp1e42qM00Sem5uLiIgI\nhIWFITg4GKmpqcjOzq53Tbt27er+fOLECXTr1s03kfqAHv/R9BgToM+4GJNrGJPr9BpXY5wmcrvd\njtDQ0LrPzWYz7HZ7g+s+/fRTREdH4/rrr8ff//5370dJREQX5DSRm0wml24yduxYFBUVYcWKFbjz\nzju9EhgREblIObFp0yaVkpJS9/mcOXPU3Llznb1E9e3bVx0+fLjB34eHhysA/OAHP/jBDzc+wsPD\nneZcpZQKghOJiYkoLi5GaWkpevfujeXLlyMrK6veNXv27EHfvn1hMpmQn58PAOjatWuDe+3evdvZ\no4iIqImcJvKgoCBkZmYiJSUFDocDU6ZMQXR0NBYtWgQASEtLw0cffYQlS5YgODgY7du3x7Jly/wS\nOBERCZNSSmkdBBERNZ3Pd3Y2tqFIC5MnT0bPnj0xYMAArUOpY7PZMGLECMTGxiIuLk4Xq39Onz6N\noUOHIiEhATExMXjyySe1DqmOw+GAxWLBjTfeqHUodcLCwjBw4EBYLBZcfvnlWocDACgvL8f48eMR\nHR2NmJgYbN68WdN4du3aBYvFUvfRsWNHXXyvv/jii4iNjcWAAQMwceJEnDlzRuuQsGDBAgwYMABx\ncXFYsGCB84sbraJ7oLq6WoWHh6uSkhJVWVmp4uPjVWFhoS8f6ZL169er/Px8FRcXp3UodQ4cOKAK\nCgqUUkr98ssvql+/frr4b3Xy5EmllFJVVVVq6NChasOGDRpHJF555RU1ceJEdeONN2odSp2wsDB1\n5MgRrcOo56677lKLFy9WSsm/YXl5ucYR/crhcKhevXqpffv2aRpHSUmJ6tOnjzp9+rRSSqnbbrtN\nvfPOO5rG9P3336u4uDh16tQpVV1drZKTk9Xu3bsveL1PR+SubCjSwrBhw9C5c2etw6inV69eSEhI\nAAC0b98e0dHR2L9/v8ZRAW3btgUAVFZWwuFwoEuXLhpHBJSVlWHlypX4wx/+AKWzyqCe4jl27Bg2\nbNiAyZMnA5A5r44dO2oc1a9Wr16N8PDwentVtHDxxRcjODgYFRUVqK6uRkVFBUJCQjSNaefOnRg6\ndChat26Nli1bYvjw4fj4448veL1PE7mrG4qovtLSUhQUFGDo0KFah4KamhokJCSgZ8+eGDFiBGJi\nYrQOCdOnT8e8efPQooW+er6ZTCYkJycjMTER//jHP7QOByUlJejevTsmTZqEQYMG4d5770VFRYXW\nYdVZtmwZJk6cqHUY6NKlCx599FFceuml6N27Nzp16oTk5GRNY4qLi8OGDRvw888/o6KiAp9//jnK\nysoueL1PfxJc3VBEvzpx4gTGjx+PBQsWoH379lqHgxYtWmDLli0oKyvD+vXrNd/C/H//93/o0aMH\nLBaLrka/APCf//wHBQUFWLVqFV577TVs2LBB03iqq6uRn5+PBx54APn5+WjXrh3mzp2raUy1Kisr\nsWLFCtx6661ah4I9e/Zg/vz5KC0txf79+3HixAl88MEHmsYUFRWFmTNn4rrrrsP1118Pi8XidODi\n00QeEhICm81W97nNZoPZbPblIw2tqqoK48aNwx133IGxY8dqHU49HTt2xA033IC8vDxN49i4cSM+\n++wz9OnTBxMmTMCaNWtw1113aRpTrUsuuQQA0L17d9x8883Izc3VNB6z2Qyz2YwhQ4YAAMaPH1+3\n10Nrq1atwuDBg9G9e3etQ0FeXh6uuuoqdO3aFUFBQbjllluwceNGrcPC5MmTkZeXh3Xr1qFTp07o\n37//Ba/1aSI/e0NRZWUlli9fjjFjxvjykYallMKUKVMQExODRx55ROtwAACHDx9GeXk5AODUqVP4\n6quvYLFYNI1pzpw5sNlsKCkpwbJly3DNNddgyZIlmsYEABUVFfjll18AACdPnsSXX36p+aqoXr16\nITQ0FD/88AMAqUnHxsZqGlOtrKwsTJgwQeswAMjod/PmzTh16hSUUli9erUuSog//fQTAGDfvn34\n5JNPnJehfD37unLlStWvXz8VHh6u5syZ4+vHuSQ1NVVdcsklqlWrVspsNqu33npL65DUhg0blMlk\nUvHx8SohIUElJCSoVatWaRrTtm3blMViUfHx8WrAgAHqpZde0jSec1mtVt2sWtm7d6+Kj49X8fHx\nKjY2Vjff61u2bFGJiYlq4MCB6uabb9bFqpUTJ06orl27quPHj2sdSp2MjAwVExOj4uLi1F133aUq\nKyu1DkkNGzZMxcTEqPj4eLVmzRqn13JDEBGRwelr2p+IiNzGRE5EZHBM5EREBsdETkRkcEzkREQG\nx0RORGRwTORERAbHRE5EZHD/D7JYZxnQr4VpAAAAAElFTkSuQmCC\n", "text": [ "" ] } ], "prompt_number": 2 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "The Purpose of Plugins" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Plugins, in a word, are meant to add new browser-based behavior to a matplotlib plot. The mpld3 package enables several plugins by default, namely the ``Reset`` button, the ``Zoom`` button, and the ``BoxZoom`` button. Note that plugins may or may not be accompanied by buttons.\n", "\n", "To see a plot with no plugins attached, we can call the ``plugins.clear`` function and remove all plugins from the figure:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from mpld3 import plugins\n", "\n", "fig, ax = plt.subplots()\n", "ax.plot(np.random.random(10))\n", "plugins.clear(fig) # clear all plugins from the figure" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "display_data", "png": "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\n", "text": [ "" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that now the figure, while still rendered in D3, does not have any interactive elements. To recover the default interactive elements, we can add them back explicitly. For example, let's say we prefer to switch the order of the ``Zoom`` and ``BoxZoom`` tools in our toolbar:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from mpld3 import plugins\n", "\n", "fig, ax = plt.subplots()\n", "ax.plot(np.random.random(10))\n", "plugins.clear(fig) # clear all plugins from the figure\n", "\n", "plugins.connect(fig, plugins.Reset(), plugins.BoxZoom(), plugins.Zoom())" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "display_data", "png": "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\n", "text": [ "" ] } ], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that the three buttons are now in a different order than they are by default; we've customized our toolbar using the built-in plugin tools." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Beyond the Default Plugins" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are many other plugins you can use which are built-in to mpld3, and the list is growing. For example, here's a plugin that allows tooltips (i.e. information which appears when you hover your mouse over points):" ] }, { "cell_type": "code", "collapsed": false, "input": [ "fig, ax = plt.subplots()\n", "points = ax.scatter(np.random.rand(40), np.random.rand(40),\n", " s=300, alpha=0.3)\n", "\n", "labels = [\"Point {0}\".format(i) for i in range(40)]\n", "tooltip = plugins.PointLabelTooltip(points, labels)\n", "\n", "plugins.connect(fig, tooltip)" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "display_data", "png": "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\n", "text": [ "" ] } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Other available plugins can be viewed in the [example gallery](http://mpld3.github.io/examples/index.html) and in other parts of the [mpld3 documentation](http://mpld3.github.io)." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Paving Your Own Way..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "While the built-in plugins are useful, one of the nicest features of mpld3 is the ability to define your own custom behaviors. This requires a bit of familiarity with both Python and Javascript, as well as some level of knowledge of the javascript side of the mpld3 implementation. Here we'll walk through the process of creating a some plugins to do various simple tasks." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First, let's do a silly plugin which writes \"hello world\" on the figure:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "class HelloWorld(plugins.PluginBase): # inherit from PluginBase\n", " \"\"\"Hello World plugin\"\"\"\n", " \n", " JAVASCRIPT = \"\"\"\n", " mpld3.register_plugin(\"helloworld\", HelloWorld);\n", " HelloWorld.prototype = Object.create(mpld3.Plugin.prototype);\n", " HelloWorld.prototype.constructor = HelloWorld;\n", " function HelloWorld(fig, props){\n", " mpld3.Plugin.call(this, fig, props);\n", " };\n", " \n", " HelloWorld.prototype.draw = function(){\n", " this.fig.canvas.append(\"text\")\n", " .text(\"hello world\")\n", " .style(\"font-size\", 72)\n", " .style(\"opacity\", 0.3)\n", " .style(\"text-anchor\", \"middle\")\n", " .attr(\"x\", this.fig.width / 2)\n", " .attr(\"y\", this.fig.height / 2)\n", " }\n", " \"\"\"\n", " def __init__(self):\n", " self.dict_ = {\"type\": \"helloworld\"}\n", " \n", "fig, ax = plt.subplots()\n", "plugins.connect(fig, HelloWorld())" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "display_data", "png": "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\nvHnz8LvSsrKyZmLUaZfKXixevFiDg4OSpMHBQS1atEhud9KXCd9ba9eu1YIFC976+GS6mda486Gn\nEansxb8dOXJEGzduzMRoGZfq70V7e/vwX19h8W2zqexDd3e3njx5ovXr16usrEwnTpzI9JgZkcpe\n1NXV6e7du8rJyVFJSYm+/vrrTI/5zphMN9P6v0E+9DRiIv9Nly5d0tGjR3XlypVpnGjmpLIXu3bt\n0oEDB+RyueQ4zpjfEQtS2YehoSHdvHlTFy9e1LNnz7R69WqtWrVKwWAwAxNmTip7sX//fpWWlioa\njaqnp0cbNmzQ7du3NXfu3AxM+O6ZaDfTGvd0fujpfZfKXkjSnTt3VFdXp0gkkvSPZe+zVPbixo0b\nqq6ulvTPC2nnzp2Tx+NRVVVVRmedTqnsg9/vV1ZWlmbPnq3Zs2dr3bp1un37trm4p7IXV69e1Z49\neyT980GeJUuW6MGDByorK8vorO+CSXUzba8IOI4zNDTkLF261Hn06JHz/PnzcV9QvXbtmtkXEVPZ\ni19//dXJy8tzrl27NkNTZkYqe/Fvn332mfPDDz9kcMLMSGUf7t+/73z00UfOy5cvnb///tspKipy\n7t69O0MTT59U9uLzzz93GhsbHcdxnN9//93xer3On3/+ORPjZsSjR49SekE11W6m9c6dDz2NSGUv\n9u3bp6dPnw4/z+zxeNTV1TWTY0+LVPbivyCVfSgoKFBlZaWKi4s1a9Ys1dXVqbCwcIYnT79U9mL3\n7t2qqalRSUmJXr16pYMHD2rhwoUzPPn02Lp1qy5fvqz+/n75/X41NTVpaGhI0uS7yYeYAMAg/pk9\nADCIuAOAQcQdAAwi7gBgEHEHAIOIOwAYRNwBwCDiDgAG/R9h/b4XlfACjQAAAABJRU5ErkJggg==\n", "text": [ "" ] } ], "prompt_number": 6 }, { "cell_type": "markdown", "metadata": {}, "source": [ "It worked! Notice here that the \"hello world\" text *did not come from Python*, but from the javascript code defined in the plugin. The code in the ``JAVASCRIPT`` class variable is injected into the javascript which defines the figure, which we can see by calling ``fig_to_html` explicitly. If you were to copy this code into an html file and open it with your browser, it would show the above figure." ] }, { "cell_type": "code", "collapsed": false, "input": [ "print(mpld3.fig_to_html(fig, template_type=\"simple\"))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "\n", "\n", "\n", "\n", "\n", "\n", "
\n", "\n" ] } ], "prompt_number": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ "There, right in the middle of our script, is our ``HelloWorld`` plugin definition!\n", "\n", "Note also that in the JSON definition at the bottom of the output, we see the following piece: ``\"plugins\": [..., {\"type\": \"helloworld\"}]``. This is what actually tells the ``draw_figure`` command that we want to connect the ``HelloWorld`` plugin to the figure." ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "What's happening in ``HelloWorld``" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's take a look at the ``HelloWorld`` javascript code. First we have this piece:\n", "``` javascript \n", "mpld3.register_plugin(\"helloworld\", HelloWorld);\n", "```\n", "This is the first piece of code you should have for every plugin. The function ``register_plugin(key, object)`` associates a ``key`` with a given plugin object, so that this key can be referenced in the figure JSON, as we saw above with the ``\"helloworld\"`` key.\n", "\n", "``` javascript\n", "HelloWorld.prototype = Object.create(mpld3.Plugin.prototype);\n", "HelloWorld.prototype.constructor = HelloWorld;\n", "function HelloWorld(fig, props){\n", " mpld3.Plugin.call(this, fig, props);\n", "};\n", "```\n", "\n", "This piece might looks complicated, but to an experienced javascript programmer it's easily recognized as an object definition. Javascript is built on *prototypical inheritance*, which is a different approach than the class-based inheritance that you may be familiar with in Python. What these lines do is to create a ``HelloWorld`` type which inherits from ``mpld3.Plugin``, and is initialized by the specified function.\n", "\n", "``` javascript\n", "HelloWorld.prototype.draw = function(){\n", " this.fig.canvas.append(\"text\")\n", " .text(\"hello world\")\n", " .style(\"font-size\", 72)\n", " .style(\"opacity\", 0.3)\n", " .style(\"text-anchor\", \"middle\")\n", " .attr(\"x\", this.fig.width / 2)\n", " .attr(\"y\", this.fig.height / 2)\n", "}\n", "```\n", "\n", "This is the meat of the plugin: when the figure is drawn to the web page, the ``draw`` method of the plugin is called. Anyone familiar with ``d3`` should recognize exactly what's happening here. ``this.fig`` references the figure object associated with the plugin instance, and the figure object holds a ``d3`` selection named ``canvas``. The canvas is the root element within the SVG created by ``mpld3.draw_figure``.\n", "\n", "We use standard d3 syntax to add an SVG text element to the canvas, and then adjust the content, position, and style to be what we want." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, we can take a look at the Python side of things, snipping out the javascript for the time being:\n", "``` python\n", "class HelloWorld(plugins.PluginBase):\n", " JAVASCRIPT = \"\"\" \"\"\"\n", " def __init__(self):\n", " self.dict_ = {\"type\": \"helloworld\"}\n", "```\n", "The ``__init__`` function simply defines a class member ``dict_``, which is a JSON serializable dictionary that is used to pass options from Python to javascript. When the plugin is connected to a figure, a JSON representation of ``dict_`` will be put in the ``\"plugins\"`` list, as we saw in the printout above. Every plugin should have a ``\"type\"`` element in the ``dict_``, which should match the key used in ``mpld3.register_plugin`` on the javascript side.\n", "\n", "That's all there is to it!" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "A More Interesting Example: Point Information" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The above example may seem like an incredibly complicated way to add some text to the plot, and it is. The real power of plugins, though, comes from the ability to use d3 to poke around in the Document Object Model (DOM) and modify the elements based on user input.\n", "\n", "Here we'll do a more interesting plugin: we'll make it so that clicking on points brings up an alert box with information about the point." ] }, { "cell_type": "code", "collapsed": false, "input": [ "from mpld3 import utils\n", "\n", "class ClickInfo(plugins.PluginBase):\n", " \"\"\"Plugin for getting info on click\"\"\"\n", " \n", " JAVASCRIPT = \"\"\"\n", " mpld3.register_plugin(\"clickinfo\", ClickInfo);\n", " ClickInfo.prototype = Object.create(mpld3.Plugin.prototype);\n", " ClickInfo.prototype.constructor = ClickInfo;\n", " ClickInfo.prototype.requiredProps = [\"id\"];\n", " function ClickInfo(fig, props){\n", " mpld3.Plugin.call(this, fig, props);\n", " };\n", " \n", " ClickInfo.prototype.draw = function(){\n", " var obj = mpld3.get_element(this.props.id);\n", " obj.elements().on(\"mousedown\",\n", " function(d, i){alert(\"clicked on points[\" + i + \"]\");});\n", " }\n", " \"\"\"\n", " def __init__(self, points):\n", " self.dict_ = {\"type\": \"clickinfo\",\n", " \"id\": utils.get_id(points)}\n", " \n", "fig, ax = plt.subplots()\n", "points = ax.scatter(np.random.rand(50), np.random.rand(50),\n", " s=500, alpha=0.3)\n", "\n", "plugins.connect(fig, ClickInfo(points))" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n", "\n", "\n", "
\n", "" ], "metadata": {}, "output_type": "display_data", "png": "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\n", "text": [ "" ] } ], "prompt_number": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you click on any of the above points, you should see a browser alert box which tells you which point you clicked on!\n", "\n", "There are just a couple extra pieces here beyond what we saw in the previous example. On the javascript side, we have this addition to the class prototype definition:\n", "``` javascript\n", "ClickInfo.prototype.requiredProps = [\"id\"];\n", "```\n", "This tells us that the plugin expects to be passed a property named ``\"id\"``, which in this case points to the plot elements that are the subject of the interaction. This id is generated by the python script, and we can find it using the ``utils.get_id`` utility:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "utils.get_id(points)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 9, "text": [ "'el92644400590224'" ] } ], "prompt_number": 9 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This output is passed to the ``dict_`` attribute in Python, which is in turn passed to the ``props`` attribute in Javascript. Because the same ``get_id`` utility is used to find the id when the points are first drawn, we can use this id to locate the correct plot elements. Finally, we do some typical ``d3`` gymnastics and write the following:\n", "``` javascript\n", "var obj = mpld3.get_element(this.props.id);\n", "obj.elements().on(\"mousedown\",\n", " function(d, i){alert(\"clicked on points[\" + i + \"]\");});\n", "```\n", "The ``mpld3.get_element`` function in javascript essentially does the opposite of the ``utils.get_id`` function in Python: it maps from the id to the Javascript object containing the points. Once the elements of this plot object are accessed, all it takes is a simple ``on(\"mousedown\", ...)`` command to add the desired behavior." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Conclusion" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We've just scraped the surface of what you can do with mpld3 plugins, but hopefully the above discussion is enough to get you started in defining your own interactive behaviors. With a familiarity with D3, the possibilities really are endless. For ideas, you can check out some of the plugins built-in to the mpld3 library (they're defined just like this, except much of the javascript is bundled with the main mpld3 source!). There are also some interesting examples in the [mpld3 gallery](http://mpld3.github.io/examples/index.html). If you come up with something you'd like to share, feel free to submit it as a pull request to the main mpld3 gallery: we'd love to see it!" ] } ], "metadata": {} } ] }python-mpld3/mplexporter/0000755000175500017550000000000012410130733015521 5ustar debacledebaclepython-mpld3/LICENSE0000644000175500017550000000272312410130733014151 0ustar debacledebacleCopyright (c) 2013, Jake Vanderplas All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the {organization} nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. python-mpld3/visualize_tests.py0000644000175500017550000001750112410130733016753 0ustar debacledebacle""" Visualize Test Plots This script will go through all the plots in the ``mpld3/test_plots`` directory, and save them as D3js to a single HTML file for inspection. """ import os import glob import sys import gc import traceback import itertools import json import contextlib import matplotlib matplotlib.use('Agg') # don't display plots import matplotlib.pyplot as plt import mpld3 from mpld3 import urls from mpld3.mpld3renderer import MPLD3Renderer from mpld3.mplexporter import Exporter plt.rcParams['figure.figsize'] = (6, 4.5) plt.rcParams['savefig.dpi'] = 80 TEMPLATE = """
{left_col}
{right_col}
""" MPLD3_TEMPLATE = """
""" JS_TEMPLATE = """ !function(mpld3){{ {extra_js} mpld3.draw_figure("fig{figid:03d}", {figure_json}); }}(mpld3); """ @contextlib.contextmanager def mpld3_noshow(): """context manager to use mpld3 with show() disabled""" import mpld3 _show = mpld3.show mpld3.show = lambda *args, **kwargs: None yield mpld3 mpld3.show = _show @contextlib.contextmanager def use_dir(dirname=None): """context manager to temporarily change the working directory""" cwd = os.getcwd() if dirname is None: dirname = cwd os.chdir(dirname) yield os.chdir(cwd) class ExecFile(object): """ Class to execute plotting files, and extract the mpl and mpld3 figures. """ def __init__(self, filename, execute=True, pngdir='_pngs'): self.filename = filename if execute: self.execute_file() if not os.path.exists(pngdir): os.makedirs(pngdir) basename = os.path.splitext(os.path.basename(filename))[0] self.pngfmt = os.path.join(pngdir, basename + "_{0:2d}.png") def execute_file(self): """ Execute the file, catching matplotlib figures """ dirname, fname = os.path.split(self.filename) print('plotting {0}'.format(fname)) # close any currently open figures plt.close('all') # close any currently open figures plt.close('all') with mpld3_noshow() as mpld3: with use_dir(dirname): try: # execute file, forcing __name__ == '__main__' exec(open(os.path.basename(self.filename)).read(), {'plt': plt, 'mpld3': mpld3, '__name__': '__main__'}) gcf = matplotlib._pylab_helpers.Gcf fig_mgr_list = gcf.get_all_fig_managers() self.figlist = sorted([manager.canvas.figure for manager in fig_mgr_list], key=lambda fig: fig.number) except: print(80 * '_') print('{0} is not compiling:'.format(fname)) traceback.print_exc() print(80 * '_') finally: ncol = gc.collect() def iter_png(self): for fig in self.figlist: fig_png = self.pngfmt.format(fig.number) fig.savefig(fig_png) yield fig_png def iter_json(self): for fig in self.figlist: renderer = MPLD3Renderer() Exporter(renderer, close_mpl=False).run(fig) fig, fig_json, extra_css, extra_js = renderer.finished_figures[0] yield (json.dumps(fig_json), extra_js, extra_css) def combine_testplots(wildcard='mpld3/test_plots/*.py', outfile='_test_plots.html', pngdir='_pngs', d3_url=None, mpld3_url=None): """Generate figures from the plots and save to an HTML file Parameters ---------- wildcard : string or list a regexp or list of regexps matching files to test outfile : string the path at which the output HTML will be saved d3_url : string the URL of the d3 library to use. If not specified, a standard web address will be used. mpld3_url : string the URL of the mpld3 library to use. If not specified, a standard web address will be used. """ if isinstance(wildcard, str): filenames = glob.glob(wildcard) else: filenames = itertools.chain(*(glob.glob(w) for w in wildcard)) fig_png = [] fig_json = [] for filename in filenames: result = ExecFile(filename, pngdir=pngdir) fig_png.extend(result.iter_png()) fig_json.extend(result.iter_json()) left_col = [MPLD3_TEMPLATE.format(figid=i) for i in range(len(fig_json))] js_commands = [JS_TEMPLATE.format(figid=figid, figure_json=figjson, extra_js=figjs) for figid, (figjson, figjs, _) in enumerate(fig_json)] right_col = ['
\n'.format(fig) for fig in fig_png] extra_css = [tup[2] for tup in fig_json] print("writing results to {0}".format(outfile)) with open(outfile, 'w') as f: f.write(TEMPLATE.format(left_col="".join(left_col), right_col="".join(right_col), d3_url=json.dumps(d3_url), mpld3_url=json.dumps(mpld3_url), js_commands="".join(js_commands), extra_css="".join(extra_css))) def run_main(): import argparse parser = argparse.ArgumentParser(description=("Run files and convert " "output to D3")) parser.add_argument("files", nargs='*', type=str) parser.add_argument("-d", "--d3-url", help="location of d3 library", type=str, default=None) parser.add_argument("-m", "--mpld3-url", help="location of the mpld3 library", type=str, default=None) parser.add_argument("-o", "--output", help="output filename", type=str, default='_test_plots.html') parser.add_argument("-j", "--minjs", action="store_true") parser.add_argument("-l", "--local", action="store_true") parser.add_argument("-n", "--nolaunch", action="store_true") args = parser.parse_args() if len(args.files) == 0: wildcard = ['mpld3/test_plots/*.py', 'examples/*.py'] else: wildcard = args.files if args.d3_url is None: args.d3_url = urls.D3_URL if args.mpld3_url is None: args.mpld3_url = urls.MPLD3_URL if args.local: args.d3_url = urls.D3_LOCAL if args.minjs: args.mpld3_url = urls.MPLD3MIN_LOCAL else: args.mpld3_url = urls.MPLD3_LOCAL else: if args.minjs: args.mpld3_url = urls.MPLD3MIN_URL print("d3 url: {0}".format(args.d3_url)) print("mpld3 url: {0}".format(args.mpld3_url)) combine_testplots(wildcard=wildcard, outfile=args.output, d3_url=args.d3_url, mpld3_url=args.mpld3_url) return args.output, args.nolaunch if __name__ == '__main__': outfile, nolaunch = run_main() if not nolaunch: # Open local file (works on OSX; maybe not on other systems) import webbrowser webbrowser.open_new('file://localhost' + os.path.abspath(outfile)) python-mpld3/package.json0000644000175500017550000000125312410130733015427 0ustar debacledebacle{ "name": "mpld3", "version": "0.0.0", "description": "D3 Viewer for Matplotlib", "main": "index.js", "directories": { "doc": "doc", "example": "examples" }, "scripts": { "test": "./node_modules/.bin/vows" }, "repository": { "type": "git", "url": "https://github.com/jakevdp/mpld3.git" }, "keywords": [ "d3", "matplotlib", "python" ], "author": "Jake VanderPlas", "license": "BSD 3-clause", "gitHead": "ec7da08f78fb58860eb14c945d0924dc81543cde", "readmeFilename": "README.md", "dependencies": { "d3": "~3.4.3", "smash": "0.0.12", "uglify-js": "~2.4.13", "vows": "~0.7.0", "jsdom": "~0.10.3" } } python-mpld3/.gitmodules0000644000175500017550000000013612410130733015315 0ustar debacledebacle[submodule "mplexporter"] path = mplexporter url = https://github.com/mpld3/mplexporter.git python-mpld3/doc/0000755000175500017550000000000012410130733013705 5ustar debacledebaclepython-mpld3/doc/themes/0000755000175500017550000000000012410130733015172 5ustar debacledebaclepython-mpld3/doc/themes/mpld3/0000755000175500017550000000000012410130733016211 5ustar debacledebaclepython-mpld3/doc/themes/mpld3/README0000644000175500017550000000024012410130733017065 0ustar debacledebaclempld3 sphinx theme ------------------ Based on the built-in sphinx haiku theme. Copyright 2014, mpld3 developers. License: BSD http://github.com/jakevdp/mpld3python-mpld3/doc/themes/mpld3/layout.html0000644000175500017550000000425412410130733020421 0ustar debacledebacle{# mpld3/layout.html ~~~~~~~~~~~~~~~~~ Sphinx layout template for the mpld3 theme. :copyright: Copyright 2014 by the mpld3 team, see AUTHORS.md :license: BSD, see LICENSE for details. Adapted from the haiku theme in the sphinx project, Copyright 2007-2011, BSD licensed. sphinx-doc.org/‎ #} {% extends "basic/layout.html" %} {% set script_files = script_files + ['_static/theme_extras.js'] %} {% set css_files = css_files + ['_static/print.css'] %} {{ css_files }} {# do not display relbars #} {% block relbar1 %}{% endblock %} {% block relbar2 %}{% endblock %} {% macro nav() %}

{%- block mpld3rel1 %} {%- endblock %} {%- if prev %} «  {{ prev.title }}   ::   {%- endif %} {{ _('Contents') }} {%- if next %}   ::   {{ next.title }}  Â» {%- endif %} {%- block mpld3rel2 %} {%- endblock %}

{% endmacro %} {% block content %}
{%- block mpld3header %} {%- if theme_full_logo != "false" %} {%- else %} {%- if logo -%} {%- endif -%}

{{ shorttitle|e }}

{{ title|striptags|e }}

{%- endif %} {%- endblock %}
{{ nav() }}
{#{%- if display_toc %}

Table Of Contents

{{ toc }}
{%- endif %}#} {% block body %}{% endblock %}
{{ nav() }}
{% endblock %} python-mpld3/doc/themes/mpld3/static/0000755000175500017550000000000012410130733017500 5ustar debacledebaclepython-mpld3/doc/themes/mpld3/static/alert_info_32.png0000644000175500017550000000222012410130733022630 0ustar debacledebacle‰PNG  IHDR szzôWIDATXý—ohUuÇ?ô"JzÑ›§W¿zqzq‹ —]d܆¬±¼É.»d“54Ü„;5TÒ´ù?ÿ¤iâ–Ž„ ¬°4©©„üG¢d âÔM¦ÎæŸm^ÝÝ·çL¯Kbн=ððãr<Ÿó|žßïœ ÿc€àp'Ì£@&¼VÔx8At®,ñ“¬ò˜(ß'"I'Â{Šc€“ÄÛåšúåÍ’kê—¥ÎËâ¿ o‡`Ò0DQ:‘!:OnzVÕk¥%{¤êu’›ž•Õœ%ß [#¨R¨£àqÔª~‘7;(>¤`õfK–êe?Û ˜!àH1²6áO¹Á“ßëÀ É&ž¥ß ['¬U@¶8‡d =r3¥ÈÉÍ”¬¡G–8&ü/Ë…-*À¢Ûd•Çe© ²úî`­<<½Û,X(lNÑ´`u"úµˆíc±ýÁo·Eð°¥ÂjŠ2„Ì Þ¶I¸­ÁÊjÁ‚°xƒp•“ p:Ö°R©¶.ù‰æp«e–·m·aiQrPøŸ P!T¶xH5[rJmëSyf¯¼òéÂ|aá5 ›(=*"»Â®Àkº"×’“?ó®âK³ª\}Sñ=*iº¤HºC®ê„Ìo,¬*8À[x²IÈM»+ט•«PlV¿Ën*–9.‹¬‘¥‚5xœÜ;Y¹†¬,Ý/KÞ’¿.x?DZƒ³€Š 75+×p[V×/›pS$zC€…‚E‚‚‹0%+«¿-«í“Ußå,¬l("@ãmÙ¤ÙÄ[²ªëbܵ`ØÿjÁÆ¢<íOí·Ê^¿–çYèsÁžöEïÊM¥údÕ¡ÿ±=!À°ÿu‚­x ˜o~\ó(¹9´¿¶OVú/¿ú_,øP°^ÐV0€S±)ëU×Þ«ôŽœjÛeéûÛ/~MÄ®†þ‡ OÛ‡Ò@rD¾¼ $€×ÃL/Oþcèb‹sJ~šÓ›Ÿç”j¼·ýîù]Éó¿F°IØNáZ‘A`?0xã!0#sðìƒSŸÉÉ5ªô½;ªÙx7ô¶l(»ú_.X+ìáŸÑáŸÞNaS\@¨~à-håËåê/È5Žð?.ô_z9Ïÿ.áNŠÈáŸÑóAz‡‡•Œà•‘ßSÀº­|£lbWà¿2Ïéå`úm°CÂý.¼SÂ?+¢ç†p»G ð2ðøÃ†ñ `.æPÖ.*ºî·¿¤[^⤢ésòë:äמ—ŸêT$Ù)ܰx«€ #\?Ÿ—Ï0ÊÿO«°˜ð¿eEI·ð/É«êVYó •ÏéWYK¯\ì€à»üâ“¿P“lÇÆ o—ð/ŠH—ˆtÊKtË•ì æ¡HÅóãE`7–Þ"rQD:_…gCq‹çGø ›&¼ƒáÑüÿÏY%Óÿµøßö”!”$IEND®B`‚python-mpld3/doc/themes/mpld3/static/mpld3.css_t0000644000175500017550000001453212410130733021561 0ustar debacledebacle/* * mpld3.css_t * ~~~~~~~~~~~ * * Sphinx stylesheet -- mpld3 theme. * */ @import url("basic.css"); html { margin: 0px; padding: 0px; background: #FFF url(bg-page.png) top left repeat-x; } body { line-height: 1.5; margin: auto; padding: 0px; font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; min-width: 59em; max-width: 70em; color: {{ theme_textcolor }}; } div.footer { padding: 8px; font-size: 11px; text-align: center; letter-spacing: 0.5px; } /* link colors and text decoration */ a:link { font-weight: bold; text-decoration: none; color: {{ theme_linkcolor }}; } a:visited { font-weight: bold; text-decoration: none; color: {{ theme_visitedlinkcolor }}; } a:hover, a:active { text-decoration: underline; color: {{ theme_hoverlinkcolor }}; } /* Some headers act as anchors, don't give them a hover effect */ h1 a:hover, a:active { text-decoration: none; color: {{ theme_headingcolor }}; } h2 a:hover, a:active { text-decoration: none; color: {{ theme_headingcolor }}; } h3 a:hover, a:active { text-decoration: none; color: {{ theme_headingcolor }}; } h4 a:hover, a:active { text-decoration: none; color: {{ theme_headingcolor }}; } a.headerlink { color: #cf2e2f; padding-left: 5px; } a.headerlink:hover { color: #ef2e2f; } /* basic text elements */ div.content { margin-top: 20px; margin-left: 40px; margin-right: 40px; margin-bottom: 50px; font-size: 0.9em; } /* heading and navigation */ div.header { position: relative; left: 0px; top: 0px; height: 85px; /* background: #eeeeee; */ padding: 0 40px; } div.header h1 { font-size: 1.6em; font-weight: normal; letter-spacing: 1px; color: {{ theme_headingcolor }}; border: 0; margin: 0; padding-top: 15px; } div.header h1 a { font-weight: normal; color: {{ theme_headingcolor }}; } div.header h2 { font-size: 1.3em; font-weight: normal; letter-spacing: 1px; text-transform: uppercase; color: #aaa; border: 0; margin-top: -3px; padding: 0; } div.header img.rightlogo { float: right; } div.header img.leftlogo { float: left; margin-right: 30px; margin-top: 16px; } div.title { font-size: 1.3em; font-weight: bold; color: {{ theme_headingcolor }}; border-bottom: dotted thin #e0e0e0; margin-bottom: 25px; } div.topnav { /* background: #e0e0e0; */ } div.topnav p { margin-top: 0; margin-left: 40px; margin-right: 40px; margin-bottom: 0px; text-align: right; font-size: 0.8em; } div.bottomnav { background: #eeeeee; } div.bottomnav p { margin-right: 40px; text-align: right; font-size: 0.8em; } a.uplink { font-weight: normal; } /* contents box */ table.index { margin: 0px 0px 30px 30px; padding: 1px; border-width: 1px; border-style: dotted; border-color: #e0e0e0; } table.index tr.heading { background-color: #e0e0e0; text-align: center; font-weight: bold; font-size: 1.1em; } table.index tr.index { background-color: #eeeeee; } table.index td { padding: 5px 20px; } table.index a:link, table.index a:visited { font-weight: normal; text-decoration: none; color: {{ theme_linkcolor }}; } table.index a:hover, table.index a:active { text-decoration: underline; color: {{ theme_hoverlinkcolor }}; } /* Rounded corner boxes */ /* Common declarations */ div.admonition { -webkit-border-radius: 10px; -khtml-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; border-style: dotted; border-width: thin; border-color: #dcdcdc; padding: 10px 15px 10px 15px; margin-bottom: 15px; margin-top: 15px; } div.note { padding: 10px 15px 10px 80px; background: #e4ffde url(alert_info_32.png) 15px 15px no-repeat; min-height: 42px; } div.warning { padding: 10px 15px 10px 80px; background: #fffbc6 url(alert_warning_32.png) 15px 15px no-repeat; min-height: 42px; } div.seealso { background: #e4ffde; } /* More layout and styles */ h1 { font-size: 1.3em; font-weight: bold; color: {{ theme_headingcolor }}; border-bottom: dotted thin #e0e0e0; margin-top: 30px; } h2 { font-size: 1.2em; font-weight: normal; color: {{ theme_headingcolor }}; border-bottom: dotted thin #e0e0e0; margin-top: 30px; } h3 { font-size: 1.1em; font-weight: normal; color: {{ theme_headingcolor }}; margin-top: 30px; } h4 { font-size: 1.0em; font-weight: normal; color: {{ theme_headingcolor }}; margin-top: 30px; } p { text-align: justify; } p.last { margin-bottom: 0; } ol { padding-left: 20px; } ul { padding-left: 5px; margin-top: 3px; } li { line-height: 1.3; } div.content ul > li { -moz-background-clip:border; -moz-background-inline-policy:continuous; -moz-background-origin:padding; background: transparent url(bullet_orange.png) no-repeat scroll left 0.45em; list-style-image: none; list-style-type: none; padding: 0 0 0 1.666em; margin-bottom: 3px; } td { vertical-align: top; } tt { background-color: #e2e2e2; font-size: 1.0em; font-family: monospace; } pre { border-color: #0c3762; border-style: dotted; border-width: thin; margin: 0 0 12px 0; padding: 0.8em; background-color: #f0f0f0; } hr { border-top: 1px solid #ccc; border-bottom: 0; border-right: 0; border-left: 0; margin-bottom: 10px; margin-top: 20px; } /* printer only pretty stuff */ @media print { .noprint { display: none; } /* for acronyms we want their definitions inlined at print time */ acronym[title]:after { font-size: small; content: " (" attr(title) ")"; font-style: italic; } /* and not have mozilla dotted underline */ acronym { border: none; } div.topnav, div.bottomnav, div.header, table.index { display: none; } div.content { margin: 0px; padding: 0px; } html { background: #FFF; } } .viewcode-back { font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; } div.viewcode-block:target { background-color: #f4debf; border-top: 1px solid #ac9; border-bottom: 1px solid #ac9; margin: -1px -12px; padding: 0 12px; } python-mpld3/doc/themes/mpld3/static/bg-page.png0000644000175500017550000000024412410130733021510 0ustar debacledebacle‰PNG  IHDR hJr†ügAMA± üa pHYs  šœtIMEÙ +ù3IDATHÇíб ±€ØÕW6`¨#_íêV’zµë#‚ ‚ ‚& ÓÝ>A“Ñklr¤×IEND®B`‚python-mpld3/doc/themes/mpld3/static/alert_warning_32.png0000644000175500017550000000204412410130733023346 0ustar debacledebacle‰PNG  IHDR szzôëIDATX…µ–ML\UÇï o(Ã(e &`uU›vlìÂÆÔUcãÆM7mhbâÎD—nÜ(u¡˜4ŠFÓ4©ñ£Áta¢1ØP†B(-TZ‡¦àÌt¾Þ»÷¸˜y3¯¶yÃL;'¹‹É}sÿ¿sîÿÞs¡zXÀ)`ˆßo‡sÿ¯;\áÛÃÃÈêê²ìîÄdfú7¹x᜜z]€ àÛFÝ–ÕÕUqDtND§DÔ–ˆsOÄ^”ÝÍ+239*¿zKΜ:êՆϜHú24=g )€ä@‡N‚$Ñ™m²³W»PmÍG¢ÉwV¶ eƒ¶ ð,XÝ`…€H–Ü­9²S_ÍZt÷ ´' Ù(ÒP°¡¹—ggP±KÀŠ4@—†*Bh´ * ;×P±Ë@©æ5¾þ®) «¢°¶A@9 eu£nýjnœböÊ.ùÁ.þö†ÑÜ€RöÊ ÊÀ-¤Q[ ŠÙ‹ãÈ—tù30 µ'óÒþ»fíQ§Qp<î/”†»ê¡Oc‡Ž^¾"îšÓ«nàq¾òšÐ.ú£$n ó€›½íÙ{„2@Y·qNårÝ/vÂc@ðž:À÷>ºÊÅÚÎO€8¥£ P1¡aÀvÊ® à3÷éÄäšýÙ7 /ÿ½žazÚM,ý„ìv Äë­¼ñe”õCÀõ§púÈ`ïÈØè ^=ÒÍÔ_¼}îmûBôt4 B*cl¾ø)ÃÄ `˜­À÷A²¹ð]Ýí¨ìTr‡Ýhœ?~_äüÏKìeéæ:‡Âpüˆæ#ýd«ÚšµÈÂi…´FPÁVt&…³“ »cnæ*•âpû¦ ûŸ tr¾fÿ÷€r ÆHÅi´ÄìêÆÜ×Â`[˜B<ŠºßL(¦ÿJuhO÷SyŒÍyš4˜í t€t\Å0ÛêS¯  <ÇsüÌÝ[˜@zmž€ùÿM8l‡³b˜|u€róQ•ÛO*Ó姘奔Æã¢xx ¸ Ìù]DËgÏ/q÷Ÿl¥x^BnÀâ×¹]7ýDüîÑñ©ÄÊÈ÷ký-–töuéh5JÌÝc:™X´9þþÝ8ð9PØ#DøÑ@sÀèøtred,ÞßÒìtöE‚t„‹åÎíh®.)N|¸áЧ÷(ž.9?€GAf2+#c‰þ–fÝÙ 2yý¯}œ©U\? ¨¯‰ZÀIà] Í#þ'°¼ôùüÿ—RBOÐñ¤‹üáy)eÛ±`QIEND®B`‚python-mpld3/doc/themes/mpld3/static/bullet_orange.png0000644000175500017550000000055512410130733023035 0ustar debacledebacle‰PNG  IHDR×z`PLTEà~*ÿÌ“ÿ»mà©÷ìåÿœ7ÿÞµÿÁ‚÷¹ÿØ«ïˆ*ÿÅ‹ÿ¼zÿ´nÿË…þñåê…*ÿ¡<ÿņÿá¼ÿ¿tÿôèãªÿÿÿ”⟄bKGD ½ pHYsHHFÉk> vpAg•Ñù’/IDAT×Á Àu†„ÿ?Õ .«’€Ùr/P›Ç5¤zü¨»=¤,„ø%š&;Î%tEXtdate:create2010-01-07T12:49:06+01:00:‘yÈ%tEXtdate:modify2010-01-07T12:49:06+01:00KÌÁtIEND®B`‚python-mpld3/doc/themes/mpld3/theme.conf0000644000175500017550000000037012410130733020162 0ustar debacledebacle[theme] inherit = basic stylesheet = mpld3.css pygments_style = autumn [options] full_logo = false textcolor = #333333 headingcolor = #0c3762 linkcolor = #af2e2f visitedlinkcolor = #6f2e2f hoverlinkcolor = #cf2e2f python-mpld3/doc/install.rst0000644000175500017550000000337412410130733016114 0ustar debacledebacle.. _installing-mpld3: Installing mpld3 ================ Installing released versions ---------------------------- The mpld3 project is compatible with Python 2.6-2.7 and 3.3-3.4. To install the latest release, you can use the `pip installer `_ as follows:: [~]$ pip install mpld3 If you've downloaded the tarball of the source distribution, you can type:: [~]$ python setup.py install or to specify another install location, use:: [~]$ python setup.py install --prefix=/path/to/location/ Installing from git ------------------- The mpld3 source is `available on GitHub `_. Installing from source requires one extra build step to sync the `mplexporter `_ submodule. When installing from the gihub source, use:: [~]$ python setup.py submodule [~]$ python setup.py install Building JavaScript Sources --------------------------- A core piece of the mpld3 package are the JavaScript libraries, which are located in the package in the ``mpld3/js/`` directory. The ``mpld3.*.js`` is automatically constructed from a number of source JavaScript files; if you modify these sources, the libraries must be re-built before mpld3 is installed. For more information, please refer to ``CONTRIBUTING.md``, found in the project repository. Dependencies ------------ The mpld3 package is compatible with Python versions 2.6, 2.7, 3.3, and 3.4. It requires `matplotlib `_ version 1.3+ and `jinja2 `_ version 2.7+. Optionally, mpld3 can be used within the `IPython `_ notebook, and requires IPython version 1.0+, and preferably IPython 2.0+ (see notes in the documentation of :func:`mpld3.enable_notebook`). python-mpld3/doc/index.rst0000644000175500017550000000326112410130733015550 0ustar debacledebacle .. raw:: html Fork me on GitHub
mpld3 ===== The mpld3 project brings together `Matplotlib `_, the popular Python-based graphing library, and `D3js `_, the popular JavaScript library for creating interactive data visualizations for the web. The result is a simple API for exporting your matplotlib graphics to HTML code which can be used within the browser, within standard web pages, blogs, or tools such as the `IPython notebook `_. See the :ref:`example-gallery` or :ref:`notebook-examples` for some interactive demonstrations of mpld3 in action. For a quick overview of the package, see the :ref:`quickstart-guide`. Contents ======== .. toctree:: :maxdepth: 2 quickstart install faq plugins examples/index notebooks/index modules/API Source and Development ====================== The source code for mpld3 can be found on `GitHub `_. Please direct questions about how to do specific plots or interactions to `Stack Overflow `_ and tag them with *mpld3* to make sure we see them. Pull requests, feature requests, and other ideas can be submitted via the GitHub page. Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` python-mpld3/doc/sphinxext/0000755000175500017550000000000012410130733015737 5ustar debacledebaclepython-mpld3/doc/sphinxext/notebook_converter.py0000644000175500017550000000545112410130733022225 0ustar debacledebacleimport sys import os import glob import shutil import jinja2 from IPython.nbformat import current as nbformat from IPython.nbconvert.exporters import HTMLExporter INDEX_TEMPLATE = jinja2.Template(""" .. _{{ sphinx_tag }}: Notebook Examples ================= .. toctree:: {% for notebook in notebooks %} ./{{ notebook }} {% endfor %} """) RST_TEMPLATE = jinja2.Template(""" {{ title }} {% for c in title %}={% endfor %} [ :download:`{{ nbroot }}.html ` | :download:`{{ nbroot }}.ipynb <{{ nbroot }}.ipynb>` ] .. raw:: html """) def get_notebook_title(nb_json, default=None): """Determine a suitable title for the notebook. This will return the text of the first header cell. If that does not exist, it will return the default. """ worksheets = nb_json['worksheets'] cells = worksheets[0]['cells'] for cell in cells: if cell['cell_type'] == 'heading': return cell['source'] return default def main(app): static_dir = os.path.join(app.builder.srcdir, '_static') target_dir = os.path.join(app.builder.srcdir, 'notebooks') source_dir = os.path.abspath(os.path.join(app.builder.srcdir, '..', 'notebooks')) rendered_dir = os.path.join(target_dir, 'rendered') if not os.path.exists(static_dir): os.makedirs(static_dir) if not os.path.exists(target_dir): os.makedirs(target_dir) if not os.path.exists(rendered_dir): os.makedirs(rendered_dir) nbroots = [] nbtitles = [] exporter = HTMLExporter(template_file='full') for nb_src in glob.glob(os.path.join(source_dir, '*.ipynb')): print("converting notebook {0}".format(nb_src)) basedir, nbname = os.path.split(nb_src) nb_dest = os.path.join(target_dir, nbname) shutil.copyfile(nb_src, nb_dest) with open(nb_dest, 'r') as f: nb_json = nbformat.reads_json(f.read()) (body, resources) = exporter.from_notebook_node(nb_json) root, ext = os.path.splitext(nbname) nb_html_dest = os.path.join(rendered_dir, root + '.html') with open(nb_html_dest, 'w') as f: f.write(body) nbroots.append(root) nbtitles.append(get_notebook_title(nb_json, root)) for nbroot, nbtitle in zip(nbroots, nbtitles): with open(os.path.join(target_dir, nbroot + '.rst'), 'w') as f: f.write(RST_TEMPLATE.render(title=nbtitle, nbroot=nbroot)) with open(os.path.join(target_dir, 'index.rst'), 'w') as f: f.write(INDEX_TEMPLATE.render(notebooks=nbroots, sphinx_tag='notebook-examples')) def setup(app): app.connect('builder-inited', main) python-mpld3/doc/sphinxext/numpy_ext/0000755000175500017550000000000012410130733017767 5ustar debacledebaclepython-mpld3/doc/sphinxext/numpy_ext/__init__.py0000644000175500017550000000000012410130733022066 0ustar debacledebaclepython-mpld3/doc/sphinxext/numpy_ext/docscrape_sphinx.py0000644000175500017550000001736412410130733023710 0ustar debacledebacleimport re, inspect, textwrap, pydoc import sphinx from docscrape import NumpyDocString, FunctionDoc, ClassDoc class SphinxDocString(NumpyDocString): def __init__(self, docstring, config=None): config = {} if config is None else config self.use_plots = config.get('use_plots', False) NumpyDocString.__init__(self, docstring, config=config) # string conversion routines def _str_header(self, name, symbol='`'): return ['.. rubric:: ' + name, ''] def _str_field_list(self, name): return [':' + name + ':'] def _str_indent(self, doc, indent=4): out = [] for line in doc: out += [' '*indent + line] return out def _str_signature(self): return [''] if self['Signature']: return ['``%s``' % self['Signature']] + [''] else: return [''] def _str_summary(self): return self['Summary'] + [''] def _str_extended_summary(self): return self['Extended Summary'] + [''] def _str_param_list(self, name): out = [] if self[name]: out += self._str_field_list(name) out += [''] for param,param_type,desc in self[name]: out += self._str_indent(['**%s** : %s' % (param.strip(), param_type)]) out += [''] out += self._str_indent(desc,8) out += [''] return out @property def _obj(self): if hasattr(self, '_cls'): return self._cls elif hasattr(self, '_f'): return self._f return None def _str_member_list(self, name): """ Generate a member listing, autosummary:: table where possible, and a table where not. """ out = [] if self[name]: out += ['.. rubric:: %s' % name, ''] prefix = getattr(self, '_name', '') if prefix: prefix = '~%s.' % prefix autosum = [] others = [] for param, param_type, desc in self[name]: param = param.strip() if not self._obj or hasattr(self._obj, param): autosum += [" %s%s" % (prefix, param)] else: others.append((param, param_type, desc)) if autosum: # GAEL: Toctree commented out below because it creates # hundreds of sphinx warnings # out += ['.. autosummary::', ' :toctree:', ''] out += ['.. autosummary::', ''] out += autosum if others: maxlen_0 = max([len(x[0]) for x in others]) maxlen_1 = max([len(x[1]) for x in others]) hdr = "="*maxlen_0 + " " + "="*maxlen_1 + " " + "="*10 fmt = '%%%ds %%%ds ' % (maxlen_0, maxlen_1) n_indent = maxlen_0 + maxlen_1 + 4 out += [hdr] for param, param_type, desc in others: out += [fmt % (param.strip(), param_type)] out += self._str_indent(desc, n_indent) out += [hdr] out += [''] return out def _str_section(self, name): out = [] if self[name]: out += self._str_header(name) out += [''] content = textwrap.dedent("\n".join(self[name])).split("\n") out += content out += [''] return out def _str_see_also(self, func_role): out = [] if self['See Also']: see_also = super(SphinxDocString, self)._str_see_also(func_role) out = ['.. seealso::', ''] out += self._str_indent(see_also[2:]) return out def _str_warnings(self): out = [] if self['Warnings']: out = ['.. warning::', ''] out += self._str_indent(self['Warnings']) return out def _str_index(self): idx = self['index'] out = [] if len(idx) == 0: return out out += ['.. index:: %s' % idx.get('default','')] for section, references in idx.iteritems(): if section == 'default': continue elif section == 'refguide': out += [' single: %s' % (', '.join(references))] else: out += [' %s: %s' % (section, ','.join(references))] return out def _str_references(self): out = [] if self['References']: out += self._str_header('References') if isinstance(self['References'], str): self['References'] = [self['References']] out.extend(self['References']) out += [''] # Latex collects all references to a separate bibliography, # so we need to insert links to it if sphinx.__version__ >= "0.6": out += ['.. only:: latex',''] else: out += ['.. latexonly::',''] items = [] for line in self['References']: m = re.match(r'.. \[([a-z0-9._-]+)\]', line, re.I) if m: items.append(m.group(1)) out += [' ' + ", ".join(["[%s]_" % item for item in items]), ''] return out def _str_examples(self): examples_str = "\n".join(self['Examples']) if (self.use_plots and 'import matplotlib' in examples_str and 'plot::' not in examples_str): out = [] out += self._str_header('Examples') out += ['.. plot::', ''] out += self._str_indent(self['Examples']) out += [''] return out else: return self._str_section('Examples') def __str__(self, indent=0, func_role="obj"): out = [] out += self._str_signature() out += self._str_index() + [''] out += self._str_summary() out += self._str_extended_summary() for param_list in ('Parameters', 'Returns', 'Raises'): out += self._str_param_list(param_list) out += self._str_warnings() out += self._str_see_also(func_role) out += self._str_section('Notes') out += self._str_references() out += self._str_examples() for param_list in ('Attributes', 'Methods'): out += self._str_member_list(param_list) out = self._str_indent(out,indent) return '\n'.join(out) class SphinxFunctionDoc(SphinxDocString, FunctionDoc): def __init__(self, obj, doc=None, config={}): self.use_plots = config.get('use_plots', False) FunctionDoc.__init__(self, obj, doc=doc, config=config) class SphinxClassDoc(SphinxDocString, ClassDoc): def __init__(self, obj, doc=None, func_doc=None, config={}): self.use_plots = config.get('use_plots', False) ClassDoc.__init__(self, obj, doc=doc, func_doc=None, config=config) class SphinxObjDoc(SphinxDocString): def __init__(self, obj, doc=None, config=None): self._f = obj SphinxDocString.__init__(self, doc, config=config) def get_doc_object(obj, what=None, doc=None, config={}): if what is None: if inspect.isclass(obj): what = 'class' elif inspect.ismodule(obj): what = 'module' elif callable(obj): what = 'function' else: what = 'object' if what == 'class': return SphinxClassDoc(obj, func_doc=SphinxFunctionDoc, doc=doc, config=config) elif what in ('function', 'method'): return SphinxFunctionDoc(obj, doc=doc, config=config) else: if doc is None: doc = pydoc.getdoc(obj) return SphinxObjDoc(obj, doc, config=config) python-mpld3/doc/sphinxext/numpy_ext/numpydoc.py0000644000175500017550000001271312410130733022203 0ustar debacledebacle""" ======== numpydoc ======== Sphinx extension that handles docstrings in the Numpy standard format. [1] It will: - Convert Parameters etc. sections to field lists. - Convert See Also section to a See also entry. - Renumber references. - Extract the signature from the docstring, if it can't be determined otherwise. .. [1] http://projects.scipy.org/numpy/wiki/CodingStyleGuidelines#docstring-standard """ import os, re, pydoc from docscrape_sphinx import get_doc_object, SphinxDocString from sphinx.util.compat import Directive import inspect def mangle_docstrings(app, what, name, obj, options, lines, reference_offset=[0]): cfg = dict(use_plots=app.config.numpydoc_use_plots, show_class_members=app.config.numpydoc_show_class_members) if what == 'module': # Strip top title title_re = re.compile(ur'^\s*[#*=]{4,}\n[a-z0-9 -]+\n[#*=]{4,}\s*', re.I|re.S) lines[:] = title_re.sub(u'', u"\n".join(lines)).split(u"\n") else: doc = get_doc_object(obj, what, u"\n".join(lines), config=cfg) lines[:] = unicode(doc).split(u"\n") if app.config.numpydoc_edit_link and hasattr(obj, '__name__') and \ obj.__name__: if hasattr(obj, '__module__'): v = dict(full_name=u"%s.%s" % (obj.__module__, obj.__name__)) else: v = dict(full_name=obj.__name__) lines += [u'', u'.. htmlonly::', ''] lines += [u' %s' % x for x in (app.config.numpydoc_edit_link % v).split("\n")] # replace reference numbers so that there are no duplicates references = [] for line in lines: line = line.strip() m = re.match(ur'^.. \[([a-z0-9_.-])\]', line, re.I) if m: references.append(m.group(1)) # start renaming from the longest string, to avoid overwriting parts references.sort(key=lambda x: -len(x)) if references: for i, line in enumerate(lines): for r in references: if re.match(ur'^\d+$', r): new_r = u"R%d" % (reference_offset[0] + int(r)) else: new_r = u"%s%d" % (r, reference_offset[0]) lines[i] = lines[i].replace(u'[%s]_' % r, u'[%s]_' % new_r) lines[i] = lines[i].replace(u'.. [%s]' % r, u'.. [%s]' % new_r) reference_offset[0] += len(references) def mangle_signature(app, what, name, obj, options, sig, retann): # Do not try to inspect classes that don't define `__init__` if (inspect.isclass(obj) and (not hasattr(obj, '__init__') or 'initializes x; see ' in pydoc.getdoc(obj.__init__))): return '', '' if not (callable(obj) or hasattr(obj, '__argspec_is_invalid_')): return if not hasattr(obj, '__doc__'): return doc = SphinxDocString(pydoc.getdoc(obj)) if doc['Signature']: sig = re.sub(u"^[^(]*", u"", doc['Signature']) return sig, u'' def setup(app, get_doc_object_=get_doc_object): global get_doc_object get_doc_object = get_doc_object_ app.connect('autodoc-process-docstring', mangle_docstrings) app.connect('autodoc-process-signature', mangle_signature) app.add_config_value('numpydoc_edit_link', None, False) app.add_config_value('numpydoc_use_plots', None, False) app.add_config_value('numpydoc_show_class_members', True, True) # Extra mangling domains app.add_domain(NumpyPythonDomain) app.add_domain(NumpyCDomain) #------------------------------------------------------------------------------ # Docstring-mangling domains #------------------------------------------------------------------------------ from docutils.statemachine import ViewList from sphinx.domains.c import CDomain from sphinx.domains.python import PythonDomain class ManglingDomainBase(object): directive_mangling_map = {} def __init__(self, *a, **kw): super(ManglingDomainBase, self).__init__(*a, **kw) self.wrap_mangling_directives() def wrap_mangling_directives(self): for name, objtype in self.directive_mangling_map.items(): self.directives[name] = wrap_mangling_directive( self.directives[name], objtype) class NumpyPythonDomain(ManglingDomainBase, PythonDomain): name = 'np' directive_mangling_map = { 'function': 'function', 'class': 'class', 'exception': 'class', 'method': 'function', 'classmethod': 'function', 'staticmethod': 'function', 'attribute': 'attribute', } class NumpyCDomain(ManglingDomainBase, CDomain): name = 'np-c' directive_mangling_map = { 'function': 'function', 'member': 'attribute', 'macro': 'function', 'type': 'class', 'var': 'object', } def wrap_mangling_directive(base_directive, objtype): class directive(base_directive): def run(self): env = self.state.document.settings.env name = None if self.arguments: m = re.match(r'^(.*\s+)?(.*?)(\(.*)?', self.arguments[0]) name = m.group(2).strip() if not name: name = self.arguments[0] lines = list(self.content) mangle_docstrings(env.app, objtype, name, None, None, lines) self.content = ViewList(lines, self.content.parent) return base_directive.run(self) return directive python-mpld3/doc/sphinxext/numpy_ext/docscrape.py0000644000175500017550000003554312410130733022316 0ustar debacledebacle"""Extract reference documentation from the NumPy source tree. """ import inspect import textwrap import re import pydoc from StringIO import StringIO from warnings import warn class Reader(object): """A line-based string reader. """ def __init__(self, data): """ Parameters ---------- data : str String with lines separated by '\n'. """ if isinstance(data,list): self._str = data else: self._str = data.split('\n') # store string as list of lines self.reset() def __getitem__(self, n): return self._str[n] def reset(self): self._l = 0 # current line nr def read(self): if not self.eof(): out = self[self._l] self._l += 1 return out else: return '' def seek_next_non_empty_line(self): for l in self[self._l:]: if l.strip(): break else: self._l += 1 def eof(self): return self._l >= len(self._str) def read_to_condition(self, condition_func): start = self._l for line in self[start:]: if condition_func(line): return self[start:self._l] self._l += 1 if self.eof(): return self[start:self._l+1] return [] def read_to_next_empty_line(self): self.seek_next_non_empty_line() def is_empty(line): return not line.strip() return self.read_to_condition(is_empty) def read_to_next_unindented_line(self): def is_unindented(line): return (line.strip() and (len(line.lstrip()) == len(line))) return self.read_to_condition(is_unindented) def peek(self,n=0): if self._l + n < len(self._str): return self[self._l + n] else: return '' def is_empty(self): return not ''.join(self._str).strip() class NumpyDocString(object): def __init__(self, docstring, config={}): docstring = textwrap.dedent(docstring).split('\n') self._doc = Reader(docstring) self._parsed_data = { 'Signature': '', 'Summary': [''], 'Extended Summary': [], 'Parameters': [], 'Returns': [], 'Raises': [], 'Warns': [], 'Other Parameters': [], 'Attributes': [], 'Methods': [], 'See Also': [], 'Notes': [], 'Warnings': [], 'References': '', 'Examples': '', 'index': {} } self._parse() def __getitem__(self,key): return self._parsed_data[key] def __setitem__(self,key,val): if not self._parsed_data.has_key(key): warn("Unknown section %s" % key) else: self._parsed_data[key] = val def _is_at_section(self): self._doc.seek_next_non_empty_line() if self._doc.eof(): return False l1 = self._doc.peek().strip() # e.g. Parameters if l1.startswith('.. index::'): return True l2 = self._doc.peek(1).strip() # ---------- or ========== return l2.startswith('-'*len(l1)) or l2.startswith('='*len(l1)) def _strip(self,doc): i = 0 j = 0 for i,line in enumerate(doc): if line.strip(): break for j,line in enumerate(doc[::-1]): if line.strip(): break return doc[i:len(doc)-j] def _read_to_next_section(self): section = self._doc.read_to_next_empty_line() while not self._is_at_section() and not self._doc.eof(): if not self._doc.peek(-1).strip(): # previous line was empty section += [''] section += self._doc.read_to_next_empty_line() return section def _read_sections(self): while not self._doc.eof(): data = self._read_to_next_section() name = data[0].strip() if name.startswith('..'): # index section yield name, data[1:] elif len(data) < 2: yield StopIteration else: yield name, self._strip(data[2:]) def _parse_param_list(self,content): r = Reader(content) params = [] while not r.eof(): header = r.read().strip() if ' : ' in header: arg_name, arg_type = header.split(' : ')[:2] else: arg_name, arg_type = header, '' desc = r.read_to_next_unindented_line() desc = dedent_lines(desc) params.append((arg_name,arg_type,desc)) return params _name_rgx = re.compile(r"^\s*(:(?P\w+):`(?P[a-zA-Z0-9_.-]+)`|" r" (?P[a-zA-Z0-9_.-]+))\s*", re.X) def _parse_see_also(self, content): """ func_name : Descriptive text continued text another_func_name : Descriptive text func_name1, func_name2, :meth:`func_name`, func_name3 """ items = [] def parse_item_name(text): """Match ':role:`name`' or 'name'""" m = self._name_rgx.match(text) if m: g = m.groups() if g[1] is None: return g[3], None else: return g[2], g[1] raise ValueError("%s is not a item name" % text) def push_item(name, rest): if not name: return name, role = parse_item_name(name) items.append((name, list(rest), role)) del rest[:] current_func = None rest = [] for line in content: if not line.strip(): continue m = self._name_rgx.match(line) if m and line[m.end():].strip().startswith(':'): push_item(current_func, rest) current_func, line = line[:m.end()], line[m.end():] rest = [line.split(':', 1)[1].strip()] if not rest[0]: rest = [] elif not line.startswith(' '): push_item(current_func, rest) current_func = None if ',' in line: for func in line.split(','): push_item(func, []) elif line.strip(): current_func = line elif current_func is not None: rest.append(line.strip()) push_item(current_func, rest) return items def _parse_index(self, section, content): """ .. index: default :refguide: something, else, and more """ def strip_each_in(lst): return [s.strip() for s in lst] out = {} section = section.split('::') if len(section) > 1: out['default'] = strip_each_in(section[1].split(','))[0] for line in content: line = line.split(':') if len(line) > 2: out[line[1]] = strip_each_in(line[2].split(',')) return out def _parse_summary(self): """Grab signature (if given) and summary""" if self._is_at_section(): return summary = self._doc.read_to_next_empty_line() summary_str = " ".join([s.strip() for s in summary]).strip() if re.compile('^([\w., ]+=)?\s*[\w\.]+\(.*\)$').match(summary_str): self['Signature'] = summary_str if not self._is_at_section(): self['Summary'] = self._doc.read_to_next_empty_line() else: self['Summary'] = summary if not self._is_at_section(): self['Extended Summary'] = self._read_to_next_section() def _parse(self): self._doc.reset() self._parse_summary() for (section,content) in self._read_sections(): if not section.startswith('..'): section = ' '.join([s.capitalize() for s in section.split(' ')]) if section in ('Parameters', 'Attributes', 'Methods', 'Returns', 'Raises', 'Warns'): self[section] = self._parse_param_list(content) elif section.startswith('.. index::'): self['index'] = self._parse_index(section, content) elif section == 'See Also': self['See Also'] = self._parse_see_also(content) else: self[section] = content # string conversion routines def _str_header(self, name, symbol='-'): return [name, len(name)*symbol] def _str_indent(self, doc, indent=4): out = [] for line in doc: out += [' '*indent + line] return out def _str_signature(self): if self['Signature']: return [self['Signature'].replace('*','\*')] + [''] else: return [''] def _str_summary(self): if self['Summary']: return self['Summary'] + [''] else: return [] def _str_extended_summary(self): if self['Extended Summary']: return self['Extended Summary'] + [''] else: return [] def _str_param_list(self, name): out = [] if self[name]: out += self._str_header(name) for param,param_type,desc in self[name]: out += ['%s : %s' % (param, param_type)] out += self._str_indent(desc) out += [''] return out def _str_section(self, name): out = [] if self[name]: out += self._str_header(name) out += self[name] out += [''] return out def _str_see_also(self, func_role): if not self['See Also']: return [] out = [] out += self._str_header("See Also") last_had_desc = True for func, desc, role in self['See Also']: if role: link = ':%s:`%s`' % (role, func) elif func_role: link = ':%s:`%s`' % (func_role, func) else: link = "`%s`_" % func if desc or last_had_desc: out += [''] out += [link] else: out[-1] += ", %s" % link if desc: out += self._str_indent([' '.join(desc)]) last_had_desc = True else: last_had_desc = False out += [''] return out def _str_index(self): idx = self['index'] out = [] out += ['.. index:: %s' % idx.get('default','')] for section, references in idx.iteritems(): if section == 'default': continue out += [' :%s: %s' % (section, ', '.join(references))] return out def __str__(self, func_role=''): out = [] out += self._str_signature() out += self._str_summary() out += self._str_extended_summary() for param_list in ('Parameters','Returns','Raises'): out += self._str_param_list(param_list) out += self._str_section('Warnings') out += self._str_see_also(func_role) for s in ('Notes','References','Examples'): out += self._str_section(s) for param_list in ('Attributes', 'Methods'): out += self._str_param_list(param_list) out += self._str_index() return '\n'.join(out) def indent(str,indent=4): indent_str = ' '*indent if str is None: return indent_str lines = str.split('\n') return '\n'.join(indent_str + l for l in lines) def dedent_lines(lines): """Deindent a list of lines maximally""" return textwrap.dedent("\n".join(lines)).split("\n") def header(text, style='-'): return text + '\n' + style*len(text) + '\n' class FunctionDoc(NumpyDocString): def __init__(self, func, role='func', doc=None, config={}): self._f = func self._role = role # e.g. "func" or "meth" if doc is None: if func is None: raise ValueError("No function or docstring given") doc = inspect.getdoc(func) or '' NumpyDocString.__init__(self, doc) if not self['Signature'] and func is not None: func, func_name = self.get_func() try: # try to read signature argspec = inspect.getargspec(func) argspec = inspect.formatargspec(*argspec) argspec = argspec.replace('*','\*') signature = '%s%s' % (func_name, argspec) except TypeError, e: signature = '%s()' % func_name self['Signature'] = signature def get_func(self): func_name = getattr(self._f, '__name__', self.__class__.__name__) if inspect.isclass(self._f): func = getattr(self._f, '__call__', self._f.__init__) else: func = self._f return func, func_name def __str__(self): out = '' func, func_name = self.get_func() signature = self['Signature'].replace('*', '\*') roles = {'func': 'function', 'meth': 'method'} if self._role: if not roles.has_key(self._role): print "Warning: invalid role %s" % self._role out += '.. %s:: %s\n \n\n' % (roles.get(self._role,''), func_name) out += super(FunctionDoc, self).__str__(func_role=self._role) return out class ClassDoc(NumpyDocString): def __init__(self, cls, doc=None, modulename='', func_doc=FunctionDoc, config=None): if not inspect.isclass(cls) and cls is not None: raise ValueError("Expected a class or None, but got %r" % cls) self._cls = cls if modulename and not modulename.endswith('.'): modulename += '.' self._mod = modulename if doc is None: if cls is None: raise ValueError("No class or documentation string given") doc = pydoc.getdoc(cls) NumpyDocString.__init__(self, doc) if config is not None and config.get('show_class_members', True): if not self['Methods']: self['Methods'] = [(name, '', '') for name in sorted(self.methods)] if not self['Attributes']: self['Attributes'] = [(name, '', '') for name in sorted(self.properties)] @property def methods(self): if self._cls is None: return [] return [name for name,func in inspect.getmembers(self._cls) if not name.startswith('_') and callable(func)] @property def properties(self): if self._cls is None: return [] return [name for name,func in inspect.getmembers(self._cls) if not name.startswith('_') and func is None] python-mpld3/doc/sphinxext/plot_generator.py0000644000175500017550000002456612410130733021352 0ustar debacledebacleimport sys import os import glob import token import tokenize import shutil import json import matplotlib matplotlib.use('Agg') # don't display plots import mpld3 from matplotlib import image from matplotlib.figure import Figure class disable_mpld3(object): """Context manager to temporarily disable mpld3.show() command""" def __enter__(self): self.show = mpld3.show mpld3.show = lambda *args, **kwargs: None return self def __exit__(self, type, value, traceback): mpld3.show = self.show RST_TEMPLATE = """ .. _{sphinx_tag}: {docstring} .. raw:: html {img_html} **Python source code:** :download:`[download source: {fname}]<{fname}>` .. literalinclude:: {fname} :lines: {end_line}- """ INDEX_TEMPLATE = """ .. raw:: html .. _{sphinx_tag}: Example Gallery =============== {toctree} {contents} .. raw:: html
""" BANNER_JS_TEMPLATE = """ var banner_data = {banner_data}; banner_data.forEach(function(d, i) {{ d.i = i; }}); var height = 150, width = 900, imageHeight = 150, imageWidth = 150, zoomfactor = 0.1; var banner = d3.select(".example-banner"); banner.style("height", height + "px") .style("width", width + "px") .style("margin-left", "auto") .style("margin-right", "auto"); var svg = banner.append("svg") .attr("width", width + "px") .attr("height", height + "px"); var anchor = svg.append("g") .attr("class", "example-anchor") .selectAll("a") .data(banner_data.slice(0, 7)); anchor.exit().remove(); var anchor_elements = anchor.enter().append("a") .attr("xlink:href", function(d) {{ return d.url; }}) .attr("xlink:title", function(d) {{ return d.title; }}); anchor_elements.append("svg:image") .attr("width", (1 - zoomfactor) * imageWidth) .attr("height", (1 - zoomfactor) * imageHeight) .attr("xlink:href", function(d){{ return d.thumb; }}) .attr("xroot", function(d){{return d3.round(imageWidth * (d.i - 0.5));}}) .attr("x", function(d){{return d3.round(imageWidth * (d.i - 0.5));}}) .attr("y", d3.round(0.5 * zoomfactor * imageHeight)) .attr("i", function(d){{return d.i;}}) .on("mouseover", function() {{ var img = d3.select(this); img.transition() .attr("width", imageWidth) .attr("height", height) .attr("x", img.attr("xroot") - d3.round(0.5 * zoomfactor * imageWidth)) .attr("y", 0); }}) .on("mouseout", function() {{ var img = d3.select(this); img.transition() .attr("width", (1 - zoomfactor) * imageWidth) .attr("height", (1 - zoomfactor) * height) .attr("x", img.attr("xroot")) .attr("y", d3.round(0.5 * zoomfactor * imageHeight)); }}); """ def create_thumbnail(infile, thumbfile, width=300, height=300, cx=0.5, cy=0.6, border=4): # this doesn't really matter, it will cancel in the end, but we # need it for the mpl API dpi = 100 baseout, extout = os.path.splitext(thumbfile) im = image.imread(infile) rows, cols = im.shape[:2] x0 = int(cx * cols - 0.5 * width) y0 = int(cy * rows - 0.5 * height) thumb = im[y0: y0 + height, x0: x0 + width] thumb[:border, :, :3] = thumb[-border:, :, :3] = 0 thumb[:, :border, :3] = thumb[:, -border:, :3] = 0 extension = extout.lower() if extension == '.png': from matplotlib.backends.backend_agg \ import FigureCanvasAgg as FigureCanvas elif extension == '.pdf': from matplotlib.backends.backend_pdf \ import FigureCanvasPDF as FigureCanvas elif extension == '.svg': from matplotlib.backends.backend_svg \ import FigureCanvasSVG as FigureCanvas else: raise ValueError("Can only handle extensions 'png', 'svg' or 'pdf'") fig = Figure(figsize=(float(width) / dpi, float(height) / dpi), dpi=dpi) canvas = FigureCanvas(fig) ax = fig.add_axes([0, 0, 1, 1], aspect='auto', frameon=False, xticks=[], yticks=[]) ax.imshow(thumb, aspect='auto', resample=True, interpolation='bilinear') fig.savefig(thumbfile, dpi=dpi) return fig def indent(s, N=4): """indent a string""" return s.replace('\n', '\n' + N * ' ') class ExampleGenerator(object): """Tools for generating an example page from a file""" def __init__(self, filename, target_dir): self.filename = filename self.target_dir = target_dir self.extract_docstring() self.exec_file() @property def dirname(self): return os.path.split(self.filename)[0] @property def fname(self): return os.path.split(self.filename)[1] @property def modulename(self): return os.path.splitext(self.fname)[0] @property def pyfilename(self): return self.modulename + '.py' @property def rstfilename(self): return self.modulename + ".rst" @property def htmlfilename(self): return self.modulename + '.html' @property def pngfilename(self): return self.modulename + '.png' @property def thumbfilename(self): # TODO: don't hard-code image path return "_images/" + self.pngfilename @property def sphinxtag(self): return self.modulename @property def pagetitle(self): return self.docstring.strip().split('\n')[0].strip() def extract_docstring(self): """ Extract a module-level docstring """ lines = open(self.filename).readlines() start_row = 0 if lines[0].startswith('#!'): lines.pop(0) start_row = 1 docstring = '' first_par = '' tokens = tokenize.generate_tokens(lines.__iter__().next) for tok_type, tok_content, _, (erow, _), _ in tokens: tok_type = token.tok_name[tok_type] if tok_type in ('NEWLINE', 'COMMENT', 'NL', 'INDENT', 'DEDENT'): continue elif tok_type == 'STRING': docstring = eval(tok_content) # If the docstring is formatted with several paragraphs, # extract the first one: paragraphs = '\n'.join(line.rstrip() for line in docstring.split('\n') ).split('\n\n') if len(paragraphs) > 0: first_par = paragraphs[0] break self.docstring = docstring self.short_desc = first_par self.end_line = erow + 1 + start_row def exec_file(self): print("running {0}".format(self.filename)) with disable_mpld3(): import matplotlib.pyplot as plt plt.close('all') my_globals = {'pl': plt, 'plt': plt} execfile(self.filename, my_globals) fig = plt.gcf() self.html = mpld3.fig_to_html(fig) thumbfile = os.path.join(self.target_dir, self.pngfilename) fig.savefig(thumbfile) create_thumbnail(thumbfile, thumbfile) def toctree_entry(self): return " ./%s\n\n" % os.path.splitext(self.htmlfilename)[0] def contents_entry(self): return (".. figure:: ./{0}\n" " :target: ./{1}\n" " :align: center\n\n" " :ref:`{2}`\n\n".format(self.pngfilename, self.htmlfilename, self.sphinxtag)) def main(app): static_dir = os.path.join(app.builder.srcdir, '_static') target_dir = os.path.join(app.builder.srcdir, 'examples') source_dir = os.path.abspath(os.path.join(app.builder.srcdir, '..', 'examples')) if not os.path.exists(static_dir): os.makedirs(static_dir) if not os.path.exists(target_dir): os.makedirs(target_dir) banner_data = [] toctree = ("\n\n" ".. toctree::\n" " :hidden:\n\n") contents = "\n\n" # Write individual example files for filename in glob.glob(os.path.join(source_dir, "*.py")): ex = ExampleGenerator(filename, target_dir) banner_data.append({"title": ex.pagetitle, "url": os.path.join('examples', ex.htmlfilename), "thumb": os.path.join(ex.thumbfilename)}) shutil.copyfile(filename, os.path.join(target_dir, ex.pyfilename)) output = RST_TEMPLATE.format(sphinx_tag=ex.sphinxtag, docstring=ex.docstring, end_line=ex.end_line, fname=ex.pyfilename, img_html=indent(ex.html, 4)) with open(os.path.join(target_dir, ex.rstfilename), 'w') as f: f.write(output) toctree += ex.toctree_entry() contents += ex.contents_entry() if len(banner_data) < 10: banner_data = (4 * banner_data)[:10] # write index file index_file = os.path.join(target_dir, 'index.rst') with open(index_file, 'w') as index: index.write(INDEX_TEMPLATE.format(sphinx_tag="example-gallery", toctree=toctree, contents=contents)) # write javascript include for front page js_file = os.path.join(static_dir, 'banner_data.js') with open(js_file, 'w') as js: js.write(BANNER_JS_TEMPLATE.format( banner_data=json.dumps(banner_data))) def setup(app): app.connect('builder-inited', main) python-mpld3/doc/quickstart.rst0000644000175500017550000001004612410130733016632 0ustar debacledebacle.. _quickstart-guide: Quick Start Guide ================= The mpld3 package is extremely easy to use: you can simply take any script generating a matplotlib plot, run it through one of mpld3's convenience routines, and embed the result in a web page. The current release of mpld3 can be installed with pip:: pip install mpld3 Then you can make an interactive plot like so:: import matplotlib.pyplot as plt, mpld3 plt.plot([3,1,4,1,5], 'ks-', mec='w', mew=5, ms=20) mpld3.show() For more information on installation, see :ref:`installing-mpld3`. For more examples of mpld3 in action, see the :ref:`example-gallery`. Next, we'll give a quick overview of the basic mpld3 functions you should know about. General Functions ----------------- .. currentmodule:: mpld3 These are the general functions used to convert matplotlib graphics into HTML and D3js. See some examples of these being used in the :ref:`example-gallery`. :func:`fig_to_html` This is the core routine which takes a figure and constructs a string of HTML and JavaScript which can be embedded in any webpage. :func:`fig_to_dict` This routine converts a matplotlib image to a JSON-serializable dictionary, which can be loaded into an appropriate HTML page and rendered via the mpld3 JavaScript library. Note that custom plugins which are not built into mpld3 will not be part of the JSON serialization. :func:`show` This function is mpld3's equivalent of matplotlib's ``plt.show`` function. It will convert the current figure to HTML using :func:`fig_to_d3`, start a local webserver which serves this HTML, and (if the operating system allows it) automatically open this page in the web browser. IPython Notebook Functions -------------------------- These are functions which enable the use of mpld3 within the IPython notebook. See some examples of these being used in the :ref:`notebook-examples`. :func:`display` This function displays a single mpld3 figure inline within the IPython notebook. It is useful if you want to use the standard static figure display hook through the notebook, but override it in a few cases. If you want every matplotlib figure to be displayed via mpld3, use the :func:`enable_notebook` function, described below. :func:`enable_notebook` This function will adjust the IPython notebook display properties so that mpld3 will be used to display every figure, without having to call :func:`display` each time. This is useful if you want every figure to be automatically embedded in the notebook as an interactive JavaScript figure. This function should be called *after* setting ``%matplotlib inline`` mode within the notebook: see the `IPython documentation `_ for details. :func:`disable_notebook` This function undoes the changes made by :func:`enable_notebook`, so that the normal matplotlib backend is used instead. Saving Figures to File ---------------------- Figures can be saved to file either in a stand-alone HTML format, or in a JSON format. mpld3 supplies the following convenience routines for this purpose: :func:`save_html` Save a figure to a stand-alone HTML file. :func:`save_json` Save the JSON representation of the figure to a file. Note that custom plugins which are not built into mpld3 will not be part of the JSON serialization. Plugins ------- The mpld3 plugin framework allows nearly endless possibilities for adding interactive behavior to matplotlib plots rendered in d3. The package includes several built-in plugins, which add zooming, panning, and other interactive behaviors to plots. Several examples of these plugins can be seen in the :ref:`example-gallery`. For some examples of built-in plugins, see :ref:`linked_brush`, :ref:`scatter_tooltip` and :ref:`html_tooltips`. For some examples of defining custom plugin behavior, see :ref:`random_walk` and :ref:`custom_plugin`. More information on using and creating plugins can be found in the :ref:`mpld3-plugins` documentation. python-mpld3/doc/faq.rst0000644000175500017550000001463212410130733015214 0ustar debacledebacle.. _faq: Frequently Asked Questions ========================== General ------- - **Does mpld3 work for large datasets?** Short answer: not really. Mpld3, like matplolib itself, is designed for small to medium-scale visualizations, and this is unlikely to change. The reason is that mpld3 is built upon the foundation of HTML's SVG, which is not particularly well-suited for large datasets. Plots with more than a few thousand elements will have noticeably slow response for interactive features. Big data visualization requires specialized tools which do careful automatic data summarization and/or take direct advantage of your system's GPU. There are a couple other Python projects that are making great headway in this area: - `Bokeh `_ is a project which targets browser-based graphics, and recent releases are beginning to do big data in the browser the right way. - `VisPy `_ is another effort to provide easy visualization of large datasets. It is based on OpenGL, with plans to add a WebGL backend. - **What matplotlib features are not supported?** matplotlib is a complicated system, and there are lots of small corner cases that are difficult to render correctly in d3. mpld3 correctly handles a large majority of matplotlib plots, but some pieces remain unsupported either because they have not yet been implemented, or because there are fundamental difficulties preventing their inclusion. We keep a list of unsupported features at https://github.com/jakevdp/mpld3/wiki#mpld3-missing-features. If you find something missing that's not on that list, please feel free to add it. - **Can I use mpld3 without matplotlib?** Yes! The client-side interface of mpld3 is a pure JavaScript library, which builds figures based on a well-defined JSON specification. This specification was designed with matplotlib in mind, but there's nothing stopping you from generating the JSON from another source, or even editing it by hand. Unfortunately, at the moment, this JSON spec is not well-documented, but we hope to address that in the future. - **Can mpld3 render to HTML5 canvas rather than SVG?** At the moment, mpld3 only renders to SVG via D3, not to canvas. However, the mpld3 JSON output is not specific to the display protocol, so it would be possible to create a canvas backend on top of the mpld3 architecture. If you're interested in a Python to canvas visualization package, you might check out the `Bokeh `_ project. IPython Notebook ---------------- - **Why does IPython notebook freeze when I run an mpld3 example?** Short answer: This most often happens when someone uses :func:`mpld3.show` within the IPython notebook. Instead, you should use :func:`mpld3.display` or :func:`mpld3.enable_notebook`. See the :ref:`quickstart-guide` for a description of the various mpld3 functions. Long answer: like matplotlib's :func:`plt.show` function, :func:`mpld3.show` does not play well with the IPython notebook. :func:`mpld3.show` generates an HTML representation of a figure, then launches a local web server and attempts to open a browser page to display it. This behavior is nice when running a stand-alone script, but is generally not what you want within the IPython notebook, which is already in a browser window! Try :func:`mpld3.display` or :func:`mpld3.enable_notebook` instead; these are specifically designed for embedding figures within the IPython notebook. If you accidentally use :func:`mpld3.show` within the notebook, you will have to interrupt the kernel (Kernel → Interrupt) to be able to continue. JavaScript ---------- - **Where is the mpld3 JavaScript library located?** There is a local copy of the mpld3 library bundled with the package, which you can find in ``mpld3/js/mpld3.v0.2.js`` where ``v0.2`` indicates the library version, and matches the version of the mpld3 Python package. This local copy is used with the command ``mpld3.show``, so that no internet connection is needed. Online copies of the library can be found at https://mpld3.github.io/js/mpld3.v0.2.js. This is automatically used within the IPython notebook, and commands like :func:`mpld3.save_html`, :func:`mpld3.fig_to_html`, etc. - **How can I use mpld3 without an internet connection?** To use mpld3 without an internet connection, you need to use a local version of the mpld3 and d3 libraries. Outside the IPython notebook, you can use the :func:`mpld3.show()` function, which automatically uses local copies of the JavaScript libraries. Inside the IPython notebook, both the :func:`mpld3.enable_notebook` and :func:`mpld3.display` functions take a boolean keyword ``local``. Setting this to ``True`` will copy the mpld3 and d3 JavaScript libraries to the notebook directory, and will use the appropriate path within IPython (``/files/*.js``) to load the libraries. Be aware, though, that currently ``local=True`` will fail for some use-cases of the notebook. See the documentation of the above functions for details. Troubleshooting --------------- - **Why is the notebook behavior breaking when I update mpld3?** Short answer: you must make sure that your notebook is pointing to the correct JavaScript libraries. The best way to do this is to follow the following steps: 1. Clear all the output in the notebook (This can be done via the toolbar, with Cell → All Output → Clear) 2. Save your notebook 3. Close the notebook window 4. Re-open the notebook window Long answer: mpld3 is a bit more complicated than the average Python package, especially when it is used in the IPython notebook. You must keep in mind that there are two distinct components which interact: the Python library, and the JavaScript library. If you have an IPython notebook that uses mpld3 and you update the library, you must make sure that your notebook is using **both** the updated Python package and the updated JavaScript package. Using the updated Python package can be as simple as restarting the kernel and running the notebook again. However, because the JavaScript library is referenced in the output cells, loaded on page load, and cached by the browser, it is very easy to find yourself using old versions of the JavaScript library even if you're using the newer version of the Python library. If you have any strange notebook issues after updating mpld3, then it is best to wipe the output, restart the browser, and start again from a clean slate. This can be done using the steps outlined above. python-mpld3/doc/modules/0000755000175500017550000000000012410130733015355 5ustar debacledebaclepython-mpld3/doc/modules/API.rst0000644000175500017550000000045112410130733016520 0ustar debacledebacleAPI documentation ================= .. automodule:: mpld3 :members: .. automodule:: mpld3.plugins :members: .. automodule:: mpld3.mplexporter :members: .. automodule:: mpld3.mpld3renderer :members: .. automodule:: mpld3.utils :members: .. automodule:: mpld3.urls :members: python-mpld3/doc/plugins.rst0000644000175500017550000000034412410130733016121 0ustar debacledebacle.. _mpld3-plugins: Plugins ======= Plugins in mpld3 offer a means of defining new interactive behaviors on matplotlib plots through the use of JavaScript and D3js. More information is available in the :ref:`notebook-examples`. python-mpld3/doc/Makefile0000644000175500017550000001521112410130733015345 0ustar debacledebacle# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* rm -rf examples rm -rf notebooks html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/mpld3.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/mpld3.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/mpld3" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/mpld3" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." python-mpld3/doc/conf.py0000644000175500017550000002062312410130733015207 0ustar debacledebacle# -*- coding: utf-8 -*- # # mpld3 documentation build configuration file, created by # sphinx-quickstart on Mon Jan 27 20:45:33 2014. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('sphinxext')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.doctest', 'sphinx.ext.coverage', 'sphinx.ext.viewcode', ] import numpy_ext.numpydoc extensions.append('numpy_ext.numpydoc') import plot_generator extensions.append('plot_generator') import notebook_converter extensions.append('notebook_converter') autosummary_generate=True # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'mpld3' copyright = u'2014, mpld3 developers' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. import mpld3 version = mpld3.__version__ # The full version, including alpha/beta/rc tags. release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'mpld3' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. html_theme_path = ['themes'] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". html_title = "Bringing Matplotlib to the Browser" # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. html_logo = 'logos/mpld3-medium.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. html_favicon = 'logos/favicon.png' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'mpld3doc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'mpld3.tex', u'mpld3 Documentation', u'mpld3 developers', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'mpld3', u'mpld3 Documentation', [u'mpld3 developers'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'mpld3', u'mpld3 Documentation', u'mpld3 developers', 'mpld3', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False python-mpld3/doc/logos/0000755000175500017550000000000012410130733015030 5ustar debacledebaclepython-mpld3/doc/logos/favicon-large.png0000644000175500017550000000672012410130733020260 0ustar debacledebacle‰PNG  IHDR1ÑaË /iCCPICC ProfileHÇ–wTTׇϽwz¡Í0Òz“.0€ô. QfÊà Mlˆ¨@DE €£¡H¬ˆb!(¨`HPb0Ѝ¨dFÖJ|yyïåå÷ǽßÚgïs÷Ù{Ÿµ.$O./– ™'àz8ÓW…Gбýx€¦0Y驾AîÁ@$/7zºÈ ü‹Þ Hü¾eèéO§ƒÿOÒ¬T¾È_ÄælN:KÄù"NʤŠí3"¦Æ$ŠF‰™/JPÄrbŽ[䥟}ÙQÌìd[ÄâœSÙÉl1÷ˆx{†#bÄGÄ\N¦ˆo‹X3I˜Ìñ[ql2‡™Š$¶ 8¬x›ˆ˜Ätñrp¤¸/8æ p²âC¹¤¤fó¹qñº.KnjmÍ {r2“8¡?“•Èä³é.)É©L^6‹gþ,qmé¢"[šZ[Zš™~Q¨ÿºø7%îí"½ øÜ3ˆÖ÷‡í¯üRê`ÌŠj³ë[Ì~:¶ wÿ›æ!$E}k¿ñÅyhây‰RmŒ333¸–‘¸ ¿ë:ü }ñ=#ñv¿—‡îʉe “tqÝX)I)B>==•ÉâÐ ÿ<Äÿ8ð¯óXȉåð9€¢yPÜõßûæƒâ›¦:±8÷Ÿýû®p‰ø‘ÎûçLg ù‹kâk Ѐ$È t!0VÀ87°ø`ֈɀ2A.Ø @Øö‚JPêA#h'@8 .€Ëà:¸ î€`Œƒç`¼óa!2Dä!UH 2€Ì d¹A>P ECqB¹Ð¨*…*¡Z¨ú:]€®BÐ=hš‚~…ÞÃL‚©°2¬ Ã Ø ö†ƒá5pœçÀùðN¸®ƒÁíðø:|ŸÃ³@ˆ QC â‚ø!H,ÂG6 …H9R‡´ ]H/r A¦‘w( Š‚¢£ Q¶(OTŠ…JCm@£*QGQí¨Ô-Ô(jõ MF+¡ Ð6h/ô*t:]€.G7 ÛЗÐwÐãè7 ††ÑÁXa<1á˜Ì:L1æ¦s3€ÃÌb±Xy¬Öë‡ebØì~ì1ì9ì vûGÄ©âÌp‡+Ç5áÎâq¸y¼^ oƒ÷óñÙø|=¾ ?ŽŸ'Htv„`Ba3¡‚ÐB¸DxHxE$Õ‰ÖÄ"—¸‰XAàPð4Ð407°7ˆÔô&Ø9¸$øAˆnˆ0¤;T242´1t.Ì5¬4ld•ñªõ«®‡+„sÃ;#°¡ ³«ÝVï]=iY9´FgMÖš«kÖ&­=%ÅŒ:Ž‹nŠþÀôcÖ1gc¼bªcfX.¬}¬çlGv{ŠcÇ)åLÄÚÅ–ÆNÆÙÅ퉛Šwˆ/Ÿæºp+¹/<jæý$.$…%µ&ã’£“Oñdx‰¼ž•”¬”TƒÔ‚Ô‘4›´½i3|o~C:”¾&½S@ýLõ u…[…£öUo3C3OfIgñ²ú²õ³wdOä¸ç|½µŽµ®;W-wsîèz§õµ  1º7jlÌß8¾ÉcÓÑ͉̈́›È3É+Í{½%lKW¾rþ¦ü±­[› $ øÃÛl·ÕlGmçnïßa¾cÿŽO…ìÂkE&EåEŠYÅ×¾2ýªâ«…±;ûK,KîÂìâíÚí°ûh©tiNéØß=íeô²Â²×{£ö^-_V^³°O¸o¤Â§¢s¿æþ]û?TÆWÞ©r®j­VªÞQ=w€}`ð ãÁ–嚢š÷‡¸‡îÖzÔ¶×iוÆÎ8ü´>´¾÷kÆ× E ðŽŒ <ÚÓhÕØØ¤ÔTÒ 7 ›§ŽE»ùë7-†-µ­´Ö¢ãà¸ðø³o£¿:á}¢û$ãdËwZßU·QÚ Û¡öìö™ŽøŽ‘ÎðÎS+NuwÙvµ}oôý‘Ój§«ÎÈž)9K8›vá\ιÙó©ç§/Ä]ëŽê~pqÕÅÛ==ý—¼/]¹ì~ùb¯Sï¹+vWN_µ¹zêãZÇuËëí}}m?XüÐÖoÙß~ÃêFçMë›]ËÎ: ^¸åzëòm¯Û×לּ302tw8rxä.ûî佤{/ïgÜŸ°é!úaá#©Gå•×ý¨÷cëˆåÈ™Q×Ѿ'AOŒ±Æžÿ”þÓ‡ñü§ä§åª“f“§§Ü§n>[ýlüyêóù邟¥®~¡ûâ»_é›Y53þ’ÿrá×âWò¯Ž¼^öº{Ööñ›ä7ós…oåß}Çx×û>ìýÄ|æ쇊z»>yz¸¼°ð÷„óû7)bKGDÿÿÿ ½§“ pHYs  šœtIMEÞ/$C—‚"IDATxÚíØ;JQ€ásó@ A!鬴tâÁ-X¹ ×bm!ØXX…Á"X¥S;ÑxÜø@.ß·ƒs†ûÏ)ã­ÕóÈØ”ȵۻ~TâmzzgµÌÓ.±[VŽn‚Fê´2–Þ#{U´ #«z: Ñ«gžÒuäš«e€bˆ €bˆ €bˆ €bˆ €bˆ €bˆ €bˆ €bˆ €bˆ €bˆ €bˆ €bˆ €bˆ€bˆ €bˆð+€ïËÌÖÎñÅ\ ìõdo»–YÊ쩟Ãe'¯j A•1˜¿Çu5oŸÑÃUü3Ä@ 1Ä@ 1Ä@ 1Ä@ 1Ä@ 1Ä@ 1ÄøV €bˆ €bˆ €bT§cü——îppv9Éffq?}t3€Ÿx^Ü<¬e–µõ¡Ï Nbˆ €bˆ €bˆ €bˆ €bˆ €bˆ €bˆ €bˆ €bˆ €bˆ €bˆ €bˆ €bˆ €ˆ €bˆ €bˆ 4UFéÚ‚@Di,A 1Ä@ 1€OM¬@ 1Ä@ 1Ä@ 1Ä@ 1Ä@ 1Ä@ Ä@ 1Ä@ 1Ä@ 1Ä@ 1Ä@ 1Ä@ 1Ä@ 1Ä@ 1Ä@ 1Ä@ 1Ä@ 1Ä@ 1Ä@ 1@ 1Ä@ 1Ä@ 1Äø¥ä86g¥&ðøIEND®B`‚python-mpld3/doc/logos/mpld3.png0000644000175500017550000004701612410130733016565 0ustar debacledebacle‰PNG  IHDRb6¡þš AiCCPICC ProfileH –wTSهϽ7½Ð" %ôz Ò;HQ‰I€P†„&vDF)VdTÀG‡"cE ƒ‚b× òPÆÁQDEåÝŒk ï­5óÞšýÇYßÙç·×Ùgï}׺Pü‚ÂtX€4¡XîëÁ\ËÄ÷XÀáffGøDÔü½=™™¨HƳöî.€d»Û,¿P&sÖÿ‘"7C$ EÕ6<~&å”S³Å2ÿÊô•)2†12¡ ¢¬"ãįlö§æ+»É˜—&ä¡Yμ4žŒ»PÞš%ᣌ¡\˜%àg£|e½TIšå÷(ÓÓøœL0™_Ìç&¡l‰2Eî‰ò”Ä9¼r‹ù9hžx¦g䊉Ib¦טiåèÈfúñ³Sùb1+”ÃMáˆxLÏô´ Ž0€¯o–E%Ym™h‘í­ííYÖæhù¿Ùß~Sý=ÈzûUñ&ìÏžAŒžYßlì¬/½ö$Z›³¾•U´m@åá¬Oï ò´Þœó†l^’Äâ ' ‹ììlsŸk.+è7ûŸ‚oÊ¿†9÷™ËîûV;¦?#I3eE妧¦KDÌÌ —Ïdý÷ÿãÀ9iÍÉÃ,œŸÀñ…èUQè” „‰h»…Ø A1ØvƒjpÔzÐN‚6p\WÀ p €G@ †ÁK0Þi‚ð¢Aª¤™BÖZyCAP8ÅC‰’@ùÐ&¨*ƒª¡CP=ô#tº]ƒú Ð 4ý}„˜Óa ض€Ù°;GÂËàDxœÀÛáJ¸>·Âáð,…_“@ÈÑFXñDBX$!k‘"¤©Eš¤¹H‘q䇡a˜Æã‡YŒábVaÖbJ0Õ˜c˜VLæ6f3ù‚¥bÕ±¦X'¬?v 6›-ÄV``[°—±Øaì;ÇÀâp~¸\2n5®·׌»€ëà á&ñx¼*Þï‚Ásðb|!¾ ߯¿' Zk‚!– $l$Tçý„Â4Q¨Ot"†yÄ\b)±ŽØA¼I&N“I†$R$)™´TIj"]&=&½!“É:dGrY@^O®$Ÿ _%’?P”(&OJEBÙN9J¹@y@yC¥R ¨nÔXª˜ºZO½D}J}/G“3—ó—ãÉ­“«‘k•ë—{%O”×—w—_.Ÿ'_!Jþ¦ü¸QÁ@ÁS£°V¡Fá´Â=…IEš¢•bˆbšb‰bƒâ5ÅQ%¼’’·O©@é°Ò%¥!BÓ¥yÒ¸´M´:ÚeÚ0G7¤ûÓ“éÅôè½ô e%e[å(ååå³ÊRÂ0`ø3R¥Œ“Œ»Œó4æ¹ÏãÏÛ6¯i^ÿ¼)•ù*n*|•"•f••ªLUoÕÕªmªOÔ0j&jajÙjûÕ.«Ï§ÏwžÏ_4ÿäü‡ê°º‰z¸újõÃê=ꓚ¾U—4Æ5šnšÉšåšç4Ç´hZ µZåZçµ^0•™îÌTf%³‹9¡­®í§-Ñ>¤Ý«=­c¨³Xg£N³Î]’.[7A·\·SwBOK/X/_¯Qï¡>QŸ­Ÿ¤¿G¿[ÊÀÐ Ú`‹A›Á¨¡Š¡¿aža£ác#ª‘«Ñ*£Z£;Æ8c¶qŠñ>ã[&°‰I’IÉMSØÔÞT`ºÏ´Ï kæh&4«5»Ç¢°ÜYY¬FÖ 9Ã<È|£y›ù+ =‹X‹Ý_,í,S-ë,Y)YXm´ê°úÃÚÄšk]c}džjãc³Î¦Ýæµ­©-ßv¿í};š]°Ý»N»Ïöö"û&û1=‡x‡½÷Øtv(»„}Õëèá¸ÎñŒã'{'±ÓI§ßYÎ)ΠΣ ðÔ-rÑqá¸r‘.d.Œ_xp¡ÔUÛ•ãZëúÌM×çvÄmÄÝØ=Ùý¸û+K‘G‹Ç”§“çÏ ^ˆ—¯W‘W¯·’÷bïjï§>:>‰>>¾v¾«}/øaýývúÝó×ðçú×ûO8¬ è ¤FV> 2 uÃÁÁ»‚/Ò_$\ÔBüCv…< 5 ]ús.,4¬&ìy¸Ux~xw-bEDCÄ»HÈÒÈG‹KwFÉGÅEÕGME{E—EK—X,Y³äFŒZŒ ¦={$vr©÷ÒÝK‡ãìâ ãî.3\–³ìÚrµå©ËÏ®_ÁYq*ßÿ‰©åL®ô_¹wåד»‡û’çÆ+çñ]øeü‘—„²„ÑD—Ä]‰cI®IIãOAµàu²_òä©””£)3©Ñ©Íi„´ø´ÓB%aа+]3='½/Ã4£0CºÊiÕîU¢@Ñ‘L(sYf»˜ŽþLõHŒ$›%ƒY ³j²ÞgGeŸÊQÌæôäšänËÉóÉû~5f5wug¾vþ†üÁ5îk­…Ö®\Û¹Nw]Áºáõ¾ëm mHÙðËFËeßnŠÞÔQ Q°¾`h³ïæÆB¹BQá½-Î[lÅllíÝf³­jÛ—"^ÑõbËâŠâO%Ü’ëßY}WùÝÌö„í½¥ö¥ûwàvwÜÝéºóX™bY^ÙЮà]­åÌò¢ò·»Wì¾Va[q`id´2¨²½J¯jGÕ§ê¤êšæ½ê{·íÚÇÛ׿ßmÓÅ>¼È÷Pk­AmÅaÜá¬ÃÏë¢êº¿g_DíHñ‘ÏG…G¥ÇÂuÕ;Ô×7¨7”6’ƱãqÇoýàõC{«éP3£¹ø8!9ñâÇøïž <ÙyŠ}ªé'ýŸö¶ÐZŠZ¡ÖÜÖ‰¶¤6i{L{ßé€ÓÎ-?›ÿ|ôŒö™š³ÊgKϑΜ›9Ÿw~òBÆ…ñ‹‰‡:Wt>º´äÒ®°®ÞË—¯^ñ¹r©Û½ûüU—«g®9];}}½í†ýÖ»ž–_ì~iéµïm½ép³ý–ã­Ž¾}çú]û/Þöº}åŽÿ‹úî.¾{ÿ^Ü=é}ÞýÑ©^?Ìz8ýhýcìã¢' O*žª?­ýÕø×f©½ôì ×`ϳˆg†¸C/ÿ•ù¯OÃÏ©Ï+F´FêG­GÏŒùŒÝz±ôÅðËŒ—Óã…¿)þ¶÷•Ñ«Ÿ~wû½gbÉÄðkÑë™?JÞ¨¾9úÖömçdèäÓwi獵ŠÞ«¾?öý¡ûcôÇ‘éìOøO•Ÿ?w| üòx&mfæß÷„óû2:Y~ pHYs  šœÕiTXtXML:com.adobe.xmp 5 2 1 °ã2Ý@IDATxí œœE™ÿßêžÉääJ@!@IÏd€ˆ°\qÅ·"{áµ+»v7Š»®ëz¬îº¢®ÇªY9„Ä€œÉ!94rÏtwý2l®éó}ߪ÷íoñyèž÷­ªç©o½éþuU½õF € @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ 2rpÄ@€@~ ØÅ‹‹+ï»ïêhevÙ#eYM7ÆÎˆ"3ÝFzÙ¢µf1Ñ:+36Z§|²è Ù]²U½ÃÿË*%„XV{ޏ!@#pG_߬MÖžbd62'êõ‰­Ií6ÃãDÙª§Í šÉ“®(Ý|óoÛ­7ò5…Ø=}s³ÑÜ4iÕǾ Ù2ýÈ}zZ-ŸF¹žÌ­<{¶/´$c-ÎdäÛ‚*N/.SŒ‹Bޱ<¥ëú¨bO 9Æj±8U«½!Ç8V®Þomác,W¢M‘­N 5Ʊrem%ªìj|[ã²f¥^ç§ã¾òutŠþvç*èj» 8ûÇ̳md½ö{ϺuÁþhk·oïë;d´Z}‹F½ÞZ©T5íè#Ùã¢jtœFÜ>.á}WdÌ?wÏžý¹K—Žúˆf"Ÿ¹½&j0Ç!@H†ÀHÿÑ=ÿ3Z©Þ«Ñ¯ "k=‰°ÛçFâlÕþûØwÝ=ÜÛûÎÕ§ÌLBlǾâ/@€š$0¼páAƒó{¿Z)Wn“èyµF¡j.}j²úز+®çhšôKzø7ŒçZÝ[å-V„kÅ @N`Õ‰'î3<¿÷í¦Í«µLèÏ5öÔm&v ãW†{û~µrÁ‚9>û!æ“>¾!@$ðPÿT °nÜtO5²£‘¦Él†t£=I£xƒC¥¾¿³ýý^nXCˆeñÊ!f@€€'ÃóûÞú‡rån °OJÉìé)ŒØÜJDöX[ýØP¹rËðqÇ[Å V„kÙ @L`ÕâÅ“4 öÕ¨úM °rÇÂÚ’ÐèØ[ÒlB,MÚø‚ d€¶8v×]×jì/2~Ã!kÝØ4Žý×P©÷"7ýÚpÁ62"ÄÚ€GQ@€@Þ hCÖ¨+$Ræ½­ãíÓÚ±sÖ”ËW¯îë›9~,©W„XRd©€ qÚs뽕ªý…DØþoJÓá;á¹¾joXµ`ÁMn¢B¬ Xd… t7-§é¹okÏ­Ïi=Xͧð䚇ž…©Íio*×—T;bI‘¥^@€@ ÜqÒI3ÖŒU®ÕôœžI’i£òO“º£!Æ5@€ÀVvñââ¦u¾¯çpöƒd;cÕÑòÏܶ;Ë[„X,©€ }Ãw­þWíZö[’D ìÁvóæ+ï]´(ÖÍkbIôuB€2F@µ¾GÓ‘ïÊXØ©†«üÇ>¹ö‰ÏÄé!'Mê‚ dÀ`oïË«Æ~6ƒ¡§²«C¥¯ˆË1B,.’Ô@È ÛúúJ¦j¿§Eé™x`wˆmT½hÕñÇ?;ŽXbqP¤@€@ ÜÞß@¹R½BÏ[œžÁðý…¬Åûc££_×è˜i7„X»)@È '"¶”+ÿ#û€ÄÑtÈZ/öR=uà=MÜ©Bl' ü @è#¥¯Ótäó;¡­IµÑVí…+,˜ßNý±vèQ€ A«/ždMõ“ =¨5šØS©T¿ÛΖ± º”` @É]½úšZ;,yOù÷ )Þ¹O®}òoZm)B¬Ur”ƒ d€¶ªØKwIþ]C7d[}ÿê… ÷h%@„X+Ô(@È(c£kJmŸŒ†dØâ¹÷†Í£ïm%8„X+Ô(@È Uýýk~Ûwúe°éɇÜâ¨B,ù®Á @ £•ʽ‰õY‰A4,€ ܨØú-[Îm6„X³ÄÈ@È ·Í‚Ö†½%ƒ¡g'd½©Ù`bÍ#? @ ƒÊåê¹µi{'ø 6=½­- •N8²‡±fh‘€ Anß0Ù×g0ô †<öºf‚Fˆ5C‹¼€ »ë7¯ÐhX¦î”ÔÐÝæÈ˜‡e³…Ü6%ĺ²Õ8¢… @ YÖVÏn¶Lšù‰n³Æ\^4æ§QW׃“&Mzäèë¯_7Ã'ž8å©ÑÑ™•JåX[N­šè%ºûó˜ñó!½º ^W-XpÄÜ+în$.„X#”È@È(U‹M]ûÄi‘†ÄBJñ²íú†±“.( /¿·VlϹñÆM:ÿÀ6û±Ë;Üß¿ :V¹@Õ¼ÌýR*—·>ó!!ÆÔdH=G,€ ˜ Tžxâ=ꎹڶª3Ƭ2]Åöýii¤¶›ÈQi``EßÈÐË‹ÅÂó%êî™(ŸãÕ‚}^£~b’" @ ƒªÖ¾(¬°Í­Ý{ïõ¼ÒŠ¿Š#®ùƒƒ7öLî9A7„^G}qÔa,B,ŽÔ@È>L#Œ¹{zѼlî²eëãŒiÎòåõv_,1ö£8ëmµ.͹Î{¨¿j#åk„y @$0ròÉ{+ìÞ B7fÓ¤bá´Ùƒƒ$›>¥ç-š¦¼3‰ú›ªÓÚ®G«Õã)ƒk„y @$PY¿¾¤5úA|×lta£w¶ŠzöÍ7?Õ],œ–k4ÒŽ :§‘@É@€@s´V鍿J$“Û-¦ßcŸ½.L¦ök;8x»Dß—v<šþ_ÆFG4â!Ö%ò@€²I ©Çí$ÖD}ü°eË6'Vÿ.OýŒÿQ1{ø.aíæ@í}ÄLtŸTìÖý:vS6ˆCv´znƒ z×ÝÂhõ~-Ü{2`Q©>lŠ]Mt:„ãúÕ°¶¢[žCˆe¢ôïeT›Nšè¼ïãSؤ'ÍMñG-ÿbx_­óœƒš!`4"æy1cÝsï½þ»™¨ÛÍ[¹aÍP©÷ëjù»Ú­«ÕòúÞo_ˆÍYqÇå ÀY¸iÐÿš¼pá t6;Û{ûMôÕtGÞnq¡`þ·R±Þ„˜¢8Ô.^\4K—VjõS“µèp€ a•ñþ|I=¶ÈË€Ž­Ì¼VÓ“cÞºO›èŽÜyÿÁõü#Äêâ< @ £´X†×ÐyjÞž{Þâ#†ÒÈÏ6hVöV¾Ç}šâXÝéI„Ø8-^!@9"`ûû»µFªÇg“Ldo5Ë–•=Æð;¾#[‰©ç!Vç!@$°rÊ”éþÃ6ûŒÁû¨OÿQÁ>«ž„X=Bœ‡ d€›æ?lûÏ1<âÓµí_Ï?B¬!ÎC€2H «\öþo­Iqï°];IÛ[yöψخ½Â@€ ݵºo=7ÞÕr½9@€²H@TïY/n„X=Bœ‡ @­°!Ö 7Ê@€ v è‘w{Ô«ƒ±z„8@€Z  }Ôb-p£ @hŸ€¦Ô«„±z„8@€Z  'ÜjEˆÕ¢Ã9@€ Ð;'Ož\«8B¬ÎA€ 67nDˆµÁ¢€ @ e'MªùàuFÄZFKA@€ P›@½GM!Äjóã, @h™@y¬X¬U!V‹ç @€@ Ý•šZ«æÉ6üR€ tCæÖ4¬—¹ë~£ŒXØÅ‹‹w?ðÀ´ÊèèôªµÓÆzz6éö©#nºi1†Ï˜X(SIHô¼Éš×u§ 175{”¬o;;\ïÝÓÒÝÒîØmÖq'È‘ ÊnÙfCzÍŠHÛW±³“=W»6‹/½Ý!•õ×£2×î5²ßËn–]#[)«y¡é<É?w=Ï–ÍßÎŽÖû½d®ï'ºÅºªsN”ýVöëílDïo“‘ ð »dIaäâ+މЕ£m5šc­=ZßCsld2Öκó®÷TÚ´yëÅ5\ê­–zð_£çóé3¥0\0v¸Ë˜¡cïÆo 1v¬Póû±Q!澤ôÜöå߉v“ûÕÿ'²7É^)›&k&¹‘go³yz}ë¶Âczu¢ä벋eN°…’œà|¾ìÌmæÄf³É]+ãí/ëºô¸ìZ™k¿3'Jk^x:zÊË5ï®÷—ÈÞ ;Cæ„v³É]?N¨‹÷íËÿNüx›]¥W'ØHFà¡þþ©V*§j„ëôáK.y…þñïUþ‚Ýúi`k~((K!²ÖýÞSïõƒ¡zVEo**58¿÷×-û¡5ö‡}CCîó…ÔâäÉk£Ê†÷75±,úâXžX婸»Xv?f'L ±¿R ï›°–tNÌ”7"Ójr_"ï–½VæF„âNî ïÅÛì ½þ·ì‹²Ûe¾RIŽß%s_Àû'Ä>ªûÌmæÜ¬’ý³ì;²QYSÖ¯ùCýƒ²Å²$®wU»5¹h±Í6êõ²ÏÉVËH9'°²¿ÿðJ¹rþš±ò륙v銵íQ³ö|i²ó%Ê~£¶/íßÕõï³Ü5Gš€ÀÑ×_ïFÝ¿G’GÕ:S“î—nÞ“pÿ&sÓ(ï%ù¥¤ê·¦½ôçkXö/27šf:Jξ'”¹/É$E˜ªß%ÍÕ‘‹d÷É>,Û[FJ‡À¹ù¨ÌM!¾]–Æõ.7[ÓTýÿ²;d—ÊŽ“‘rH`xþ ‡ •J_+—+wH ½-Y¶3@{¸FØ>û‡r御R߇î8é¤;çào„DÀjOMæYˆ¹Ñ¾¿‘¹_æNín½—'š\ ï“Ý){s¢žž®Ü .'€ÜˆÔëdFæ3 矔= s¿Êö“‘’#ð2UíØß˨Û÷¹âFao–¹~oe:TÅH!;ÇF[~-1ô§šJltV%þ¦X;ÓÚê§6¯[/AV:'~Ôxhgýí&êw­3¯BlO5õDz”¹÷¾“[[õ-ÙweI}A¾PuÉÜ’Ñ)·&÷Eü^Ù ì¤ sq¢«ÂWÈi§’˜ËºÏ×ï·ÉܺLR† ¬Z¼x’Ï—%À.ÒXO(MQ,û¸˜Û•+?þ9¡ÄE'0Z­Ö\ßžG!ö\5þFÙ©ãzu ¦—Éœ0‹+¹><_ö ™ 9¤à–ÉΓù­S¹HÝjÅÊ.”…ÊÔ‰Ã+e‘2HàŽ¾¾Y£w®^&Á㦻ƒLŠí¥•-£«†{{Ï2@‚êXF»´Ôj|Þ„ØÉj¬›™S«ÑžÏ-”ÿå²ÞâpS‘?‘] ml¢æ¹©Œ’]*cíØD”;îøýTöge÷šË‰ÄÏÈ>/ËÛçŽW°I;*õŸ¼¹RÐÐ'&í«Ýú5:6£Zµßìíý'·F»õQqèšf˵êÉÓ…úV5Ô ea’>¿Nv†¬ÕôBtS‘!Žü5Ò¦Ó•i…¬¿‘ÌäÙ…À:r“ì”]΄}ÀÝú}Yž>{Â&ÞFtšî;×F•«%pâÅo#¢‹VíyC_zñðü—4»=QƒÈÆ  …܈¹_ÚŸ}S6©q4Þsºˆ‹el2×ÞóeY˜Š¬×´C•ág²Ùõ2r~/Ð_N„¹ÃÑìüñ…úÏÙ ·3#*-8KÛE|Y òÝôw“=ÃF¸vÕ‰'ºíuHðF §»;×B̉’oË>âp{ŽÝ¨À§e_l°—ÿë²,MEÖkšû¼BÆ4e=ROŸ±^œxMs[ŠÆ"k.×û”ýÜæŠ;-#ýýó´•êi$Ì}Æf6)þc7þxÕ¢Eܹ›Ù^Ìvàúd[¶ls­Vd}zàïÔ¸7Öj`FνKq~¸N¬n Ø·dg×É—ÅÓnd燲ŒþòN ¹»ãÔ­­ 掵6[î~€,j³ŠÇLà×'œ°oµ\¾L‹ßs1­§v,[»ö²{-š3*ªƒ@#¶ÔË”e!æÖ-©×À wÓ«oš Þ.ÿoYDçMܺÖéËäx´@ þW–‹/Çmýé®ë¯É¦lû›Ïì¢E][¶Œ.•x9Ìs(±ºW{^ôÄãO|Ÿü±bÍDeÖ÷9ã3mªç<«BÌÝùmY¦‡Íwê×·뢎»uoKe‹w:žÇ?ÝÝn^ÒŽŽÑŸîîÈ=w<œ‹¿ž«V¸ hI^ûä¿h§üS%¶>ó¨˜*ƒ&Põú¹i©9-éÐeQˆ9¨nzf†k@Î’]—Èænk—›‚r úÏÜöw'¼¸5snÒÓ×ËU²ýr ä<µMk’H> èqAoÑNõïöCâ¾õ¬Ê•½½§&î!ð*Äb}=Yb.ÞïÊÜš¢¼¦½Ô0÷T÷ü#ÙËe”\»'"¢Èms’‡»cëõ¥›: ÏëQJðüƒ'ž8ÅFöÂ]QµïÊ6úŽÛ 6ˆ€"qššô*ÄŒžª×Hßs§õâÛùü:ð²æðïƒÕ¦Ûen„¬“Û8Òº‘ÏNNNˆÔ!þDít?>~Ó!í ª™mÜømUq@PA%ŒžQ¹¹¢¹Æfm ")"y¯× nøK&ZWÏy–.ÄÏ©1©× ïT6Þ…ŸÔ›âøúÚ)"Ìu¯[#ù—ÚÏ^›½õnB¹g•vLÒè_¿ð÷uLƒ;¹¡ÆïÚZ]gOÖß%!6Ñ…õÚÈùlp7d¼-›¡u‹ÎQ¹¼lÍÑ"‚ô‹=¹ö)m|퓾g—ž—Ž«ÎõR¶!ֹݟۖööîU©Ú/„ÐÀb¡py#q Ä¡Dž0]B/¤ý0kk-B,aÆTŸ.;ûû÷3Ö^­)÷ézÞ7cš70°b7gv9„Û %p‚âb‹@;'°¼ïÿ“@›B«òÐÐ"´J`xþqÇn,W® åÑUZ¨…1zäw‰/¶ ‘%n±þ±²¡ ¢!ˆ¤ ™´ê÷»ã8ü!¡RékÍy6;M®—þ #Y£Ë7˜b ‚"[W± º"ñ ž#î󩜸§u gð=«¡Ÿëʇf‡IÀM?n*—ÿHâë…ÆD/Öû\mS¡ÿBJæ7“fÏþy4ÔØ×B,¤¾#–z­—ó¹!à>›’Ý—›…ׯÏà …@`õi§õT׬™±±R9¨`ÌÁ¶Z=ØX½{p™c7•‘èÒÈ—ÄWXêë|…¢ùÐÜ¥KGŸ9PçM^…˜p»lÍ6{D¯OÉö•=Kæ>€Ü-òûÈòš¶¨a;3X§cûÉÆ”ô~OYVÒ¡Y ÔSœOÊï*ÙCÛì ½º'°Ífë5K×üaŠ÷>)fvÉ’ÂðÅ—¸k#Iߺë«wµ‚uŸéîó|¾œ+úr~¶Þ»Ï³Cõ¥ì–.2B@SНU¨ŸÖlâd-°Ÿ¬÷Sd=ë÷Ð3Ó‹Õmã\[Ç»¶Š®@•×ö̹¡48ø?Ûª÷>OBl­{…ÌÍËþTæDG­äž¯æ¥òJÙd³dYOªã ~¦÷ê4Èõÿ dã ÜZÈéЃóÛzù½X¶TæúÜý™(¹þþcÙëe¯’….ÂTŒ¤Üsùån3×°oÖ2ænMŸ^fŠÅËæ~ø féÒJ-à m}¥ÄÙbMWR+/ç `Ì^¶jõc+´iÅöØŠ…4[CØÿk“È_‘©C£·Êœ­'”%rÿ¨¯‘'s ƒ?!s£HYLUý¯2ÇàÙ%²z"LY¶®¿¹Z¯ï—¹Ñ’’Õú"×i¯i–Wïá9ÿ¡B:Jv¶Ì ðz}çÖ[¹)î9XöuYÈi¿ƒËrl뻺f„¿‰¢õZûóW½¯:ó¨ÞááóJ+Vüªžsm)Ý|óoK#ƒ_îzQ±XÐfžf$Ô6W> è.Éïèz½©ÙÖe]ˆÝ£ÿ‘ì27-Ójr¢å|Ù1²ÛZ­ÄS¹;å÷DÙûdëÛˆÁ‰×¿•Í“ÝÕF=I–dåªû1Åzºì527 ÙJzJ…þTv†ÌMõ„˜23u"¼Z1ÆÆ‚b`WwwwÍ•û¢Y²ÄýÀl)ͼª÷¬3ûT߇$ìÜu&`nÜ¿«ø—­8ɲs_F/‘]ßJÃ'(ã„Ý)²Ænu˜ ’ÿ^¾ƒå1út"ì…2·¾,´45´€<Äó¸|¾XvyL¾ÝT¾FAÉeÃÕ0"Ö0ªæ2V*•ð„˜1Ãûwu½rîÀÀ͵f÷¹“ »PkË^/1–ÕÙŽÝ7Ž£a0æöIÓ¦¼bÖÀÀÆV˪sS0gÉ~ÓJ£ë”që¬^$[Y'ŸïÓ›À™²X>´vjŒx‹d¡Œuºs‹ïhŠû‡Â°ê|«,´‘FÄÔ)I$S(„%ÄŒy´§`Îhõ‹¬#‰±Ø‚yidÌX­|œƒ@+$òÛ5©û¥so¼ÑýHn)eUˆ] Ö^ÛR‹+äþŸ-skjBMQ`7'œ›®z›¬åébswÕtrz£¿"!«ÞO%Tw«Õ†~3A«íò^Nw©M÷Äv˜¨pî1ƒƒ÷ow(Ö·}CCËLd>k¥TÖñ´&ìwÝÅŸ̻å–Û‘E!æF>ßN£,;¨|nñzˆÉ‰¤O!°åã )øiÔE' ±o Ò•‚j1ß'UnM‹e“(6-‰J©S¿®lÁmH2#¥¡K’¦wxð úâüAÒ~¨¿3h$ìÓ ¦oîà`ÛËx²(ľ¨nv ÓH•“ߦá¨IŸUþ–梛ôã²ÿ?™~!$]û™œ8z_ -w7­\˜‚ŸF] Ä%Õd>ˆõ4Y$¹ì…èã>“¯Ý 3¦¿]S”i}´.å$ /!̧JGù'³cùnÌšsS…n›†´’[àùµ´œ5èÇ­ û·óÆ‘Í}93ŽŠ¨£eŸPÉ–×4éõËÊÿp“e’ÊÞék“âªÄì¤ä*o¦fó@ï™gþ°™íäÝukµxÿKíÔAÙÎ%  O˜¨x†¦º?ÒÈ–*’Êš»A s‹éÓLÉYH뤖)ž´Ñ}5MàøÚ€ùü¯Ž$ûÇ&UÿÝd]4\;#b £j.£>ЂÓÐÅílSÑ\«ŸÎ=ݘѨXZ3 ­„H™ ˜«Œ´ 4²"®;ÖŸieÖ„XÒkdž³Ý›ôþçÛýíûí=àîžü•¿¸Œ¢ï ‚[™fr ÷CH±„zAS“AŒˆYSLm4låÖé$]6þ7¯¨MÀ¦ÆÝMn ß©Ûwùõ_`DÌ­{È‹sœO `¢ÿ˜wÆ?M+P„Xc¤ŸT¶ûËšh.ŸbÔMUý!ÑÖQùÎnÚù@Šß–¢¯‰\¹íJœ‘b'PðþÙ¯;Ð|Ípl¥©ur!L¿ÇÞ³TØ>jÕ~bè’K5ÒßtûµÕ¯Áû?Æú!>“cõ3ïü¼yÌÛ¼Â`¹ÿ#îG5lU3™Ì›¥å bˆ·jk­ÿÏþjáÁx[Õdmz¬R“%ÈÞI¬}~u¬<8T*}Ð.Y’è¿—D+¹Ï|‹´ï\Û>Ÿ#b.72HJ€OñïóõpzMГÿ)´ CËî cü 1Óå÷óÄÚÔ·BÊîÓ¡‘k=Òd]'Ÿ¾äÒ«$ÈL C–„˜Ï/%Ç?’Ö¦ž]o!ˆÑ‰bËãq'†|¦¦n²ô峯šô­U0žSWµšö~ˆ;´Ø˜hýøÐò)Öšá‘ÞÞ3&ÈÒÖá,}ȹÞ}¦„ |^éûö-ÄÖ¥ßd<¦A@룼öWzz¼ ±48ã#O쾕ª½t¨Ôw„Y¬?d¼ÿcl¢›|‹÷x%ß ¾{ ]ÿ¾G béöwjÞlS““ÊåJj Æb"`mõ|‰±KV-Z4=¦*#„X\$Ó©Ç·K§•x'àû‹ !6Þ¹{5YúìÏ}”uöŒ±µk¯]Ý×73Ž–dé#"$Š`ÇUO` M£¤2–ÏX¶ÉX—n`´ˆ¿o}Å^sG_߬vCË’ aj°]Þí–‡A»)ß vßLÜä… ;gsµúËÕ îÑŽ³, ±vÚIY@€ +Œ¹a󿝷S)B¬z”… @ £ HŒ¥ühB¬Ur”ƒ @"`#ûé¡RÿÉ­À@ˆµB2€ @`œ€µ]6ª|ÿÎþþýÆ5úŠk”ù @ˆ‡€5åÈß[ôÄÓ–ñZ¬µq¬òþñ?}庒" @±è¼H]d/.>|Ï==N™ÒSܲ¥Ç”Ë=£ÕÝOÛ¸ç;>mÕh–KuHdíñzä¤X‚H ÅøÎ;N:éÓG_}Ãû0"Ä誄 @ >³t©۸Ͷ/p×öŒ¿¨¿ê#cöÖTNÕ¬S%ÊæŸ áU?Úk˺ ç*–Ï4S“’" @^ ÌØXYñ“ÞááôŽ Ï×Ô‹d·y j'çU½ÕâÅ Ú!ÄvÈŸ€ dƒ€Ù/K{ïÝWˆ ï5Æø~>ïÓдVlì®»ßÜ(A„X£¤È@€@p̲eåÒÈàç» f‘‰¢ ͦ)Ê74 !Ö()òA€ ,c‡ óº îÆ4Ñómw#°bP" @Á˜?4ôc™¦·ˆ½aÖN½­R9¾‘zbP" @™ PZñÅ(2¿ñlµ½°‘bP" @™  EûVöo¾ƒµÆ"Ä|wþ!@HŸ@aÆ´¯k­˜ÛŸÌ_²ÑIvÑ¢ºûµ2"毋ð @€@æ_wÝZÙ&PuÃUj³Ùé+×­;¢^„X=Bœ‡ @ ƒ ·øºZ.P/„X=Bœ‡ @ s´Fk¥ï µXmV½bõq€ ̘Z,zôQ¡1"–¹+‡€!@h›ÀQj§ýß·]QhT!Ö?ŠB€ m«}†o­Aˆùì|C€ à‘€1Oyôî\³FÌsà€ o¬ï‡€ï_¯é,Ö¯Gˆó€ d•À¯›hj=ÿ±z„8@€@V x3ÖN®!Vç!@È$-–÷*Ä´Ø”zàbõq€ l(D^Ÿ7ɈX6/¢† @ mÒ#ý%9ŸTÏ;#bõq€ ´HÀö÷w×*Š«E‡s€ @  GB¬ ~… @-Ø„k™!@€@[ʱ¶øQ€ ´L`´««X«0kÄjÑá @hƒ@÷è(B¬ ~… @-cD¬ev„ @m(1"ÖA C€  t‹±ÙQ € ´E  ^Öª€Åúµèp€ ´AÀT«±6øQ€ ´L`ÔNBˆµL‚€ @  ¦›±6ðQ€ ´NÀÔY#ÖÕzÕ”„ @ T÷.Z4ùɵO½Ðg|“Lõžc††VûŒ!tß±Ð{ˆø @-ظnÝþÖV~ÒBÑØŠl±æ“ªìÿÅVa+²ÆØZas×d-:œƒ @mè.—«µŠ#ÄjÑá @hƒ€-kƒE!@€@˪LM¶ÌŽ‚€ @ -Õ±"S“m¤0 @h‘@¡Ç–keX-:œƒ @mЫU!V‹ç @€@ºªUFÄÚàGQ@€ Ð2mØÊˆXËô(@€Ú 0!Ö=ŠB€ 6ðÊWn®Uœ5bµèp€ ´HÀDѨY²„í+ZäG1@Hˆ@¹PàYÇ ±¥Úpè9“5GÃ\¤Œˆ…Ó_DìJ æ/É]³s$+ÌØØŒ¬ÄJœh•€±vS½²±z„8ø$€óI?AßcÅ¢W!fmÔ“`ó¨ã6Œ¿™è!6ŽC“@Póa¹ÄG-0ÕªW!¦°÷j1tŠA qÆñh- WÁmMôX½ö3"Vç!à€o!v„¿¦oõÜI£a©nå /ï_Цjõu}ÝÞ×wHdíL_þÓò+±Yw¡xÒ±ØÈxbÆX¿#bQ´¦c„X=Bœ‡€?ûs9ß¾§F;i4lzš}mlgˆVÍóÒäíËWo±è]ˆE6:ÈWû·ù=ʧÿB5úC=ÿ±z„8ùsÍ÷è{ÜuÍåŽgŠá5Á—êÂuímTŽ[[Uú>C¥Žl«’– W¶\4CÍÀÀ˜ÛÙÝgÈZ‹wô¯O8Á˨ت㶦&óÙ~J"Ä|v¾!Ð&STÞ×G!Œ¤õ²¥Í~Š£xª#b!,ÖÚ–Wů…:^ÒB™¬ñ:*&Ám6Žþ‘xå-å“|øÝÑg!¶#þ‚@¦¸_‘ýž"öõ¹}sÓHuA²}P ½OuA±~¥§%rëà2gÕÉûé¡RÿÉÚÒÀë±7ªv…ëkŸNþ¬F`ÝÊÔ“~pxñ»}Cõo5bÛá=2Hà½b>Z>ñàwg—i‰…„ØœŸðß^GIži›µÇ/\˜ò¢ÊÛŸñßo´XÞ»Ó:±7?Ôß?5MÜ«-š®Ñ¸7§ésw¾&uwÿ~wÇ·?ƱíiðáxƒB:<å°^Ÿ²¿‰ÜuÒˆXÚkò‚bnÚÊnÞòW]q_¹pá³t·äkâ®7äút×à¾ãsëÿP©œ“f£OÔt¹& Œôöž¡µa¯m²X²V‡Ñ{xùÎÕO#–¡±ÊÝ-ééŽÜí[hïÜþ¯‰Þ#Ä&"Ãq„Eà"…3;áœ;/aÍT¿©™Ìmä­ûPÞ6ên¦èÛšÉÜfÞ ¦&ÇÛ`#ûŽ•}}Çÿ÷ëýýûUlôå¸ëÍF}&Œ1ÁR?Ÿ7Ü×÷ÇIrs7chˌą}ƒmhˆ=B¬Ašdƒ€g{Èÿe²ŠÃíìþÙþ ÕßJµëZ)ÔB™‡Z(“D·°¸;‰Šw®³«Px|çc>ÿvÓ…•ª½ôöþþâŽÃíaµ±\¹Jë…b¯;îX“¨¯0©ȈØÖihS­Úo w\"›¬Žüs­­|G×SÚFwL2"–ÄEMðHÀÝYw“,‰)¬ÏªÞylÛî\wš{– |lw â>V4摸ël·>M8Z®\çÝu#'Ÿ¼÷–-[~.Vj7¾¬–Ÿwè¡÷k3ÂÍÁÄ/A\+ÿjdÁ‚þ8céïŸW»NrÏçIvh’~ð¬ÜáÀ¡'ˆÃ€À®Ü­þú°‰^·ë©–Žì§Rß–¥vçZQ¦%ÄÜ—T(#D«XÄö¹Ï­û â&ú)¶¬c'¬+ÜÖÛ{|»•Žôõ½ ºnÝMZ+Ô×n]Y.o–.­h[è‚jƒžóY-W~9TZËçØ`oï™wׄ4ê©EúO{úé·5Â!Ö%ò@ ,î–ìïÉ܇ëóZ ÍMEº©°_ËÞÔbIKKˆ¹v„2=é>“¯ý™ *©4wéÒÑȘPÖÆíÐLM+=f£†J¥®^¸ÐMÉ7•Üz0•ýÏj¥º,ŒÛM…ŸHf=[ôªD*n£Rõó M#~O}õ«V×ÞÖ×W*õ^Uí%ª/ÕM‘ë7Ý^g–,©ÖÏEîØd“À‰ ûFÙ­²Ëe?’ Ëô™´Û´¯ŽºÑ–Óe/“í# 9¥)Ä~'ILù¶ÂwŠ ý§ì¥² d#²ø“ÜôdÓB'þ@vS£µ]ºˆÿ~æÍÔí•Zò󽞞®«æ,_¾Û‘¼Õ}}3×[ûò¨½VëÁ^¬©¬µÛMäA*ÍÏ«ûɃ“X>¹R©.W?ߢ®Ëµ®êŠÞÁÁáÝmû S³ò¸ã޵c•WHá¼²\©.Ôu䀒Äï5òFˆ5JŠ|—€»ÛÌÙGeeÙ™ÛÍùI™û•èàÏ”eíË)ÍéÂûÄ'´ôäìjÙWdnTc­,–¤Í&Ô—àá±T–P%ú’íÑtÓ™QT9sóæJ44¿´E#y+=SEßËhÚmÖúJՉקÓD?CÆÏwàë±gœ±bøâKš |).ÝèhOPל × †zûʃ¥ÞG´¶í:¦kÞî¥'0ð¤ö4¿½NçŒÀÜlÁüKΚå­9Úõÿ3óV¬hù®k„˜·®Ã1 0Ó’ã¡< 7M/¶/œÑ×_f4nÂnƒÀ”iÓ>¥‘œß¶QEE@ ïÙoÚ”·!Ö=ÊBIpÏTô™:j¤ «PøšOØøöCàèë¯_gŠ…·IH°p¿Õ.ÐV …báœçÜxã¦V«påbíУ, 7·¯•oapbŠ»a¡Öwìà ˆgn 5>âJŽ@ipðÚäõ_“óïšÅîüùƒƒ×¶ÛJ„X»)ÄIà"Uæî^ô>ë;€4ý"ó•4ýá+{ì³×‡u%ë›ìÝ%ù¿¥¡6Yl·Ùb»ÅÂA@À·H>”_çßQ,+<0ðâr}öü¦¨ÜÓ HFà°eË6w̉6tXÓÛh®y {ê”·JŒÅ2­‹k£+( „ ü¹êï¤GwÇâ= 3m´z' ß-‹åƒ¶Q§¾ò¹/c­:þ†/ÿ©û5f“¦•|m‘’zsë9|zzºøzTÔÖÅùëµ)î«çÞxcl?\bõ¹“¾¸=­Îõå܃ßЦݺ©ozààÅew±øe}—½8OÓ©1cE½FÂ!¶wmFz…˜¼w»C¼Ý‰€F7›¨xÆÖMqw:×Ο±vèQÉpSd_MÞwKAˆ»¼Pq­ñN'…æ®Xq·‰ìgRpåÍ…¾H«…‚9{þÐн°ã¾¡¡/iŠ2´DaÓ‰°×êY’WÇB,n¢Ôø ¼GUêζÜ&×¶sma‹eù)R#÷:õc+¡LÇ~I˜‚ù+Ý)øß±Wœ£ KCCçiíSGmáR¯û¶ xkÞÒʽëÕíÎ#Ä¡Dø%àErºìA¿a$âÝí¢¦,äµp×*¾¿N¤õUêöC*ÌÛ +–pŒ)ü½DÆ¿ÅRYŽ+q Ð{‡‡þZwÒ~$ÇÍl¸ia£š²=»42ø½† 5™!Ö$0²CÀä÷TÙ#žü'áÖ2½Fv_•Ç\çTßE1×duó††~®%ɡܽ #‰ŠÏõ^KeRIidèSA<×uH“wi¦Úþ¸6l}Iïðð·w9ã„XŒ0©  ¸Sõ¿DödÂ~ÒªÞ- ¾&-g1øù Õñ1Ô|½GÍþ€ÄØ•ÁÚP€æ›ó‡;bD³!Mdêú ‘S$Hr;]=!cVG¦çDmØšøgBlÂ^à‚$àv|©ÌMée99A“µi"72àîbýt–Á7»Yº´2eÆ´×iáömä5F¾Ú{Ö™×~O¡¶3ɸÜÎñ&zÖ|] _ ëˆí\ô#äšÉ=“Nì^~W’lÇëFˆ“àÙ!p“B](ûuvBÞ!ÒÏé¯wíp$[|Xá¾S¶.[a7­{aqÒ¤—éË÷ŽæJ†‘["ìŸ4½ö—fÉ’ŽZ‹«'J#?Û é¹÷ä~tL[›Ds¾F„ÿxÎòåÅů^=±z„80 ¸©‚eZÏ“™´Q‘¾Yö~YÖïBü²Úp´ì»²Ü¦y·Üò`÷´©'IŒý*+T¬UÞ|H"ìo³sVâtÓtyÓ¨é*u-ÔŸp#Âiö B,MÚø‚@¼ÜZ±—É>&‹·êØk»W5>_æöEËKzH y“l‘,ÓSxŠÂävŸvà¬SõEõƒ 3…r˜‡t‡Û‹5zË3CiVHqämtÌ w‚}fÚ¬ú{‡oôÁ!æƒ:>!7²ô²ãe^>DhÊO•ç8Ùpy³˜åÝ's#}Oe±õbž}å•[´¥Áëô…u޾¸¯—ßÇy‚]®u=ó%Â~éçùt£cÝG9GÓ•oÔ5‘™Óñ~RÌV×Ì Ý]½ûwŸKû!–6qüA Näœ ûˆìÉd\4]«‰Ÿ¹Q» ¿¼›nÑÄ\[ÝÚ·£d_‘­‘å.é ë&š6G_`ߦqÆÜmLñõ`§§¹®'˜ö{ dîÒ¥£nƒÜÞ‘áèš8Vö=&+”ÏŸÝ’yZ€™KºŠ…>]3¯™?0°r·S<ˆK6® 0'>%;Dv¾,µÅ¦òµ}rq\$;Ræâè¤ÅÒ¿W{ß!;@v’ÌM‘eõ¦ …¾k*ܰF_`¯×èØÉš®¼D_l~úט‡µIë;z÷ÞkŽž“Ž0ÜYGÑ5±Jöžgug¢ÂŸ÷Puc4Zm¾k fFwÏzúAçatMWa #÷‹ÔD¹·÷Õenê2éäDÈ¥2÷¼Âß$í,ðú8¹a›}H¯GÈÜÓœ,+Ê24:v½pýÊþþÃ+åêû¬µoÐlϾ‰6jëóþìUšSúö~S¦\잨?*ošÀ¬wSÎל­ìë;®lí+´éÅóµÏ³Q4£é Û( º5Öš Ñ%ÅÙ³¯r#xmT—XQý˜!A»!àžµö¾ÝOóÐL9‹k¿°ƒU׫egÉÜz­É²v“»³h•ì ÙdËeú¬%Õ!°·ÎÏ—¾sçZIsTÈë6vÉ’ÂÊË.[h+öåÖØ—éJèÕÅÐþwŒ1êaäÆ~ES¾çFäZD¿Üõ±ê²ËæU¬=ÉJ˜)½ÚCc‹Ê˜ŠÄÞݺân“P¿­hÌÕóÎ8ãº,l_Òþ?’Ø(R‚"7!¶=\7ãÖ2•¶™{ng{è½Yëw²µúûN™ûÂwÓmwË‚ü…©¸²šöQàãíP½w#ÓdS뼞¢ó«eÁ¤‡úû§êy\GW+•9…j4§j¶NUï¥/Ëú²œn#3Cï{ô¥¹ÞX­k4[otxÒêUÇï×ñ]ÝÝn `E ±¸£¯oÖ¨µ½ú°Ù_ÏÔu2Sý¿Ÿ~ÏÍ”ßO×ÈL]îÚ×5b×iý™¦í:r­Ó´¸^íczböí:¿júüÚç‚ûXÁP °•€bntǧé‰@y&Àbý<÷.mƒ @ h± »‡à @È3„Xž{—¶A€ 4„XÐÝCp€ ä™B,ϽKÛ @šB,èî!8@€òL!–çÞ¥m€ M!t÷ @y&€ËsïÒ6@€‚&€ º{€ <@ˆå¹wi @A@ˆÝ=@€@ž ÄòÜ»´ €   Ă @ Ïbyî]Ú@€@ÐbAwÁA€ g±<÷.mƒ @ h± »‡à @È3„Xž{—¶A€ 4„XÐÝCp€ ä™B,ϽKÛ @šB,èî!8@€òL!–çÞ¥m€ M!t÷ @y&€ËsïÒ6@€‚&€ º{€ <@ˆå¹wi @A@ˆÝ=@€@ž ÄòÜ»´ €   Ă @ Ïbyî]Ú@€@ÐbAwÁA€ g±<÷.mƒ @ h± »‡à @È3„Xž{—¶A€ 4„XÐÝCp€ ä™B,ϽKÛ @šB,èî!8@€òL!–çÞ¥m€ M!t÷ @y&€ËsïÒ6@€‚&€ º{€ <@ˆå¹wi @A@ˆÝ=@€@ž ÄòÜ,´6â†IDAT»´ €   Ă @ Ïbyî]Ú@€@ÐbAwÁA€ g±<÷.mƒ @ h± »‡à @È3„Xž{—¶A€ 4„XÐÝCp€ ä™B,ϽKÛ @šB,èî!8@€òL!–çÞ¥m€ M!t÷ @y&€ËsïÒ6@€‚&€ º{€ <@ˆå¹wi @A@ˆÝ=@€@ž ÄòÜ»´ €   Ă @ ϺòÜ8Ú6Ü ²SÛ(GÑÍqTB€ @€ @€ @€ @€ @€@úþ?› t[Ʀ}àIEND®B`‚python-mpld3/doc/logos/mpld3-medium.png0000644000175500017550000001274112410130733020040 0ustar debacledebacle‰PNG  IHDRPPw¼ /iCCPICC ProfileHÇ–wTTׇϽwz¡Í0Òz“.0€ô. QfÊà Mlˆ¨@DE €£¡H¬ˆb!(¨`HPb0Ѝ¨dFÖJ|yyïåå÷ǽßÚgïs÷Ù{Ÿµ.$O./– ™'àz8ÓW…Gбýx€¦0Y驾AîÁ@$/7zºÈ ü‹Þ Hü¾eèéO§ƒÿOÒ¬T¾È_ÄælN:KÄù"NʤŠí3"¦Æ$ŠF‰™/JPÄrbŽ[䥟}ÙQÌìd[ÄâœSÙÉl1÷ˆx{†#bÄGÄ\N¦ˆo‹X3I˜Ìñ[ql2‡™Š$¶ 8¬x›ˆ˜Ätñrp¤¸/8æ p²âC¹¤¤fó¹qñº.KnjmÍ {r2“8¡?“•Èä³é.)É©L^6‹gþ,qmé¢"[šZ[Zš™~Q¨ÿºø7%îí"½ øÜ3ˆÖ÷‡í¯üRê`ÌŠj³ë[Ì~:¶ wÿ›æ!$E}k¿ñÅyhây‰RmŒ333¸–‘¸ ¿ë:ü }ñ=#ñv¿—‡îʉe “tqÝX)I)B>==•ÉâÐ ÿ<Äÿ8ð¯óXȉåð9€¢yPÜõßûæƒâ›¦:±8÷Ÿýû®p‰ø‘ÎûçLg ù‹kâk Ѐ$È t!0VÀ87°ø`ֈɀ2A.Ø @Øö‚JPêA#h'@8 .€Ëà:¸ î€`Œƒç`¼óa!2Dä!UH 2€Ì d¹A>P ECqB¹Ð¨*…*¡Z¨ú:]€®BÐ=hš‚~…ÞÃL‚©°2¬ Ã Ø ö†ƒá5pœçÀùðN¸®ƒÁíðø:|ŸÃ³@ˆ QC â‚ø!H,ÂG6 …H9R‡´ ]H/r A¦‘w( Š‚¢£ Q¶(OTŠ…JCm@£*QGQí¨Ô-Ô(jõ MF+¡ Ð6h/ô*t:]€.G7 ÛЗÐwÐãè7 ††ÑÁXa<1á˜Ì:L1æ¦s3€ÃÌb±Xy¬Öë‡ebØì~ì1ì9ì vûGÄ©âÌp‡+Ç5áÎâq¸y¼^ oƒ÷óñÙø|=¾ ?ŽŸ'Htv„`Ba3¡‚ÐB¸DxHxE$Õ‰ÖÄ"—¸‰XAàPð4Ð407°7ˆÔô&Ø9¸$øAˆnˆ0¤;T242´1t.Ì5¬4ld•ñªõ«®‡+„sÃ;#°¡ ³«ÝVï]=iY9´FgMÖš«kÖ&­=%ÅŒ:Ž‹nŠþÀôcÖ1gc¼bªcfX.¬}¬çlGv{ŠcÇ)åLÄÚÅ–ÆNÆÙÅ퉛Šwˆ/Ÿæºp+¹/<jæý$.$…%µ&ã’£“Oñdx‰¼ž•”¬”TƒÔ‚Ô‘4›´½i3|o~C:”¾&½S@ýLõ u…[…£öUo3C3OfIgñ²ú²õ³wdOä¸ç|½µŽµ®;W-wsîèz§õµ  1º7jlÌß8¾ÉcÓÑ͉̈́›È3É+Í{½%lKW¾rþ¦ü±­[› $ øÃÛl·ÕlGmçnïßa¾cÿŽO…ìÂkE&EåEŠYÅ×¾2ýªâ«…±;ûK,KîÂìâíÚí°ûh©tiNéØß=íeô²Â²×{£ö^-_V^³°O¸o¤Â§¢s¿æþ]û?TÆWÞ©r®j­VªÞQ=w€}`ð ãÁ–嚢š÷‡¸‡îÖzÔ¶×iוÆÎ8ü´>´¾÷kÆ× E ðŽŒ <ÚÓhÕØØ¤ÔTÒ 7 ›§ŽE»ùë7-†-µ­´Ö¢ãà¸ðø³o£¿:á}¢û$ãdËwZßU·QÚ Û¡öìö™ŽøŽ‘ÎðÎS+NuwÙvµ}oôý‘Ój§«ÎÈž)9K8›vá\ιÙó©ç§/Ä]ëŽê~pqÕÅÛ==ý—¼/]¹ì~ùb¯Sï¹+vWN_µ¹zêãZÇuËëí}}m?XüÐÖoÙß~ÃêFçMë›]ËÎ: ^¸åzëòm¯Û×לּ302tw8rxä.ûî佤{/ïgÜŸ°é!úaá#©Gå•×ý¨÷cëˆåÈ™Q×Ѿ'AOŒ±Æžÿ”þÓ‡ñü§ä§åª“f“§§Ü§n>[ýlüyêóù邟¥®~¡ûâ»_é›Y53þ’ÿrá×âWò¯Ž¼^öº{Ööñ›ä7ós…oåß}Çx×û>ìýÄ|æ쇊z»>yz¸¼°ð÷„óû7)bKGDÿÿÿ ½§“ pHYs  šœtIMEÞ.Öà 3IDATxÚí{ŒUÅÇ?s÷ ‚""©áá™swy¶¡O´¥Ô´šÔ˜¦ˆ1¶jlµÆh4ÁhZúŒÕ&¶jµ¯Tik%µ¥b«Œåq½s.A «TAT–ÇËÞóë÷¬î.»wÎ}qÙÝù$¸ó8sf¾ç7ó›33‡c £\ Œöñc·sþ|Îå•¢ò^6~*wïnfÇǵÚwD]("ca(Ú%‰Údö˜ÆFüW_µ‹n[ã´á¹0\¶`Üg¦ìm˜8j, #&¹º¯ÌM†bUþ¨ GÔȱ#¬yo·Í‹õ¬ìÚ×&·¿Ÿ°å™H(µê¹×Ãööœ²> Š×ž[þ¥%}„O¶Õò!Ïxú0¢@”GSÙ`iÜüÖ\ì±`Sãé™÷‹ DßR×ûÜÅ+'üø7HS*î]9¨.ŽiwçLjyb—€Ñq"JÌ ql½ ¡ ‰™&OsƒV¨ú8SÕ3žþ—ÀôÑÇ#òÌ;Ïg1Úÿ˜J§›³ZãÁɺë˜ÝTyå•Qw­/ ÷Ä\÷~ß,¯²àNô\W6éS`eûjÑ3í]TbiÐ8««à:§ZHÔÕ]túy~ê:?\í"¸R,]¡IÕ8¯«Zùð­@o< |·Šõ`{_ù ©FMÔ`1%Çý “í-À2»2ž> j?ð®KŽö2éÖÀ›ƒ¬/ëÉ=Zfø?-áoW¹.þf _S;«`5»cdÓÁiB.×qÀhή§9•*Kta™¢Ûc ?^åºx¯Ìð*—Äæ•Ÿ¨Î¨«Š÷$ò’ñô’©™Ì©£ôJ{ëA®–Bõ‡³U)í¢ëoIŽØnXâ(J®QB½(™Œ0‡üTÙ‹Å[ÛU²NtŽØèlºx ¥©‰Î}¬ÆÓÏÊÉSiÝÈxú’T6X]‹îÕ1@è\Ö÷ ÉËc$Y\«1c€áC£IŸÀþFçSNtŽJûÿ°D¹Ð‰ÎQiÕÙVcw¢sTVsJÅÞ9çDç8å8Ñ9œè79ìÀh=T„·éûÝm¸:• V9Ñ9*‰m aÅVM»îÕáÆtŽßVƒMt¶áİ–ͶndÛ³`Þa(¶î·}°ŠÎ·„O¯¢h Ž‹D)Û"ÍsËÉ¿`Áã-ý,x}¥¬Ç쬢»Ô~Uy·Åˆ3¥@Ó±{™þµ™©Ózû£S‹)q·š²¯GÁ×z/SS§po³d±}°Š®ž¾7þ$)ü]›5Ûãú7ÈÙz2•ˆ,K5oáå‹òÂÛÚù1„ª Ÿ)µRT"™‹aÆ?m<ÿó›¢=öñƒ4í/Œ14Y?˜‰ï“?ìp Ð@~“òìgÛjœ8ﯧË)ã=ú§í1ÒOÌxºeİúsŒ§ÏhëÈ0ÚŸœË…ÇÊ©mÒ¢òçáY„'«ŒÖK:rá(£ýá!Œ2ž¾‘Õve«5O rïõ`/ùևȟ?gëžmܵÏ^u3BþT„ú.Ýׯ˜eм'p‘C"òFe¼˜Äí1ÇD¤ ‘’?ÁÕî…ˆJÃM™”„Íš³…òŠÈÒæ=œÀ¤kuSÒÔ„(Yk±ä%£PÔÙÌ^œèJÂ6nû]™ù¿_‹›Ré4¥Ô UºÄ§j^g r—%|9ñö§öÅ¿kucë¦^„˜_ïTü"­®ð³fÏ`ÝOÊHÛJþð÷–z™œ}Eém«öPÆ)ðs›·’Õ)†%’çP¡ý¿ õ`*02©î'u 6Ñ ôcRãPs/öý½2då êþ’¶'ë˜@Œù¶BxA†cÒ‘K9Ye8µÜÏšçãgÒƒZt?îlf±íAq'²¸¹”Â¥²æN¥ÔÏŠHòæ°º!gÌ|ÕTäH‰T Jޤ²Á¥¸§DÅ]âæv£}üìÉg›w]CÊ|–%Üv~Zœ‡ Ç/lŽî÷–xO“_òSÊÉåã€[ÈÖ ^ÁæÏÇÌMÀ|PÍ¢v(ÔU©l0iZfcgwxf™õßéIx—âÁ2cUþ:ó¿-‘L4¤ó¼Ñ³ðSµìšW­piµTü=À²^~ŸEþûÃÉÄ¥…üç*ù™¦òŸ´š5þðHÔÏw ´ „±@Šƒ šSA÷ïí÷ÙÈ]éº3?]ãgýÔèP™gK~B°?Ût6hÈx>©¬a0Ñ ¿¯?w;¼ö¸)‡ÉÎáp¢s8Ñ9Nt':‡Ã‰ÎáDçp¢s8œèNt‡ÉÎá°3ÐΧ;@ßÛè•]çpôƒº9ø?ì}{¡_e#êIEND®B`‚python-mpld3/doc/logos/favicon.png0000644000175500017550000000605412410130733017170 0ustar debacledebacle‰PNG  IHDR szzô /iCCPICC ProfileHÇ–wTTׇϽwz¡Í0Òz“.0€ô. QfÊà Mlˆ¨@DE €£¡H¬ˆb!(¨`HPb0Ѝ¨dFÖJ|yyïåå÷ǽßÚgïs÷Ù{Ÿµ.$O./– ™'àz8ÓW…Gбýx€¦0Y驾AîÁ@$/7zºÈ ü‹Þ Hü¾eèéO§ƒÿOÒ¬T¾È_ÄælN:KÄù"NʤŠí3"¦Æ$ŠF‰™/JPÄrbŽ[䥟}ÙQÌìd[ÄâœSÙÉl1÷ˆx{†#bÄGÄ\N¦ˆo‹X3I˜Ìñ[ql2‡™Š$¶ 8¬x›ˆ˜Ätñrp¤¸/8æ p²âC¹¤¤fó¹qñº.KnjmÍ {r2“8¡?“•Èä³é.)É©L^6‹gþ,qmé¢"[šZ[Zš™~Q¨ÿºø7%îí"½ øÜ3ˆÖ÷‡í¯üRê`ÌŠj³ë[Ì~:¶ wÿ›æ!$E}k¿ñÅyhây‰RmŒ333¸–‘¸ ¿ë:ü }ñ=#ñv¿—‡îʉe “tqÝX)I)B>==•ÉâÐ ÿ<Äÿ8ð¯óXȉåð9€¢yPÜõßûæƒâ›¦:±8÷Ÿýû®p‰ø‘ÎûçLg ù‹kâk Ѐ$È t!0VÀ87°ø`ֈɀ2A.Ø @Øö‚JPêA#h'@8 .€Ëà:¸ î€`Œƒç`¼óa!2Dä!UH 2€Ì d¹A>P ECqB¹Ð¨*…*¡Z¨ú:]€®BÐ=hš‚~…ÞÃL‚©°2¬ Ã Ø ö†ƒá5pœçÀùðN¸®ƒÁíðø:|ŸÃ³@ˆ QC â‚ø!H,ÂG6 …H9R‡´ ]H/r A¦‘w( Š‚¢£ Q¶(OTŠ…JCm@£*QGQí¨Ô-Ô(jõ MF+¡ Ð6h/ô*t:]€.G7 ÛЗÐwÐãè7 ††ÑÁXa<1á˜Ì:L1æ¦s3€ÃÌb±Xy¬Öë‡ebØì~ì1ì9ì vûGÄ©âÌp‡+Ç5áÎâq¸y¼^ oƒ÷óñÙø|=¾ ?ŽŸ'Htv„`Ba3¡‚ÐB¸DxHxE$Õ‰ÖÄ"—¸‰XAàPð4Ð407°7ˆÔô&Ø9¸$øAˆnˆ0¤;T242´1t.Ì5¬4ld•ñªõ«®‡+„sÃ;#°¡ ³«ÝVï]=iY9´FgMÖš«kÖ&­=%ÅŒ:Ž‹nŠþÀôcÖ1gc¼bªcfX.¬}¬çlGv{ŠcÇ)åLÄÚÅ–ÆNÆÙÅ퉛Šwˆ/Ÿæºp+¹/<jæý$.$…%µ&ã’£“Oñdx‰¼ž•”¬”TƒÔ‚Ô‘4›´½i3|o~C:”¾&½S@ýLõ u…[…£öUo3C3OfIgñ²ú²õ³wdOä¸ç|½µŽµ®;W-wsîèz§õµ  1º7jlÌß8¾ÉcÓÑ͉̈́›È3É+Í{½%lKW¾rþ¦ü±­[› $ øÃÛl·ÕlGmçnïßa¾cÿŽO…ìÂkE&EåEŠYÅ×¾2ýªâ«…±;ûK,KîÂìâíÚí°ûh©tiNéØß=íeô²Â²×{£ö^-_V^³°O¸o¤Â§¢s¿æþ]û?TÆWÞ©r®j­VªÞQ=w€}`ð ãÁ–嚢š÷‡¸‡îÖzÔ¶×iוÆÎ8ü´>´¾÷kÆ× E ðŽŒ <ÚÓhÕØØ¤ÔTÒ 7 ›§ŽE»ùë7-†-µ­´Ö¢ãà¸ðø³o£¿:á}¢û$ãdËwZßU·QÚ Û¡öìö™ŽøŽ‘ÎðÎS+NuwÙvµ}oôý‘Ój§«ÎÈž)9K8›vá\ιÙó©ç§/Ä]ëŽê~pqÕÅÛ==ý—¼/]¹ì~ùb¯Sï¹+vWN_µ¹zêãZÇuËëí}}m?XüÐÖoÙß~ÃêFçMë›]ËÎ: ^¸åzëòm¯Û×לּ302tw8rxä.ûî佤{/ïgÜŸ°é!úaá#©Gå•×ý¨÷cëˆåÈ™Q×Ѿ'AOŒ±Æžÿ”þÓ‡ñü§ä§åª“f“§§Ü§n>[ýlüyêóù邟¥®~¡ûâ»_é›Y53þ’ÿrá×âWò¯Ž¼^öº{Ööñ›ä7ós…oåß}Çx×û>ìýÄ|æ쇊z»>yz¸¼°ð÷„óû7)bKGDÿÿÿ ½§“ pHYs  šœtIMEÞ0Ø~Ë?~IDATXÃí–Ï+DQÇ?ç¾7ó$?b!Ca6¤0dã`Aþ+[²agËBŠ ÿˆR¨Yø(J“üÌB¡Ä̼7dž0ÍðÞ4cÞwynçö9÷|ϽWN{:¾+ ,õ¥VÉ_8_ïR@îKØ7ÀL¤k~‡²ß“M^ÜòKn)9¿nòç * 0¶°íË„Å$™µ)ÐŒ‹líBNãÏk{«“¦X±ÅÄi®mw7§‡¼—¬@ÔFçÆáä²C ê÷ , ҾĈ]ošõÒî¬æŠ^Ýc Ç!ëùp€ `9´XX$¶ƒWµ)ð¼Üõ”@\µ€ä™½‘<³ž­¶XƒmŒX¥LA°JÕÔ¤ž;FVö/Ҁã[M ´ÖŸÜõ_ß $@ mpld3/js/mpld3.v$(VERSION).js: $(shell node_modules/.bin/smash --ignore-missing --list src/mpld3.js) package.json @rm -f $@ node_modules/.bin/smash src/mpld3.js | node_modules/.bin/uglifyjs - -b indent-level=2 -o $@ @chmod a-w $@ mpld3/js/mpld3.v$(VERSION).min.js: mpld3/js/mpld3.v$(VERSION).js bin/uglify @rm -f $@ bin/uglify $< > $@ @chmod a-w $@ clean: rm -f -- $(GENERATED_FILES) sync_current : mplexporter rsync -r mplexporter/mplexporter mpld3/ submodule : mplexporter python setup.py submodule build : javascript submodule python setup.py build inplace : build python setup.py build_ext --inplace install : build python setup.py install python-mpld3/src/0000755000175500017550000000000012410351464013735 5ustar debacledebaclepython-mpld3/src/utils/0000755000175500017550000000000012412635415015100 5ustar debacledebaclepython-mpld3/src/utils/index.js0000644000175500017550000000003612410130733016533 0ustar debacledebacleimport "util"; import "icons";python-mpld3/src/utils/util.js0000644000175500017550000001653012410130733016407 0ustar debacledebacle/**********************************************************************/ /* Plugin registry */ mpld3.register_plugin = function(name, obj){ mpld3.plugin_map[name] = obj; }; /**********************************************************************/ /* Data Parsing Functions */ mpld3.draw_figure = function(figid, spec) { var element = document.getElementById(figid); if (element === null) { throw (figid + " is not a valid id"); } var fig = new mpld3.Figure(figid, spec); mpld3.figures.push(fig); fig.draw(); return fig; }; /**********************************************************************/ /* Convenience Functions */ mpld3.cloneObj = mpld3_cloneObj; function mpld3_cloneObj(oldObj) { var newObj = {}; for(var key in oldObj){ newObj[key] = oldObj[key]; } return newObj; } mpld3.merge_objects = function(_) { var output = {}; var obj; for (var i = 0; i < arguments.length; i++) { obj = arguments[i]; for (var attr in obj) { output[attr] = obj[attr]; } } return output; } mpld3.generate_id = function(N, chars) { console.warn("mpld3.generate_id is deprecated. " + "Use mpld3.generateId instead.") return mpld3_generateId(N, chars); } mpld3.generateId = mpld3_generateId; function mpld3_generateId(N, chars) { N = (typeof(N) !== "undefined") ? N : 10; chars = (typeof(chars) !== "undefined") ? chars : "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // make sure first character is a letter, not a digit (HTML 4 rules) var id = chars.charAt(Math.round(Math.random() * (chars.length - 11))); for (var i = 1; i < N; i++) id += chars.charAt(Math.round(Math.random() * (chars.length - 1))); return id; } // TODO: should elements be stored in a map/hash table instead? // It would make this more efficient. mpld3.get_element = function(id, fig) { var figs_to_search, ax, el; if (typeof(fig) === "undefined") { figs_to_search = mpld3.figures; } else if (typeof(fig.length) === "undefined") { figs_to_search = [fig]; } else { figs_to_search = fig; } for (var i = 0; i < figs_to_search.length; i++) { fig = figs_to_search[i]; if (fig.props.id === id) { return fig; } for (var j = 0; j < fig.axes.length; j++) { ax = fig.axes[j]; if (ax.props.id === id) { return ax; } for (var k = 0; k < ax.elements.length; k++) { el = ax.elements[k]; if (el.props.id === id) { return el; } } } } return null; } // Function to insert some CSS into the header mpld3.insert_css = function(selector, attributes) { var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); var css = selector + " {" for (var prop in attributes) { css += prop + ":" + attributes[prop] + "; " } css += "}" style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); }; // needed for backward compatibility mpld3.process_props = function(obj, properties, defaults, required) { console.warn("mpld3.process_props is deprecated. " + "Plot elements should derive from mpld3.PlotElement"); Element.prototype = Object.create(mpld3_PlotElement.prototype); Element.prototype.constructor = Element Element.prototype.requiredProps = required; Element.prototype.defaultProps = defaults; function Element(props) { mpld3_PlotElement.call(this, null, props); } var el = new Element(properties); return el.props; }; mpld3.interpolateDates = mpld3_interpolateDates; function mpld3_interpolateDates(a, b) { var interp = d3.interpolate([a[0].valueOf(), a[1].valueOf()], [b[0].valueOf(), b[1].valueOf()]) return function(t) { var i = interp(t); return [new Date(i[0]), new Date(i[1])]; } } function isUndefined(x) { return (typeof(x) === "undefined"); } function isUndefinedOrNull(x) { return (x == null || isUndefined(x)); } function getMod(L, i) { return (L.length > 0) ? L[i % L.length] : null; } mpld3.path = function() { return mpld3_path(); } function mpld3_path(_) { var x = function(d, i) { return d[0]; }; var y = function(d, i) { return d[1]; }; var defined = function(d, i) { return true; }; // number of vertices for each SVG code var n_vertices = { M: 1, m: 1, L: 1, l: 1, Q: 2, q: 2, T: 1, t: 1, S: 2, s: 2, C: 3, c: 3, Z: 0, z: 0 }; function path(vertices, pathcodes) { var fx = d3.functor(x), fy = d3.functor(y); var points = [], segments = [], i_v = 0, i_c = -1, halt = 0, nullpath = false; // If pathcodes is not defined, use straight line segments if (!pathcodes) { pathcodes = ["M"]; for (var i = 1; i < vertices.length; i++) pathcodes.push("L"); } while (++i_c < pathcodes.length) { halt = i_v + n_vertices[pathcodes[i_c]]; points = []; while (i_v < halt) { if (defined.call(this, vertices[i_v], i_v)) { points.push(fx.call(this, vertices[i_v], i_v), fy.call(this, vertices[i_v], i_v)); i_v++; } else { points = null; i_v = halt; } } if (!points) { nullpath = true; } else if (nullpath && points.length > 0) { segments.push("M", points[0], points[1]); nullpath = false; } else { segments.push(pathcodes[i_c]); segments = segments.concat(points); } } if (i_v != vertices.length) console.warn("Warning: not all vertices used in Path"); return segments.join(" "); } path.x = function(_) { if (!arguments.length) return x; x = _; return path; }; path.y = function(_) { if (!arguments.length) return y; y = _; return path; }; path.defined = function(_) { if (!arguments.length) return defined; defined = _; return path; }; path.call = path; return path; } mpld3.multiscale = mpld3_multiscale; function mpld3_multiscale(_){ var args = Array.prototype.slice.call(arguments, 0); var N = args.length; function scale(x) { args.forEach(function(mapping){ x = mapping(x); }); return x; } scale.domain = function(x) { if (!arguments.length) return args[0].domain(); args[0].domain(x); return scale; }; scale.range = function(x) { if (!arguments.length) return args[N - 1].range(); args[N - 1].range(x); return scale; }; scale.step = function(i) { return args[i]; }; return scale; } python-mpld3/src/start.js0000644000175500017550000000205412410130733015423 0ustar debacledebacle/* mpld3.js: javascript backend for displaying interactive matplotlib plots */ /* Author: Jake Vanderplas */ /* License: 3-clause BSD (see http://github.com/jakevdp/mpld3) */ /* */ /* Notes: */ /* - the objects here use prototype-based definitions rather than */ /* closure-based definitions for the sake of memory efficiency. */ /* */ /* - this assumes that d3 is defined in the global namespace, and the */ /* result is that mpld3 is defined in the global namespace. */ /* */ !function(d3) { var mpld3 = { _mpld3IsLoaded: true, // used when loading lib in case global variable mpld3 is set to something else figures: [], plugin_map: {}, }; python-mpld3/src/core/0000755000175500017550000000000012410130733014657 5ustar debacledebaclepython-mpld3/src/core/axis.js0000644000175500017550000000640512410130733016166 0ustar debacledebacleimport "element"; import "grid"; import "../utils/"; /**********************************************************************/ /* Axis Object: */ mpld3.Axis = mpld3_Axis; mpld3_Axis.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Axis.prototype.constructor = mpld3_Axis; mpld3_Axis.prototype.requiredProps = ["position"]; mpld3_Axis.prototype.defaultProps = { nticks: 10, tickvalues: null, tickformat: null, fontsize: "11px", fontcolor: "black", axiscolor: "black", scale: "linear", grid: {}, zorder: 0 }; function mpld3_Axis(ax, props) { mpld3_PlotElement.call(this, ax, props); var trans = { bottom: [0, this.ax.height], top: [0, 0], left: [0, 0], right: [this.ax.width, 0] }; var xy = { bottom: 'x', top: 'x', left: 'y', right: 'y' } this.transform = "translate(" + trans[this.props.position] + ")"; this.props.xy = xy[this.props.position]; this.cssclass = "mpld3-" + this.props.xy + "axis"; this.scale = this.ax[this.props.xy + "dom"]; } mpld3_Axis.prototype.getGrid = function() { var gridprop = { nticks: this.props.nticks, zorder: this.props.zorder, tickvalues: this.props.tickvalues, xy: this.props.xy } if (this.props.grid) { for (var key in this.props.grid) { gridprop[key] = this.props.grid[key]; } } return new mpld3_Grid(this.ax, gridprop); }; mpld3_Axis.prototype.draw = function() { if (this.props.tickvalues) { // FIXME: store the tick format type explicitly tick_labels = d3.scale.threshold() .domain(this.props.tickvalues.slice(1)) .range(this.props.tickformat); } else { tick_labels = null; } this.axis = d3.svg.axis() .scale(this.scale) .orient(this.props.position) .ticks(this.props.nticks) .tickValues(this.props.tickvalues) .tickFormat(tick_labels); // good tips: http://bl.ocks.org/mbostock/3048166 in response to http://stackoverflow.com/questions/11286872/how-do-i-make-a-custom-axis-formatter-for-hours-minutes-in-d3-js this.elem = this.ax.baseaxes.append('g') .attr("transform", this.transform) .attr("class", this.cssclass) .call(this.axis); // We create header-level CSS to style these elements, because // zooming/panning creates new elements with these classes. mpld3.insert_css("div#" + this.ax.fig.figid + " ." + this.cssclass + " line, " + " ." + this.cssclass + " path", { "shape-rendering": "crispEdges", "stroke": this.props.axiscolor, "fill": "none" }); mpld3.insert_css("div#" + this.ax.fig.figid + " ." + this.cssclass + " text", { "font-family": "sans-serif", "font-size": this.props.fontsize, "fill": this.props.fontcolor, "stroke": "none" }); }; mpld3_Axis.prototype.zoomed = function() { // if we set tickValues for the axis, we are responsible for // updating them when they pan or zoom off of the chart if (this.props.tickvalues != null) { var d = this.axis.scale().domain(); this.axis.tickValues(this.props.tickvalues.filter( function (v) { return (v >= d[0]) && (v <= d[1]); })); } this.elem.call(this.axis); }; python-mpld3/src/core/index.js0000644000175500017550000000014512410130733016324 0ustar debacledebacleimport "element"; import "figure"; import "axes"; import "axis"; import "grid"; import "coordinates";python-mpld3/src/core/axes.js0000644000175500017550000002454712410130733016171 0ustar debacledebacleimport "element"; import "axis"; import "../elements/"; import "../utils/"; /**********************************************************************/ /* Axes Object: */ mpld3.Axes = mpld3_Axes; mpld3_Axes.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Axes.prototype.constructor = mpld3_Axes; mpld3_Axes.prototype.requiredProps = ["xlim", "ylim"]; mpld3_Axes.prototype.defaultProps = { "bbox": [0.1, 0.1, 0.8, 0.8], "axesbg": "#FFFFFF", "axesbgalpha": 1.0, "gridOn": false, "xdomain": null, "ydomain": null, "xscale": "linear", "yscale": "linear", "zoomable": true, "axes": [{ position: "left" }, { position: "bottom" }], "lines": [], "paths": [], "markers": [], "texts": [], "collections": [], "sharex": [], "sharey": [], "images": [] }; function mpld3_Axes(fig, props) { mpld3_PlotElement.call(this, fig, props); this.axnum = this.fig.axes.length; this.axid = this.fig.figid + '_ax' + (this.axnum + 1) this.clipid = this.axid + '_clip' this.props.xdomain = this.props.xdomain || this.props.xlim; this.props.ydomain = this.props.ydomain || this.props.ylim; this.sharex = []; this.sharey = []; this.elements = []; var bbox = this.props.bbox; this.position = [bbox[0] * this.fig.width, (1 - bbox[1] - bbox[3]) * this.fig.height]; this.width = bbox[2] * this.fig.width; this.height = bbox[3] * this.fig.height; // In the case of date scales, set the domain function buildDate(d) { return new Date(d[0], d[1], d[2], d[3], d[4], d[5]); } function setDomain(scale, domain) { return (scale !== "date") ? domain : [buildDate(domain[0]), buildDate(domain[1]) ]; } this.props.xdomain = setDomain(this.props.xscale, this.props.xdomain); this.props.ydomain = setDomain(this.props.yscale, this.props.ydomain); /***************************************************************** There are 3 different scales which come into play with axes. - screen pixel scale - data range - data domain The data range and domain are only different in the case of date axes. For log or linear axes, the two are identical. To convert between these, we have the following mappings: - [x,y]dom : map from domain to screen - [x,y] : map from range to screen Here we'll construct these mappings. *****************************************************************/ function build_scale(scale, domain, range) { var dom = (scale === 'date') ? d3.time.scale() : (scale === 'log') ? d3.scale.log() : d3.scale.linear(); return dom.domain(domain).range(range); } this.x = this.xdom = build_scale(this.props.xscale, this.props.xdomain, [0, this.width]); this.y = this.ydom = build_scale(this.props.yscale, this.props.ydomain, [this.height, 0]); if (this.props.xscale === "date") { this.x = mpld3.multiscale(d3.scale.linear() .domain(this.props.xlim) .range(this.props.xdomain.map(Number)), this.xdom); } if (this.props.yscale === "date") { this.x = mpld3.multiscale(d3.scale.linear() .domain(this.props.ylim) .range(this.props.ydomain.map(Number)), this.ydom); } // Add axes and grids var axes = this.props.axes; for (var i = 0; i < axes.length; i++) { var axis = new mpld3.Axis(this, axes[i]) this.elements.push(axis); if (this.props.gridOn || axis.props.grid.gridOn) { this.elements.push(axis.getGrid()); } } // Add paths var paths = this.props.paths; for (var i = 0; i < paths.length; i++) { this.elements.push(new mpld3.Path(this, paths[i])); } // Add lines var lines = this.props.lines; for (var i = 0; i < lines.length; i++) { this.elements.push(new mpld3.Line(this, lines[i])); } // Add markers var markers = this.props.markers; for (var i = 0; i < markers.length; i++) { this.elements.push(new mpld3.Markers(this, markers[i])); } // Add texts var texts = this.props.texts; for (var i = 0; i < texts.length; i++) { this.elements.push(new mpld3.Text(this, texts[i])); } // Add collections var collections = this.props.collections; for (var i = 0; i < collections.length; i++) { this.elements.push(new mpld3.PathCollection(this, collections[i])); } // Add images var images = this.props.images; for (var i = 0; i < images.length; i++) { this.elements.push(new mpld3.Image(this, images[i])); } // Sort all elements by zorder this.elements.sort(function(a, b) { return a.props.zorder - b.props.zorder }); } mpld3_Axes.prototype.draw = function() { for (var i = 0; i < this.props.sharex.length; i++) { this.sharex.push(mpld3.get_element(this.props.sharex[i])); } for (var i = 0; i < this.props.sharey.length; i++) { this.sharey.push(mpld3.get_element(this.props.sharey[i])); } this.zoom = d3.behavior.zoom(); this.zoom.last_t = this.zoom.translate() this.zoom.last_s = this.zoom.scale() this.zoom_x = d3.behavior.zoom().x(this.xdom); this.zoom_y = d3.behavior.zoom().y(this.ydom); this.baseaxes = this.fig.canvas.append("g") .attr('transform', 'translate(' + this.position[0] + ',' + this.position[1] + ')') .attr('width', this.width) .attr('height', this.height) .attr('class', "mpld3-baseaxes"); this.clip = this.baseaxes.append("svg:clipPath") .attr("id", this.clipid) .append("svg:rect") .attr("x", 0) .attr("y", 0) .attr("width", this.width) .attr("height", this.height) this.axes = this.baseaxes.append("g") .attr("class", "mpld3-axes") .attr("clip-path", "url(#" + this.clipid + ")"); this.axesbg = this.axes.append("svg:rect") .attr("width", this.width) .attr("height", this.height) .attr("class", "mpld3-axesbg") .style("fill", this.props.axesbg) .style("fill-opacity", this.props.axesbgalpha); for (var i = 0; i < this.elements.length; i++) { this.elements[i].draw(); } }; mpld3_Axes.prototype.enable_zoom = function() { if (this.props.zoomable) { this.zoom.on("zoom", this.zoomed.bind(this, true)); this.axes.call(this.zoom); this.axes.style("cursor", 'move'); } }; mpld3_Axes.prototype.disable_zoom = function() { if (this.props.zoomable) { this.zoom.on("zoom", null); this.axes.on('.zoom', null) this.axes.style('cursor', null); } }; mpld3_Axes.prototype.zoomed = function(propagate) { // propagate is a boolean specifying whether to propagate movements // to shared axes, specified by sharex and sharey. Default is true. propagate = (typeof propagate == 'undefined') ? true : propagate; if (propagate) { // update scale and translation of zoom_x and zoom_y, // based on change in this.zoom scale and translation values var dt0 = this.zoom.translate()[0] - this.zoom.last_t[0]; var dt1 = this.zoom.translate()[1] - this.zoom.last_t[1]; var ds = this.zoom.scale() / this.zoom.last_s; this.zoom_x.translate([this.zoom_x.translate()[0] + dt0, 0]); this.zoom_x.scale(this.zoom_x.scale() * ds) this.zoom_y.translate([0, this.zoom_y.translate()[1] + dt1]); this.zoom_y.scale(this.zoom_y.scale() * ds) // update last translate and scale values for future use this.zoom.last_t = this.zoom.translate(); this.zoom.last_s = this.zoom.scale(); // update shared axes objects this.sharex.forEach(function(ax) { ax.zoom_x.translate(this.zoom_x.translate()) .scale(this.zoom_x.scale()); }.bind(this)); this.sharey.forEach(function(ax) { ax.zoom_y.translate(this.zoom_y.translate()) .scale(this.zoom_y.scale()); }.bind(this)); // render updates this.sharex.forEach(function(ax) { ax.zoomed(false); }); this.sharey.forEach(function(ax) { ax.zoomed(false); }); } for (var i = 0; i < this.elements.length; i++) { this.elements[i].zoomed(); } }; mpld3_Axes.prototype.reset = function(duration, propagate) { this.set_axlim(this.props.xdomain, this.props.ydomain, duration, propagate); }; mpld3_Axes.prototype.set_axlim = function(xlim, ylim, duration, propagate) { xlim = isUndefinedOrNull(xlim) ? this.xdom.domain() : xlim; ylim = isUndefinedOrNull(ylim) ? this.ydom.domain() : ylim; duration = isUndefinedOrNull(duration) ? 750 : duration; propagate = isUndefined(propagate) ? true : propagate; // Create a transition function which will interpolate // from the current axes limits to the final limits var interpX = (this.props.xscale === 'date') ? mpld3.interpolateDates(this.xdom.domain(), xlim) : d3.interpolate(this.xdom.domain(), xlim); var interpY = (this.props.yscale === 'date') ? mpld3.interpolateDates(this.ydom.domain(), ylim) : d3.interpolate(this.ydom.domain(), ylim); var transition = function(t) { this.zoom_x.x(this.xdom.domain(interpX(t))); this.zoom_y.y(this.ydom.domain(interpY(t))); this.zoomed(false); // don't propagate here; propagate below. }.bind(this); // select({}) is a trick to make transitions run concurrently d3.select({}) .transition().duration(duration) .tween("zoom", function() { return transition; }); // propagate axis limits to shared axes if (propagate) { this.sharex.forEach(function(ax) { ax.set_axlim(xlim, null, duration, false); }); this.sharey.forEach(function(ax) { ax.set_axlim(null, ylim, duration, false); }); } // finalize the reset operation. this.zoom.scale(1).translate([0, 0]); this.zoom.last_t = this.zoom.translate(); this.zoom.last_s = this.zoom.scale(); this.zoom_x.scale(1).translate([0, 0]); this.zoom_y.scale(1).translate([0, 0]); }; python-mpld3/src/core/element.js0000644000175500017550000000425112410130733016650 0ustar debacledebacleimport "figure"; import "../utils/"; /**********************************************************************/ /* Base Object for Plot Elements */ mpld3.PlotElement = mpld3_PlotElement; function mpld3_PlotElement(parent, props) { this.parent = isUndefinedOrNull(parent) ? null : parent; this.props = isUndefinedOrNull(props) ? {} : this.processProps(props); this.fig = (parent instanceof mpld3_Figure) ? parent : (parent && "fig" in parent) ? parent.fig : null; this.ax = (parent instanceof mpld3_Axes) ? parent : (parent && "ax" in parent) ? parent.ax : null; } mpld3_PlotElement.prototype.requiredProps = []; mpld3_PlotElement.prototype.defaultProps = {}; mpld3_PlotElement.prototype.processProps = function(props) { // clone so that input is not overwritten props = mpld3_cloneObj(props); var finalProps = {}; // Check that all required properties are specified var this_name = this.name(); this.requiredProps.forEach(function(p) { if (!(p in props)) { throw ("property '" + p + "' " + "must be specified for " + this_name); } finalProps[p] = props[p]; delete props[p]; }); // Use defaults where necessary for (var p in this.defaultProps) { if (p in props) { finalProps[p] = props[p]; delete props[p]; } else { finalProps[p] = this.defaultProps[p]; } } // Assign ID, generating one if necessary if ("id" in props) { finalProps.id = props.id; delete props.id; } else if (!("id" in finalProps)) { finalProps.id = mpld3.generateId(); } // Warn if there are any unrecognized properties for (var p in props) { console.warn("Unrecognized property '" + p + "' " + "for object " + this.name() + " (value = " + props[p] + ")."); } return finalProps; } // Method to get the class name for console messages mpld3_PlotElement.prototype.name = function() { var funcNameRegex = /function (.{1,})\(/; var results = (funcNameRegex).exec(this.constructor.toString()); return (results && results.length > 1) ? results[1] : ""; }; python-mpld3/src/core/figure.js0000644000175500017550000001300612410130733016476 0ustar debacledebacleimport "element"; import "axes"; import "../toolbar/"; import "../plugins/"; /**********************************************************************/ /* Figure object: */ mpld3.Figure = mpld3_Figure; mpld3_Figure.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Figure.prototype.constructor = mpld3_Figure; mpld3_Figure.prototype.requiredProps = ["width", "height"]; mpld3_Figure.prototype.defaultProps = { data: {}, axes: [], plugins: [{type: "reset"}, {type: "zoom"}, {type: "boxzoom"}] }; function mpld3_Figure(figid, props) { mpld3_PlotElement.call(this, null, props); this.figid = figid; this.width = this.props.width; this.height = this.props.height; this.data = this.props.data; this.buttons = []; // Make a root div with relative positioning, // so we can position elements absolutely within it. this.root = d3.select('#' + figid) .append("div").style("position", "relative"); // Create all the axes elements in the figure this.axes = []; for (var i = 0; i < this.props.axes.length; i++) this.axes.push(new mpld3_Axes(this, this.props.axes[i])); // Connect the plugins to the figure this.plugins = []; for (var i = 0; i < this.props.plugins.length; i++) this.add_plugin(this.props.plugins[i]); // Create the figure toolbar // do this last because plugins may modify the button list this.toolbar = new mpld3.Toolbar(this, { buttons: this.buttons }); } // getBrush contains boilerplate for defining a d3 brush over the axes mpld3_Figure.prototype.getBrush = function() { if (typeof this._brush === "undefined"){ // use temporary linear scales here: we'll replace // with the real x and y scales below. var brush = d3.svg.brush() .x(d3.scale.linear()) .y(d3.scale.linear()); // this connects the axes instance to the brush elements this.root.selectAll(".mpld3-axes") .data(this.axes) .call(brush); // need to call the brush on each axes with correct x/y domains this.axes.forEach(function(ax){ brush.x(ax.xdom).y(ax.ydom); ax.axes.call(brush); }) this._brush = brush; this.hideBrush(); } return this._brush; }; mpld3_Figure.prototype.showBrush = function(extentClass) { extentClass = (typeof extentClass === "undefined") ? "" : extentClass; var brush = this.getBrush(); brush.on("brushstart", function(d){brush.x(d.xdom).y(d.ydom);}); this.canvas.selectAll("rect.background") .style("cursor", "crosshair") .style("pointer-events", null); this.canvas.selectAll("rect.extent, rect.resize") .style("display", null) .classed(extentClass, true); }; mpld3_Figure.prototype.hideBrush = function(extentClass) { extentClass = (typeof extentClass === "undefined") ? "" : extentClass; var brush = this.getBrush(); brush.on("brushstart", null) .on("brush", null) .on("brushend", function(d){d.axes.call(brush.clear());}); this.canvas.selectAll("rect.background") .style("cursor", null) .style("pointer-events", "visible"); this.canvas.selectAll("rect.extent, rect.resize") .style("display", "none") .classed(extentClass, false); }; mpld3_Figure.prototype.add_plugin = function(props) { var plug = props.type; if (typeof plug === "undefined"){ console.warn("unspecified plugin type. Skipping this"); return; } // clone props without the "type" argument props = mpld3_cloneObj(props); delete props.type; if (plug in mpld3.plugin_map) plug = mpld3.plugin_map[plug]; if (typeof(plug) !== "function") { console.warn("Skipping unrecognized plugin: " + plug); return; } if (props.clear_toolbar) { this.props.toolbar = []; } if ("buttons" in props) { if (typeof(props.buttons) === "string") { this.props.toolbar.push(props.buttons); } else { for (var i = 0; i < props.buttons.length; i++) { this.props.toolbar.push(props.buttons[i]); } } } this.plugins.push(new plug(this, props)); }; mpld3_Figure.prototype.draw = function() { this.canvas = this.root.append('svg:svg') .attr('class', 'mpld3-figure') .attr('width', this.width) .attr('height', this.height); for (var i = 0; i < this.axes.length; i++) { this.axes[i].draw(); } // disable zoom by default; plugins or toolbar items might change this. this.disable_zoom(); for (var i = 0; i < this.plugins.length; i++) { this.plugins[i].draw(); } this.toolbar.draw(); }; mpld3_Figure.prototype.reset = function(duration) { this.axes.forEach(function(ax) { ax.reset(duration, false); }); }; mpld3_Figure.prototype.enable_zoom = function() { for (var i = 0; i < this.axes.length; i++) { this.axes[i].enable_zoom(); } this.zoom_on = true; }; mpld3_Figure.prototype.disable_zoom = function() { for (var i = 0; i < this.axes.length; i++) { this.axes[i].disable_zoom(); } this.zoom_on = false; }; mpld3_Figure.prototype.toggle_zoom = function() { if (this.zoom_on) { this.disable_zoom(); } else { this.enable_zoom(); } }; mpld3_Figure.prototype.get_data = function(data) { if (data === null || typeof(data) === "undefined") { return null; } else if (typeof(data) === "string") { return this.data[data]; } else { return data; } } python-mpld3/src/core/coordinates.js0000644000175500017550000000323112410130733017526 0ustar debacledebacle/***********************************************************************/ /* Coordinates Object: Converts from given units to screen/pixel units */ /* `trans` is one of ["data", "figure", "axes", "display"] */ mpld3.Coordinates = mpld3_Coordinates; function mpld3_Coordinates(trans, ax) { if (typeof(ax) === "undefined") { this.ax = null; this.fig = null; if (this.trans !== "display") throw "ax must be defined if transform != 'display'"; } else { this.ax = ax; this.fig = ax.fig; } this.zoomable = (trans === "data"); this.x = this["x_" + trans]; this.y = this["y_" + trans]; if (typeof(this.x) === "undefined" || typeof(this.y) === "undefined") throw "unrecognized coordinate code: " + trans; } mpld3_Coordinates.prototype.xy = function(d, ix, iy) { ix = (typeof(ix) === "undefined") ? 0 : ix; iy = (typeof(iy) === "undefined") ? 1 : iy; return [this.x(d[ix]), this.y(d[iy])]; }; mpld3_Coordinates.prototype.x_data = function(x) { return this.ax.x(x); } mpld3_Coordinates.prototype.y_data = function(y) { return this.ax.y(y); } mpld3_Coordinates.prototype.x_display = function(x) { return x; } mpld3_Coordinates.prototype.y_display = function(y) { return y; } mpld3_Coordinates.prototype.x_axes = function(x) { return x * this.ax.width; } mpld3_Coordinates.prototype.y_axes = function(y) { return this.ax.height * (1 - y); } mpld3_Coordinates.prototype.x_figure = function(x) { return x * this.fig.width - this.ax.position[0]; } mpld3_Coordinates.prototype.y_figure = function(y) { return (1 - y) * this.fig.height - this.ax.position[1]; }python-mpld3/src/core/grid.js0000644000175500017550000000410312410130733016140 0ustar debacledebacleimport "element"; import "../utils/"; /**********************************************************************/ /* Grid Object */ mpld3.Grid = mpld3_Grid; mpld3_Grid.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Grid.prototype.constructor = mpld3_Grid; mpld3_Grid.prototype.requiredProps = ["xy"]; mpld3_Grid.prototype.defaultProps = { color: "gray", dasharray: "2,2", alpha: "0.5", nticks: 10, gridOn: true, tickvalues: null, zorder: 0 }; function mpld3_Grid(ax, prop) { mpld3_PlotElement.call(this, ax, prop); this.cssclass = "mpld3-" + this.props.xy + "grid"; if (this.props.xy == "x") { this.transform = "translate(0," + this.ax.height + ")"; this.position = "bottom"; this.scale = this.ax.xdom; this.tickSize = -this.ax.height; } else if (this.props.xy == "y") { this.transform = "translate(0,0)"; this.position = "left"; this.scale = this.ax.ydom; this.tickSize = -this.ax.width; } else { throw "unrecognized grid xy specifier: should be 'x' or 'y'"; } } mpld3_Grid.prototype.draw = function() { this.grid = d3.svg.axis() .scale(this.scale) .orient(this.position) .ticks(this.props.nticks) .tickValues(this.props.tickvalues) .tickSize(this.tickSize, 0, 0) .tickFormat(""); this.elem = this.ax.axes.append("g") .attr("class", this.cssclass) .attr("transform", this.transform) .call(this.grid); // We create header-level CSS to style these elements, because // zooming/panning creates new elements with these classes. mpld3.insert_css("div#" + this.ax.fig.figid + " ." + this.cssclass + " .tick", { "stroke": this.props.color, "stroke-dasharray": this.props.dasharray, "stroke-opacity": this.props.alpha }); mpld3.insert_css("div#" + this.ax.fig.figid + " ." + this.cssclass + " path", { "stroke-width": 0 }); }; mpld3_Grid.prototype.zoomed = function() { this.elem.call(this.grid); }; python-mpld3/src/elements/0000755000175500017550000000000012410130733015543 5ustar debacledebaclepython-mpld3/src/elements/path.js0000644000175500017550000000501012410130733017031 0ustar debacledebacleimport "../core/element"; import "../core/coordinates"; import "../utils/"; /**********************************************************************/ /* Path Element */ mpld3.Path = mpld3_Path; mpld3_Path.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Path.prototype.constructor = mpld3_Path; mpld3_Path.prototype.requiredProps = ["data"]; mpld3_Path.prototype.defaultProps = { xindex: 0, yindex: 1, coordinates: "data", facecolor: "green", edgecolor: "black", edgewidth: 1, dasharray: "none", pathcodes: null, offset: null, offsetcoordinates: "data", alpha: 1.0, zorder: 1 }; function mpld3_Path(ax, props) { mpld3_PlotElement.call(this, ax, props); this.data = ax.fig.get_data(this.props.data); this.pathcodes = this.props.pathcodes; this.pathcoords = new mpld3_Coordinates(this.props.coordinates, this.ax); this.offsetcoords = new mpld3_Coordinates(this.props.offsetcoordinates, this.ax); this.datafunc = mpld3_path(); } mpld3_Path.prototype.nanFilter = function(d, i) { return (!isNaN(d[this.props.xindex]) && !isNaN(d[this.props.yindex])); }; mpld3_Path.prototype.draw = function() { this.datafunc .defined(this.nanFilter.bind(this)) .x(function(d) { return this.pathcoords.x(d[this.props.xindex]); }) .y(function(d) { return this.pathcoords.y(d[this.props.yindex]); }); this.path = this.ax.axes.append("svg:path") .attr("d", this.datafunc(this.data, this.pathcodes)) .attr('class', "mpld3-path") .style("stroke", this.props.edgecolor) .style("stroke-width", this.props.edgewidth) .style("stroke-dasharray", this.props.dasharray) .style("stroke-opacity", this.props.alpha) .style("fill", this.props.facecolor) .style("fill-opacity", this.props.alpha) .attr("vector-effect", "non-scaling-stroke"); if (this.props.offset !== null) { var offset = this.offsetcoords.xy(this.props.offset); this.path.attr("transform", "translate(" + offset + ")"); } }; mpld3_Path.prototype.elements = function(d) { return this.path; }; mpld3_Path.prototype.zoomed = function() { if (this.pathcoords.zoomable) { this.path.attr("d", this.datafunc(this.data, this.pathcodes)); } if (this.props.offset !== null && this.offsetcoords.zoomable) { var offset = this.offsetcoords.xy(this.props.offset); this.path.attr("transform", "translate(" + offset + ")"); } }; python-mpld3/src/elements/image.js0000644000175500017550000000244112410130733017164 0ustar debacledebacle/**********************************************************************/ /* Image Object */ mpld3.Image = mpld3_Image; mpld3_Image.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Image.prototype.constructor = mpld3_Image; mpld3_Image.prototype.requiredProps = ["data", "extent"]; mpld3_Image.prototype.defaultProps = { alpha: 1.0, coordinates: "data", zorder: 1 }; function mpld3_Image(ax, props) { mpld3_PlotElement.call(this, ax, props); this.coords = new mpld3_Coordinates(this.props.coordinates, this.ax); } mpld3_Image.prototype.draw = function() { this.image = this.ax.axes.append("svg:image") .attr('class', 'mpld3-image') .attr('xlink:href', "data:image/png;base64," + this.props.data) .style({ 'opacity': this.props.alpha }) .attr("preserveAspectRatio", "none"); this.zoomed(); }; mpld3_Image.prototype.elements = function(d) { return d3.select(this.image); }; mpld3_Image.prototype.zoomed = function() { var extent = this.props.extent; this.image .attr("x", this.coords.x(extent[0])) .attr("y", this.coords.y(extent[3])) .attr("width", this.coords.x(extent[1]) - this.coords.x(extent[0])) .attr("height", this.coords.y(extent[2]) - this.coords.y(extent[3])); };python-mpld3/src/elements/line.js0000644000175500017550000000215212410130733017030 0ustar debacledebacleimport "../core/element"; import "path"; /**********************************************************************/ /* Line Element: inherits from mpld3.Path */ mpld3.Line = mpld3_Line; mpld3_Line.prototype = Object.create(mpld3_Path.prototype); mpld3_Line.prototype.constructor = mpld3_Line; mpld3_Line.prototype.requiredProps = ["data"]; mpld3_Line.prototype.defaultProps = { xindex: 0, yindex: 1, coordinates: "data", color: "salmon", linewidth: 2, dasharray: "none", alpha: 1.0, zorder: 2 }; function mpld3_Line(ax, props) { mpld3_PlotElement.call(this, ax, props); // Map line properties to path properties var pathProps = this.props; pathProps.facecolor = "none"; pathProps.edgecolor = pathProps.color; delete pathProps.color; pathProps.edgewidth = pathProps.linewidth; delete pathProps.linewidth; // Process path properties this.defaultProps = mpld3_Path.prototype.defaultProps; mpld3_Path.call(this, ax, pathProps); // This is optional, but is more efficient than relying on path this.datafunc = d3.svg.line().interpolate("linear"); } python-mpld3/src/elements/text.js0000644000175500017550000000327112410130733017070 0ustar debacledebacle/**********************************************************************/ /* Text Element */ mpld3.Text = mpld3_Text; mpld3_Text.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Text.prototype.constructor = mpld3_Text; mpld3_Text.prototype.requiredProps = ["text", "position"]; mpld3_Text.prototype.defaultProps = { coordinates: "data", h_anchor: "start", v_baseline: "auto", rotation: 0, fontsize: 11, color: "black", alpha: 1.0, zorder: 3 }; function mpld3_Text(ax, props) { mpld3_PlotElement.call(this, ax, props); this.text = this.props.text; this.position = this.props.position; this.coords = new mpld3_Coordinates(this.props.coordinates, this.ax); }; mpld3_Text.prototype.draw = function() { if (this.props.coordinates == "data") { this.obj = this.ax.axes.append("text"); } else { this.obj = this.ax.baseaxes.append("text"); } this.obj.attr("class", "mpld3-text") .text(this.text) .style("text-anchor", this.props.h_anchor) .style("dominant-baseline", this.props.v_baseline) .style("font-size", this.props.fontsize) .style("fill", this.props.color) .style("opacity", this.props.alpha); this.applyTransform(); }; mpld3_Text.prototype.elements = function(d) { return d3.select(this.obj); }; mpld3_Text.prototype.applyTransform = function() { var pos = this.coords.xy(this.position); this.obj.attr("x", pos[0]).attr("y", pos[1]); if (this.props.rotation) this.obj.attr("transform", "rotate(" + this.props.rotation + "," + pos + ")"); } mpld3_Text.prototype.zoomed = function() { if (this.coords.zoomable) this.applyTransform(); }; python-mpld3/src/elements/markers.js0000644000175500017550000000354312410130733017552 0ustar debacledebacleimport "path_collection" /**********************************************************************/ /* Markers Element */ mpld3.Markers = mpld3_Markers; mpld3_Markers.prototype = Object.create(mpld3_PathCollection.prototype); mpld3_Markers.prototype.constructor = mpld3_Markers; mpld3_Markers.prototype.requiredProps = ["data"]; mpld3_Markers.prototype.defaultProps = { xindex: 0, yindex: 1, coordinates: "data", facecolor: "salmon", edgecolor: "black", edgewidth: 1, alpha: 1.0, markersize: 6, markername: "circle", markerpath: null, zorder: 3 }; function mpld3_Markers(ax, props) { mpld3_PlotElement.call(this, ax, props); // Construct the marker path if (this.props.markerpath !== null) { this.marker = (this.props.markerpath[0].length == 0) ? null : mpld3.path().call(this.props.markerpath[0], this.props.markerpath[1]); } else { this.marker = (this.props.markername === null) ? null : d3.svg.symbol(this.props.markername) .size(Math.pow(this.props.markersize, 2))(); } // Call the PathCollection constructor var PCprops = { paths: [this.props.markerpath], offsets: ax.fig.get_data(this.props.data), xindex: this.props.xindex, yindex: this.props.yindex, offsetcoordinates: this.props.coordinates, edgecolors: [this.props.edgecolor], edgewidths: [this.props.edgewidth], facecolors: [this.props.facecolor], alphas: [this.props.alpha], zorder: this.props.zorder, id: this.props.id } this.requiredProps = mpld3_PathCollection.prototype.requiredProps; this.defaultProps = mpld3_PathCollection.prototype.defaultProps; mpld3_PathCollection.call(this, ax, PCprops); }; mpld3_Markers.prototype.pathFunc = function(d, i) { return this.marker; }; python-mpld3/src/elements/index.js0000644000175500017550000000015012410130733017204 0ustar debacledebacleimport "path"; import "path_collection"; import "line"; import "markers"; import "image"; import "text";python-mpld3/src/elements/path_collection.js0000644000175500017550000000742312410130733021256 0ustar debacledebacleimport "../core/element"; /**********************************************************************/ /* Path Collection Element */ mpld3.PathCollection = mpld3_PathCollection; mpld3_PathCollection.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_PathCollection.prototype.constructor = mpld3_PathCollection; mpld3_PathCollection.prototype.requiredProps = ["paths", "offsets"]; mpld3_PathCollection.prototype.defaultProps = { xindex: 0, yindex: 1, pathtransforms: [], pathcoordinates: "display", offsetcoordinates: "data", offsetorder: "before", edgecolors: ["#000000"], edgewidths: [1.0], facecolors: ["#0000FF"], alphas: [1.0], zorder: 2 }; function mpld3_PathCollection(ax, props) { mpld3_PlotElement.call(this, ax, props); if (this.props.facecolors == null || this.props.facecolors.length == 0) { this.props.facecolors = ["none"]; } if (this.props.edgecolors == null || this.props.edgecolors.length == 0) { this.props.edgecolors = ["none"]; } var offsets = this.ax.fig.get_data(this.props.offsets); if (offsets === null || offsets.length === 0) offsets = [null]; // For use in the draw() command, expand offsets to size N var N = Math.max(this.props.paths.length, offsets.length); if (offsets.length === N) { this.offsets = offsets; } else { this.offsets = []; for (var i = 0; i < N; i++) this.offsets.push(getMod(offsets, i)); } this.pathcoords = new mpld3_Coordinates(this.props.pathcoordinates, this.ax); this.offsetcoords = new mpld3_Coordinates(this.props.offsetcoordinates, this.ax); } mpld3_PathCollection.prototype.transformFunc = function(d, i) { var t = this.props.pathtransforms; var transform = (t.length == 0) ? "" : d3.transform("matrix(" + getMod(t, i) + ")").toString(); var offset = (d === null || typeof(d) === "undefined") ? "translate(0, 0)" : ("translate(" + this.offsetcoords.xy(d, this.props.xindex, this.props.yindex) + ")"); return (this.props.offsetorder === "after") ? transform + offset : offset + transform; }; mpld3_PathCollection.prototype.pathFunc = function(d, i) { return mpld3_path() .x(function(d) { return this.pathcoords.x(d[0]); }.bind(this)) .y(function(d) { return this.pathcoords.y(d[1]); }.bind(this)) .apply(this, getMod(this.props.paths, i)); }; mpld3_PathCollection.prototype.styleFunc = function(d, i) { var styles = { "stroke": getMod(this.props.edgecolors, i), "stroke-width": getMod(this.props.edgewidths, i), "stroke-opacity": getMod(this.props.alphas, i), "fill": getMod(this.props.facecolors, i), "fill-opacity": getMod(this.props.alphas, i), } var ret = "" for (var key in styles) { ret += key + ":" + styles[key] + ";" } return ret }; mpld3_PathCollection.prototype.draw = function() { this.group = this.ax.axes.append("svg:g"); this.pathsobj = this.group.selectAll("paths") .data(this.offsets) .enter().append("svg:path") .attr("d", this.pathFunc.bind(this)) .attr("class", "mpld3-path") .attr("transform", this.transformFunc.bind(this)) .attr("style", this.styleFunc.bind(this)) .attr("vector-effect", "non-scaling-stroke"); }; mpld3_PathCollection.prototype.elements = function(d) { return this.group.selectAll("path"); }; mpld3_PathCollection.prototype.zoomed = function() { if (this.props.pathcoordinates === "data") { this.pathsobj.attr("d", this.pathFunc.bind(this)); } if (this.props.offsetcoordinates === "data") { this.pathsobj.attr("transform", this.transformFunc.bind(this)); } }; python-mpld3/src/toolbar/0000755000175500017550000000000012410130733015371 5ustar debacledebaclepython-mpld3/src/toolbar/button.js0000644000175500017550000000363212410130733017246 0ustar debacledebacle/**********************************************************************/ /* Button object: */ mpld3.Button = mpld3_Button; mpld3_Button.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Button.prototype.constructor = mpld3_Button; function mpld3_Button(toolbar, key) { mpld3_PlotElement.call(this, toolbar); this.toolbar = toolbar; this.fig = this.toolbar.fig; this.cssclass = "mpld3-" + key + "button"; this.active = false; } mpld3_Button.prototype.setState = function(state) { (state) ? this.activate() : this.deactivate(); } mpld3_Button.prototype.click = function() { this.active ? this.deactivate() : this.activate(); }; mpld3_Button.prototype.activate = function() { this.toolbar.deactivate_by_action(this.actions); this.onActivate(); this.active = true; this.toolbar.toolbar.select('.' + this.cssclass) .classed({ pressed: true }); if (!this.sticky) this.deactivate(); }; mpld3_Button.prototype.deactivate = function() { this.onDeactivate(); this.active = false; this.toolbar.toolbar.select('.' + this.cssclass) .classed({ pressed: false }); } mpld3_Button.prototype.sticky = false; mpld3_Button.prototype.actions = []; mpld3_Button.prototype.icon = function() { return ""; } mpld3_Button.prototype.onActivate = function() {}; mpld3_Button.prototype.onDeactivate = function() {}; mpld3_Button.prototype.onDraw = function() {}; /* Factory for button classes */ mpld3.ButtonFactory = function(members) { if (typeof members.buttonID !== "string"){ throw "ButtonFactory: buttonID must be present and be a string"; } function B(toolbar) { mpld3_Button.call(this, toolbar, this.buttonID); } B.prototype = Object.create(mpld3_Button.prototype); B.prototype.constructor = B; for (var key in members){ B.prototype[key] = members[key]; } return B; } python-mpld3/src/toolbar/index.js0000644000175500017550000000004212410130733017032 0ustar debacledebacleimport "toolbar"; import "button";python-mpld3/src/toolbar/toolbar.js0000644000175500017550000000610112410130733017367 0ustar debacledebacle/**********************************************************************/ /* Toolbar object: */ mpld3.Toolbar = mpld3_Toolbar; mpld3_Toolbar.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Toolbar.prototype.constructor = mpld3_Toolbar; mpld3_Toolbar.prototype.defaultProps = { buttons: ["reset", "move"] }; function mpld3_Toolbar(fig, props) { mpld3_PlotElement.call(this, fig, props) this.buttons = []; this.props.buttons.forEach(this.addButton.bind(this)); } mpld3_Toolbar.prototype.addButton = function(button) { this.buttons.push(new button(this)); }; mpld3_Toolbar.prototype.draw = function() { mpld3.insert_css("div#" + this.fig.figid + " .mpld3-toolbar image", { cursor: "pointer", opacity: 0.2, display: "inline-block", margin: "0px" }) mpld3.insert_css("div#" + this.fig.figid + " .mpld3-toolbar image.active", { opacity: 0.4 }) mpld3.insert_css("div#" + this.fig.figid + " .mpld3-toolbar image.pressed", { opacity: 0.6 }) function showButtons() { this.buttonsobj.transition(750).attr("y", 0); } function hideButtons() { this.buttonsobj.transition(750) .delay(250).attr("y", 16); } // buttons will be shown and hidden on mouse movements. // (the buttons will be also be shown on touch events.) this.fig.canvas .on("mouseenter", showButtons.bind(this)) .on("mouseleave", hideButtons.bind(this)) .on("touchenter", showButtons.bind(this)) .on("touchstart", showButtons.bind(this)); this.toolbar = this.fig.canvas.append("svg:svg") .attr("width", 16 * this.buttons.length) .attr("height", 16) .attr("x", 2) .attr("y", this.fig.height - 16 - 2) .attr("class", "mpld3-toolbar"); this.buttonsobj = this.toolbar.append("svg:g").selectAll("buttons") .data(this.buttons) .enter().append("svg:image") .attr("class", function(d) { return d.cssclass; }) .attr("xlink:href", function(d) { return d.icon(); }) .attr("width", 16) .attr("height", 16) .attr("x", function(d, i) { return i * 16; }) .attr("y", 16) .on("click", function(d) { d.click(); }) .on("mouseenter", function() { d3.select(this).classed({ active: 1 }) }) .on("mouseleave", function() { d3.select(this).classed({ active: 0 }) }); for (var i = 0; i < this.buttons.length; i++) this.buttons[i].onDraw(); }; mpld3_Toolbar.prototype.deactivate_all = function() { this.buttons.forEach(function(b) { b.deactivate(); }); }; mpld3_Toolbar.prototype.deactivate_by_action = function(actions) { function filt(e) { return actions.indexOf(e) !== -1; } if (actions.length > 0) { this.buttons.forEach(function(button) { if (button.actions.filter(filt).length > 0) button.deactivate(); }); } }; python-mpld3/src/version.js0000644000175500017550000000003212410351464015753 0ustar debacledebaclempld3.version = '0.3git'; python-mpld3/src/end.js0000644000175500017550000000036212410130733015034 0ustar debacledebacle // put mpld3 in the global namespace if (typeof module === "object" && module.exports) { module.exports = mpld3; } else { this.mpld3 = mpld3; } console.log("Loaded mpld3 version " + mpld3.version); }(d3); python-mpld3/src/plugins/0000755000175500017550000000000012410130733015410 5ustar debacledebaclepython-mpld3/src/plugins/zoom.js0000644000175500017550000000274412410130733016741 0ustar debacledebacleimport "base"; import "../toolbar/button" import "../utils/icons" /**********************************************************************/ /* Zoom Plugin */ mpld3.ZoomPlugin = mpld3_ZoomPlugin; mpld3.register_plugin("zoom", mpld3_ZoomPlugin); mpld3_ZoomPlugin.prototype = Object.create(mpld3_Plugin.prototype); mpld3_ZoomPlugin.prototype.constructor = mpld3_ZoomPlugin; mpld3_ZoomPlugin.prototype.requiredProps = []; mpld3_ZoomPlugin.prototype.defaultProps = { button: true, enabled: null }; function mpld3_ZoomPlugin(fig, props) { mpld3_Plugin.call(this, fig, props); if (this.props.enabled === null){ this.props.enabled = !(this.props.button); } var enabled = this.props.enabled; if (this.props.button){ var ZoomButton = mpld3.ButtonFactory({ buttonID: "zoom", sticky: true, actions: ["scroll", "drag"], onActivate: this.activate.bind(this), onDeactivate: this.deactivate.bind(this), onDraw: function(){this.setState(enabled);}, icon: function() { return mpld3.icons["move"]; } }); this.fig.buttons.push(ZoomButton); } } mpld3_ZoomPlugin.prototype.activate = function(){ this.fig.enable_zoom(); }; mpld3_ZoomPlugin.prototype.deactivate = function(){ this.fig.disable_zoom() }; mpld3_ZoomPlugin.prototype.draw = function(){ if(this.props.enabled) this.fig.enable_zoom(); else this.fig.disable_zoom(); } python-mpld3/src/plugins/base.js0000644000175500017550000000075112410130733016663 0ustar debacledebacleimport "../core/element"; /**********************************************************************/ /* Plugin Base Class */ mpld3.Plugin = mpld3_Plugin; mpld3_Plugin.prototype = Object.create(mpld3_PlotElement.prototype); mpld3_Plugin.prototype.constructor = mpld3_Plugin; mpld3_Plugin.prototype.requiredProps = []; mpld3_Plugin.prototype.defaultProps = {}; function mpld3_Plugin(fig, props){ mpld3_PlotElement.call(this, fig, props); }; mpld3_Plugin.prototype.draw = function(){}; python-mpld3/src/plugins/mouseposition.js0000644000175500017550000000275312410130733020672 0ustar debacledebacleimport "base"; import "../toolbar/button"; import "../utils/icons"; /**********************************************************************/ /* Mouse Position Plugin */ mpld3.register_plugin("mouseposition", MousePositionPlugin); MousePositionPlugin.prototype = Object.create(mpld3.Plugin.prototype); MousePositionPlugin.prototype.constructor = MousePositionPlugin; MousePositionPlugin.prototype.requiredProps = []; MousePositionPlugin.prototype.defaultProps = {fontsize: 12, fmt: ".3g"}; function MousePositionPlugin(fig, props){ mpld3.Plugin.call(this, fig, props); }; MousePositionPlugin.prototype.draw = function(){ var fig = this.fig; var fmt = d3.format(this.props.fmt); var coords = fig.canvas.append("text") .attr("class", "mpld3-coordinates") .style("text-anchor", "end") .style("font-size", this.props.fontsize) .attr("x", this.fig.width - 5) .attr("y", this.fig.height - 5); for (var i=0; i < this.fig.axes.length; i++) { var update_coords = function() { var ax = fig.axes[i]; return function() { var pos = d3.mouse(this), x = ax.x.invert(pos[0]), y = ax.y.invert(pos[1]); coords.text("(" + fmt(x) + ", " + fmt(y) + ")"); }; }(); fig.axes[i].baseaxes .on("mousemove", update_coords) .on("mouseout", function() { coords.text(""); }); } }; python-mpld3/src/plugins/tooltip.js0000644000175500017550000000457212410130733017450 0ustar debacledebacleimport "base"; /**********************************************************************/ /* Tooltip Plugin */ mpld3.TooltipPlugin = mpld3_TooltipPlugin; mpld3.register_plugin("tooltip", mpld3_TooltipPlugin); mpld3_TooltipPlugin.prototype = Object.create(mpld3_Plugin.prototype); mpld3_TooltipPlugin.prototype.constructor = mpld3_TooltipPlugin; mpld3_TooltipPlugin.prototype.requiredProps = ["id"]; mpld3_TooltipPlugin.prototype.defaultProps = { labels: null, hoffset: 0, voffset: 10, location: 'mouse' }; function mpld3_TooltipPlugin(fig, props) { mpld3_Plugin.call(this, fig, props); } mpld3_TooltipPlugin.prototype.draw = function() { var obj = mpld3.get_element(this.props.id, this.fig); var labels = this.props.labels; var loc = this.props.location; this.tooltip = this.fig.canvas.append("text") .attr("class", "mpld3-tooltip-text") .attr("x", 0) .attr("y", 0) .text("") .style("visibility", "hidden"); if (loc == "bottom left" || loc == "top left") { this.x = obj.ax.position[0] + 5 + this.props.hoffset; this.tooltip.style("text-anchor", "beginning") } else if (loc == "bottom right" || loc == "top right") { this.x = obj.ax.position[0] + obj.ax.width - 5 + this.props.hoffset; this.tooltip.style("text-anchor", "end"); } else { this.tooltip.style("text-anchor", "middle"); } if (loc == "bottom left" || loc == "bottom right") { this.y = obj.ax.position[1] + obj.ax.height - 5 + this.props.voffset; } else if (loc == "top left" || loc == "top right") { this.y = obj.ax.position[1] + 5 + this.props.voffset; } function mouseover(d, i) { this.tooltip .style("visibility", "visible") .text((labels === null) ? "(" + d + ")" : getMod(labels, i)); } function mousemove(d, i) { if (loc === "mouse") { var pos = d3.mouse(this.fig.canvas.node()) this.x = pos[0] + this.props.hoffset; this.y = pos[1] - this.props.voffset; } this.tooltip .attr('x', this.x) .attr('y', this.y); } function mouseout(d, i) { this.tooltip.style("visibility", "hidden"); } obj.elements() .on("mouseover", mouseover.bind(this)) .on("mousemove", mousemove.bind(this)) .on("mouseout", mouseout.bind(this)); }python-mpld3/src/plugins/index.js0000644000175500017550000000020012410130733017045 0ustar debacledebacleimport "base"; import "reset"; import "zoom"; import "boxzoom"; import "tooltip"; import "linkedbrush"; import "mouseposition"; python-mpld3/src/plugins/reset.js0000644000175500017550000000153712410130733017076 0ustar debacledebacleimport "base"; import "../toolbar/button"; import "../utils/icons"; /**********************************************************************/ /* Reset Plugin */ mpld3.ResetPlugin = mpld3_ResetPlugin; mpld3.register_plugin("reset", mpld3_ResetPlugin); mpld3_ResetPlugin.prototype = Object.create(mpld3_Plugin.prototype); mpld3_ResetPlugin.prototype.constructor = mpld3_ResetPlugin; mpld3_ResetPlugin.prototype.requiredProps = []; mpld3_ResetPlugin.prototype.defaultProps = {}; function mpld3_ResetPlugin(fig, props) { mpld3_Plugin.call(this, fig, props); var ResetButton = mpld3.ButtonFactory({ buttonID: "reset", sticky: false, onActivate: function() { this.toolbar.fig.reset(); }, icon: function() { return mpld3.icons["reset"]; } }); this.fig.buttons.push(ResetButton); } python-mpld3/src/plugins/linkedbrush.js0000644000175500017550000001042312410130733020260 0ustar debacledebacleimport "base"; import "../toolbar/button" import "../utils/icons" mpld3.LinkedBrushPlugin = mpld3_LinkedBrushPlugin; mpld3.register_plugin("linkedbrush", mpld3_LinkedBrushPlugin); mpld3_LinkedBrushPlugin.prototype = Object.create(mpld3.Plugin.prototype); mpld3_LinkedBrushPlugin.prototype.constructor = mpld3_LinkedBrushPlugin; mpld3_LinkedBrushPlugin.prototype.requiredProps = ["id"]; mpld3_LinkedBrushPlugin.prototype.defaultProps = { button: true, enabled: null }; function mpld3_LinkedBrushPlugin(fig, props){ mpld3.Plugin.call(this, fig, props); if (this.props.enabled === null){ this.props.enabled = !(this.props.button); } var enabled = this.props.enabled; if (this.props.button){ var BrushButton = mpld3.ButtonFactory({ buttonID: "linkedbrush", sticky: true, actions: ["drag"], onActivate: this.activate.bind(this), onDeactivate: this.deactivate.bind(this), onDraw: function(){this.setState(enabled);}, icon: function(){return mpld3.icons["brush"];}, }); this.fig.buttons.push(BrushButton); } this.extentClass = "linkedbrush"; } mpld3_LinkedBrushPlugin.prototype.activate = function(){ if(this.enable) this.enable(); }; mpld3_LinkedBrushPlugin.prototype.deactivate = function(){ if(this.disable) this.disable(); }; mpld3_LinkedBrushPlugin.prototype.draw = function(){ var obj = mpld3.get_element(this.props.id); if(obj === null){ throw("LinkedBrush: no object with id='" + this.props.id + "' was found"); } var fig = this.fig; if(!("offsets" in obj.props)){ throw("Plot object with id='" + this.props.id + "' is not a scatter plot"); } var dataKey = ("offsets" in obj.props) ? "offsets" : "data"; mpld3.insert_css("#" + fig.figid + " rect.extent." + this.extentClass, {"fill": "#000", "fill-opacity": .125, "stroke": "#fff"}); mpld3.insert_css("#" + fig.figid + " path.mpld3-hidden", {"stroke": "#ccc !important", "fill": "#ccc !important"}); var dataClass = "mpld3data-" + obj.props[dataKey]; var brush = fig.getBrush(); // Label all data points & find data in each axes var dataByAx = []; fig.axes.forEach(function(ax){ var axData = []; ax.elements.forEach(function(el){ if(el.props[dataKey] === obj.props[dataKey]){ el.group.classed(dataClass, true); axData.push(el); } }); dataByAx.push(axData); }); // For fast brushing, precompute a list of selection properties // properties to apply to the selction. var allData = []; var dataToBrush = fig.canvas.selectAll("." + dataClass); var currentAxes; function brushstart(d){ if(currentAxes != this){ d3.select(currentAxes).call(brush.clear()); currentAxes = this; brush.x(d.xdom).y(d.ydom); } } function brushmove(d){ var data = dataByAx[d.axnum]; if(data.length > 0){ var ix = data[0].props.xindex; var iy = data[0].props.yindex; var e = brush.extent(); if (brush.empty()){ dataToBrush.selectAll("path").classed("mpld3-hidden", false); } else { dataToBrush.selectAll("path") .classed("mpld3-hidden", function(p) { return e[0][0] > p[ix] || e[1][0] < p[ix] || e[0][1] > p[iy] || e[1][1] < p[iy]; }); } } } function brushend(d){ if (brush.empty()){ dataToBrush.selectAll("path").classed("mpld3-hidden", false); } } this.enable = function(){ this.fig.showBrush(this.extentClass); brush.on("brushstart", brushstart) .on("brush", brushmove) .on("brushend", brushend); this.enabled = true; } this.disable = function(){ d3.select(currentAxes).call(brush.clear()); this.fig.hideBrush(this.extentClass); this.enabled = false; } this.disable(); } python-mpld3/src/plugins/boxzoom.js0000644000175500017550000000445012410130733017446 0ustar debacledebacleimport "base"; import "../toolbar/button" import "../utils/icons" mpld3.BoxZoomPlugin = mpld3_BoxZoomPlugin; mpld3.register_plugin("boxzoom", mpld3_BoxZoomPlugin); mpld3_BoxZoomPlugin.prototype = Object.create(mpld3_Plugin.prototype); mpld3_BoxZoomPlugin.prototype.constructor = mpld3_BoxZoomPlugin; mpld3_BoxZoomPlugin.prototype.requiredProps = []; mpld3_BoxZoomPlugin.prototype.defaultProps = { button: true, enabled: null }; function mpld3_BoxZoomPlugin(fig, props) { mpld3_Plugin.call(this, fig, props); if (this.props.enabled === null){ this.props.enabled = !(this.props.button); } var enabled = this.props.enabled; if (this.props.button){ // add a button to enable/disable box zoom var BoxZoomButton = mpld3.ButtonFactory({ buttonID: "boxzoom", sticky: true, actions: ["drag"], onActivate: this.activate.bind(this), onDeactivate: this.deactivate.bind(this), onDraw: function(){this.setState(enabled);}, icon: function(){return mpld3.icons["zoom"];}, }); this.fig.buttons.push(BoxZoomButton); } this.extentClass = "boxzoombrush"; } mpld3_BoxZoomPlugin.prototype.activate = function(){ if(this.enable) this.enable(); }; mpld3_BoxZoomPlugin.prototype.deactivate = function(){ if(this.disable) this.disable(); }; mpld3_BoxZoomPlugin.prototype.draw = function(){ mpld3.insert_css("#" + this.fig.figid + " rect.extent." + this.extentClass, {"fill": "#fff", "fill-opacity": 0, "stroke": "#999"}); // getBrush is a d3.svg.brush() object, set up for use on the figure. var brush = this.fig.getBrush(); this.enable = function(){ this.fig.showBrush(this.extentClass); brush.on("brushend", brushend.bind(this)); this.enabled = true; } this.disable = function(){ this.fig.hideBrush(this.extentClass); this.enabled = false; } this.toggle = function(){ this.enabled ? this.disable() : this.enable(); } function brushend(d){ if(this.enabled){ var extent = brush.extent(); if(!brush.empty()){ d.set_axlim([extent[0][0], extent[1][0]], [extent[0][1], extent[1][1]]); } } d.axes.call(brush.clear()); } this.disable(); } python-mpld3/src/mpld3.js0000644000175500017550000000021412410130733015301 0ustar debacledebacleimport "start"; import "version"; import "core/"; import "elements/"; import "toolbar/"; import "plugins/"; import "utils/"; import "end";python-mpld3/_mpld3_setup.py0000644000175500017550000001747212410130733016123 0ustar debacledebacle""" Tools to help with setup.py Much of this is based on tools in the IPython project: http://github.com/ipython/ipython """ import os import subprocess import sys import warnings import shutil try: from setuptools import Command except: from distutils.cmd import Command SUBMODULES = ['mplexporter'] SUBMODULE_SYNC_PATHS = [('mplexporter/mplexporter', 'mpld3/mplexporter')] def get_version(): """Get the version info from the mpld3 package without importing it""" with open(os.path.join("mpld3", "__about__.py"), "r") as init_file: exec(compile(init_file.read(), 'mpld3/__about__.py', 'exec'), globals()) try: return __version__ except NameError: raise ValueError("version could not be located") def is_repo(d): """is d a git repo?""" return os.path.exists(os.path.join(d, '.git')) def check_submodule_status(root=None): """check submodule status Has three return values: 'missing' - submodules are absent 'unclean' - submodules have unstaged changes 'clean' - all submodules are up to date """ if root is None: root = os.path.dirname(os.path.abspath(__file__)) if hasattr(sys, "frozen"): # frozen via py2exe or similar, don't bother return 'clean' if not is_repo(root): # not in git, assume clean return 'clean' for submodule in SUBMODULES: if not os.path.exists(submodule): return 'missing' # Popen can't handle unicode cwd on Windows Python 2 if sys.platform == 'win32' and sys.version_info[0] < 3 \ and not isinstance(root, bytes): root = root.encode(sys.getfilesystemencoding() or 'ascii') # check with git submodule status proc = subprocess.Popen('git submodule status', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, cwd=root, ) status, _ = proc.communicate() status = status.decode("ascii", "replace") for line in status.splitlines(): if line.startswith('-'): return 'missing' elif line.startswith('+'): return 'unclean' return 'clean' def update_submodules(repo_dir): """update submodules in a repo""" subprocess.check_call("git submodule init", cwd=repo_dir, shell=True) subprocess.check_call("git submodule update --recursive", cwd=repo_dir, shell=True) def sync_files(source, dest): """Syncs files copies files from `source` directory to the `dest` directory. A check is first done to see if the `dest` directory exists, if so, the directory is removed to provide a clean install. """ if os.path.isdir(source) and os.path.isdir(dest): try: print("Remove {0}".format(dest)) shutil.rmtree(dest) except OSError as e: # An error occured tyring to remove directory print(e.errno) print(e.filename) print(e.strerror) print("Copying {0} to {1}".format(source, dest)) shutil.copytree(source, dest) def sync_submodules(repo_dir): for source, dest in SUBMODULE_SYNC_PATHS: source = os.path.join(repo_dir, source) dest = os.path.join(repo_dir, dest) sync_files(source, dest) def require_clean_submodules(repo_dir, argv): """Check on git submodules before distutils can do anything Since distutils cannot be trusted to update the tree after everything has been set in motion, this is not a distutils command. """ # Only do this if we are in the git source repository. if not is_repo(repo_dir): return # don't do anything if nothing is actually supposed to happen for do_nothing in ('-h', '--help', '--help-commands', 'clean', 'submodule', 'buildjs'): if do_nothing in argv: return status = check_submodule_status(repo_dir) if status == "missing": print("checking out submodules for the first time") update_submodules(repo_dir) elif status == "unclean": print('\n'.join([ "Cannot build / install mpld3 with unclean submodules", "Please update submodules with", " python setup.py submodule", "or commit any submodule changes you have made." ])) sys.exit(1) sync_submodules(repo_dir) class UpdateSubmodules(Command): """Update git submodules""" description = "Update git submodules" user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): failure = False try: self.spawn('git submodule init'.split()) self.spawn('git submodule update --recursive'.split()) except Exception as e: failure = e print(e) if not check_submodule_status() == 'clean': print("submodules could not be checked out") sys.exit(1) BUILD_WARNING = """ # It appears that the javascript sources may have been modified. # If this is the case, then the JS libraries should be rebuilt. # Please run # python setup.py buildjs # to re-build the javascript libraries. # This requires npm to be installed: see CONTRIBUTING.md for details. # If you have not modified the javascript sources, then you can safely # disregard this message. """ VERSION_ERROR = """ # Javascript libraries for mpld3 version {0} are missing. # Please run # python setup.py buildjs # to re-build the javascript libraries. # This requires npm to be installed: see CONTRIBUTING.md for details. """ def check_js_build_status(version, root=None, srcdir=None): """Check the javascript build status. Summary: - if we're not in the git repo, or if the source directory doesn't exist, then do nothing. - if the JS libraries do not exist, return an error with a message about building them. - if the JS sources have been modified, return a warning with a message about how to use them to build the libraries. """ if root is None: root = os.path.dirname(os.path.abspath(__file__)) if srcdir is None: srcdir = os.path.join(root, 'src') # If we're not in the git repo, then we perform no checks if not is_repo(root): return # If the source directory doesn't exist, then perform no checks # (this is the case in the packaged distribution) if not os.path.exists(srcdir): return # these are the built javascript libraries js_libs = [os.path.join(root, "mpld3", "js", lib.format(version)) for lib in ('mpld3.v{0}.js', 'mpld3.v{0}.min.js')] # if the js libraries don't exist, then throw an error if not all(os.path.exists(lib) for lib in js_libs): raise ValueError(VERSION_ERROR.format(version)) # these are the javascript sources js_sources = [os.path.join(root, 'package.json')] for (directory, subdirs, flist) in os.walk(srcdir): js_sources.extend([os.path.join(directory, f) for f in flist if f.endswith('.js')]) # if it looks like the sources have been modified, then warn that # they should be rebuilt last_modified_src = max([os.stat(f).st_mtime for f in js_sources]) first_modified_lib = min([os.stat(f).st_mtime for f in js_libs]) if last_modified_src > first_modified_lib: warnings.warn(BUILD_WARNING) class BuildJavascript(Command): """Build the javascript libraries""" description = "Build the mpld3 javascript libraries" user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): failure = False try: self.spawn('make javascript'.split()) except Exception as e: failure = e print(e) python-mpld3/.travis.yml0000644000175500017550000000173412410130733015256 0ustar debacledebaclelanguage: python python: - 2.7 - 3.3 env: - DEPS="numpy=1.8 matplotlib=1.3 jinja2=2.7.2 pandas=0.13.1 nose" install: - conda create -n testenv --yes python=$TRAVIS_PYTHON_VERSION - source activate testenv - conda install --yes $DEPS - python setup.py install before_install: # install npm packages first, to use system python - sudo apt-get install npm - npm config set python python2.7 - npm install d3 vows smash jsdom # then install python version to test - if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then wget http://repo.continuum.io/miniconda/Miniconda-2.2.2-Linux-x86_64.sh -O miniconda.sh; else wget http://repo.continuum.io/miniconda/Miniconda3-2.2.2-Linux-x86_64.sh -O miniconda.sh; fi - chmod +x miniconda.sh - ./miniconda.sh -b - export PATH=/home/travis/anaconda/bin:$PATH # Learned the hard way: miniconda is not always up-to-date with conda. - conda update --yes conda script: - nosetests mpld3 - make test # Javascript tests python-mpld3/CONTRIBUTING.md0000644000175500017550000001602512410130733015375 0ustar debacledebacle# Contributing The [mpld3](https://mpld3.github.io) project welcomes new contributors. The package contains both JavaScript code and Python code, which require slightly different development setups. Details are described below. ## General guidelines Code contribution is done via github. You can fork and clone the source from the [mpld3 github page](http://github.com/jakevdp/mpld3). Whether you are working on the JavaScript side, the Python side, or both, we recommend doing the following (for information about how to use GitHub, please see the [GitHub help page](https://help.github.com/)): 1. Register for a GitHub account. 2. Fork the [main mpld3 repository](http://github.com/jakevdp/mpld3), and clone it to your local machine. 3. Create a new branch in which to write your feature: e.g. [~]$ git checkout -b my-feature-name 4. Modify the Python and/or JavaScript code to implement your new feature 5. Add tests and/or examples for your feature if applicable (see instructions below) 6. Run JavaScript and/or Python unit tests and make sure they pass (see instructions below) 7. Push your new branch to your fork on GitHub: e.g. [~]$ git push origin my-feature-name 8. Go to http://github.com/yourusername/mpld3 and open a pull request against the main mpld3 repository (if you followed the above steps, you should see a big green "Compare and Pull Request" button on your fork's webpage). One of the mpld3 maintainers will then respond and (hopefully!) merge your contribution into the repository. ## Building the Python Code The python code is built in the typical manner: you can instally the package in your standard Python path using [~]$ python setup.py install or to build the package locally run [~]$ python setup.py build ### mplexporter submodule If you are building the package within the git repository, there is an additional step that must be taken. The mpld3 build depends on the the ``mplexporter`` submodule via the ``git submodule`` tool. This submodule is in a separate git repository, and must be fetched before the build can take place. To fetch this dependency, you should run [~]$ python setup.py submodule Once the submodule is fetched, it needs to be synced from its location at ``./mplexporter/mplexporter`` into the mpld3 repository at ``mpld3/mplexporter``: this is done automatically when you run ``python setup.py build`` or ``python setup.py install``. Because mpld3 is a pure Python package, there are no compiled extensions to build, and it can be built and used locally. ## Building the JavaScript code The JavaScript portion of mpld3 is built from source using the ``smash`` and ``uglify`` tools that are part of [node.js](http://nodejs.org/). The benefit of this approach is that the code can be organized, validated, and tested before being automatically formatted and compiled into the final JavaScript library. Because of this build process, any modification of the JavaScript source requires the installation of [npm](https://www.npmjs.org/). Once the npm executable is installed on your system, run [~]$ npm install in the main directory to set up the development environment. This install command will parse the file ``package.json``, and from this information, create a directory ``node_modules`` which contains the tools for building and testing the JavaScript side of mpld3. Though you may be tempted to modify the JavaScript in ``mpld3/js/`` directly, **this is not a good idea** because these files are overwritten in the build process. Instead, modify the sources in the ``src/`` directory, and then run [~]$ python setup.py buildjs The built libraries will be saved to ``mpld3/js/mpld3.v($VERSION).js`` and ``mpld3/js/mpld3.v($VERSION).min.js``, where ``($VERSION)`` is replaced by the current version defined in ``mpld3/__about__.py``. The mpld3 Python package will link to the matching mpld3 version. When contributing a JavaScript patch or enhancement, please include **both the JavaScript sources and the built ``mpld3/js/*.js`` libraries**. This is important so that users who don't wish to modify the JavaScript can install the package without needing ``npm`` and ``nodejs``. Additionally, if possible please add JavaScript unit tests of your new functionality to the ``test`` directory (see details below). ## Testing the package Currently, mpld3 has three different levels of testing, though we hope to streamline this in the future: - There are automated JavaScript tests using [vows](https://www.npmjs.org/package/vows). These should be run if you modify the JavaScript code. - There are automated Python tests using [nose](http://nose.readthedocs.org). These should be run if you modify the Python code. - There are manual plot tests using the ``visualize_tests.py`` script in the repository. These should be run if either the Python or JavaScript code is modified. ### Testing Python with nose There is a set of non-comprehensive unit tests for the Python code which can be run with the command: [~]$ nosetests mpld3 To run these, you will need to install the [nose](http://nose.readthedocs.org) test suite, which can be done by running [~]$ pip install nose These tests are in various directories within the Python source tree, for example ``mpld3/mplexporter/tests/`` In addition to running nosetests, you should check any Python modifications using the ``visualize_tests.py`` script, described below. ### Testing JavaScript with vows Like the Python nosetests, there is a minimal test suite for the mpld3 JavaScript which is controlled with ``npm`` using the ``vows`` package. The tests can be executed via [~]$ npm test This requires installation of ``npm``, which is described above. The tests are located in the ``test`` subdirectory of the main repository. In addition to running the vows tests, before submitting any JavaScript change, you should examine the output of ``visualize_tests.py``, as described below. ### Comprehensive JS/Python Test: ``visualize_tests.py`` Until we can figure out a way to make the automatic tests with ``nose`` and ``vows`` more comprehensive, it is important to actually examine the interactive output of the mpld3 plot. In order to facilitate this, there is a script in the main directory, ``visualize_tests.py``, which allows the developer a side-by-side comparison of the matplotlib output and mpld3 output for a range of plot types. These test plots can be viewed by running [~]$ python visualize_tests.py --local This will generate a file ``test_plots.html`` containing embedded pngs and mpld3 scripts. If your system allows it, the command will finish by automatically opening this file in a web browser. It is important to open the JavaScript console (see your browser documentation) and check for errors in the JavaScript execution as you interact with the plots. Note that the ``--local`` argument in the above command assures that the local copies of the JavaScript libraries are used (i.e. the versions in ``mpld3/js/*.js``). If you omit this argument, the test plots will be run using the mpld3/d3 library versions available on the web at http://mpld3.github.io.