Repository: bokeh/bokeh

Issue:
Bokeh GMapOptions error
Bokeh version - 0.12.16
Python - 3.5
OS - Windows 10
Browser - IE, Chrome, Firefox
Other relevant packages - GMapOptions, gmap

I'm fairly new to Bokeh so please excuse me for my lack of knowledge/experience with bokeh. I am trying to create a geographic visualization using bokeh and then integrate my bokeh server app into flask to deploy it on a VPS. When run independently my code produces the necessary visualization but, gives an error in the command line. The error is occuring at the gmap call. I tried looking this error up and found a few relevant results all of which pointed to bugs in the Bokeh library. Where I am really getting stuck is, at the point of deployment of this visualization either independently as a bokeh server app or by integrating it with Flask because of this error. Any help on this is greatly appreciated. Thanks!


```
from bokeh.io import curdoc
from bokeh.models import GMapOptions
from bokeh.plotting import gmap
map_options = GMapOptions(lat=37.686293, lng=-97.3614409, map_type="roadmap", zoom=13)
p = gmap(google_api_key="My Google Maps API Key", map_options=map_options, title="Resolutions Clients", plot_width=1000, plot_height=600)
curdoc().add_root(p)
```


C:\Users\Administrator\PycharmProjects\FlaskApp>bokeh serve --show test.py
2018-06-11 14:20:52,449 Starting Bokeh server version 0.12.16 (running on Tornad
o 5.0.2)
2018-06-11 14:20:52,463 Bokeh app running at: http://localhost:5006/test
2018-06-11 14:20:52,464 Starting Bokeh server with process id: 9972
2018-06-11 14:20:52,816 200 GET /test (::1) 161.02ms
2018-06-11 14:20:53,072 101 GET /test/ws?bokeh-protocol-version=1.0&bokeh-sessio
n-id=YwriVJupgcBKp7IEeFdj5R95PJG2lxe6g82SFqbObcDA (::1) 1.00ms
2018-06-11 14:20:53,072 WebSocket connection opened
2018-06-11 14:20:53,072 ServerConnection created
2018-06-11 14:20:53,120 error handling message Message 'PATCH-DOC' (revision 1):
 TypeError("__init__() missing 2 required positional arguments: 'google_api_key'
 and 'map_options'",)





Discussion:
@anujnimkar just to be clear, when I ran the code, I saw the error message, but everything still worked as expected. Are you saying that things are different for you, or not working? If the former, you can simply ignore the message for now, and we will work to suppress it. If things are somehow not working, then we will have to try to reproduce, so a more detailed description of the failure mode is needed. 
@bryevdv First of all, thanks for your quick response. Really appreciate it!
If I am to run my app independently, it runs fine even with this command line error. But where I am getting stuck is when I try to deploy this app to something like Heroku. Because of this error, my deployment is failing.
Sorry I am not especially familiar with Heroku, do you mean their process monitors examine the logs and if they see "error" in it somewhere, automatically abort or something? That seems like a strange policy, but not something we have aloof control over if it is true. We should leave this issue on GH to fix the spurious message on the Bokeh side, but in the mean time I'd suggest posting to the mailing list or SO with a more Heroku-specific question about how to make Heroku not fall just because of spurious log messages.  Otherwise the only immediate suggestion I have is to try to raise the Bokeh log level to critical (not sure if that will suppress the message) or try to route all bokeh log output to `/dev/null`
@bryevdv, even if I don't use Heroku, if I try to integrate my bokeh server app with Flask, I still get the same error in Flask and cannot complete the integration.  I am using the GMapOptions library in bokeh to generate a visualization showing the distribution of my client data across a geographical area. I get the following error when I run the Flask app code,
`TypeError: __init__() missing 2 required positional arguments: 'google_api_key' and 'map_options' `
I get the same message in the command prompt when I run the bokeh server app independently in the command prompt using the bokeh serve command, but the app runs nevertheless.

Here is my code for the visualization,
```
from bokeh.plotting import output_file
from bokeh.plotting import gmap
from bokeh.io import curdoc
from bokeh.models import Button, GMapOptions, ColumnDataSource, CategoricalColorMapper
from bokeh.models import *
from bokeh.layouts import column, row
import pandas as pd
import numpy as np
import pymssql
 
 
 
# parameters
server = 'X.X.X.X\PQR'
db = 'ABC'
 
# Create the connection
conn = pymssql.connect(database = db, host = server)
cur = conn.cursor()
map_options = GMapOptions(lat=37.686293, lng=-97.3614409, map_type="roadmap", zoom=13)
p = gmap("My Google Maps API Key", map_options, title="Resolutions Clients", plot_width=1000, plot_height=600)
 
sql = """
        with CTE AS
            (SELECT
            CR.ClientID, CR.Latitude, CR.Longtitude
            FROM 
            Company C LEFT JOIN ClientRegistration CR on C.CompanyID = CR.CompanyID
            WHERE
            C.CompanyID = 555 AND (CR.Latitude IS NOT NULL AND CR.Longtitude IS NOT NULL)
            )
        SELECT
        C.ClientID, C.Latitude, C.Longtitude, CL.Sex
        FROM
        CTE C LEFT JOIN Clients CL on C.ClientID = CL.ClientID
    """
 
df = pd.read_sql(sql, conn)
 
 
 
df[['Latitude', 'Longtitude']] = df[['Latitude', 'Longtitude']].apply(pd.to_numeric)
df['Sex'] = df['Sex'].astype('str')
 
map_options = GMapOptions(lat=37.686293, lng=-97.3614409, map_type="roadmap", zoom=10)
p = gmap("My Google Maps API Key", map_options, title="Resolutions Clients Genderwise", plot_width=1000,
             plot_height=600)
 
lat = df['Latitude'].tolist()
lon = df['Longtitude'].tolist()
sex = df['Sex'].tolist()
 
source = ColumnDataSource(
        data=dict(latitude=lat,
                  longitude=lon,
                  gender=sex
                  )
)
 
 
color_mapper = CategoricalColorMapper(factors=['M', 'F', 'U'], palette=['Red', 'Blue', 'Green'])
 
 
p.circle(x="longitude", y="latitude", size=4, fill_alpha=0.9, source=source,
             fill_color={'field': 'gender', 'transform': color_mapper},
             line_color={'field': 'gender', 'transform': color_mapper})
 
x = np.linspace(0, 4 * np.pi, 100)
y = np.sin(x)
 
p.circle(x, y, legend="Male", color="red")
p.circle(x, 2 * y, legend="Female", color="Blue")
p.circle(x, 3 * y, legend="Unknown", color="Green")
 
def update():
    # query db
    curdoc().clear()
    sql = """
            with CTE AS
                (SELECT
                CR.ClientID, CR.Latitude, CR.Longtitude
                FROM
                Company C LEFT JOIN ClientRegistration CR on C.CompanyID = CR.CompanyID
                WHERE
                C.CompanyID = 555 AND (CR.Latitude IS NOT NULL AND CR.Longtitude IS NOT NULL)
                )
            SELECT
                C.ClientID, C.Latitude, C.Longtitude,
                CASE WHEN age > 0 AND age <= 15 THEN 'Children'
                     WHEN age > 15 AND age <= 30 THEN 'Young Adult'
                     WHEN age > 30 AND age <= 55 THEN 'Adult'
                     WHEN age > 55 THEN 'Senior Citizen'
                     END AS 'Age_Group'
            FROM
            CTE C LEFT JOIN Clients CL on C.ClientID = CL.ClientID
    """
    df = pd.read_sql(sql, conn)
 
    df[['Latitude', 'Longtitude']] = df[['Latitude', 'Longtitude']].apply(pd.to_numeric)
    df['Age_Group'] = df['Age_Group'].astype('str')
 
    df['Latitude'].median()
    df['Longtitude'].median()
 
    map_options = GMapOptions(lat=37.686293, lng=-97.3614409, map_type="roadmap", zoom=10)
 
    p = gmap("My Google Maps API Key", map_options, title="Resolutions Clients Age wise",
             plot_width=1000, plot_height=600)
 
    lat = df['Latitude'].tolist()
    lon = df['Longtitude'].tolist()
    age = df['Age_Group'].tolist()
 
    source = ColumnDataSource(
        data=dict(latitude=lat,
                  longitude=lon,
                  age_Group=age
                  )
    )
 
    color_mapper = CategoricalColorMapper(factors=['Children', 'Young Adult', 'Adult', 'Senior Citizen'],
                                          palette=['Red', 'Blue', 'Green', 'Yellow'])
 
    p.add_tools(LassoSelectTool())
    p.add_tools(ZoomInTool())
    p.add_tools(ZoomOutTool())
 
    p.circle(x="longitude", y="latitude", size=4, fill_alpha=0.9, source=source,
             fill_color={'field': 'age_Group', 'transform': color_mapper},
             line_color={'field': 'age_Group', 'transform': color_mapper})
 
    x = np.linspace(0, 4 * np.pi, 100)
    y = np.sin(x)
 
    p.circle(x, y, legend="Children : Age <= 15", color="red")
    p.circle(x, 2 * y, legend="Young Adult : 30 >= Age > 15", color="Blue")
    p.circle(x, 3 * y, legend="Adult : 55 >= Age > 30 ", color="Green")
    p.circle(x, 4 * y, legend="Senior Citizen : Age > 55", color="Yellow")
 
    curdoc().add_root(row(button1, button2))
    curdoc().add_root(column(p))
 
def update1():
    # query db
    curdoc().clear()
    sql = """
            with CTE AS
                (SELECT
                CR.ClientID, CR.Latitude, CR.Longtitude
                FROM
                Company C LEFT JOIN ClientRegistration CR on C.CompanyID = CR.CompanyID
                WHERE
                C.CompanyID = 555 AND (CR.Latitude IS NOT NULL AND CR.Longtitude IS NOT NULL)
                )
            SELECT
            C.ClientID, C.Latitude, C.Longtitude, CL.Sex
            FROM
            CTE C LEFT JOIN Clients CL on C.ClientID = CL.ClientID
        """
    df = pd.read_sql(sql, conn)
 
    df[['Latitude', 'Longtitude']] = df[['Latitude', 'Longtitude']].apply(pd.to_numeric)
    df['Sex'] = df['Sex'].astype('str')
 
    map_options = GMapOptions(lat=37.686293, lng=-97.3614409, map_type="roadmap", zoom=10)
    p = gmap("My Google Maps API Key", map_options, title="Resolutions Clients Genderwise",
             plot_width=1000,
             plot_height=600)
 
    lat = df['Latitude'].tolist()
    lon = df['Longtitude'].tolist()
    sex = df['Sex'].tolist()
 
    source = ColumnDataSource(
        data=dict(latitude=lat,
                  longitude=lon,
                  gender=sex
                  )
    )
 
 
    color_mapper = CategoricalColorMapper(factors=['M', 'F', 'U'], palette=['Red', 'Blue', 'Green'])
 
    p.circle(x="longitude", y="latitude", size=4, fill_alpha=0.9, source=source,
             fill_color={'field': 'gender', 'transform': color_mapper},
             line_color={'field': 'gender', 'transform': color_mapper})
 
    x = np.linspace(0, 4 * np.pi, 100)
    y = np.sin(x)
 
    p.circle(x, y, legend="Male", color="red")
    p.circle(x, 2 * y, legend="Female", color="Blue")
    p.circle(x, 3 * y, legend="Unknown", color="Green")
 
    curdoc().add_root(row(button1, button2))
    curdoc().add_root(column(p))
 
# add a button widget and configure with the call back
button1 = Button(label="Gender")
button2 = Button(label="Age")
 
button1.on_click(update1)
button2.on_click(update)
 
# put the button and plot in a layout and add to the document
curdoc().add_root(row(button1, button2))
curdoc().add_root(column(p))
```
And here are my app.py, index.html and main.css files
```
from flask import Flask, render_template
from bokeh.embed import autoload_static
from bokeh.client import pull_session
 
#instantiating the flask app
app = Flask(__name__)
 
#create the index page function
 
@app.route("/")
def index():
    session = pull_session(url="http://localhost:5006/Button_test_update_version2")
    bokeh_script = autoload_static(None, url="http://localhost:5006/Button_test_update_version2", session_id=session.id)
    return render_template("index.html", bokeh_script=bokeh_script)
 
#run the app
if __name__ == "_main_":
    app.run(debug=True)
```
```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Therasoft Visualization</title>
    <link rel="stylesheet" href={‌{url_for('static', filename='css/main.css')}}>
</head>
<body>
<h1> Therasoft Visualization</h1>
<div>
    {‌{bokeh_script|safe}}
</div>
</body>
</html>
```
```
h3{
    color : olive;
}
```
The code above has database connections and other extraneous things that prevent anyone else from running it for debugging purposes. Please provide a complete minimal example that others can work with. 
Also, FYI I can't imagine any circumstance in which `autoload_static`, which exists explicitly to embed *non-server* standalone documents, would ever be useful in conjunction with `pull_session`, which is explicitly for interacting with server apps. 
@anujnimkar I don't mean to be overly critical, but you are going about things in a way that is very confusing and not helpful for the maintainers. You have asked different versions of this question, with lots of unrelated details here, on SO, and the mailing lists. That makes it very hard for maintainers to focus on and solve the actual core problem. 

None of the Flask code is relevant to this discussion at all. I empathize that that is your immediate problem and that you want it to work, but is distracting and unhelpful noise in this context. 

To re-focus the discussion here, the *only* thing that Bokeh needs to fix is that this MRE generates a TypeError:
```
from bokeh.io import curdoc
from bokeh.models import GMapOptions
from bokeh.plotting import gmap, figure

map_options = GMapOptions(lat=30.2861, lng=-97.7394, map_type="roadmap", zoom=13)
p = gmap(google_api_key="API KEY", map_options=map_options)

curdoc().add_root(p)
```
And that is all that this issue will be used to discuss going forward. 
FWIW the basic issue is partly at least that the client seems to be sending patch updates immediately back to the server for the document it just rendered, and I don't think that should be happening at all. Run with:
```
python -m bokeh serve --show --log-level=trace foo.py
```
and you will see e.g.
```
2018-06-15 12:40:32,171 Patching attribute 'end' of Range1d(id='0ba0241f-6535-4d14-a466-5bbadbb00bc8', ...) with -10875417.893821724
2018-06-15 12:40:32,172 Not sending notification back to client <bokeh.server.connection.ServerConnection object at 0x114faccf8> for a change it requested
```

But the server initiated these changes at startup, the client should not be sending change notifications in the first place. 


That accidentally is harmless (but wasteful) in the case of Plot but for GMapPlot there is some interaction with the subclassing that is causing the extra subclass attrs to not be sent back. Making it  not send the unnecessary patching at all should incidentally fix this as well. 


Resolving patch:
diff --git a/bokeh/plotting/gmap.py b/bokeh/plotting/gmap.py
--- a/bokeh/plotting/gmap.py
+++ b/bokeh/plotting/gmap.py
@@ -65,6 +65,15 @@ class GMap(GMapPlot):
     ''' A subclass of :class:`~bokeh.models.plots.Plot` that simplifies plot
     creation with default axes, grids, tools, etc.
 
+    Args:
+        google_api_key (str):
+            Google requires an API key be supplied for maps to function. See:
+
+            https://developers.google.com/maps/documentation/javascript/get-api-key
+
+        map_options: (GMapOptions)
+            Configuration specific to a Google Map
+
     In addition to all the Bokeh model property attributes documented below,
     the ``Figure`` initializer also accepts the following options, which can
     help simplify configuration:
@@ -77,7 +86,7 @@ class GMap(GMapPlot):
     __subtype__ = "GMap"
     __view_model__ = "GMapPlot"
 
-    def __init__(self, google_api_key, map_options, **kw):
+    def __init__(self, **kw):
 
         if 'plot_width' in kw and 'width' in kw:
             raise ValueError("Figure called with both 'plot_width' and 'width' supplied, supply only one")
@@ -94,8 +103,7 @@ def __init__(self, google_api_key, map_options, **kw):
         if isinstance(title, string_types):
             kw['title'] = Title(text=title)
 
-        super(GMap, self).__init__(api_key=google_api_key, map_options=map_options,
-                                   x_range=Range1d(), y_range=Range1d(), **kw)
+        super(GMap, self).__init__(x_range=Range1d(), y_range=Range1d(), **kw)
 
         xf = MercatorTickFormatter(dimension="lon")
         xt = MercatorTicker(dimension="lon")
@@ -203,4 +211,4 @@ def gmap(google_api_key, map_options, **kwargs):
 
     '''
 
-    return GMap(google_api_key, map_options, **kwargs)
+    return GMap(api_key=google_api_key, map_options=map_options, **kwargs)


Test patch:
diff --git a/bokeh/tests/test_model.py b/bokeh/tests/test_model.py
--- a/bokeh/tests/test_model.py
+++ b/bokeh/tests/test_model.py
@@ -164,3 +164,14 @@ def test_model_js_on_change_ignores_dupe_callbacks():
     m = SomeModel()
     m.js_on_change('foo', cb, cb)
     assert m.js_property_callbacks == {"foo": [cb]}
+
+from bokeh.models import * # NOQA
+from bokeh.plotting import * # NOQA
+def test_all_builtin_models_default_constructible():
+    bad = []
+    for name, cls in Model.__class__.model_class_reverse_map.items():
+        try:
+            cls()
+        except:
+            bad.append(name)
+        assert bad == []