Color And Colormap Options#

Visual styling options to adjust colors and colormapping:

Parameters

Description

bgcolor (str or None, default=None)

Background color of the data area of the plot

color (str or list or column name or None, default=None)

Defines the color(s) to use for the plot. Accepts:

  • a single color name (e.g., 'red', 'blue')

  • a HEX color code (e.g., '#ff5733')

  • a list of colors for multiple elements

  • a column name from the dataset to map colors based on values.

c (str or list or column name or None, default=None)

Alias for color. If both color and c are provided, the color keyword takes precedence.

cmap (str or list or dict or colormap object or None, default=None)

The colormap to use for continuous or categorical color mapping.

Accepts:

  • a predefined colormap name from Bokeh, Matplotlib, or Colorcet (e.g., 'viridis', 'plasma')

  • a list of named colors or HEX color codes.

  • a dictionary mapping categories to colors for discrete colormaps.

  • A colormap object from HoloViews or Matplotlib.

If not specified, a default colormap is automatically chosen based on the data type:

  • Linear data: Uses the kbc_r colormap.

  • Categorical data: Uses glasbey_category10 colormap from Colorcet.

  • Cyclic data: Uses colorwheel colormap.

  • Diverging data: Uses coolwarm colormap.

You can override these defaults by explicitly setting cmap=<colormap_name>. Only one of cmap, colormap, or color_key can be specified at a time.

colorbar (bool or None, default=None)

Enables a colorbar. Enabled by default for these plots: bivariate, contour, contourf, heatmap, image, hexbin, quadmesh, polygons. Enabled by default for rasterized plots.

colormap (str or list or colormap object or None, default=None)

Alias for cmap. Accepts the same values as cmap. See cmap for more details. Only one of cmap, colormap, or color_key can be specified at a time.

color_key (str or list or dict or None, default=None)

Alias for cmap. Accepts the same values as cmap. See cmap for more details. Only one of cmap, colormap, or color_key can be specified at a time.

clim (tuple or None, default=None)

Lower and upper bound of the color scale

cnorm (str, default=’linear’)

Color scaling which must be one of 'linear', 'log' or 'eq_hist'.

rescale_discrete_levels (bool or None, default=None)

If cnorm='eq_hist' and there are only a few discrete values, then rescale_discrete_levels=True (the default) decreases the lower limit of the autoranged span so that the values are rendering towards the (more visible) top of the cmap range, thus avoiding washout of the lower values. Has no effect if cnorm!=`eq_hist.

robust (bool or None, default=None)

If this option is True and no clim was provided, the colormap range is computed with 2nd and 98th percentiles instead of the extreme values for image elements. For RGB elements, clips the “RGB”, or raw reflectance values between 2nd and 98th percentiles. Follows the same logic as xarray’s robust option.

symmetric (bool or None, default=None)

Whether the data are symmetric around zero. If left unset, the data will be checked for symmetry as long as the size is less than check_symmetric_max.

check_symmetric_max (int, default=1000000)

Size above which to stop checking for symmetry by default on the data.

bgcolor#

The bgcolor option sets the background color of the data area of the plot. It accepts any valid CSS color string such as ‘white’, ‘lightgray’, or hex codes like ‘#f0f0f0’. This can be useful to improve contrast or match the theme of a larger dashboard or presentation.

import hvplot.pandas  # noqa

df = hvplot.sampledata.earthquakes("pandas")

df.hvplot.scatter(
    x='lon', y='lat', c='mag', cmap='inferno_r',
    bgcolor='#f5f5f5',  # light gray background
    title="Earthquake Magnitudes by Location",
)

color#

The color option sets the color of the plotted elements. It accepts:

  • A single color name or hex code (e.g., 'red', '#1f77b4') to apply uniformly.

  • A list of colors to cycle through when plotting multiple groups (e.g., with by='column').

  • A column name to map colors based on data values (for categorical or continuous color encoding).

  • A column containing per-point color values (e.g., hex codes).

If both color and c are provided, color takes precedence. For categorical data, hvPlot automatically uses a discrete colormap unless overridden.

import hvplot.pandas  # noqa

df = hvplot.sampledata.penguins("pandas")
df['custom_color'] = df['species'].map({
    'Adelie': 'red',
    'Gentoo': 'purple',
    'Chinstrap': 'grey',
})

plot_opts = dict(x="flipper_length_mm", y="body_mass_g", frame_width=250)
(
    df.hvplot.scatter(
        color="#d133ff", title="Colored by single hex color", **plot_opts
    ) +
    df.hvplot.scatter(
        by="species", color=["blue", "green", "orange"],
        title="Groups colored by custom list", **plot_opts
    ) +
    df.hvplot.scatter(
        color="species", title="Colored by column name", **plot_opts
    ) +
    df.hvplot.scatter(
        color="custom_color", title="Colored by mapped color column", **plot_opts
    )
).cols(2)

Note

Coloring Categorical Data: color vs by

When visualizing categorical data, both the color and by keywords can produce color-separated groups, but they behave differently:

  • color='<categorical column name>' performs vectorized color mapping within a single plot. Each unique value in the column is mapped to a distinct color, using the default glasbey_category10 categorical colormap. This approach is efficient and results in a single-layer plot with all points colored by their category.

  • by='<categorical column name>' splits the data into multiple groups and creates an overlay of plots, one per unique value in the column. However, it does not honor the cmap you provide. Instead, it assigns colors by cycling through a color list. If no colors are specified, it defaults to the glasbey_hv color cycle. You can override this by passing a custom list of colors to color=[...].

In addition, using color='<categorical column>' is usually faster than by='<categorical column>', especially when working with large datasets or many unique categories. This is because color performs vectorized color mapping within a single plot, while by generates an overlay of multiple plots — each of which is rendered and managed separately. See by keyword

Summary of differences:

Keyword

Coloring Mechanism

Supports cmap

Default Color Scheme

Faster

color

Vectorized color mapping

✅ Yes

glasbey_category10

✅Yes

by

Splits into overlays by category

❌ No

glasbey_hv

❌ No

Use color when you want a single plot with color-encoded values.
Use by when you want separate layers per category — for subplots or layout purposes.

See also

cmap

c#

Alias for color above.

cmap#

The cmap option controls the colormap used when mapping numerical or categorical data values to color. It supports:

  • Named colormaps from Bokeh, Matplotlib, or Colorcet (e.g., 'viridis', 'plasma', 'coolwarm')

  • Lists of color strings or hex codes (for custom sequences)

  • Dictionaries (for categorical color mappings)

  • Colormap objects from Matplotlib or HoloViews

hvPlot selects a default colormap based on the data type, but cmap lets you override this behavior. Only one of cmap, colormap, or color_key should be used at a time.

import hvplot.pandas  # noqa
import matplotlib as mpl

df = hvplot.sampledata.earthquakes("pandas")

plot_opts = dict(x="lon", y="lat", color="mag", frame_width=250)
plot1 = df.hvplot.scatter(
    cmap="plasma_r", title="Named cmap 'plasma_r'", **plot_opts
)
plot2 = df.hvplot.scatter(
    cmap=[
        '#f7fbff', '#deebf7', '#c6dbef', '#9ecae1',
        '#6baed6', '#4292c6', '#2171b5', '#084594',
    ], title="Custom list cmap", **plot_opts
)
plot3 = df.hvplot.scatter(
    cmap=mpl.colormaps["OrRd"], title="MPL colormap object 'OrRd'", **plot_opts
)
plot4 = df.hvplot.scatter(
    cmap={
        'Shallow': 'orange',
        'Intermediate': '#C70039',
        'Deep': '#581845',
    }, title="Dict keys categorical cmap", **{**plot_opts, **{"color": "depth_class"}},
)
(plot1 + plot2 + plot3 + plot4).cols(2)

Tip

Prefer Colorcet for color mapping

While you can use any valid Matplotlib or Bokeh colormap with cmap, we recommend using the Colorcet library when possible. It provides a wide selection of perceptually accurate, well-tested colormaps optimized for data visualization.

Colorcet is also natively integrated with other HoloViz tools like HoloViews and Datashader, which means:

  • No extra setup is required

  • Colormaps work consistently across all visualizations

  • Defaults like glasbey_category10 and kbc_r come from Colorcet

This makes it a reliable and visually accessible choice for both scientific and presentation-quality plots.

colormap#

Alias for cmap above.

color_key#

Alias for cmap above.

clim#

The clim option sets the lower and upper bounds of the color scale for continuous color mapping. It accepts a tuple like (min, max) and is useful when:

  • You want consistent color scaling across multiple plots.

  • You want to clip outliers or focus on a specific data range.

This option is most effective when used with gridded plots like image, heatmap, or rasterized plots (datashade=True, rasterize=True). It works especially well with xarray datasets or plots where a colorbar is enabled.

In standard scatter plots or overlays created from tabular (pandas) data, clim may have no visible effect unless color mapping and a colorbar are explicitly involved.

If clim is not specified, the color scale is inferred from the data — or from the 2nd and 98th percentiles when robust=True.

import hvplot.xarray  # noqa

df = hvplot.sampledata.air_temperature("xarray").sel(time="2014-02-25 12:00")

plot1 = df.hvplot.image(clim=(250, 280), title="Colorbar clipped at clim values", frame_width=250)
plot2 = df.hvplot.image(title="Default colorbar scale", frame_width=250)
plot1 + plot2

See also

robust.

cnorm#

The cnorm option controls how data values are mapped to colors in a colormap. It affects the distribution of colors across the range of values.

Accepted values:

  • ‘linear’ (default): evenly maps values across the colormap.

  • ‘log’: applies logarithmic scaling, useful for data with large dynamic range.

  • ‘eq_hist’: uses histogram equalization to emphasize contrast in sparse or skewed data.

import hvplot.pandas  # noqa

df = hvplot.sampledata.earthquakes("pandas")

opts = dict(
    x='lon', y='lat', c='depth',
    cmap='plasma_r', frame_width=200,
)
plot1 = df.hvplot.scatter(title="Linear (default) color scaling", **opts,)
plot2 = df.hvplot.scatter(cnorm='log', title="Log color scaling", **opts,)
plot3 = df.hvplot.scatter(cnorm='eq_hist', title="Histogram Equalization", **opts,)
(plot1 + plot2 + plot3).cols(2)

rescale_discrete_levels#

The rescale_discrete_levels option improves the visual contrast of discrete values when using cnorm='eq_hist'. By default, it adjusts the lower bound of the colormap so that non-zero values appear higher on the scale–helpful when low counts would otherwise appear faded.

This only has an effect if:

  • cnorm='eq_hist' is set

  • The color values are discrete (e.g., counts or categories).

import hvplot.pandas  # noqa

df = hvplot.sampledata.earthquakes("pandas")

# Simulate discrete values by binning magnitude
df['mag_bin'] = df['mag'].round()

opts = dict(
    x='lon', y='lat', c='mag_bin', cmap='viridis_r',
    cnorm='eq_hist', frame_width=250,
)
plot1 = df.hvplot.scatter(title="Discrete Color Scaling (Default)", **opts)
plot2 = df.hvplot.scatter(rescale_discrete_levels=False, title="Without Discrete Color Scaling", **opts)
plot1 + plot2

robust#

The robust option adjusts how the colormap range is computed for image plots. When set to True and no explicit color limits (clim) are provided, hvPlot calculates the color limits based on the 2nd and 98th percentiles rather than the extreme minimum and maximum values, reducing the impact of outliers.

In the following example using the air_temperature dataset, we will add 2 extreme data points to show how the robust keyword can help with visualizing the data without the outliers distorting the plot.

import hvplot.xarray  # noqa

ds = hvplot.sampledata.air_temperature("xarray").sel(time="2014-02-25 12:00")
ds.air[0, 0] = 50
ds.air[-1, -1] = 500

opts = dict(width=350, cmap='viridis',)
plot1 = ds.hvplot.image(title="Plot with outliers", **opts)
plot2 = ds.hvplot.image(robust=True, title="Using robust=True", **opts)
plot1 + plot2

Notice how the colorbar in the second plot is now clipped to within the range of 240 to 290 with the colors in the plot evenly distributed.

symmetric#

The symmetric option controls whether the colormap range is centered around zero. If you do not explicitly set symmetric=True and no color limits are provided via clim, hvPlot automatically checks your data by computing the 5th and 95th percentiles. If the 5th percentile is below 0 and the 95th percentile is above 0, the option is enabled so that the colormap is balanced about 0.

Note

For lazily loaded or very large xarray datasets, this check is skipped for performance reasons and defaults to False.

import hvplot.xarray  # noqa

ds = hvplot.sampledata.air_temperature("xarray")

# Select a single date and convert to Celsius to get
# both negative and positive values around 0
data = ds.sel(time='2014-02-25 12:00') - 273.15
plot1 = data.hvplot.image(title="Symmetric True by default", width=350)
plot2 = data.hvplot.image(symmetric=False, title="Symmetric=False", width=350)
plot1 + plot2

In this example, the left image uses the symmetric colormap scaling (centered at zero), while the right image shows the default color scaling without enforcing symmetry. Notice that when the temperature values are symmetric around 0, the coolwarm colormap is used by default.

check_symmetric_max#

The check_symmetric_max option sets an upper limit on the number of data elements for which the automatic symmetry check is performed. When the dataset’s size exceeds this threshold, hvPlot skips the symmetry check and defaults to treating the data as non-symmetric. By default this limit is 1,000,000 elements which usually works well for most datasets. However, you can adjust it if you want to force or avoid the symmetric check for smaller or larger datasets.

import hvplot.xarray  # noqa

da = hvplot.sampledata.air_temperature("xarray").sel(time="2014-02-25 12:00") - 273.15

plot1 = da.hvplot.image(width=350, title="Default check for symmetry")
plot2 = da.hvplot.image(check_symmetric_max=10, width=350, title="Avoid symmetry check above 10")
plot1 + plot2
This web page was generated from a Jupyter notebook and not all interactivity will work on this website.