Search code examples
pythonexpressplotlyline

Create line chart with same color for each row group and different line styles for columns


I have the dataframe df as shown below. What do I have to change, that each run has its own line (color) and the values from column "Val_B" are dashed, and "Val_A" solid?

import pandas as pd
import plotly.express as px


df = pd.DataFrame(
    {
        "Run": (
            1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6
        ),
        "Point": (
            1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3,
        ),
        "Val_A": (
            78, 79, 77, 78, 79, 77, 78, 79, 77, 78, 79, 77, 78, 79, 77, 78, 79, 77,
        ),
        "Val_B": (
            76, 75, 74, 76, 75, 74, 76, 75, 74, 76, 75, 74, 76, 75, 74, 76, 75, 74,
        ),
    }
)

# Create the line plot with solid line for Val_A and dashed line for Val_B
fig = px.line(df, x="Point", y=["Val_A", "Val_B"], color="Run",
              title="Line Plot with Solid and Dashed Lines for Each Run")

# Show the plot
fig.show()

So I should end up with a plot, with 12 lines, 6 colors and two line styles.


Solution

  • Since express does not allow detailed settings, I used a graph object. Extract the data by row category in a data frame and draw a line graph with the data. There are two types of line graph targets, so we specify two types. Specify a different line type for each. Specify the color to be the same color with a loop counter. Also, since the two types of legends are enumerated as they are, they are grouped together and used as a legend for each value. If you do not need the grouping, disable it.

    import plotly.graph_objects as go
    import plotly.express as px
    
    colors = px.colors.qualitative.Plotly
    
    fig = go.Figure()
    
    for i,r in enumerate(df['Run'].unique()):
        dff = df.query('Run == @r')
        fig.add_trace(go.Scatter(
            x=dff['Point'],
            y=dff['Val_A'],
            mode='lines',
            name=str(r),
            legendgroup='Val_A',
            legendgrouptitle=dict(text='Val_A'),
            line=dict(color=colors[i])))
        fig.add_trace(go.Scatter(
            x=dff['Point'],
            y=dff['Val_B'],
            mode='lines',
            name=str(r),
            legendgroup='Val_B',
            legendgrouptitle=dict(text='Val_B'),
            line=dict(color=colors[i],dash='dash')
                     ))
    
    fig.update_layout(height=500, xaxis_title='Point', yaxis_title='value')
    fig.show()
    

    enter image description here