How to adjust the bars in the chart based on the subset condition

I am facing an issue as shown in the image below, i am trying to generate the bar chart based on the treatments as group, based on the drop down, if i unselect a treatment the bar should disappear and show the bars of remaining treatments, however when i unselect a treatment, there are gaps created. how to avoid them, please help

def plot_(data, selected_trt):
    """
    Function to plot a bar chart without markers initially and dynamically add markers
    based on selected AVALC values.
    
    Parameters:
    - data (pd.DataFrame): The DataFrame containing the data.
    - selected_avalc (list): A list of AVALC values for which symbols will be used in the plot.
    """
    import matplotlib.pyplot as plt
    from matplotlib.lines import Line2D
    import streamlit as st

    # Create the bar chart
    plt.figure(figsize=(10, 20))
    # plt.barh(data['USUBJID_numeric'], data['max_ady'], color='skyblue', edgecolor='black', alpha=0.8)
    # Use seaborn's barplot to color bars by treatment group
    # Define a color mapping for treatment groups
    treatment_colors = {
        'TRT-0': '#ADD8E6',
        # 'TRT--1': '#90EE90',
        'TRT-1': '#E6E6FA',
        'TRT-2': '#FFDAB9',
        'TRT-3': '#EEE8AA',
        'TRT-4': '#FFE4E1',
        'TRT-5': '#FFE4E1',
        'TRT-6': '#FFE4E1',
        'TRT-7': '#FFE4E1',
        'TRT-8': '#FFE4E1',
        'TRT-9': '#FFE4E1',
        'TRT-10': '#FFE4E1',
        'TRT-11': '#FFE4E1',
        'TRT-12': '#FFE4E1',
        'TRT-13': '#FFE4E1',
        }

    data = data[data['TRT01P'].isin(selected_trt)]
    # Assign colors based on the treatment group
    data['color'] = data['TRT01P'].map(treatment_colors)
    xupper = data['max_ady'].max()

    # Create the bar chart
    plt.figure(figsize=(10, 7))

    for _, row in data.iterrows():
        plt.barh(
        row['USUBJID_numeric'],  # Subject on the y-axis
        row['max_ady'],          # Days of treatment on the x-axis
        color=row['color'],      # Color based on treatment group
        edgecolor='black',
        alpha=0.8
        )

    legend_elements = [
        Line2D([0], [0], color=color, lw=4, label=treatment)
        for treatment, color in treatment_colors.items()
    ]
    plt.legend(handles=legend_elements, title='Treatments', loc='best')
    # Update the y-axis ticks to show original USUBJID values
    plt.yticks(data['USUBJID_numeric'], data['USUBJID'])

    # Add labels and title
    plt.xlabel('Days of Treatment')
    plt.ylabel('Subjects')
    # plt.title('Swimmer Plot for Treatment Exposure')
    # Adjust axis limits to start at (0, 0)
    plt.margins(x=0, y=0.01)
    ax = plt.gca()
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    plt.xlim(0, xupper+100) 

    # Display the plot in Streamlit
    st.pyplot(plt.gcf())

selected_trt = st.sidebar.multiselect("Select Responses to Highlight", options=unique_trt, default=unique_trt)
  df = df[df['TRT01P'].isin(selected_trt)]
                plot_(df,selected_trt)

You are giving specific locations on the y-axis to position each bar in the plot. To have them sequentially positioned, you could pass a dummy range, something like:

dummy_yaxis = np.arange(len(row['USUBJID_numeric']))

ax.barh(
    dummy_yaxis,
    data['max_ady'],
    color=data['color']
    ...
)

instead. The tick labels won’t be meaningful though, so will have to modify them:

ax.set_yticks(dummy_yaxis)   # it will add a tick to every bar
ax.set_yticklabels(filtered["USUBJID"].astype(str), fontsize=6)

pd. there is no need to add each individual bar iterating through each row in the dataframe, you can pass Series as arguments to ax.barh.

Thank you @edsaac for your response. The issue is resolved when i re-derived the USUBJID_numeric after the subset

df2['USUBJID_numeric'] = pd.Categorical(df2['USUBJID']).codes

TIL categorical values work directly as axis’ values!
https://matplotlib.org/stable/gallery/lines_bars_and_markers/categorical_variables.html

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.