Repository: bokeh/bokeh

Issue:
output_notebook resources
I use gist frequently to share notebooks, code and ideas.  `output_notebook` uses `INLINE` Resources as a default and it creates an enormous file.  Files that are too large in a Gist will require the files to be edited locally and pushed to the Gist repository.

After some digging, I found how to use the `CDN` to render the notebooks.  Using the `CDN` Resource reduces the file size so that the gist can still be edited online.  

This [Gist](https://gist.github.com/tonyfast/fae0eacea79bbd28996d) describes this issue in a bit more detail.  But, ultimately the `CDN` reduces the file size by an order of magnitude for this particular example.

It might be valuable to consider a different default mode for the `output_notebook` method or at least provide a warning or message that there is a way to reduce the file size.



Discussion:
This is a valuable observation... not sure about changing the default, but definitely some kind of warning could be added.

I am in favor of changing the default. I'm not sure what the rational for inline being the default is, but maybe it's "so it's a self-contained document.' 

To my mind, you would typically email that self-contained document to someone, so if they can get the document they can get the resources. I know I was initially shocked at the size of document produced and it took me a while to find mode='cdn.' And I know other users have experienced the same - a recent example: https://twitter.com/birdsarah/status/610451709408739329

I think it's a bad first impression, and it's not like we'd be disappearing the inline version, just changing the default.

On a semi-related note, I'd also love an argument where you could specify the url(s) where your assets live.

I also agree that the file size is an overarching bad impression judging from some stackoverflow posts I've seen.  If you are sharing a notebook and the limitation is whether Gist or Nbviewer can use it then the file does not need to be self contained.

Specifying other Url(s) for assets would be a great way for people to create reusable and portable style sheets.

I think I am being persuaded to support changing the default.

As I said... I am not sure... but if a lot of people is asking for that, probably is something to change...

I should have said, my observations come from output_file, where I'd like to see the default be 'cdn.' But I can imagine the same arguments applying for output_notebook.

@damianavila you said "I am not sure" - can I ask why? I'd be curious to know what the thoughts were behind the original 'inline' default.

The motivation was exactly to have self-contained documents that are guaranteed to always work.

> The motivation was exactly to have self-contained documents that are guaranteed to always work.

Essentially... there are potential scenarios where the connectivity is not guaranteed and having a self-contained document could be a solution... but I understand that maybe those scenarios are less frequent as time goes...

@damianavila or @birdsarah can one of you pose the question on the mailing list to solicit feedback?

on it.

done.

Just saw the link to this issue in the mailing list. I'm in favor of changing the default. Bokeh operates within a web browser, therefore it's fair to assume an internet connection. It's nice to have INLINE for when that assumption is false, but as an exception, not a rule.


Resolving patch:
diff --git a/bokeh/io.py b/bokeh/io.py
--- a/bokeh/io.py
+++ b/bokeh/io.py
@@ -52,7 +52,7 @@
 # Classes and functions
 #-----------------------------------------------------------------------------
 
-def output_file(filename, title="Bokeh Plot", autosave=False, mode="inline", root_dir=None):
+def output_file(filename, title="Bokeh Plot", autosave=False, mode="cdn", root_dir=None):
     '''Configure the default output state to generate output saved
     to a file when :func:`show` is called.
 
@@ -319,9 +319,9 @@ def _get_save_args(state, filename, resources, title):
         raise RuntimeError("save() called but no filename was supplied and output_file(...) was never called, nothing saved")
 
     if resources is None:
-        warnings.warn("save() called but no resources was supplied and output_file(...) was never called, defaulting to resources.INLINE")
-        from .resources import INLINE
-        resources = INLINE
+        warnings.warn("save() called but no resources were supplied and output_file(...) was never called, defaulting to resources.CDN")
+        from .resources import CDN
+        resources = CDN
 
     if title is None:
         warnings.warn("save() called but no title was supplied and output_file(...) was never called, using default title 'Bokeh Plot'")
diff --git a/bokeh/state.py b/bokeh/state.py
--- a/bokeh/state.py
+++ b/bokeh/state.py
@@ -150,7 +150,7 @@ def reset(self):
         '''
         self._reset_with_doc(Document())
 
-    def output_file(self, filename, title="Bokeh Plot", autosave=False, mode="inline", root_dir=None):
+    def output_file(self, filename, title="Bokeh Plot", autosave=False, mode="cdn", root_dir=None):
         """Output to a standalone HTML file.
 
         Does not change the current Document from curdoc(). File,
@@ -169,7 +169,7 @@ def output_file(self, filename, title="Bokeh Plot", autosave=False, mode="inline
                 command). If False, then the file is only saved upon calling
                 :func:`show` or :func:`save`.
 
-            mode (str, optional) : how to include BokehJS (default: ``'inline'``)
+            mode (str, optional) : how to include BokehJS (default: ``'cdn'``)
                 One of: ``'inline'``, ``'cdn'``, ``'relative(-dev)'`` or
                 ``'absolute(-dev)'``. See :class:`bokeh.resources.Resources` for more details.
 
diff --git a/bokeh/util/notebook.py b/bokeh/util/notebook.py
--- a/bokeh/util/notebook.py
+++ b/bokeh/util/notebook.py
@@ -30,11 +30,11 @@ def load_notebook(resources=None, verbose=False, hide_banner=False):
     global _notebook_loaded
 
     from .. import __version__
-    from ..resources import INLINE
+    from ..resources import CDN
     from ..templates import NOTEBOOK_LOAD
 
     if resources is None:
-        resources = INLINE
+        resources = CDN
 
     if resources.mode == 'inline':
         js_info = 'inline'


Test patch:
diff --git a/bokeh/tests/test_io.py b/bokeh/tests/test_io.py
--- a/bokeh/tests/test_io.py
+++ b/bokeh/tests/test_io.py
@@ -46,7 +46,7 @@ def tearDown(self):
 class testOutputFile(DefaultStateTester):
 
     def test_noarg(self):
-        default_kwargs = dict(title="Bokeh Plot", autosave=False, mode="inline", root_dir=None)
+        default_kwargs = dict(title="Bokeh Plot", autosave=False, mode="cdn", root_dir=None)
         io.output_file("foo.html")
         self._check_func_called(io._state.output_file, ("foo.html",), default_kwargs)
 
@@ -115,13 +115,13 @@ def test_default_resources(self):
 
     @patch('warnings.warn')
     def test_missing_resources(self, mock_warn):
-        from bokeh.resources import INLINE
+        from bokeh.resources import CDN
         io._state.file = None
         filename, resources, title = io._get_save_args(io._state, "filename", None, "title")
-        self.assertEqual(resources, INLINE)
+        self.assertEqual(resources, CDN)
         self.assertTrue(mock_warn.called)
-        self.assertEqual(mock_warn.call_args[0], ("save() called but no resources was supplied and output_file(...) "
-                                                  "was never called, defaulting to resources.INLINE",))
+        self.assertEqual(mock_warn.call_args[0], ("save() called but no resources were supplied and output_file(...) "
+                                                  "was never called, defaulting to resources.CDN",))
         self.assertEqual(mock_warn.call_args[1], {})
 
     def test_explicit_title(self):
@@ -140,7 +140,7 @@ def test_missing_title(self, mock_warn):
         filename, resources, title = io._get_save_args(io._state, "filename", "resources", None)
         self.assertEqual(title, "Bokeh Plot")
         self.assertTrue(mock_warn.called)
-        self.assertEqual(mock_warn.call_args[0], ("save() called but no title was supplied and output_file(...) " 
+        self.assertEqual(mock_warn.call_args[0], ("save() called but no title was supplied and output_file(...) "
                                                   "was never called, using default title 'Bokeh Plot'",))
         self.assertEqual(mock_warn.call_args[1], {})
 
diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py
--- a/tests/integration/conftest.py
+++ b/tests/integration/conftest.py
@@ -29,7 +29,7 @@ def output_file_url(request, base_url):
     filename = request.function.__name__ + '.html'
     file_path = request.fspath.dirpath().join(filename).strpath
 
-    output_file(file_path)
+    output_file(file_path, mode='inline')
 
     def fin():
         os.remove(file_path)