gmaps: interactive Google maps inside Jupyter notebooks
Google maps for Jupyter notebooks
At a glance
- What is it?
- gmaps is a Jupyter notebook plugin that renders Google maps as ipywidgets, with heatmap, GeoJSON and symbol layers over datasets such as taxi rides and country boundaries. It needs a Google API key and a notebook extension enabled, and it is a notebook-era project whose last push was on 2026-04-13.
- Who is it for?
- gmaps suits a data scientist who wants a map in a notebook rather than a dashboard, since the layer API and the bundled datasets make a choropleth or a heatmap a few lines of Python. It does not suit a production application, because the widget needs a live notebook frontend and a Google API key per user.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What gmaps is and how it fits in a notebook
gmaps is a plugin for including interactive Google maps in the IPython Notebook. The stated audience is data scientists, and the stated goal is that data scientists should be able to visualize geographical data on a map with minimal friction, and beyond visualization integrate gmaps into their own widgets so they can build interactive applications.
The mechanism is the Jupyter widget system. A map is created with a figure call, layers are attached to it, and the figure is displayed as the cell's output, which is why the examples end with a bare expression rather than a print. The map is not a static image that gets written to disk. It is a live widget with a JavaScript frontend that talks to the Google Maps API in the browser.
That design is also the constraint. The output is only interactive inside a notebook frontend that can run the widget, and each user of the notebook needs their own API key configured, because the key is passed to the widget at render time rather than being held by a server on their behalf.
The layer types are the feature surface. A heatmap layer takes a set of location pairs. A GeoJSON layer takes features and per-feature fill and stroke colours, which is what makes choropleth maps possible. A symbol layer places markers with a fill colour, a stroke colour and a scale.
Plotting a heatmap of taxi pickups
The first example in the README plots a heatmap of taxi pickups in San Francisco, and it is the shortest complete piece of code in the documentation.
import gmaps
import gmaps.datasets
gmaps.configure(api_key="AI...") # Your Google API key
locations = gmaps.datasets.load_dataset("taxi_rides")
fig = gmaps.figure()
fig.add_layer(gmaps.heatmap_layer(locations))
figFour things happen in that block. The API key is configured once with gmaps.configure, and the README is explicit that this must happen before creating widgets. The dataset is loaded through gmaps.datasets, which ships with the package rather than fetching from a URL. The figure is created, the heatmap layer is added to it, and the trailing fig is what renders it as the cell output.
The dataset loader returns a NumPy array of latitude and longitude pairs, and the taxi_rides dataset is the one used in the documentation images. A related loader, load_dataset_as_df, returns a pandas DataFrame instead, which is what the symbol layer example uses because it filters rows first.
Building a choropleth with GeoJSON and matplotlib colours
The GeoJSON example is the most instructive piece of code in the README, because it shows how the library deliberately stays out of the colour decision and leaves it to matplotlib.
The geometry comes from gmaps.geojson_geometries.load_geometry with the countries set. The data comes from gmaps.datasets.load_dataset with the gini set, which returns rows of tuples, and those become a dictionary mapping country name to Gini coefficient.
countries_geojson = gmaps.geojson_geometries.load_geometry('countries') # Load GeoJSON of countries
rows = gmaps.datasets.load_dataset('gini') # 'rows' is a list of tuples
country2gini = dict(rows) # dictionary mapping 'country' -> gini coefficientThen a local function does the colour work. It normalises the coefficient into the zero to one range, inverts it so that high inequality gives a dark colour, maps it through the matplotlib viridis colormap, and converts that to a CSS colour with to_hex and keep_alpha set to false.
mpl_color = viridis(inverse_gini)
gmaps_color = to_hex(mpl_color, keep_alpha=False)The layer call then takes a list of colours parallel to the features, and the README passes the same list as fill_color and stroke_color with a fill opacity of 0.8. A country with no Gini value gets a fallback of a translucent black, which is the KeyError branch in the loop.
That design is the point: gmaps does not have a choropleth colour scale of its own, it hands you the geometry and lets matplotlib do the visualisation, and it takes the result back as CSS colours.
The symbol layer and the bundled datasets
The third example plots every Starbucks in the UK, and it is the shortest of the three because the symbol layer takes points directly.
df = gmaps.datasets.load_dataset_as_df('starbucks_kfc_uk')
starbucks_df = df[df['chain_name'] == 'starbucks']
starbucks_df = starbucks_df[['latitude', 'longitude']]
starbucks_layer = gmaps.symbol_layer(
fill_color="green", stroke_color="green", scale=2
)
fig = gmaps.figure()
fig.add_layer(starbucks_layer)The dataset name is starbucks_kfc_uk, so one loader covers both chains and the example filters on the chain_name column. Selecting the latitude and longitude columns matters, because the symbol layer expects points rather than a wider table, and the scale argument sets the marker size.
Three datasets are named in the README, taxi_rides as a NumPy array of coordinate pairs, gini as a list of tuples, and starbucks_kfc_uk as a DataFrame. The bundled datasets are the reason the documentation can show a real result in a few lines, and they are also the fastest way to check whether an installation works before you point it at your own data.
The package is called gmaps on PyPI and the import is gmaps, but the project is titled jupyter-gmaps in the documentation and the homepage is on readthedocs, so search results and error messages may use either name.
Installing for classic Notebook and for JupyterLab
The easiest install is conda, from the conda-forge channel.
$ conda install -c conda-forge gmapsFor pip, the classic Notebook needs the ipywidgets extension enabled first, which the README describes as a requirement rather than an optional step.
$ jupyter nbextension enable --py --sys-prefix widgetsnbextension
$ pip install gmaps
$ jupyter nbextension enable --py --sys-prefix gmapsThat third command is the one people miss. Installing the Python package is not enough, the JavaScript extension has to be registered with the notebook server separately, and until it is, the cells that create a map produce a widget that does nothing.
JupyterLab takes a different route, because Lab has its own extension mechanism. The widgets manager for Lab is installed first, then gmaps itself.
$ jupyter labextension install @jupyter-widgets/jupyterlab-manager
$ pip install gmapsAfter that, Lab asks you to rebuild itself the next time you open it, because the jupyter-gmaps frontend code has to be included in the Lab installation. You can trigger the same thing from the command line.
$ jupyter lab buildFor Lab versions before 1.0 the README asks you to pin both the manager and gmaps, pointing at a compatibility table, and gives a JupyterLab 0.35.x example with a pinned manager version and a pinned gmaps release.
$ jupyter labextension install @jupyter-widgets/[email protected]
$ pip install gmaps==0.8.4
$ jupyter lab buildDependencies, API keys and where gmaps is the wrong tool
The runtime requirements are short and worth reading as a compatibility statement. The requirements file lists six, ipython at 5.3.0 or above, ipywidgets at 7.0.0 or above, traitlets at 4.3.0 or above, and geojson at 2.0.0 or above.
The ipywidgets 7 requirement is the significant one, since the widget protocol changed between ipywidgets 6 and 7 and a notebook environment on the older protocol will not render the map. The geojson dependency is what the GeoJSON layer parses, and six is a Python 2 compatibility shim that the project has carried for a long time.
The Google API key is a requirement for anything except the built-in datasets. The README explains that the key tells Google who you are, presumably so it can keep track of rate limits, and the key is passed to gmaps.configure before creating widgets.
With that in place, the limitations follow. First, gmaps is a notebook widget, so it needs a live notebook frontend, a browser with network access to Google, and a key per user. A dashboard, a web application or a scheduled job has no place for it, and a team that wanted the map in a report will find the widget output does not travel.
Second, the layer set is small. A heatmap, a GeoJSON layer and a symbol layer, with a GeoJSON layer that does the choropleth work. There is no clustering, no custom styling language, no drawing tools and no offline or tile-caching behaviour, because the tiles are Google's.
Third, the roadmap in the README lists responding to events such as user clicks and adding greater flexibility and customisability such as choosing map styles. Those are stated as priorities, and a reader should treat them as a wish list rather than a feature list, particularly given the release history: the newest tagged release listed is v0.2 from January 2016, with v0.1.6 and v0.1.5 from December 2014, while the last push to the repository was on 2026-04-13.
Fourth, the alternative is named in the README itself. The library was inspired by ipyleaflet, which aims to provide much of the same functionality for Leaflet maps rather than Google maps, and it is the route to take if you need open tiles or a different provider, since the widget approach is the same.
Licence, maintenance and the cost of a notebook dependency
The project is under a licence GitHub cannot classify, with the terms in a LICENSE.txt file at the root of the repository, so the actual terms have to be read from that file rather than assumed from the badge.
The repository is not archived and the last push was on 2026-04-13, so there is recent activity even though the published release tags are old. The default branch is master, and the project uses the older reStructuredText README format rather than Markdown, with the documentation built by Sphinx into a readthedocs site.
The build system is worth noting because it explains a constraint. The setup.py has custom setuptools commands for building the JavaScript, including a jsdeps command that runs npm over the js/ directory, and a prerelease decorator that skips the JavaScript build for a source distribution when the built assets are already present. So the JavaScript frontend is compiled at package build time, which means an install from a source checkout needs a working Node toolchain, while an install from a wheel does not.
The cost of depending on gmaps in a notebook is modest and mostly environmental. The package is small, the dependency list is short, and the datasets mean an analysis can be demonstrated without any data plumbing. The cost is that the environment has to be prepared: an extension registered, a Lab rebuild, an API key per user, and a browser with access to Google. In a team that shares one notebook environment, the extension registration is the step most likely to be missing for a new arrival, and it is the one that produces a silent failure rather than an error message.
Editorial conclusion
gmaps suits a data scientist who wants a map in a notebook rather than a dashboard, since the layer API and the bundled datasets make a choropleth or a heatmap a few lines of Python. It does not suit a production application, because the widget needs a live notebook frontend and a Google API key per user. Verify the Jupyter front end you are on first, since the extension installation differs between classic Notebook and JupyterLab, and note that the pip package name is gmaps while the import is also gmaps but the docs and the project name disagree.
Frequently asked questions
How do I install gmaps in a Jupyter notebook?
The easiest route is conda install -c conda-forge gmaps. With pip you also have to enable the ipywidgets extension, then install the package, then register the gmaps extension with jupyter nbextension enable --py --sys-prefix gmaps, otherwise the map widget will not render.
Does gmaps work with JupyterLab?
Yes, with a different installation path. You install the JupyterLab widgets manager with jupyter labextension install @jupyter-widgets/jupyterlab-manager, then pip install gmaps, then rebuild Lab with jupyter lab build so the frontend code is included in the installation.
How do I make a choropleth map with gmaps?
Load the geometry with gmaps.geojson_geometries.load_geometry, load the per-country values with gmaps.datasets.load_dataset, compute a colour for each feature yourself using a matplotlib colormap, then pass the list of colours to gmaps.geojson_layer as fill_color and stroke_color. The library does not provide a colour scale of its own.
What datasets ship with gmaps?
Three are named in the README: taxi_rides, loaded as a NumPy array of latitude and longitude pairs, gini, loaded as a list of tuples for the choropleth example, and starbucks_kfc_uk, loaded as a pandas DataFrame for the symbol layer example. A Google API key is required for your own data.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pbugnion-gmaps)Was this useful?