Updating Barpolar color using updating traces

I’ve adapted the following code snipped from this post: graph - Python Plotly Polar Chart Slice Alignment - Stack Overflow

Here is the adaptation:

labels = df.index.tolist()[1:]
ratings = scaled_bidrates
weights = df['sum_cnt'].dropna()

def make_barpolar(ratings, weights, labels=None, colors=None, layout_options = None, **fig_kwargs):
    # infer slice angles
    
    angles = [(weight / sum(weights) * 360) for weight in weights]
    num_slices = len(ratings)
    theta = [0.5 * angle for angle in angles]
    for index, angle in enumerate(angles):
        for subsequent_index in range(index + 1, len(angles)):
            theta[subsequent_index] += angle
    print("angles", angles)
    print("theta", theta)
    width = angles
    
    # optionally infer colors
    # if colors is None:
    #     color_seq = px.colors.sequential.Reds
    #     color_indices = range(0, len(color_seq), len(color_seq) // num_slices)
    #     colors = [color_seq[i] for i in color_indices]

    if layout_options is None:
        layout_options = {}

    if labels is None:
        labels = ["" for _ in range(num_slices)]
    
    layout_options["showlegend"] = False

    # make figure
    barpolar_plots = [go.Barpolar(r=[r], theta=[t], width=[w], name=n, **fig_kwargs)
                      for r, t, w, n in zip(ratings, theta, width, labels)]
    
    fig = go.Figure(barpolar_plots)
    
    # additional layout parameters
    fig.update_layout(**layout_options)
    return fig


layout_options = {"title": "FPP Chart",
                  "title_font_size": 24,
                  "title_x": 0.5,
                  "legend_x": 0.85,
                  "legend_y": 0.5,
                  "polar_radialaxis_ticks": "",
                  "polar_radialaxis_showticklabels": False,
                  "polar_radialaxis_range": [0, max(ratings)],
                  "polar_angularaxis_ticks": "",
                  "polar_angularaxis_showticklabels": False}

fig = make_barpolar(ratings, weights, labels, layout_options=layout_options, opacity = 0.3)
fig.update_traces(marker={
        "colorscale": px.colors.sequential.Reds,
        "showscale": True,
        "color": df['winrate'].dropna(),
        "line_color": None,
        "line_width": 1,
        "cmin": df['winrate'].min(),
        "cmax": df['winrate'].max(),
    }, selector=dict(type='barpolar'))
fig.show()
print(fig.data)

And the result is not what I intended.

I’ve tried printing fig.data to see there is an issue with the data but the values are there.
What am I missing?

I am the original poster of the answer from SO. Here is some updated code that achieves what you want. The key is to refactor the call of go.Figure(barpolar_plots) inside the function definition so that there is only a single go.Barpolar() call passed. Then fig.update_traces() works as you intend.

import plotly.graph_objects as go
import plotly.express as px
import pandas as pd


ratings = [3, 2, 5, 1, 2]
weights = [65, 79, 81, 98, 38]
labels = ["Strength", "Intelligence", "Dexterity", "Wisdom", "Stealth"]

def make_barpolar(ratings, weights, labels=None, colors=None, layout_options = None, **fig_kwargs):
    # infer slice angles
    
    angles = [(weight / sum(weights) * 360) for weight in weights]
    num_slices = len(ratings)
    theta = [0.5 * angle for angle in angles]
    for index, angle in enumerate(angles):
        for subsequent_index in range(index + 1, len(angles)):
            theta[subsequent_index] += angle
    width = angles
    
    # optionally infer colors
    #if colors is None:
    #    color_seq = px.colors.sequential.Reds
    #    color_indices = range(0, len(color_seq), len(color_seq) // num_slices)
    #
    # \    colors = [color_seq[i] for i in color_indices]

    if layout_options is None:
        layout_options = {}

    if labels is None:
        labels = ["" for _ in range(num_slices)]
        layout_options["showlegend"] = False

    # make figure
    fig = go.Figure(go.Barpolar(r=ratings, theta=theta, width=width, marker_color=colors, **fig_kwargs))
    
    # additional layout parameters
    fig.update_layout(**layout_options)
    
    return fig


layout_options = {"title": "FPP Chart",
                  "title_font_size": 24,
                  "title_x": 0.5,
                  "legend_x": 0.85,
                  "legend_y": 0.5,
                  "polar_radialaxis_ticks": "",
                  "polar_radialaxis_showticklabels": False,
                  "polar_radialaxis_range": [0, max(ratings)],
                  "polar_angularaxis_ticks": "",
                  "polar_angularaxis_showticklabels": False}
                  
df = pd.DataFrame({'winrate': [2, 3, 4, 2, 1]})

fig = make_barpolar(ratings, weights, layout_options=layout_options, opacity = 0.7)
fig.update_traces(marker={
        "colorscale": px.colors.sequential.Reds,
        "showscale": True,
        "color": df['winrate'].dropna(),
        "line_color": None,
        "line_width": 1,
        "cmin": df['winrate'].min(),
        "cmax": df['winrate'].max(),
    }, selector=dict(type='barpolar'))
fig.show()

3 Likes

Christopher @Frodnar
Welcome to the community, and thank you for sharing your answer with others on this Forum :pray:t4:

Thanks a lot @Frodnar for taking the time to adjust the code :).

@Frodnar Do you know a way to represent labels, text annotation on the plot itself instead of appearing in the legend?
Instead of plotting the degrees, plot text values?

I tried passing a list of strings to text in go.BarPolar but to no effect, when I set angularaxis = dict(showticklabels=True) I still get the degrees shown.