diff --git a/plotly/graph_reference/default-schema.json b/plotly/graph_reference/default-schema.json index f238807bf48..adff88bc8f5 100644 --- a/plotly/graph_reference/default-schema.json +++ b/plotly/graph_reference/default-schema.json @@ -426,12 +426,14 @@ ] }, "dragmode": { - "description": "Determines the mode of drag interactions.", + "description": "Determines the mode of drag interactions. *select* and *lasso* apply only to scatter traces with markers or text. *orbit* and *turntable* apply only to 3D scenes.", "role": "info", "valType": "enumerated", "values": [ "zoom", "pan", + "select", + "lasso", "orbit", "turntable" ] diff --git a/plotly/offline/__init__.py b/plotly/offline/__init__.py index 30da5a36c18..f4a5fc2d2b6 100644 --- a/plotly/offline/__init__.py +++ b/plotly/offline/__init__.py @@ -5,7 +5,10 @@ """ from . offline import ( download_plotlyjs, + enable_mpl_offline, init_notebook_mode, iplot, - plot + iplot_mpl, + plot, + plot_mpl ) diff --git a/plotly/offline/offline.py b/plotly/offline/offline.py index 4944b4e7f17..53ebd853c6b 100644 --- a/plotly/offline/offline.py +++ b/plotly/offline/offline.py @@ -17,6 +17,19 @@ from plotly.exceptions import PlotlyError +try: + import IPython + _ipython_imported = True +except ImportError: + _ipython_imported = False + +try: + import matplotlib + _matplotlib_imported = True +except ImportError: + _matplotlib_imported = False + + __PLOTLY_OFFLINE_INITIALIZED = False @@ -191,9 +204,7 @@ def plot(figure_or_data, from plotly.offline import plot import plotly.graph_objs as go - plot([ - go.Scatter(x=[1, 2, 3], y=[3, 2 6]) - ], filename='my-graph.html') + plot([go.Scatter(x=[1, 2, 3], y=[3, 2, 6])], filename='my-graph.html') ``` More examples below. @@ -298,3 +309,164 @@ def plot(figure_or_data, ]) else: return plot_html + + +def plot_mpl(mpl_fig, resize=False, strip_style=False, + verbose=False, show_link=True, link_text='Export to plot.ly', + validate=True, output_type='file', include_plotlyjs=True, + filename='temp-plot.html', auto_open=True): + """ + Convert a matplotlib figure to a Plotly graph stored locally as HTML. + + For more information on converting matplotlib visualizations to plotly + graphs, call help(plotly.tools.mpl_to_plotly) + + For more information on creating plotly charts locally as an HTML document + or string, call help(plotly.offline.plot) + + mpl_fig -- a matplotlib figure object to convert to a plotly graph + + Keyword arguments: + resize (default=False) -- allow plotly to choose the figure size. + strip_style (default=False) -- allow plotly to choose style options. + verbose (default=False) -- print message. + show_link (default=True) -- display a link in the bottom-right corner of + of the chart that will export the chart to Plotly Cloud or + Plotly Enterprise + link_text (default='Export to plot.ly') -- the text of export link + validate (default=True) -- validate that all of the keys in the figure + are valid? omit if your version of plotly.js has become outdated + with your version of graph_reference.json or if you need to include + extra, unnecessary keys in your figure. + output_type ('file' | 'div' - default 'file') -- if 'file', then + the graph is saved as a standalone HTML file and `plot` + returns None. + If 'div', then `plot` returns a string that just contains the + HTML
that contains the graph and the script to generate the + graph. + Use 'file' if you want to save and view a single graph at a time + in a standalone HTML file. + Use 'div' if you are embedding these graphs in an HTML file with + other graphs or HTML markup, like a HTML report or an website. + include_plotlyjs (default=True) -- If True, include the plotly.js + source code in the output file or string. + Set as False if your HTML file already contains a copy of the plotly.js + library. + filename (default='temp-plot.html') -- The local filename to save the + outputted chart to. If the filename already exists, it will be + overwritten. This argument only applies if `output_type` is 'file'. + auto_open (default=True) -- If True, open the saved file in a + web browser after saving. + This argument only applies if `output_type` is 'file'. + + Example: + ``` + from plotly.offline import init_notebook_mode, plot_mpl + import matplotlib.pyplot as plt + + init_notebook_mode() + + fig = plt.figure() + x = [10, 15, 20, 25, 30] + y = [100, 250, 200, 150, 300] + plt.plot(x, y, "o") + + plot_mpl(fig) + ``` + """ + plotly_plot = tools.mpl_to_plotly(mpl_fig, resize, strip_style, verbose) + return plot(plotly_plot, show_link, link_text, validate, output_type, + include_plotlyjs, filename, auto_open) + + +def iplot_mpl(mpl_fig, resize=False, strip_style=False, + verbose=False, show_link=True, + link_text='Export to plot.ly', validate=True): + """ + Convert a matplotlib figure to a plotly graph and plot inside an IPython + notebook without connecting to an external server. + + To save the chart to Plotly Cloud or Plotly Enterprise, use + `plotly.plotly.plot_mpl`. + + For more information on converting matplotlib visualizations to plotly + graphs call `help(plotly.tools.mpl_to_plotly)` + + For more information on plotting plotly charts offline in an Ipython + notebook call `help(plotly.offline.iplot)` + + mpl_fig -- a matplotlib.figure to convert to a plotly graph + + Keyword arguments: + resize (default=False) -- allow plotly to choose the figure size. + strip_style (default=False) -- allow plotly to choose style options. + verbose (default=False) -- print message. + show_link (default=True) -- display a link in the bottom-right corner of + of the chart that will export the chart to Plotly Cloud or + Plotly Enterprise + show_link (default=True) -- display a link in the bottom-right corner of + of the chart that will export the chart to + Plotly Cloud or Plotly Enterprise + link_text (default='Export to plot.ly') -- the text of export link + validate (default=True) -- validate that all of the keys in the figure + are valid? omit if your version of plotly.js + has become outdated with your version of + graph_reference.json or if you need to include + extra, unnecessary keys in your figure. + + Example: + ``` + from plotly.offline import init_notebook_mode, iplot_mpl + import matplotlib.pyplot as plt + + init_notebook_mode() + + fig = plt.figure() + x = [10, 15, 20, 25, 30] + y = [100, 250, 200, 150, 300] + plt.plot(x, y, "o") + + iplot_mpl(fig) + ``` + """ + plotly_plot = tools.mpl_to_plotly(mpl_fig, resize, strip_style, verbose) + return iplot(plotly_plot, show_link, link_text, validate) + + +def enable_mpl_offline(resize=False, strip_style=False, + verbose=False, show_link=True, + link_text='Export to plot.ly', validate=True): + """ + Convert mpl plots to locally hosted HTML documents. + + 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. + + (idea taken from `mpld3._display.enable_notebook`) + + Example: + ``` + from plotly.offline import init_notebook_mode, plotly_takeover + import matplotlib.pyplot as plt + + init_notebook_mode() + enable_mpl_offline() + + fig = plt.figure() + x = [10, 15, 20, 25, 30] + y = [100, 250, 200, 150, 300] + plt.plot(x, y, "o") + fig + ``` + """ + if not __PLOTLY_OFFLINE_INITIALIZED: + init_notebook_mode() + ip = IPython.core.getipython.get_ipython() + formatter = ip.display_formatter.formatters['text/html'] + formatter.for_type(matplotlib.figure.Figure, + lambda fig: iplot_mpl(fig, resize, strip_style, verbose, + show_link, link_text, validate)) + diff --git a/plotly/tests/test_optional/test_offline/test_offline.py b/plotly/tests/test_optional/test_offline/test_offline.py index 16fb70ebc7e..5f4944b8c27 100644 --- a/plotly/tests/test_optional/test_offline/test_offline.py +++ b/plotly/tests/test_optional/test_offline/test_offline.py @@ -5,10 +5,25 @@ from __future__ import absolute_import from nose.tools import raises +from nose.plugins.attrib import attr + from unittest import TestCase +import json import plotly +# TODO: matplotlib-build-wip +from plotly.tools import _matplotlylib_imported + +if _matplotlylib_imported: + import matplotlib + # Force matplotlib to not use any Xwindows backend. + matplotlib.use('Agg') + import matplotlib.pyplot as plt + + +PLOTLYJS = plotly.offline.offline.get_plotlyjs() + class PlotlyOfflineTestCase(TestCase): def setUp(self): @@ -22,3 +37,54 @@ def test_iplot_works_after_you_call_init_notebook_mode(self): plotly.tools._ipython_imported = True plotly.offline.init_notebook_mode() plotly.offline.iplot([{}]) + + @attr('matplotlib') + def test_iplot_mpl_works_after_you_call_init_notebook_mode(self): + # Generate matplotlib plot for tests + fig = plt.figure() + + x = [10, 20, 30] + y = [100, 200, 300] + plt.plot(x, y, "o") + + plotly.tools._ipython_imported = True + plotly.offline.init_notebook_mode() + plotly.offline.iplot_mpl(fig) + + +class PlotlyOfflineMPLTestCase(TestCase): + def setUp(self): + pass + + def _read_html(self, file_url): + """ Read and return the HTML contents from a file_url in the + form e.g. file:///Users/chriddyp/Repos/plotly.py/plotly-temp.html + """ + with open(file_url.replace('file://', '').replace(' ', '')) as f: + return f.read() + + @attr('matplotlib') + def test_default_mpl_plot_generates_expected_html(self): + # Generate matplotlib plot for tests + fig = plt.figure() + + x = [10, 20, 30] + y = [100, 200, 300] + plt.plot(x, y, "o") + + figure = plotly.tools.mpl_to_plotly(fig) + data = figure['data'] + layout = figure['layout'] + data_json = json.dumps(data, cls=plotly.utils.PlotlyJSONEncoder) + layout_json = json.dumps(layout, cls=plotly.utils.PlotlyJSONEncoder) + html = self._read_html(plotly.offline.plot_mpl(fig)) + + # just make sure a few of the parts are in here + # like PlotlyOfflineTestCase(TestCase) in test_core + self.assertTrue('Plotly.newPlot' in html) # plot command is in there + self.assertTrue(data_json in html) # data is in there + self.assertTrue(layout_json in html) # layout is in there too + self.assertTrue(PLOTLYJS in html) # and the source code + # and it's an doc + self.assertTrue(html.startswith('') and html.endswith('')) + diff --git a/plotly/version.py b/plotly/version.py index 6c08d428eb4..a4f8693ffb7 100644 --- a/plotly/version.py +++ b/plotly/version.py @@ -1 +1 @@ -__version__ = '1.9.4' +__version__ = '1.9.5'