Repository: altair-viz/altair
Pull request #1476 (2019-05-06 19:51:02)

ENH: add mark_*() methods to layer charts
In Altair 3, layered charts can have their own marks which are inherited by all layers.

This PR adds ``mark_*()`` methods to the layered chart to make this easier to use.


Patch:
diff --git a/CHANGES.md b/CHANGES.md
index 906df9ed..d89c296f 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -2,6 +2,12 @@
 
 ## Version 3.1.0 (unreleased)
 
+### Enhancements
+
+- ``alt.LayerChart`` now supports ``mark_*()`` methods. If a layer specifies a
+  mark at the top level, all child charts will inherit it (unless they override
+  it explicitly).
+
 ## Version 3.0.1
 
 Fix version info bug for HTML output and Colab & Kaggle renderers.
diff --git a/altair/vegalite/v3/api.py b/altair/vegalite/v3/api.py
index 9e2ccd63..61d709af 100644
--- a/altair/vegalite/v3/api.py
+++ b/altair/vegalite/v3/api.py
@@ -1434,6 +1434,20 @@ class EncodingMixin(object):
         copy.encoding = core.FacetedEncoding(**encoding)
         return copy
 
+    def facet(self, row=Undefined, column=Undefined, data=Undefined, **kwargs):
+        """Create a facet chart from the current chart.
+
+        Faceted charts require data to be specified at the top level; if data
+        is not specified, the data from the current chart will be used at the
+        top level.
+        """
+        if data is Undefined:
+            data = self.data
+            self = self.copy()
+            self.data = Undefined
+        return FacetChart(spec=self, facet=FacetMapping(row=row, column=column),
+                          data=data, **kwargs)
+
 
 class Chart(TopLevelMixin, EncodingMixin, mixins.MarkMethodMixin,
             core.TopLevelUnitSpec):
@@ -1562,20 +1576,6 @@ class Chart(TopLevelMixin, EncodingMixin, mixins.MarkMethodMixin,
         return self.add_selection(selection_interval(bind='scales',
                                                      encodings=encodings))
 
-    def facet(self, row=Undefined, column=Undefined, data=Undefined, **kwargs):
-        """Create a facet chart from the current chart.
-
-        Faceted charts require data to be specified at the top level; if data
-        is not specified, the data from the current chart will be used at the
-        top level.
-        """
-        if data is Undefined:
-            data = self.data
-            self = self.copy()
-            self.data = Undefined
-        return FacetChart(spec=self, facet=FacetMapping(row=row, column=column),
-                          data=data, **kwargs)
-
 
 def _check_if_valid_subspec(spec, classname):
     """Check if the spec is a valid sub-spec.
@@ -1730,7 +1730,8 @@ def vconcat(*charts, **kwargs):
 
 
 @utils.use_signature(core.TopLevelLayerSpec)
-class LayerChart(TopLevelMixin, EncodingMixin, core.TopLevelLayerSpec):
+class LayerChart(TopLevelMixin, EncodingMixin, mixins.MarkMethodMixin,
+                 core.TopLevelLayerSpec):
     """A Chart with layers within a single panel"""
     def __init__(self, data=Undefined, layer=(), **kwargs):
         # TODO: move common data to top level?
@@ -1781,20 +1782,6 @@ class LayerChart(TopLevelMixin, EncodingMixin, core.TopLevelLayerSpec):
         copy.layer[0] = copy.layer[0].interactive(name=name, bind_x=bind_x, bind_y=bind_y)
         return copy
 
-    def facet(self, row=Undefined, column=Undefined, data=Undefined, **kwargs):
-        """Create a facet chart from the current chart.
-
-        Faceted charts require data to be specified at the top level; if data
-        is not specified, the data from the current chart will be used at the
-        top level.
-        """
-        if data is Undefined:
-            data = self.data
-            self = self.copy()
-            self.data = Undefined
-        return FacetChart(spec=self, facet=FacetMapping(row=row, column=column),
-                          data=data, **kwargs)
-
 
 def layer(*charts, **kwargs):
     """layer multiple charts"""


Test patch:
diff --git a/altair/vegalite/v3/tests/test_api.py b/altair/vegalite/v3/tests/test_api.py
index c15991fa..4df3a574 100644
--- a/altair/vegalite/v3/tests/test_api.py
+++ b/altair/vegalite/v3/tests/test_api.py
@@ -407,6 +407,25 @@ def test_resolve_methods():
     assert chart.resolve == alt.Resolve(scale=alt.ScaleResolveMap(x='shared', y='independent'))
 
 
+def test_layer_marks():
+    chart = alt.LayerChart().mark_point()
+    assert chart.mark == 'point'
+
+    chart = alt.LayerChart().mark_point(color='red')
+    assert chart.mark == alt.MarkDef('point', color='red')
+
+    chart = alt.LayerChart().mark_bar()
+    assert chart.mark == 'bar'
+
+    chart = alt.LayerChart().mark_bar(color='green')
+    assert chart.mark == alt.MarkDef('bar', color='green')
+
+
+def test_layer_encodings():
+    chart = alt.LayerChart().encode(x='column:Q')
+    assert chart.encoding.x == alt.X(shorthand='column:Q')
+
+
 def test_add_selection():
     selections = [alt.selection_interval(),
                   alt.selection_single(),