mapbox / mapboxgl-jupyter Goto Github PK
View Code? Open in Web Editor NEWUse Mapbox GL JS to visualize data in a Python Jupyter notebook
License: MIT License
Use Mapbox GL JS to visualize data in a Python Jupyter notebook
License: MIT License
A time slider/filter is a critical component to many data visualizations. We should start thinking about how to add a time slider component to any viz class type, where a mapboxgl filter
could be applied for each time step or filter category in the slider.
Questions to consider:
Having the js/html portions of the application written as python strings is not ideal for maintenance.
We could instead write them as jinja2 templates in order to make them easier to find and edit.
There are several viz class functions that are common among every viz class type:
We should wrap these functions and common objects in a base parent class, and inherit it for each child viz type.
Add support to extrude
a Choropleth polygon layer. Expose the option as height*
properties to the Choropleth Viz.
height_stops
height_property
height_default
Example Viz: 3D Population Density - www.mapbox.com/bites/00273
As the API for mapboxgl-jupyter solidifies:
To hit a 1.0 release, we need great documentation. Let's use this ticket to track docs to-dos:
cc/ @perrygeo
it would be great to have a geopandas integration.
I can envision it working like this (tqdm-pandas style):
import mapboxgl as mbx
import geopandas as gp
mbx.mapboxgl() # initialisation - checking serial number and adding function to geodataFrame
gdf = gp.read_file('points.geojson')
gdf.mbx_plot(figsize=(18,10), column='Avg Medicare Payments', cmap='...')
it would be awesome ( in my opinion ) to mimic matplotlib-esque interface in this case as much as it is possible - all the way to
ax = gdf.mbx_plot(figsize=(18,10)
gdf2.mbx_plot(ax=ax) # second layer
Not exactly related to this project, but still - it would be awesome to have an alternative geojson extension (or alternative engine for the same extension), as current jupyterlab geojson viewer is very, very slow
Currently, the create_color_stops
function accepts a string that defines a color palette from ColorBrewer. This function should also allow the user to pass a custom color palette as a list of color strings. The documentation claims this is possible today, but it is not yet implemented.
Make a PR to add support for passing a custom list of colors to create_color_stops
-> https://github.com/mapbox/mapboxgl-jupyter/blob/master/mapboxgl/utils.py#L109
cc @pveugen
This ticket tracks the project roadmap. If you have a specific feature request, please open a new ticket and track there!
style_url
does not use resources from Mapbox APIs - which means that you created a style sheet yourself from public or locally hosted map data sources - then a Mapbox Access Token is not required.mapboxgl.viz.*(data)
is sent to Mapbox APIs in any way.Hi,
#57 indicates the library doesn't need a Mapbox token as long as the style_url
doesn't use resources from Mapbox APIs but the MapViz class raises a TokenError
when access_token
is None, even when using a custom style_url
.
Cf this line:
mapboxgl-jupyter/mapboxgl/viz.py
Line 42 in e7106f1
Currently we have to pass "pk" in the token attribute to circumvent the issue.
It would be nice to be able to load a custom json file with a malboxgl style in it, instead of using mapbox ones.
For all circle* viz types, add a parameter option to use a data property as a text-label.
An example of labels on top of circles based on a data property:
https://www.mapbox.com/mapbox-gl-js/example/cluster/
I'm attempting to use a color_property or radius_property with a ClusteredCircleViz, which the table of params includes. However, from looking at the source and the errors I'm getting, these options don't seem to be present!
Is this an issue with the documentation?
We should create an auto-deployed Anaconda
distribution of mapboxgl-jupyter
. Data scientists and analysts frequently use the Anaconda distribution of Python.
Process: https://conda.io/docs/user-guide/tutorials/build-pkgs-skeleton.html
This is a feature request to save the map to file such that it could be subsequently served to a web browser, a la folium's save
(see cell 3 in this example)
I believe I'm seeing a bug in GraduatedCircleViz
.
Here's the JS console error:
Error: layers.circle.paint.circle-radius[4]: Expected number but found string instead.
emitErrors — validate_style.js:10
addLayer — style.js:531
addLayer — map.js:1125
Here's the paint
it is attempting to set on the layer, which is failing validation (I believe this is because my default radius has at some point been converted from a number to a string):
{
"circle-color": [
"match", [
"get",
"category"
],
"A",
"rgb(255,0,0)",
"B",
"rgb(255,255,0)",
"C",
"rgb(0,255,0)",
"D",
"rgb(0,255,255)",
"E",
"rgb(0,0,255)",
"gray"
],
"circle-radius": [
"match", [
"get",
"category"
],
"A", 1,
"B", 2,
"C", 3,
"D", 4,
"E", 5,
"10"
],
"circle-stroke-color": "grey",
"circle-stroke-width": [
"interpolate", [
"linear"
],
[
"zoom"
], 0, 0.01, 18, 1
],
"circle-opacity": 1
}
Here's my python code:
viz = mapboxgl.viz.GraduatedCircleViz(
map_geojson,
access_token=MAPBOX_ACCESS_TOKEN,
# label_property = 'name',
color_property = 'category',
color_stops = [
['A', 'rgb(255,0,0)'],
['B', 'rgb(255,255,0)'],
['C', 'rgb(0,255,0)'],
['D', 'rgb(0,255,255)'],
['E', 'rgb(0,0,255)'],
],
color_function_type = 'match',
color_default = 'gray',
radius_property = 'category',
radius_stops = [
['A', 1.0],
['B', 2.0],
['C', 3.0],
['D', 4.0],
['E', 5.0]
],
radius_function_type = 'match',
radius_default = 10,
center = (-40, 25),
zoom = 3,
height='500px'
)
viz.show()
A common data science workflow is to include a static image version of a visual for sharing or screen shot creating.
This could be added as a saveImage()
HTML button on a viz
class object that downloads the current map viewport as a PNG, or it could be a viz.toImage() python function that outputs a PNG of the viz at the stated zoom, center, pitch, and bearing.
In the current master branch, the radius is not adjustable for the circle
visualization. We should add a radius
parameter just like the GraduatedCircleViz
Users have reported issues installing the jenks
package via
We should bundle up jenks
with the mapboxgl
library, as it will be one of the most common breaks classifiers to use on a domain of values.
cc @perrygeo
Rendering points as output of calculations and other processing is a good first step.
A user should be able to select points, and groups of points, for further analysis. This is similar to the Keep Only
or Exclude
functions that are used in Tableau's mapping functions.
Kept (selected data) or Excluded (All - Selected) should then be exported back to a DF for additional analysis.
mapboxgl version: 0.1.0
Upgrade GL JS version to fix a common bug in Chrome browsers that causes the map to ficker on render.
property function
generation to GL Expression generation.Hi there,
I would like to add support to show polygons. Before I start with an implementation, I would like to discuss with you the best approach.
I was thinking about the following steps:
polygon.html
.viz.py
a new Class PolygonViz
.viz.py
a new base Class Viz
. PolygonViz
, GraduatedCircleViz
, and CircleViz
inherit from this Class. Below is the rough outline of the Viz
Class.I am happy for any feedback about the above. Since I am new to the project, I am also open for a complete different approach to show polygons.
Looking forward to work on this 😊
class Viz(object):
"""Base class for all visualisations"""
def __init__(self,
access_token=None,
center=(0, 0),
div_id='map',
height='500px',
style_url="mapbox://styles/mapbox/light-v9?optimize=true",
width='100%',
zoom=0):
if access_token is None:
access_token = os.environ.get('MAPBOX_ACCESS_TOKEN', '')
if not access_token.startswith('pk'):
raise TokenError('Mapbox access token must be public (pk)')
self.access_token = access_token
self.div_id = div_id
self.width = width
self.height = height
self.data = data
self.style_url = style_url
self.center = center
self.zoom = zoom
def as_iframe(self, html_data):
"""Build the HTML representation for the mapviz."""
...
def show(self, **kwargs):
"""Load the HTML iframe and display the the iframe in the current jupyter notebook view"""
...
It's really exciting to see this project - there is a definite gap in the market for maps within Jupyter notebooks. Folium doesn't scale well to 1000+ data points.
I noted that for the demo notebook, points.csv is missing. It would be handy to have that file to get up and running as quickly as possible.
I see in the roadmap that you want to be able to add raster data layers from numpy arrays.
I wanted that as well so set up a very basic tile server that runs within a jupyter notebook and will project, tile and render a numpy array quickly on the fly.
Its still rough around the edges but works very nicely for me using folium and ipyleaflet to view tiles.
https://github.com/artttt/livemaptiles
I am showing near 40k data and someplace circle overlapping is happening I want to see all circle separately.is there any property i can use.
Currently, there is business logic occurring in both the Python mapboxgl
library and the javascript templates. Since this is a Python library, we should isolate all business logic to Python, and make the Javascript/HTML components true templates only. This should greatly increase supportability of the mapboxgl
library as it grows by isolating bugs to Mapbox GL Style Spec changes, which are much rarer than changes to the Mapbox GL JS Javascript library.
cc @perrygeo
Create a new Viz class tyle, LinestringViz, that allows a user to create a line map from a geojson source or a vector tile source. Follow the same techniques used to make the Choropleth Viz. #40
Example:
Databricks notebooks use the displayHTML
function instead of Jupyter's display
function to show HTML in a results pane.
We should adopt the show
function to work with dataBricks notebooks, by falling back to the displayHTML
function if needed. A secondary option would be to add a viz.showDatabricks()
function.
As we add more visualization types, it will be useful to pull in multiple visualization layers into the same visualization. To do this, we'll need an API to addLayer
to an existing visualization.
For example, users may want to create a heatmap
visualization at low zoom levels, and a graduatedCircle
visualization at high zoom levels.
A user may also want to add two or more layers to a map from different data sources.
minZoom
and maxZoom
properties to each viz typeaddLayer
function to add a layer to an existing viz objectPassing a datetime Pandas datatype column to df_to_geojson() as a property output throws a JSON serialization error.
See https://github.com/mapbox/mapboxgl-jupyter/blob/master/mapboxgl/utils.py#L28
Add a data type check and JSON-safe stringification method for all Pandas datatypes datetime64
, timedelta[ns]
, and boolean
.
I would be lovely to be able to adjust the opacity of the heatmap, graduated circle, and circle layers, so that the underlying streets are visible.
Hi,
I was trying to plot a CircleViz and my points wouldn't appear. Once I supplied the color_stops argument they showed up.
If color_stops are required to plot data they should raise an error when missing, or be set to a meaningful default.
Related to #13 I think.
Cheers
Investigate creating a streaming data architecture from a Pandas dataframe to a map using the approach in the Smalltalk
python library https://github.com/murphy214/smalltalk.
A CircleViz today requires a Python dictionary formatted as geoJSON. The Python dict is stringified when the user passes the geoJSON-format dict as the data
parameter, which in turn is and passed to an HTML-format string object used to create the viz.
To increase the load-time performance and data volume limit the data for the viz could be served from the Python web server back end. This could be accomplished by either saving data to a static file, or directly querying data from a Pandas data frame via an API to geojson.
The Jupyter Notebook Server API we could use for this architecture is here: https://github.com/jupyter/jupyter/wiki/Jupyter-Notebook-Server-API
Currently, the create_color_stops function is in colors.py - this is confusing for users, as the majority of utility functions are in utils.py.
I tried to reproduce the example given in the README
with an OpenMapTiles
style but the data does not show, I only see the tiles. This is the result:
And this is the code:
import pandas as pd
import os
from mapboxgl.utils import *
from mapboxgl.viz import *
# Load data from sample csv
data_url = 'https://raw.githubusercontent.com/mapbox/mapboxgl-jupyter/master/examples/points.csv'
df = pd.read_csv(data_url)
# Create a geojson file export from a Pandas dataframe
df_to_geojson(df, filename='points.geojson',
properties=['Avg Medicare Payments', 'Avg Covered Charges', 'date'],
lat='lat', lon='lon', precision=3)
# Generate data breaks and color stops from colorBrewer
color_breaks = [0,10,100,1000,10000]
color_stops = create_color_stops(color_breaks, colors='YlGnBu')
# Create the viz from the dataframe
viz = CircleViz('points.geojson',
height='400px',
access_token='pk',
color_property = "Avg Medicare Payments",
color_stops = color_stops,
center = (-95, 40),
zoom = 3,
#below_layer = 'waterway-label',
style_url='https://openmaptiles.github.io/osm-bright-gl-style/style-cdn.json',
)
viz.show()
I'm using mapboxgl 0.5.1 installed with pip 9.0.1 in Python 3.4 and latest JupyterLab.
Configuration:
The maps is displayed, is correctly centered and zoomed, but no points are displayed.
When converting data using:
df_to_geojson(shocks[["longitude", "latitude"]],properties=None, lat='latitude', lon='longitude')
the resulting JSON looks lilke:
{'features': [{'geometry': {'coordinates': [43.625447000000001,
1.3775569999999999],
'type': 'Point'},
'properties': {'latitude': 43.625447000000001,
'longitude': 1.3775569999999999},
'type': 'Feature'},
{'geometry': {'coordinates': [43.625250000000001, 1.377567],
'type': 'Point'},
'properties': {'latitude': 43.625250000000001, 'longitude': 1.377567},
'type': 'Feature'},
{'geometry': {'coordinates': [43.625250000000001, 1.377567],
'type': 'Point'},
'properties': {'latitude': 43.625250000000001, 'longitude': 1.377567},
'type': 'Feature'},
{'geometry': {'coordinates': [43.625312000000001, 1.377515],
'type': 'Point'},
'properties': {'latitude': 43.625312000000001, 'longitude': 1.377515},
'type': 'Feature'},
{'geometry': {'coordinates': [43.632674999999999, 1.371165],
'type': 'Point'},
[...]
Is it a desired behaviour?
If a user were to have an invalid access token (token deleted or Mapbox account expired) on their visual, we should present a relevant splash screen message. That way a user of the visual understands a) who to contact and b) what to do in the case that a visual has an invalid token.
Noticed you have this on your roadmap - I made some small changes to viz.py, circle.html and graduated_circle.html allowing user to use Mapbox's "categorical" type to assign circle color or radius. My implementation includes properties for default color and radius mentioned in #13 . I have a branch ready to submit as a PR at your convenience.
viz.py
12 class CircleViz(object):
13 """Create a circle map"""
14
15 def __init__(self,
16 data,
17 access_token=None,
18 center=(0, 0),
19 color_property=None,
20 color_stops=None,
21 label_property=None,
22 color_function_type='interval',
23 default_color='grey',
24 div_id='map',
25 height='500px',
26 style_url="mapbox://styles/mapbox/light-v9?optimize=true",
27 width='100%',
28 zoom=0):
etc.
and
circle.html
41 map.addLayer({
42 "id": "circle",
43 "source": "data",
44 "type": "circle",
45 "paint": {
46 "circle-color": {
47 // Data property to style color by from python variable
48 "property": "{{ colorProperty }}",
49 // Color stops array to use based on data values from python variable
50 "stops": {{ colorStops }},
51 // Type of function to use for assigning colors provided via colorStops
52 "type": "{{ colorType }}",
53 // Default color for if colorProperty does not match any of color stops
54 "default": "{{ defaultColor }}",
55 },
56 "circle-radius" : {
57 "stops": [[0,1], [18,10]]
58 },
59 "circle-stroke-color": "white",
60 "circle-stroke-width": {
61 "stops": [[0,0.01], [18,1]]
62 }
63 }
64 }, "label");
This appears not to be possible currently and it would be a huge gain.
Pysal
depends on scipy
, which can be a difficult dependancy to require users to install to get stared. Removing pysal
from the examples should increase a first-time users ease of running the examples.
Use a pandas.Series.quantile
to calculate breaks (instead of jenks / natural breaks with pysal). https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.quantile.html
Tracking the current changelog for v0.6.0 release, targeting to release this week on pypi:
style_url
property is now just style
to reflect that a local style sheet may be used, not just a URLlabel_size
, label_color
, label_halo_color
, label_halo_width
, stroke_color
, stroke_width
properties to all Circle* Viz typesheatmap_intensity
style optionexponential
function with base 1.2
utils.create_color_stops()
#521
instead of None
#72utils.df_to_geojson()
now coverts data row-by-row, saving massive amounts of memory when converting large dataframes to geojson files. #69In the current master branch, the radius_default
is None. This should be 1
.
The Mapbox GL JS library has tons of built-in error checking for tokens, styles, and sources. In order to provide relevant and useful error messages to a user creating a visualization, we'd have to re-create many error checks in the Python mapboxgl
library.
Propagate errors that affect the visualization (invalid token, invalid Mapbox style sheet, missing source, etc) and throw them from the python mapboxgl
code execution. We wouldn't want to propagate all types of errors - only ones that prevent a valid data visualization layer from being drawn on the map, or from the map being initialized.
Reference PR by @EtienneDesticourt - #59 (comment)
Currently, each viz class data
object only supports geojson format data from a URL or local variable geoJSON format object. We should enable users to pass a data as a vector tile source.
I propose we maintain that the data
object should be a URL or local geoJSON format object. We can add another optional parameter to each parent viz class named vector_source_layername
. This will parameter specifies the name of the vector tile layer to create the visual from a layer in a vector tile.
If the user passes the optional vector_source_layername
parameter, the visualization will create a layer from a vector tile source instead of a geojson source.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.