Repository: bokeh/bokeh

Issue:
Gmaps incompatible with DataRange1d, make error louder/earlier
Runtime Info:

notebook server is 5.0.0
Python 3.6.1 |Continuum Analytics, Inc.| (default, May 11 2017, 13:09:58)
IPython 6.0.0
bokeh '0.12.9'
ipywidgets '7.0.1'
ubuntu 16

When i run the gmaps demo with push notebook it displays the dots in the wrong location until i interact with he map.

```python
from bokeh.io import output_file, show
from bokeh.models import (
  GMapPlot, GMapOptions, ColumnDataSource, Circle, DataRange1d, PanTool, WheelZoomTool, BoxSelectTool
)

map_options = GMapOptions(lat=30.29, lng=-97.73, map_type="roadmap", zoom=11)

plot = GMapPlot(
    x_range=DataRange1d(), y_range=DataRange1d(), map_options=map_options
)
plot.title.text = "Austin"


plot.api_key = API_KEY

source = ColumnDataSource(
    data=dict(
        lat=[],
        lon=[],
    )
)

circle = Circle(x="lon", y="lat", size=15, fill_color="blue", fill_alpha=0.8, line_color=None)
plot.add_glyph(source, circle)

plot.add_tools(PanTool(), WheelZoomTool(), BoxSelectTool())
h = show(plot, notebook_handle=True)
```


```python
source.data = dict(
        lat=[30.29, 30.20, 30.29],
        lon=[-97.70, -97.74, -97.78],
    )
push_notebook(handle=h)
```

pre interaction
![image](https://user-images.githubusercontent.com/6456637/31361444-5e1874bc-ad21-11e7-9223-5783ab8d5338.png)


post interaction
![image](https://user-images.githubusercontent.com/6456637/31361409-37162508-ad21-11e7-9c87-c4c642981212.png)



Discussion:
DataRange1d is incompatible with GmapPlot, which must defer to the google maps API to set ranges. Use Range1d instead. I’ll leave this issue as a task to make it fail earlier and louder. 
Thanks for the quick reply, this was exactly what was needed! You might want to also mark this as a task to change the documentation as well. 
@mhamilton723 is it demonstrated incorrectly with a `DataRange1d` some place? If so a specific pointer to a location would help. If not, I'll probably leave it:

* demonstrated correctly everywhere
* with a very descriptive immediate error stating what the corrective action is 
@mattpap I think the proper way to do this will mean factoring much of `Plot` into a `BasePlot` that both `Plot` and `MapPlot` can separately inherit from. Then `GMapPlot` can define more restrictive range properties. 
I'm not sure if such deep changes are really needed for this purpose. An error message can be achieved by cheaper means. If however want to proceed, then I would leave this for the next release, so at least I have some time to give this a thought.
The only other way to catch it in all cases is a validation error, which also does not seem ideal. 
This started getting pretty hairy, I think I will just add a check at `__init__` as well as a validation error after all. 

Resolving patch:
diff --git a/bokeh/core/validation/errors.py b/bokeh/core/validation/errors.py
--- a/bokeh/core/validation/errors.py
+++ b/bokeh/core/validation/errors.py
@@ -44,6 +44,9 @@
 1011 *(MALFORMED_GRAPH_SOURCE)*
     The ``GraphSource`` is incorrectly configured.
 
+1012 *(INCOMPATIBLE_MAP_RANGE_TYPE)*
+    Map plots can only support ``Range1d`` types, not data ranges.
+
 9999 *(EXT)*
     Indicates that a custom error check has failed.
 
@@ -61,6 +64,7 @@
     1009: ("INCOMPATIBLE_SCALE_AND_RANGE", "A Scale is incompatible with one or more ranges on the same plot dimension"),
     1010: ("CDSVIEW_SOURCE_DOESNT_MATCH", "CDSView used by Glyph renderer must have a source that matches the Glyph renderer's data source"),
     1011: ("MALFORMED_GRAPH_SOURCE", "The GraphSource is incorrectly configured"),
+    1012: ("INCOMPATIBLE_MAP_RANGE_TYPE", "Map plots can only support Range1d types, not data ranges"),
     9999: ("EXT",                    "Custom extension reports error"),
 }
 
diff --git a/bokeh/models/map_plots.py b/bokeh/models/map_plots.py
--- a/bokeh/models/map_plots.py
+++ b/bokeh/models/map_plots.py
@@ -8,7 +8,7 @@
 from ..core.properties import Bool, Enum, Float, Instance, Int, JSON, Override, String
 from ..core.validation import error, warning
 from ..core.validation.warnings import MISSING_RENDERERS, NO_DATA_RENDERERS
-from ..core.validation.errors import REQUIRED_RANGE, MISSING_GOOGLE_API_KEY
+from ..core.validation.errors import INCOMPATIBLE_MAP_RANGE_TYPE, REQUIRED_RANGE, MISSING_GOOGLE_API_KEY
 from ..model import Model
 from .plots import Plot
 
@@ -36,6 +36,21 @@ class MapPlot(Plot):
 
     '''
 
+    def __init__(self, *args, **kw):
+        from ..models.ranges import Range1d
+        for r in ('x_range', 'y_range'):
+            if r in kw and not isinstance(kw.get(r), Range1d):
+                raise ValueError('Invalid value for %r, MapPlot ranges may only be Range1d, not data ranges' % r)
+        super(MapPlot, self).__init__(*args, **kw)
+
+    @error(INCOMPATIBLE_MAP_RANGE_TYPE)
+    def _check_incompatible_map_range_type(self):
+        from ..models.ranges import Range1d
+        if self.x_range is not None and not isinstance(self.x_range, Range1d):
+            return "%s.x_range" % str(self)
+        if self.y_range is not None and not isinstance(self.y_range, Range1d):
+            return "%s.y_range" % str(self)
+
 class GMapOptions(MapOptions):
     ''' Options for GMapPlot objects.
 
@@ -64,9 +79,11 @@ class GMapOptions(MapOptions):
 class GMapPlot(MapPlot):
     ''' A Bokeh Plot with a `Google Map`_ displayed underneath.
 
-    Data placed on this plot should be specified in decimal lat long coordinates e.g. 37.123, -122.404.
-    It will be automatically converted into the web mercator projection to display properly over
-    google maps tiles.
+    Data placed on this plot should be specified in decimal lat/lon coordinates
+    e.g. ``(37.123, -122.404)``. It will be automatically converted into the
+    web mercator projection to display properly over google maps tiles.
+
+    Please also note that only ``Range1d`` ranges are supported by ``GMapPlot``.
 
     .. _Google Map: https://www.google.com/maps/
 


Test patch: