Skip to content

Commit 329beb9

Browse files
Merge pull request #1937 from plotly/px_new_functions
New mapbox functions in PX
2 parents e3ef26a + 8ce78be commit 329beb9

File tree

6 files changed

+198
-31
lines changed

6 files changed

+198
-31
lines changed

packages/python/plotly/plotly/express/__init__.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"""
55
from __future__ import absolute_import
66
from plotly import optional_imports
7+
from ._imshow import imshow
78

89
pd = optional_imports.get_module("pandas")
910
if pd is None:
@@ -12,7 +13,6 @@
1213
Plotly express requires pandas to be installed."""
1314
)
1415

15-
1616
from ._chart_types import ( # noqa: F401
1717
scatter,
1818
scatter_3d,
@@ -44,9 +44,10 @@
4444
treemap,
4545
funnel,
4646
funnel_area,
47+
choropleth_mapbox,
48+
density_mapbox,
4749
)
4850

49-
from ._imshow import imshow
5051

5152
from ._core import ( # noqa: F401
5253
set_mapbox_access_token,
@@ -66,6 +67,7 @@
6667
"scatter_matrix",
6768
"density_contour",
6869
"density_heatmap",
70+
"density_mapbox",
6971
"line",
7072
"line_3d",
7173
"line_polar",
@@ -82,6 +84,7 @@
8284
"strip",
8385
"histogram",
8486
"choropleth",
87+
"choropleth_mapbox",
8588
"pie",
8689
"sunburst",
8790
"treemap",

packages/python/plotly/plotly/express/_chart_types.py

+83-2
Original file line numberDiff line numberDiff line change
@@ -842,15 +842,13 @@ def choropleth(
842842
hover_name=None,
843843
hover_data=None,
844844
custom_data=None,
845-
size=None,
846845
animation_frame=None,
847846
animation_group=None,
848847
category_orders={},
849848
labels={},
850849
color_continuous_scale=None,
851850
range_color=None,
852851
color_continuous_midpoint=None,
853-
size_max=None,
854852
projection=None,
855853
scope=None,
856854
center=None,
@@ -983,6 +981,8 @@ def scatter_mapbox(
983981
opacity=None,
984982
size_max=None,
985983
zoom=8,
984+
center=None,
985+
mapbox_style=None,
986986
title=None,
987987
template=None,
988988
width=None,
@@ -998,6 +998,85 @@ def scatter_mapbox(
998998
scatter_mapbox.__doc__ = make_docstring(scatter_mapbox)
999999

10001000

1001+
def choropleth_mapbox(
1002+
data_frame=None,
1003+
geojson=None,
1004+
locations=None,
1005+
color=None,
1006+
hover_name=None,
1007+
hover_data=None,
1008+
custom_data=None,
1009+
animation_frame=None,
1010+
animation_group=None,
1011+
category_orders={},
1012+
labels={},
1013+
color_continuous_scale=None,
1014+
range_color=None,
1015+
color_continuous_midpoint=None,
1016+
opacity=None,
1017+
zoom=8,
1018+
center=None,
1019+
mapbox_style=None,
1020+
title=None,
1021+
template=None,
1022+
width=None,
1023+
height=None,
1024+
):
1025+
"""
1026+
In a Mapbox choropleth map, each row of `data_frame` is represented by a
1027+
colored region on a Mapbox map.
1028+
"""
1029+
return make_figure(
1030+
args=locals(),
1031+
constructor=go.Choroplethmapbox,
1032+
trace_patch=dict(
1033+
geojson=geojson
1034+
if not hasattr(geojson, "__geo_interface__")
1035+
else geojson.__geo_interface__
1036+
),
1037+
)
1038+
1039+
1040+
choropleth_mapbox.__doc__ = make_docstring(choropleth_mapbox)
1041+
1042+
1043+
def density_mapbox(
1044+
data_frame=None,
1045+
lat=None,
1046+
lon=None,
1047+
z=None,
1048+
hover_name=None,
1049+
hover_data=None,
1050+
custom_data=None,
1051+
animation_frame=None,
1052+
animation_group=None,
1053+
category_orders={},
1054+
labels={},
1055+
color_continuous_scale=None,
1056+
range_color=None,
1057+
color_continuous_midpoint=None,
1058+
opacity=None,
1059+
zoom=8,
1060+
center=None,
1061+
mapbox_style=None,
1062+
radius=None,
1063+
title=None,
1064+
template=None,
1065+
width=None,
1066+
height=None,
1067+
):
1068+
"""
1069+
In a Mapbox density map, each row of `data_frame` contributes to the intensity of
1070+
the color of the region around the corresponding point on the map
1071+
"""
1072+
return make_figure(
1073+
args=locals(), constructor=go.Densitymapbox, trace_patch=dict(radius=radius)
1074+
)
1075+
1076+
1077+
density_mapbox.__doc__ = make_docstring(density_mapbox)
1078+
1079+
10011080
def line_mapbox(
10021081
data_frame=None,
10031082
lat=None,
@@ -1015,6 +1094,8 @@ def line_mapbox(
10151094
color_discrete_sequence=None,
10161095
color_discrete_map={},
10171096
zoom=8,
1097+
center=None,
1098+
mapbox_style=None,
10181099
title=None,
10191100
template=None,
10201101
width=None,

packages/python/plotly/plotly/express/_core.py

+29-27
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ def make_trace_kwargs(args, trace_spec, g, mapping_labels, sizeref):
287287
v_label_col = get_decorated_label(args, col, None)
288288
mapping_labels[v_label_col] = "%%{customdata[%d]}" % (position)
289289
elif k == "color":
290-
if trace_spec.constructor == go.Choropleth:
290+
if trace_spec.constructor in [go.Choropleth, go.Choroplethmapbox]:
291291
result["z"] = g[v]
292292
result["coloraxis"] = "coloraxis1"
293293
mapping_labels[v_label] = "%{z}"
@@ -380,6 +380,8 @@ def configure_axes(args, constructor, fig, orders):
380380
go.Scatterpolargl: configure_polar_axes,
381381
go.Barpolar: configure_polar_axes,
382382
go.Scattermapbox: configure_mapbox,
383+
go.Choroplethmapbox: configure_mapbox,
384+
go.Densitymapbox: configure_mapbox,
383385
go.Scattergeo: configure_geo,
384386
go.Choropleth: configure_geo,
385387
}
@@ -502,13 +504,11 @@ def configure_cartesian_axes(args, fig, orders):
502504

503505

504506
def configure_ternary_axes(args, fig, orders):
505-
fig.update(
506-
layout=dict(
507-
ternary=dict(
508-
aaxis=dict(title=get_label(args, args["a"])),
509-
baxis=dict(title=get_label(args, args["b"])),
510-
caxis=dict(title=get_label(args, args["c"])),
511-
)
507+
fig.update_layout(
508+
ternary=dict(
509+
aaxis=dict(title=get_label(args, args["a"])),
510+
baxis=dict(title=get_label(args, args["b"])),
511+
caxis=dict(title=get_label(args, args["c"])),
512512
)
513513
)
514514

@@ -562,28 +562,28 @@ def configure_3d_axes(args, fig, orders):
562562

563563

564564
def configure_mapbox(args, fig, orders):
565-
fig.update(
566-
layout=dict(
567-
mapbox=dict(
568-
accesstoken=MAPBOX_TOKEN,
569-
center=dict(
570-
lat=args["data_frame"][args["lat"]].mean(),
571-
lon=args["data_frame"][args["lon"]].mean(),
572-
),
573-
zoom=args["zoom"],
574-
)
565+
center = args["center"]
566+
if not center and "lat" in args and "lon" in args:
567+
center = dict(
568+
lat=args["data_frame"][args["lat"]].mean(),
569+
lon=args["data_frame"][args["lon"]].mean(),
570+
)
571+
fig.update_layout(
572+
mapbox=dict(
573+
accesstoken=MAPBOX_TOKEN,
574+
center=center,
575+
zoom=args["zoom"],
576+
style=args["mapbox_style"],
575577
)
576578
)
577579

578580

579581
def configure_geo(args, fig, orders):
580-
fig.update(
581-
layout=dict(
582-
geo=dict(
583-
center=args["center"],
584-
scope=args["scope"],
585-
projection=dict(type=args["projection"]),
586-
)
582+
fig.update_layout(
583+
geo=dict(
584+
center=args["center"],
585+
scope=args["scope"],
586+
projection=dict(type=args["projection"]),
587587
)
588588
)
589589

@@ -1083,7 +1083,7 @@ def infer_config(args, constructor, trace_patch):
10831083
# Compute final trace patch
10841084
trace_patch = trace_patch.copy()
10851085

1086-
if constructor == go.Histogram2d:
1086+
if constructor in [go.Histogram2d, go.Densitymapbox]:
10871087
show_colorbar = True
10881088
trace_patch["coloraxis"] = "coloraxis1"
10891089

@@ -1221,6 +1221,8 @@ def make_figure(args, constructor, trace_patch={}, layout_patch={}):
12211221
go.Parcats,
12221222
go.Parcoords,
12231223
go.Choropleth,
1224+
go.Choroplethmapbox,
1225+
go.Densitymapbox,
12241226
go.Histogram2d,
12251227
go.Sunburst,
12261228
go.Treemap,
@@ -1321,7 +1323,7 @@ def make_figure(args, constructor, trace_patch={}, layout_patch={}):
13211323
)
13221324
layout_patch = layout_patch.copy()
13231325
if show_colorbar:
1324-
colorvar = "z" if constructor == go.Histogram2d else "color"
1326+
colorvar = "z" if constructor in [go.Histogram2d, go.Densitymapbox] else "color"
13251327
range_color = args["range_color"] or [None, None]
13261328

13271329
colorscale_validator = ColorscaleValidator("colorscale", "make_figure")

packages/python/plotly/plotly/express/_doc.py

+11
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@
164164
colref_desc,
165165
"Values from this column or array_like are used to assign mark sizes.",
166166
],
167+
radius=["int (default is 30)", "Sets the radius of influence of each point.",],
167168
hover_name=[
168169
colref_type,
169170
colref_desc,
@@ -445,6 +446,12 @@
445446
"Dict keys are `'lat'` and `'lon'`",
446447
"Sets the center point of the map.",
447448
],
449+
mapbox_style=[
450+
"str (default `'basic'`, needs Mapbox API token)",
451+
"Identifier of base map style, some of which require a Mapbox API token to be set using `plotly.express.set_mapbox_access_token()`.",
452+
"Allowed values which do not require a Mapbox API token are `'open-street-map'`, `'white-bg'`, `'carto-positron'`, `'carto-darkmatter'`, `'stamen-terrain'`, `'stamen-toner'`, `'stamen-watercolor'`.",
453+
"Allowed values which do require a Mapbox API token are `'basic'`, `'streets'`, `'outdoors'`, `'light'`, `'dark'`, `'satellite'`, `'satellite-streets'`.",
454+
],
448455
points=[
449456
"str or boolean (default `'outliers'`)",
450457
"One of `'outliers'`, `'suspectedoutliers'`, `'all'`, or `False`.",
@@ -456,6 +463,10 @@
456463
],
457464
box=["boolean (default `False`)", "If `True`, boxes are drawn inside the violins."],
458465
notched=["boolean (default `False`)", "If `True`, boxes are drawn with notches."],
466+
geojson=[
467+
"GeoJSON-formatted dict",
468+
"Must contain a Polygon feature collection, with IDs, which are references from `locations`.",
469+
],
459470
cumulative=[
460471
"boolean (default `False`)",
461472
"If `True`, histogram values are cumulative.",
Binary file not shown.

test/percy/plotly-express.py

+70
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,37 @@
435435

436436
import plotly.express as px
437437

438+
sample_geojson = {
439+
"type": "FeatureCollection",
440+
"features": [
441+
{
442+
"type": "Feature",
443+
"id": "the_polygon",
444+
"geometry": {
445+
"type": "Polygon",
446+
"coordinates": [
447+
[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]]
448+
],
449+
},
450+
}
451+
],
452+
}
453+
fig = px.choropleth_mapbox(
454+
geojson=sample_geojson, locations=["the_polygon"], color=[10], zoom=6,
455+
)
456+
fig.write_html(os.path.join(dir_name, "choropleth_mapbox.html"), auto_play=False)
457+
458+
import plotly.express as px
459+
460+
carshare = px.data.carshare()
461+
fig = px.density_mapbox(
462+
carshare, lat="centroid_lat", lon="centroid_lon", z="peak_hour",
463+
)
464+
fig.write_html(os.path.join(dir_name, "density_mapbox.html"), auto_play=False)
465+
466+
import plotly.express as px
467+
468+
438469
gapminder = px.data.gapminder()
439470
fig = px.scatter_geo(
440471
gapminder,
@@ -470,3 +501,42 @@
470501
range_color=[20, 80],
471502
)
472503
fig.write_html(os.path.join(dir_name, "choropleth.html"), auto_play=False)
504+
505+
import plotly.express as px
506+
507+
tips = px.data.tips()
508+
fig = px.pie(tips, names="smoker", values="total_bill")
509+
fig.write_html(os.path.join(dir_name, "pie.html"), auto_play=False)
510+
511+
import plotly.express as px
512+
513+
tips = px.data.tips()
514+
fig = px.funnel_area(tips, names="smoker", values="total_bill")
515+
fig.write_html(os.path.join(dir_name, "funnel_area.html"), auto_play=False)
516+
517+
import plotly.express as px
518+
519+
fig = px.treemap(
520+
names=["Eve", "Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura"],
521+
parents=["", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve"],
522+
values=[10, 14, 12, 10, 2, 6, 6, 4, 4],
523+
)
524+
fig.write_html(os.path.join(dir_name, "treemap.html"), auto_play=False)
525+
526+
527+
import plotly.express as px
528+
529+
fig = px.sunburst(
530+
names=["Eve", "Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura"],
531+
parents=["", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve"],
532+
values=[10, 14, 12, 10, 2, 6, 6, 4, 4],
533+
)
534+
fig.write_html(os.path.join(dir_name, "sunburst.html"), auto_play=False)
535+
536+
537+
import plotly.express as px
538+
539+
fig = px.funnel(
540+
y=["first", "second", "first", "second"], x=[3, 1, 4, 2], color=["A", "A", "B", "B"]
541+
)
542+
fig.write_html(os.path.join(dir_name, "funnel.html"), auto_play=False)

0 commit comments

Comments
 (0)