Repository: vega/altair

Issue:
NO viz when using headless renderer with JSON data transformer
When using 
```python  
alt.renderers.enable('png')  # or alt.renderers.enable('svg') 
alt.data_transformers.enable('json')
```
The viz is empty in the notebook in jupyterlab. Using `default` in either renderer or data_transformer behaves correct. Seems something wrong with the utils.headless (not sure)?


Discussion:
I'm using `altair==2.0.0rc2` under Windows
Yes, I would not expect this to work. The json data transformer is meant for live renderers.

Run ``alt.data_transformers.enable('default')`` and the headless renderer will work.
Thanks. So what might be the best practice if we want to plot large dataset in svg/png in the notebook (for data security reason or simply want to turn off the 3 buttons in the vega-based plot)? I guess the most straightforward way is to increase the row_limit option in data_transformer and use svg/png in the renderer?
Oh, I see... that's an issue.

As soon as #776 is merged you'll be able to do
```
alt.data_transformers.enable('default', max_rows=None)
```
and it will work.

We should make the headless renderers use that automatically... the max rows error is intended for the live rendering use-case.
Thanks, that will be great. Right now it can be done via setting an arbitrary number:
```python
alt.data_transformers.register('no_limit', lambda data: alt.pipe(data, alt.limit_rows(max_rows=1000000), alt.to_values))
alt.data_transformers.enable('no_limit')
alt.renderers.enable('svg')
```
Just one more thing (not very related): the bottom of the guide in data transformers (https://altair-viz.github.io/user_guide/data_transformers.html) it not correct. I think it should be 
```python
alt.data_transformers.register('s3', lambda data: pipe(data, sample, to_s3('mybucket'))) # not pipe(sample, to_s3('mybucket'))
alt.data_transformers.enable('s3')
```

Resolving patch:
diff --git a/altair/vegalite/v1/api.py b/altair/vegalite/v1/api.py
--- a/altair/vegalite/v1/api.py
+++ b/altair/vegalite/v1/api.py
@@ -115,7 +115,7 @@ def savechart(self, fp, format=None, **kwargs):
         )
         return self.save(fp, format=None, **kwargs)
 
-    def save(self, fp, format=None, **kwargs):
+    def save(self, fp, format=None, override_data_transformer=True, **kwargs):
         """Save a chart to file in a variety of formats
 
         Supported formats are json, html, png, svg
@@ -127,16 +127,31 @@ def save(self, fp, format=None, **kwargs):
         format : string (optional)
             the format to write: one of ['json', 'html', 'png', 'svg'].
             If not specified, the format will be determined from the filename.
+        override_data_transformer : boolean (optional)
+            If True (default), then the save action will be done with the
+            default data_transformer with max_rows set to None. If False,
+            then use the currently active data transformer.
         **kwargs :
             Additional keyword arguments are passed to the output method
             associated with the specified format.
         """
         from ...utils.save import save
-        return save(self, fp=fp, format=format,
-                         vegalite_version=VEGALITE_VERSION,
-                         vega_version=VEGA_VERSION,
-                         vegaembed_version=VEGAEMBED_VERSION,
-                         **kwargs)
+
+        kwds = dict(chart=self, fp=fp, format=format,
+                    vegalite_version=VEGALITE_VERSION,
+                    vega_version=VEGA_VERSION,
+                    vegaembed_version=VEGAEMBED_VERSION,
+                    **kwargs)
+
+        # By default we override the data transformer. This makes it so
+        # that save() will succeed even for large datasets that would
+        # normally trigger a MaxBinsError
+        if override_data_transformer:
+            with data_transformers.enable('default', max_rows=None):
+                result = save(**kwds)
+        else:
+            result = save(**kwds)
+        return result
 
     # transform method
     @utils.use_signature(core.Transform)
diff --git a/altair/vegalite/v2/api.py b/altair/vegalite/v2/api.py
--- a/altair/vegalite/v2/api.py
+++ b/altair/vegalite/v2/api.py
@@ -372,7 +372,7 @@ def savechart(self, fp, format=None, **kwargs):
         )
         return self.save(fp, format=None, **kwargs)
 
-    def save(self, fp, format=None, **kwargs):
+    def save(self, fp, format=None, override_data_transformer=True, **kwargs):
         """Save a chart to file in a variety of formats
 
         Supported formats are json, html, png, svg
@@ -384,16 +384,31 @@ def save(self, fp, format=None, **kwargs):
         format : string (optional)
             the format to write: one of ['json', 'html', 'png', 'svg'].
             If not specified, the format will be determined from the filename.
+        override_data_transformer : boolean (optional)
+            If True (default), then the save action will be done with the
+            default data_transformer with max_rows set to None. If False,
+            then use the currently active data transformer.
         **kwargs :
             Additional keyword arguments are passed to the output method
             associated with the specified format.
         """
         from ...utils.save import save
-        return save(self, fp=fp, format=format,
-                         vegalite_version=VEGALITE_VERSION,
-                         vega_version=VEGA_VERSION,
-                         vegaembed_version=VEGAEMBED_VERSION,
-                         **kwargs)
+
+        kwds = dict(chart=self, fp=fp, format=format,
+                    vegalite_version=VEGALITE_VERSION,
+                    vega_version=VEGA_VERSION,
+                    vegaembed_version=VEGAEMBED_VERSION,
+                    **kwargs)
+
+        # By default we override the data transformer. This makes it so
+        # that save() will succeed even for large datasets that would
+        # normally trigger a MaxBinsError
+        if override_data_transformer:
+            with data_transformers.enable('default', max_rows=None):
+                result = save(**kwds)
+        else:
+            result = save(**kwds)
+        return result
 
     # Layering and stacking
 


Test patch: