Repository: plotly/plotly.py

Issue:
No plotly.js found if init_notebook_mode run twice.
Hello,

I have been running into issues when using the offline notebook mode of plotly with jupyter.  Specifically, if I run init_notebook_mode twice, and then save and close the notebook with a plotted figure, upon re-opening the figure no longer shows and I can no longer get any plots to show.

Below is a notebook that reproduces the error.  To break it, run all cells, then run cell 2 again, save, and close.  Upon reload, it is not possible to get a plotly plot to show.  Interestingly, if you run cell 1 and 2 again, save, and close, the issue is fixed upon next re-open.

The issue does not show up at all if you do not include a plot in your saved notebook.

Cell 1:

```
from plotly.offline import init_notebook_mode
```

Cell 2:

```
init_notebook_mode()
```

Cell 3:

```
import plotly as py
import plotly.graph_objs as go

trace = go.Scatter3d(
    x=[1,0],
    y=[1,0],
    z=[1,0]
)
fig = go.Figure(data=[trace])
py.offline.iplot(fig)
```

My jupyter logs show the following:

> [W 17:32:55.779 NotebookApp] 404 GET /static/plotly.js?v=20160512163326 (127.0.0.1) 4.02ms referer=http://localhost:8895/notebooks/experiments/Test.ipynb

I am running version 1.9.10 as installed from pip on python 2.7.



Discussion:
This bug is present in version 1.9.11, too.
`404 GET /static/plotly.js?v=20160517213924 (::1) 8.00ms referer=http://localhost:8888/notebooks/Plotly-tst.ipynb`


Resolving patch:
diff --git a/plotly/offline/offline.py b/plotly/offline/offline.py
--- a/plotly/offline/offline.py
+++ b/plotly/offline/offline.py
@@ -14,6 +14,7 @@
 
 import plotly
 from plotly import tools, utils
+from plotly.exceptions import PlotlyError
 
 try:
     import IPython
@@ -28,6 +29,7 @@
 except ImportError:
     _matplotlib_imported = False
 
+__PLOTLY_OFFLINE_INITIALIZED = False
 
 def download_plotlyjs(download_url):
     warnings.warn('''
@@ -50,16 +52,11 @@ def init_notebook_mode():
     yet. This is an idempotent method and can and should be called from any
     offline methods that require plotly.js to be loaded into the notebook dom.
     """
-    warnings.warn('''
-        `init_notebook_mode` is deprecated and will be removed in the
-        next release. Notebook mode is now automatically initialized when
-        notebook methods are invoked, so it is no
-        longer necessary to manually initialize.
-    ''', DeprecationWarning)
-
     if not _ipython_imported:
         raise ImportError('`iplot` can only run inside an IPython Notebook.')
 
+    global __PLOTLY_OFFLINE_INITIALIZED
+    # Inject plotly.js into the output cell
     script_inject = (
         ''
         '<script type=\'text/javascript\'>'
@@ -68,7 +65,6 @@ def init_notebook_mode():
         '{script}'
         '}});'
         'require([\'plotly\'], function(Plotly) {{'
-        'console.log(Plotly);'
         'window.Plotly = Plotly;'
         '}});'
         '}}'
@@ -76,6 +72,7 @@ def init_notebook_mode():
         '').format(script=get_plotlyjs())
 
     display(HTML(script_inject))
+    __PLOTLY_OFFLINE_INITIALIZED = True
 
 
 def _plot_html(figure_or_data, show_link, link_text,
@@ -177,13 +174,22 @@ def iplot(figure_or_data, show_link=True, link_text='Export to plot.ly',
 
     Example:
     ```
-    from plotly.offline import iplot
-
+    from plotly.offline import init_notebook_mode, iplot
+    init_notebook_mode()
     iplot([{'x': [1, 2, 3], 'y': [5, 2, 7]}])
     ```
     """
-
-    init_notebook_mode()
+    if not __PLOTLY_OFFLINE_INITIALIZED:
+        raise PlotlyError('\n'.join([
+            'Plotly Offline mode has not been initialized in this notebook. '
+            'Run: ',
+            '',
+            'import plotly',
+            'plotly.offline.init_notebook_mode() '
+            '# run at the start of every ipython notebook',
+        ]))
+    if not tools._ipython_imported:
+        raise ImportError('`iplot` can only run inside an IPython Notebook.')
 
     plot_html, plotdivid, width, height = _plot_html(
         figure_or_data, show_link, link_text, validate,
@@ -415,7 +421,7 @@ def iplot_mpl(mpl_fig, resize=False, strip_style=False,
 
     Example:
     ```
-    from plotly.offline import iplot_mpl
+    from plotly.offline import init_notebook_mode, iplot_mpl
     import matplotlib.pyplot as plt
 
     fig = plt.figure()
@@ -423,11 +429,10 @@ def iplot_mpl(mpl_fig, resize=False, strip_style=False,
     y = [100, 250, 200, 150, 300]
     plt.plot(x, y, "o")
 
+    init_notebook_mode()
     iplot_mpl(fig)
     ```
     """
-    init_notebook_mode()
-
     plotly_plot = tools.mpl_to_plotly(mpl_fig, resize, strip_style, verbose)
     return iplot(plotly_plot, show_link, link_text, validate)
 
diff --git a/plotly/version.py b/plotly/version.py
--- a/plotly/version.py
+++ b/plotly/version.py
@@ -1 +1 @@
-__version__ = '1.9.13'
+__version__ = '1.10.0'


Test patch:
diff --git a/plotly/tests/test_optional/test_offline/test_offline.py b/plotly/tests/test_optional/test_offline/test_offline.py
--- a/plotly/tests/test_optional/test_offline/test_offline.py
+++ b/plotly/tests/test_optional/test_offline/test_offline.py
@@ -29,7 +29,8 @@ class PlotlyOfflineTestCase(TestCase):
     def setUp(self):
         pass
 
-    def test_iplot_works_wihout_calling_init_notebook_mode(self):
+    @raises(plotly.exceptions.PlotlyError)
+    def test_iplot_doesnt_work_before_you_call_init_notebook_mode(self):
         plotly.offline.iplot([{}])
 
     def test_iplot_works_after_you_call_init_notebook_mode(self):
@@ -86,4 +87,3 @@ def test_default_mpl_plot_generates_expected_html(self):
         self.assertTrue(PLOTLYJS in html)         # and the source code
         # and it's an <html> doc
         self.assertTrue(html.startswith('<html>') and html.endswith('</html>'))
-