Search code examples
pythonchartsplotlyradar-chart

Plotly Radar Chart: arranging y-axis labelled with string by levels


Assume I have a df:

df = pd.DataFrame({'category': ['Apple', 'Pear', 'Banana', 'Orange', 'Cherry'],
                   'value': [1, 1, 3, 2, 0],
                  'mark': ['Average', 'Average', 'Terrible', 'Bad', 'Good']})

What I want to do is plot df on radar chart via Plotly. The outcome looks like this:

enter image description here

Except this round, instead of numbers, I'm replacing the y-axis or radius with strings. For example: 0 is 'good', 1 is 'average', 2 is 'bad', & 3 is 'terrible'. However once I plot it, the orders were randomized:

enter image description here

How do I re-sort the y-axis?

This is the code I'm currently using:

import plotly.express as px
display(px.line_polar(df.sort_values(by= 'category'), theta= 'category', r= 'mark').update_traces(fill='toself'))

Solution

  • Use two primary techniques

    1. consider mark to be a categorical in dataframe. Use ordered index to build polar figure
    2. update radialaxis from codes assigned in step 1 back to text
    import pandas as pd
    import plotly.express as px
    
    df = pd.DataFrame({'category': ['Apple', 'Pear', 'Banana', 'Orange', 'Cherry'],
                       'value': [1, 1, 3, 2, 0],
                      'mark': ['Average', 'Average', 'Terrible', 'Bad', 'Good']})
    
    # need order of categoricals...
    cat = ['Good', 'Average', 'Bad', 'Terrible']
    
    # output radial as an ordered number
    df2 = df.assign(mark=pd.Categorical(df["mark"], ordered=True, categories=cat).codes).sort_values(by= 'category')
    fig = px.line_polar(df2, theta= 'category', r= 'mark').update_traces(fill='toself')
    
    # change axis back to text
    fig.update_layout(polar={"radialaxis":{"tickmode":"array","tickvals":[i for i in range(len(cat))],"ticktext":cat}})
    
    fig
    

    enter image description here

    without use of categorical

    import pandas as pd
    import plotly.express as px
    
    df = pd.DataFrame({'category': ['Apple', 'Pear', 'Banana', 'Orange', 'Cherry'],
                       'value': [1, 1, 3, 2, 0],
                      'mark': ['Average', 'Average', 'Terrible', 'Bad', 'Good']})
    
    
    # output radial as an ordered number
    fig = px.line_polar(df.sort_values("category"), theta= 'category', r= 'value').update_traces(fill='toself')
    
    # get mapping of value to mark
    df2 = df.loc[:,["value","mark"]].drop_duplicates().sort_values("value")
    # change axis to text
    fig.update_layout(polar={"radialaxis":{"tickmode":"array","tickvals":df2["value"],"ticktext":df2["mark"]}})
    
    fig