Search code examples
pythonplotlyplotly-python

plotly: change background color for areas of polar chart


There has been a question about how to colorize the rings of a plotly polar chart. I would like to add different background colors depending on the categories.

Consider a skill rating where I would like to highlight the kind of skill in the overall overview:

import plotly.graph_objects as go

categories = [
    "[lang] English", "[lang] Spanish", "[lang] German",
    "[dev] JS", "[dev] Python", "[dev] Go", "[dev] C#",
    "[skill] leadership", "[skill] creativity"
]
# remove prefix, this should be reflected by the background color
categories = [c.split("] ")[1] for c in categories]

ratings = {
    "Alice": [4,5,0,3,4,5,2,3,5],
    "Bob":   [3,1,4,2,3,1,1,3,2],
}

fig = go.Figure()

for name in ratings.keys():
    fig.add_trace(go.Scatterpolar(
        r=ratings[name] + [ratings[name][0]],
        theta=categories + [categories[0]],
        name=name,
    ))


fig.show()

Is it possible to highlight the kind of the categories by changing the background color so it looks similar to this (faked) example?

example image

I searched the net and looked for different options, but all I found was the other question I linked.


Solution

  • You can do this by adding a go.Barpolar trace to the current figure, where the categories are placed along the angular axis in the same way as for the Scatterpolar trace, and where on the radial axis the magnitude is the same for all bars, that is, the maximum value of ratings (so that the coloured areas span the polar chart evenly). Specify the color of each category slice using the marker_color property.

    categories = [
        "[lang] English", "[lang] Spanish", "[lang] German",
        "[dev] JS", "[dev] Python", "[dev] Go", "[dev] C#",
        "[skill] leadership", "[skill] creativity"
    ]
    
    kinds = [re.search('^\[(.+)\]', c).group(1) for c in categories]
    categories = [c.split("] ")[1] for c in categories]
    
    ratings = {
        "Alice": [4,5,0,3,4,5,2,3,5],
        "Bob":   [3,1,4,2,3,1,1,3,2],
    }
    
    fig = go.Figure()
    
    for name in ratings.keys():
        fig.add_trace(go.Scatterpolar(
            r=ratings[name] + [ratings[name][0]],
            theta=categories + [categories[0]],
            name=name,
        ))
    
    # Pick a color palette and give a color to each kind of category
    colors = px.colors.qualitative.D3
    colormap = { kind: colors[i] for i, kind in enumerate(set(kinds)) }
    
    fig.add_trace(go.Barpolar(
        theta=categories,
        r=len(categories)*[max(x for v in ratings.values() for x in v)],
        marker_color=list(map(lambda kind: colormap[kind], kinds)),
        opacity=0.6,
        name='Kind'
    ))
    
    fig.update_polars(bargap=0)
    
    fig.show()
    

    output