Repository: altair-viz/altair
Pull request #541 (2018-03-01 18:57:06)

Fix condition
This fixes some subtle bugs in ``alt.condition`` that were constructing invalid condition specs.

I prefer not to reveal how long this took me to fix :smile:


Patch:
diff --git a/altair/utils/schemapi.py b/altair/utils/schemapi.py
index a2bc703d..aa7019d6 100644
--- a/altair/utils/schemapi.py
+++ b/altair/utils/schemapi.py
@@ -1,6 +1,6 @@
 # The contents of this file are automatically written by
 # tools/generate_schema_wrapper.py. Do not modify directly.
-# 2018-02-28 08:23
+# 2018-03-01 10:48
 import collections
 import json
 
diff --git a/altair/vega/v2/schema/core.py b/altair/vega/v2/schema/core.py
index 09d72726..0db12522 100644
--- a/altair/vega/v2/schema/core.py
+++ b/altair/vega/v2/schema/core.py
@@ -1,6 +1,6 @@
 # The contents of this file are automatically written by
 # tools/generate_schema_wrapper.py. Do not modify directly.
-# 2018-02-28 08:23
+# 2018-03-01 10:48
 
 from altair.utils.schemapi import SchemaBase, Undefined
 
diff --git a/altair/vega/v3/schema/core.py b/altair/vega/v3/schema/core.py
index 8d94cfa3..4ec953fe 100644
--- a/altair/vega/v3/schema/core.py
+++ b/altair/vega/v3/schema/core.py
@@ -1,6 +1,6 @@
 # The contents of this file are automatically written by
 # tools/generate_schema_wrapper.py. Do not modify directly.
-# 2018-02-28 08:23
+# 2018-03-01 10:48
 
 from altair.utils.schemapi import SchemaBase, Undefined
 
diff --git a/altair/vegalite/v1/schema/channels.py b/altair/vegalite/v1/schema/channels.py
index aa1a759d..24b03239 100644
--- a/altair/vegalite/v1/schema/channels.py
+++ b/altair/vegalite/v1/schema/channels.py
@@ -1,6 +1,6 @@
 # The contents of this file are automatically written by
 # tools/generate_schema_wrapper.py. Do not modify directly.
-# 2018-02-28 08:23
+# 2018-03-01 10:48
 
 import six
 from . import core
@@ -51,6 +51,7 @@ class Row(core.PositionChannelDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -61,7 +62,7 @@ class Row(core.PositionChannelDef):
         self._kwds.update(kwds)
         return super(Row, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Column(core.PositionChannelDef):
@@ -107,6 +108,7 @@ class Column(core.PositionChannelDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -117,7 +119,7 @@ class Column(core.PositionChannelDef):
         self._kwds.update(kwds)
         return super(Column, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class X(core.PositionChannelDef):
@@ -162,6 +164,7 @@ class X(core.PositionChannelDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -172,7 +175,7 @@ class X(core.PositionChannelDef):
         self._kwds.update(kwds)
         return super(X, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Y(core.PositionChannelDef):
@@ -217,6 +220,7 @@ class Y(core.PositionChannelDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -227,7 +231,7 @@ class Y(core.PositionChannelDef):
         self._kwds.update(kwds)
         return super(Y, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class X2(core.FieldDef):
@@ -266,6 +270,7 @@ class X2(core.FieldDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -276,7 +281,7 @@ class X2(core.FieldDef):
         self._kwds.update(kwds)
         return super(X2, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Y2(core.FieldDef):
@@ -315,6 +320,7 @@ class Y2(core.FieldDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -325,7 +331,7 @@ class Y2(core.FieldDef):
         self._kwds.update(kwds)
         return super(Y2, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Color(core.ChannelDefWithLegend):
@@ -371,6 +377,7 @@ class Color(core.ChannelDefWithLegend):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -381,7 +388,7 @@ class Color(core.ChannelDefWithLegend):
         self._kwds.update(kwds)
         return super(Color, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Opacity(core.ChannelDefWithLegend):
@@ -427,6 +434,7 @@ class Opacity(core.ChannelDefWithLegend):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -437,7 +445,7 @@ class Opacity(core.ChannelDefWithLegend):
         self._kwds.update(kwds)
         return super(Opacity, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Size(core.ChannelDefWithLegend):
@@ -483,6 +491,7 @@ class Size(core.ChannelDefWithLegend):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -493,7 +502,7 @@ class Size(core.ChannelDefWithLegend):
         self._kwds.update(kwds)
         return super(Size, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Shape(core.ChannelDefWithLegend):
@@ -539,6 +548,7 @@ class Shape(core.ChannelDefWithLegend):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -549,7 +559,7 @@ class Shape(core.ChannelDefWithLegend):
         self._kwds.update(kwds)
         return super(Shape, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Detail(core.FieldDef):
@@ -588,6 +598,7 @@ class Detail(core.FieldDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -598,7 +609,7 @@ class Detail(core.FieldDef):
         self._kwds.update(kwds)
         return super(Detail, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Text(core.FieldDef):
@@ -637,6 +648,7 @@ class Text(core.FieldDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -647,7 +659,7 @@ class Text(core.FieldDef):
         self._kwds.update(kwds)
         return super(Text, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Label(core.FieldDef):
@@ -686,6 +698,7 @@ class Label(core.FieldDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -696,7 +709,7 @@ class Label(core.FieldDef):
         self._kwds.update(kwds)
         return super(Label, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Path(core.OrderChannelDef):
@@ -737,6 +750,7 @@ class Path(core.OrderChannelDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -747,7 +761,7 @@ class Path(core.OrderChannelDef):
         self._kwds.update(kwds)
         return super(Path, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Order(core.OrderChannelDef):
@@ -788,6 +802,7 @@ class Order(core.OrderChannelDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -798,4 +813,4 @@ class Order(core.OrderChannelDef):
         self._kwds.update(kwds)
         return super(Order, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
diff --git a/altair/vegalite/v1/schema/core.py b/altair/vegalite/v1/schema/core.py
index 7dc61ec5..270da7f0 100644
--- a/altair/vegalite/v1/schema/core.py
+++ b/altair/vegalite/v1/schema/core.py
@@ -1,6 +1,6 @@
 # The contents of this file are automatically written by
 # tools/generate_schema_wrapper.py. Do not modify directly.
-# 2018-02-28 08:23
+# 2018-03-01 10:48
 
 from altair.utils.schemapi import SchemaBase, Undefined
 
diff --git a/altair/vegalite/v2/api.py b/altair/vegalite/v2/api.py
index c7b1c6a0..f7b843b9 100644
--- a/altair/vegalite/v2/api.py
+++ b/altair/vegalite/v2/api.py
@@ -23,6 +23,11 @@ def _get_channels_mapping():
     return mapping
 
 
+def value(value, **kwargs):
+    """Specify a value for use in an encoding"""
+    return dict(value=value, **kwargs)
+
+
 # -------------------------------------------------------------------------
 # Tools for working with selections
 class SelectionMapping(SchemaBase):
@@ -117,14 +122,16 @@ def condition(predicate, if_true, if_false):
                                   "".format(type(predicate)))
 
     if isinstance(if_true, SchemaBase):
-        condition = if_true.copy()
-        setattr(condition, prop, val)
+        # convert to dict for now; the from_dict call below will wrap this
+        # dict in the appropriate schema
+        if_true = if_true.to_dict()
     elif isinstance(if_true, six.string_types):
-        condition = {prop: val, 'field': if_true}
-    else:
-        condition = dict({prop: val}, **if_true)
+        if_true = {'field': if_true}
+    condition = dict({prop: val}, **if_true)
 
     if isinstance(if_false, SchemaBase):
+        # For the selection, the channel definitions all allow selections
+        # already. So use this SchemaBase wrapper if possible.
         selection = if_false.copy()
         selection.condition = condition
     elif isinstance(if_false, six.string_types):
@@ -291,9 +298,14 @@ class Chart(TopLevelMixin, mixins.MarkMethodMixin, core.TopLevelFacetedUnitSpec)
                 return obj
 
             if isinstance(obj, six.string_types):
-                pass
-            elif 'values' in obj:
-                clsname += 'Values'
+                obj = {'field': obj}
+
+            # if obj is not a string or Schema, it must be a mapping
+            if 'field' in obj:
+                obj = obj.copy()
+                obj.update(parse_shorthand(obj['field']))
+            if 'value' in obj:
+                clsname += 'Value'
             cls = getattr(channels, clsname)
 
             # Do not validate now, because it will be validated later
diff --git a/altair/vegalite/v2/examples/trellis_histogram.py b/altair/vegalite/v2/examples/trellis_histogram.py
index 7df3f786..1a8476b0 100644
--- a/altair/vegalite/v2/examples/trellis_histogram.py
+++ b/altair/vegalite/v2/examples/trellis_histogram.py
@@ -11,7 +11,7 @@ cars = alt.load_dataset('cars')
 chart = alt.Chart(cars).mark_bar().encode(
     x=alt.X("Horsepower",
             type="quantitative",
-            bin=alt.BinTransform(
+            bin=alt.BinParams(
                 maxbins=15
             )),
     y='count(*):Q',
diff --git a/altair/vegalite/v2/schema/channels.py b/altair/vegalite/v2/schema/channels.py
index f2314fd7..1abb4463 100644
--- a/altair/vegalite/v2/schema/channels.py
+++ b/altair/vegalite/v2/schema/channels.py
@@ -1,6 +1,6 @@
 # The contents of this file are automatically written by
 # tools/generate_schema_wrapper.py. Do not modify directly.
-# 2018-02-28 08:23
+# 2018-03-01 10:48
 
 import six
 from . import core
@@ -94,6 +94,7 @@ class Color(core.MarkPropFieldDefWithCondition):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -104,7 +105,7 @@ class Color(core.MarkPropFieldDefWithCondition):
         self._kwds.update(kwds)
         return super(Color, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class ColorValue(core.MarkPropValueDefWithCondition):
@@ -183,6 +184,7 @@ class Column(core.FacetFieldDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -193,7 +195,7 @@ class Column(core.FacetFieldDef):
         self._kwds.update(kwds)
         return super(Column, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Detail(core.FieldDef):
@@ -247,6 +249,7 @@ class Detail(core.FieldDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -257,7 +260,7 @@ class Detail(core.FieldDef):
         self._kwds.update(kwds)
         return super(Detail, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Href(core.FieldDefWithCondition):
@@ -323,6 +326,7 @@ class Href(core.FieldDefWithCondition):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -333,7 +337,7 @@ class Href(core.FieldDefWithCondition):
         self._kwds.update(kwds)
         return super(Href, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class HrefValue(core.ValueDefWithCondition):
@@ -442,6 +446,7 @@ class Opacity(core.MarkPropFieldDefWithCondition):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -452,7 +457,7 @@ class Opacity(core.MarkPropFieldDefWithCondition):
         self._kwds.update(kwds)
         return super(Opacity, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class OpacityValue(core.MarkPropValueDefWithCondition):
@@ -528,6 +533,7 @@ class Order(core.OrderFieldDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -538,7 +544,7 @@ class Order(core.OrderFieldDef):
         self._kwds.update(kwds)
         return super(Order, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Row(core.FacetFieldDef):
@@ -596,6 +602,7 @@ class Row(core.FacetFieldDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -606,7 +613,7 @@ class Row(core.FacetFieldDef):
         self._kwds.update(kwds)
         return super(Row, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Shape(core.MarkPropFieldDefWithCondition):
@@ -695,6 +702,7 @@ class Shape(core.MarkPropFieldDefWithCondition):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -705,7 +713,7 @@ class Shape(core.MarkPropFieldDefWithCondition):
         self._kwds.update(kwds)
         return super(Shape, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class ShapeValue(core.MarkPropValueDefWithCondition):
@@ -814,6 +822,7 @@ class Size(core.MarkPropFieldDefWithCondition):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -824,7 +833,7 @@ class Size(core.MarkPropFieldDefWithCondition):
         self._kwds.update(kwds)
         return super(Size, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class SizeValue(core.MarkPropValueDefWithCondition):
@@ -916,6 +925,7 @@ class Text(core.TextFieldDefWithCondition):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -926,7 +936,7 @@ class Text(core.TextFieldDefWithCondition):
         self._kwds.update(kwds)
         return super(Text, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class TextValue(core.TextValueDefWithCondition):
@@ -1018,6 +1028,7 @@ class Tooltip(core.TextFieldDefWithCondition):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -1028,7 +1039,7 @@ class Tooltip(core.TextFieldDefWithCondition):
         self._kwds.update(kwds)
         return super(Tooltip, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class TooltipValue(core.TextValueDefWithCondition):
@@ -1146,6 +1157,7 @@ class X(core.PositionFieldDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -1156,7 +1168,7 @@ class X(core.PositionFieldDef):
         self._kwds.update(kwds)
         return super(X, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class XValue(core.ValueDef):
@@ -1224,6 +1236,7 @@ class X2(core.FieldDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -1234,7 +1247,7 @@ class X2(core.FieldDef):
         self._kwds.update(kwds)
         return super(X2, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class X2Value(core.ValueDef):
@@ -1345,6 +1358,7 @@ class Y(core.PositionFieldDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -1355,7 +1369,7 @@ class Y(core.PositionFieldDef):
         self._kwds.update(kwds)
         return super(Y, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class YValue(core.ValueDef):
@@ -1423,6 +1437,7 @@ class Y2(core.FieldDef):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {}
@@ -1433,7 +1448,7 @@ class Y2(core.FieldDef):
         self._kwds.update(kwds)
         return super(Y2, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {})
+                                                context=context)
 
 
 class Y2Value(core.ValueDef):
diff --git a/altair/vegalite/v2/schema/core.py b/altair/vegalite/v2/schema/core.py
index 79643632..2b9440e9 100644
--- a/altair/vegalite/v2/schema/core.py
+++ b/altair/vegalite/v2/schema/core.py
@@ -1,6 +1,6 @@
 # The contents of this file are automatically written by
 # tools/generate_schema_wrapper.py. Do not modify directly.
-# 2018-02-28 08:23
+# 2018-03-01 10:48
 
 from altair.utils.schemapi import SchemaBase, Undefined
 
diff --git a/altair/vegalite/v2/schema/mixins.py b/altair/vegalite/v2/schema/mixins.py
index 60f88d79..284c7d76 100644
--- a/altair/vegalite/v2/schema/mixins.py
+++ b/altair/vegalite/v2/schema/mixins.py
@@ -1,6 +1,6 @@
 # The contents of this file are automatically written by
 # tools/generate_schema_wrapper.py. Do not modify directly.
-# 2018-02-28 08:23
+# 2018-03-01 10:48
 from . import core
 from altair.utils import use_signature
 from altair.utils.schemapi import Undefined
diff --git a/tools/generate_schema_wrapper.py b/tools/generate_schema_wrapper.py
index 78230718..19d3f1bf 100644
--- a/tools/generate_schema_wrapper.py
+++ b/tools/generate_schema_wrapper.py
@@ -29,6 +29,7 @@ class {classname}(core.{basename}):
 
     def to_dict(self, validate=True, ignore=(), context=None):
         type_ = getattr(self, 'type', Undefined)
+        context = context or {{}}
         if not isinstance(self.field, six.string_types):
             # field is a RepeatSpec or similar; cannot infer type
             kwds = {{}}
@@ -39,7 +40,7 @@ class {classname}(core.{basename}):
         self._kwds.update(kwds)
         return super({classname}, self).to_dict(validate=validate,
                                                 ignore=ignore,
-                                                context=context or {{}})
+                                                context=context)
 '''
 
 VALUE_TEMPLATE = '''


Test patch:
diff --git a/altair/utils/tests/test_schemapi.py b/altair/utils/tests/test_schemapi.py
index 27c954f0..b2223507 100644
--- a/altair/utils/tests/test_schemapi.py
+++ b/altair/utils/tests/test_schemapi.py
@@ -1,6 +1,6 @@
 # The contents of this file are automatically written by
 # tools/generate_schema_wrapper.py. Do not modify directly.
-# 2018-02-28 08:23
+# 2018-03-01 10:48
 import jsonschema
 import pytest
 
diff --git a/altair/vegalite/v2/tests/test_api.py b/altair/vegalite/v2/tests/test_api.py
index e38e1bea..63228b2e 100644
--- a/altair/vegalite/v2/tests/test_api.py
+++ b/altair/vegalite/v2/tests/test_api.py
@@ -92,3 +92,25 @@ def test_chart_operations():
     assert len(chart.vconcat) == 3
     chart &= chart4
     assert len(chart.vconcat) == 4
+
+
+def test_selection_to_dict():
+    brush = alt.selection(type='interval')
+
+    # test some value selections
+    # Note: X and Y cannot have conditions
+    chart_values = alt.Chart('path/to/data.json').mark_point().encode(
+        color=alt.condition(brush, alt.ColorValue('red'), alt.ColorValue('blue')),
+        opacity=alt.condition(brush, alt.value(0.5), alt.value(1.0)),
+        text=alt.condition(brush, alt.TextValue('foo'), alt.value('bar'))
+    ).to_dict()
+
+    # test some field selections
+    # Note: X and Y cannot have conditions
+    # Conditions cannot both be fields
+    chart_fields = alt.Chart('path/to/data.json').mark_point().encode(
+        color=alt.condition(brush, alt.Color('col1:N'), alt.value('blue')),
+        opacity=alt.condition(brush, 'col1:N', alt.value(0.5)),
+        text=alt.condition(brush, alt.value('abc'), alt.Text('col2:N')),
+        size=alt.condition(brush, alt.value(20), 'col2:N')
+    ).to_dict()