- Using same solution custom color_continuous_scale but making MWE work with generally available geometry
- I did find one subtle issue,
pd.cut()can return negative edges when all values are positive. This will cause plotly to fail. Have floored minimum edge to zero - I'd always go with using px. Have also provided go
import geopandas as gpd
import pandas as pd
import numpy as np
import plotly.express as px
# sample data
gdf = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
edges = pd.cut(gdf["gdp_md_est"], bins=5, retbins=True)[1]
edges = edges[:-1] / edges[-1]
# color scales don't like negative edges...
edges = np.maximum(edges, np.full(len(edges), 0))
colors = ["#e5e5e5", "#ffe5f0", "#facfdf", "#f3b8ce", "#eca2bf", "#e37fb1"]
cc_scale = (
[(0, colors[0])]
+ [(e, colors[(i + 1) // 2]) for i, e in enumerate(np.repeat(edges, 2))]
+ [(1, colors[5])]
)
fig = px.choropleth(
gdf,
geojson=gdf.__geo_interface__,
locations=gdf.index,
hover_data=["iso_a3","name"],
color="gdp_md_est",
color_continuous_scale=cc_scale,
)
fig.update_geos(fitbounds="locations", visible=False)
import plotly.graph_objects as go
go.Figure(
go.Choropleth(
geojson=gdf.__geo_interface__,
locations=gdf.index,
z=gdf["gdp_md_est"],
coloraxis="coloraxis",
)
).update_geos(fitbounds="locations", visible=False).update_layout(
coloraxis={"colorscale": cc_scale}
)
output - discrete color bins

- Using same solution custom color_continuous_scale but making MWE work with generally available geometry
- I did find one subtle issue,
pd.cut()can return negative edges when all values are positive. This will cause plotly to fail. Have floored minimum edge to zero - I'd always go with using px. Have also provided go
import geopandas as gpd
import pandas as pd
import numpy as np
import plotly.express as px
# sample data
gdf = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
edges = pd.cut(gdf["gdp_md_est"], bins=5, retbins=True)[1]
edges = edges[:-1] / edges[-1]
# color scales don't like negative edges...
edges = np.maximum(edges, np.full(len(edges), 0))
colors = ["#e5e5e5", "#ffe5f0", "#facfdf", "#f3b8ce", "#eca2bf", "#e37fb1"]
cc_scale = (
[(0, colors[0])]
+ [(e, colors[(i + 1) // 2]) for i, e in enumerate(np.repeat(edges, 2))]
+ [(1, colors[5])]
)
fig = px.choropleth(
gdf,
geojson=gdf.__geo_interface__,
locations=gdf.index,
hover_data=["iso_a3","name"],
color="gdp_md_est",
color_continuous_scale=cc_scale,
)
fig.update_geos(fitbounds="locations", visible=False)
import plotly.graph_objects as go
go.Figure(
go.Choropleth(
geojson=gdf.__geo_interface__,
locations=gdf.index,
z=gdf["gdp_md_est"],
coloraxis="coloraxis",
)
).update_geos(fitbounds="locations", visible=False).update_layout(
coloraxis={"colorscale": cc_scale}
)
output - discrete color bins

There are some borderline bug behaviors with go.
val_to_color = sorted([
(0, 'red'),
(1, 'green'),
(99, 'yellow'),
(100, 'purple'),
(101, 'orange'),
]) # your desired mapping, keys could be ints, strings, whatever.
colorscale=[]
colorscale_normalizer = {val: i / len(val_to_color) for i, (val, _) in enumerate(val_to_color)}
for i, (orig_idx, color_to_set) in enumerate(sorted(val_to_color)):
# We add the whole interval rather than just one endpoint because we want the color
# not to change during the interval. Thus colorscale has twice as many entries as idx_to_color
colorscale.append([i/len(val_to_color), color_to_set])
colorscale.append([(i+1)/len(val_to_color), color_to_set])
val_array = [99,1,0,100, 100] # Values from your data
plotly.graph_objects.Scatter( # Or whatever graph object type
...
# It is VERY IMPORTANT that you include cmin and cmax! Otherwise, the colorscale will change based on the data and you will not get the mapping that you intended when you have missing values in the data!
marker=dict(color=[colorscale_normalizer[i] for i in val_array]], size=1.0, colorscale=colorscale,cmin=0,cmax=len(val_to_color),
)
Generally, changing the color scheme for a plotly express figure is very straight-forward. What's causing the problems here is the fact that species is a categorical variable. Continuous or numerical values are actually easier, but we'll get to that in a bit.
For categorical values, using color_discrete_map is a perfectly valid, albeit cumbersome approach. I prefer using the keyword argument continuous_colorscale in combination with px.colors.qualitative.Antique, where Antique can be changed to any of the discrete color schemes available in plotly express. Just run dir(px.colors.qualitative) to see what are available to you in the plotly version you are running:
['Alphabet',
'Antique',
'Bold',
'D3',
'Dark2',
'Dark24',
'G10',......]
Code 1:
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length",
color="species", color_discrete_sequence=px.colors.qualitative.Antique)
fig.show()
Plot 1:

So what about continuous variables?
Consider the following snippet:
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length",
color="sepal_length", color_continuous_scale=px.colors.sequential.Viridis)
fig.show()
Running this will produce this plot:

You can change the colors to any other theme available under dir(px.colors.sequential), for example color_continuous_scale=px.colors.sequential.Inferno, and get this plot:

What's possibly causing confusion here, is that setting color='species, and keeping color_continuous_scale=px.colors.sequential.Inferno will give you this plot:

The figure now jumps straight back to using the default plotly colors, without giving you any warning about color_continuous_scale=px.colors.sequential.Inferno not having an effect.
This is because species is a categorical variable with these different values : ['setosa', 'versicolor', 'virginica'], so color_continuous_scale is simply ignored. For color_continuous_scale to take effect you'll have to use a numerical value, like sepal_length = [5.1, 4.9, 4.7, 4.6, 5. , 5.4, ...]
And this brings us right back to my initial answer for categorical values:
Use the keyword argument
continuous_colorscalein combination withpx.colors.qualitative
You can use a method called color_discrete_map, which is a dict of k,v pairs where the k is the value for the color and v is the colorscheme. For example:
fig = px.scatter(df, x='sepal_length', y='sepal_width',
color='species', color_discrete_map={'setosa': 'lightcyan',
'versicolor': 'royalblue', 'virginica': 'darkblue'})

Similar to accepted response but with ability to use builtin names that can be found in this tutorial
colors contains list of n_colors that can be trated as list.
import plotly.express as px
n_colors = 25
colors = px.colors.sample_colorscale("turbo", [n/(n_colors -1) for n in range(n_colors)])
Here is full example:
import plotly.graph_objects as go
import plotly.express as px
n_colors = 25
colors = px.colors.sample_colorscale("turbo", [n/(n_colors -1) for n in range(n_colors)])
fig = go.Figure()
# for i, c in enumerate(greys15):
for i, c in enumerate(colors):
fig.add_bar(x=[i], y = [15], marker_color = c, showlegend = False, name=c)
f = fig.full_figure_for_development(warn=False)
fig.show()

If you don't mind rgb colors, then n_colors is one way to go. Here's an example of 15 colors in a gray scale between 'rgb(0, 0, 0)' and 'rgb(255, 255, 255)':
n_colors('rgb(0, 0, 0)', 'rgb(255, 255, 255)', 15, colortype='rgb')

And here's an example of 25 colors between blue 'rgb(0, 0, 255)'and red , 'rgb(255, 0, 0)' :
n_colors('rgb(0, 0, 255)', 'rgb(255, 0, 0)', 25, colortype = 'rgb')

Complete code:
import numpy as np
import pandas as pd
import plotly.graph_objects as go
import plotly.express as px
import datetime
from plotly.colors import n_colors
pd.set_option('display.max_rows', None)
pd.options.plotting.backend = "plotly"
# greys15 = n_colors('rgb(0, 0, 0)', 'rgb(255, 255, 255)', 15, colortype='rgb')
redVSblue = n_colors('rgb(0, 0, 255)', 'rgb(255, 0, 0)', 25, colortype = 'rgb')
fig = go.Figure()
# for i, c in enumerate(greys15):
for i, c in enumerate(redVSblue):
fig.add_bar(x=[i], y = [i+1], marker_color = c, showlegend = False)
f = fig.full_figure_for_development(warn=False)
fig.show()