• 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

Answer from Rob Raymond on Stack Overflow
🌐
Plotly
plotly.com › python › discrete-color
Discrete colors in Python
This page is about using color to represent categorical data using discrete colors, but Plotly can also represent continuous values with color. This document explains the following discrete-color-related concepts: color sequences are lists of colors to be mapped onto discrete data values. No interpolation occurs when using color sequences, unlike with continuous color scales, and each color is used as-is.
🌐
Plotly
plotly.com › python › builtin-colorscales
Built-in continuous color scales in Python
When using continuous color scales, you will often want to configure various aspects of its range and colorbar. Plotly also comes with some built-in discrete color sequences which are not intended to be used with the color_continuous_scale argument as they are not designed for interpolation to occur between adjacent colors.
🌐
Plotly
plotly.com › python › colorscales
Continuous color scales and color bars in Python
Over 29 examples of Continuous Color Scales and Color Bars including changing color, size, log axes, and more in Python.
Top answer
1 of 2
1
  • 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

2 of 2
0

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), 
    )
🌐
Plotly
plotly.com › r › discrete-color
Discrete colors in R
This page is about using color to represent categorical data using discrete colors, but Plotly can also represent continuous values with color. This document explains the following discrete-color-related concepts: color sequences are lists of colors to be mapped onto discrete data values. No interpolation occurs when using color sequences, unlike with continuous color scales, and each color is used as-is.
🌐
Plotly
community.plotly.com › plotly.js
About discrete colorscale - plotly.js - Plotly Community Forum
January 12, 2024 - Does any one has any idea how to create discreate color scale? I mean how we assign colors to boxes[rectangles] depending on data range?
🌐
GeeksforGeeks
geeksforgeeks.org › python › discrete-colour-scale-in-plotly-python
Discrete Colour Scale in Plotly Python - GeeksforGeeks
July 23, 2025 - For discrete colors, we need to calculate the exact values of the 'tip' instead of the value range. For doing this simply we will convert the value range of 'tip' to the string and then we will plot it.
Top answer
1 of 2
35

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_colorscale in combination with px.colors.qualitative

2 of 2
20

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'})

🌐
Naomi Aro
naomiaro.hashnode.dev › how-to-create-custom-continuous-and-discrete-colorscales-with-plotlyjs
How to create custom continuous and discrete colorscales with Plotly.js
September 9, 2024 - The scale will include "pairs" of colours, defining the start and stop explicitly and avoiding all interpolation between colours. Because the treatment of 0 and 1 is slightly different here the formula for the increment is also slightly different.
Find elsewhere
🌐
Plotly
plotly.com › python-api-reference › generated › plotly.express.colors.html
plotly.express.colors package — 7.1.0 documentation
This figure demonstrates the color scales and sequences in this module, as stacked bar charts. ... Qualitative color sequences are appropriate for data that has no natural ordering, such as categories, colors, names, countries etc. The color sequences in this module are mostly meant to be passed in as the color_discrete_sequence argument to various functions.
🌐
Medium
medium.com › data-science › discrete-colour-scale-in-plotly-python-26f2d6e21c77
Discrete Colour Scale in Plotly Python | by Kyle Pastor | TDS Archive | Medium
July 2, 2020 - All the function does is take in a list of lists of colour elements. It then figures out how to make discrete blocks of colour for the various inputs.
Top answer
1 of 3
12

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()

2 of 3
10

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()
🌐
Plotly
plotly.com › python-api-reference › generated › plotly.colors.html
plotly.colors package — 7.1.0 documentation
This figure demonstrates the color scales and sequences in this module, as stacked bar charts. ... Qualitative color sequences are appropriate for data that has no natural ordering, such as categories, colors, names, countries etc. The color sequences in this module are mostly meant to be passed in as the color_discrete...
🌐
Plotly
community.plotly.com › 📊 plotly python
Colors for discrete ranges in heatmaps - 📊 Plotly Python - Plotly Community Forum
January 17, 2018 - I’m trying to make a heatmap using different colors for discreet ranges of data, using Plotly in python/pandas. My colleague sent me an image of the color ranges she would like used for the data. I used the “Custom Discretized Heatmap Colorscale” example at https://plot.ly/python/colorscales/ ...
🌐
GitHub
github.com › plotly › plotly.py › blob › main › doc › python › builtin-colorscales.md
plotly.py/doc/python/builtin-colorscales.md at main · plotly/plotly.py
When using continuous color scales, you will often want to configure various aspects of its range and colorbar. Plotly also comes with some built-in discrete color sequences which are not intended to be used with the color_continuous_scale argument as they are not designed for interpolation to occur between adjacent colors.
Author: plotly
🌐
GitHub
github.com › plotly › plotly.py › blob › main › doc › python › colorscales.md
plotly.py/doc/python/colorscales.md at main · plotly/plotly.py
Color scale defaults depend on the layout.colorscales attributes of the active template, and can be explicitly specified using the color_continuous_scale argument for many Plotly Express functions or the colorscale argument in various graph_objects such as layout.coloraxis or marker.colorscale in go.Scatter traces or colorscale in go.Heatmap traces.
Author: plotly
🌐
Bomberbot
bomberbot.com › python › mastering-discrete-colour-scales-in-plotly-python-a-comprehensive-guide
Mastering Discrete Colour Scales in Plotly Python: A Comprehensive Guide - Bomberbot
While Plotly's default colours are carefully chosen, you may want to customize the colour scale to align with your brand identity or improve accessibility. Plotly offers a range of built-in colour sequences, and you can also define your own: custom_colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8'] fig = px.scatter(df, x='Region', y='Sales', color='Category', color_discrete_sequence=custom_colors, title='Sales by Region and Category (Custom Colors)') fig.show()
🌐
Plotly
plotly.com › r › builtin-colorscales
Built-in continuous color scales in R
When using continuous color scales, you will often want to configure various aspects of its range and colorbar. Plotly also comes with some built-in discrete color sequences.
🌐
GeeksforGeeks
geeksforgeeks.org › python-plotly-how-to-set-up-a-color-palette
Python Plotly - How to set up a color palette? - GeeksforGeeks
April 15, 2025 - px. bar() method is used to plot a barplot of the data we provide. The list of colours is passed to the color_discrete_sequence parameter of the px.bar() method. as we're working on discrete data.