add another column as second X axis label in Python

63 Views Asked by At

I have a 15minutes interval time series for several camera. each camera can collect 3 types of movement in four different leg. There is a control_factor that was present for an hour for each camera. I want to show the total of counts in each leg for each camera (each camera in separate plots ) for every 15minutes. and in the x axis, which is the time, next to each time, or under, I want to write yes, if the factor is true and no if the factor is false.

You can create the data using the following lines.

import pandas as pd
from datetime import datetime, timedelta
import matplotlib.pyplot as plt

# Function to create date range with 15-minute intervals
def create_date_range(start_date, end_date, interval):
    date_range = []
    current_date = start_date
    while current_date <= end_date:
        date_range.append(current_date)
        current_date += interval
    return date_range

# Function to create DataFrame
def create_dataframe(start_date, end_date, interval):
    date_range = create_date_range(start_date, end_date, interval)

    data = []
    for date_time in date_range:
        for camera in range(1, 5):
            for leg in range(1, 5):
                for movement in range(1, 4):
                    count = 1  # You can set count based on your requirements
                    control_factor = True if date_time.hour == 14 and camera == 1 else False
                    data.append([date_time, f'Cam{camera}', f'Leg{leg}', f'Move{movement}', count, control_factor])

    columns = ['DateTime', 'Camera', 'Leg', 'Movement', 'Count', 'control_factor']
    df = pd.DataFrame(data, columns=columns)
    return df

# Set start and end dates
start_date = datetime(2024, 1, 27, 14, 0, 0)
end_date = datetime(2024, 1, 27, 16, 0, 0)

# Set time interval
interval = timedelta(minutes=15)

# Create DataFrame
df = create_dataframe(start_date, end_date, interval)

# Display DataFrame
print(df)

I tried the plot:

# List of unique cameras in your data
unique_cameras = df['Camera'].unique()

# Iterate over each camera
for camera in unique_cameras:
    # Filter data for the current camera
    df_camera = df[df['Camera'] == camera]

    # Group by DateTime, Leg, and Movement, summing the counts and taking the first control_factor value
    grouped_df = df_camera.groupby(['DateTime', 'Leg', 'Movement'])[['Count', 'control_factor']].agg({'Count': 'sum', 'control_factor': 'first'}).reset_index()

    # Plot the data
    plt.figure(figsize=(15, 8))
    ax = sns.barplot(x='DateTime', y='Count', hue='Leg', data=grouped_df, ci=None)

    # Rotate x-axis labels for better visibility
    ax.set_xticklabels(ax.get_xticklabels(), rotation=45, ha='right')

    plt.title(f'Sum of Counts for Each Leg Over Time ({camera})')
    plt.xlabel('Time')
    plt.ylabel('Sum of Counts')

    # Annotate bars with control_factor values
    for index, row in grouped_df.iterrows():
        plt.text(index, row['Count'], str(row['control_factor']), ha='center', va='bottom')

    plt.show()

it shows true or false over each bar, but I want it under the x axis along with the time. I also want to make the colours like lighter for those bars with control-factor = False. Just same colour as the other bars, but a bit lighter.

Here is what I am trying to do!

enter image description here

I am open to use other library as well.

1

There are 1 best solutions below

2
Suraj Shourie On

You get weird-looking graphs that extend to infinity on the x-axis because of this line of code, where you are looping through each row item, which is not necessary :

    # # Annotate bars with control_factor values
for index, row in grouped_df.iterrows():
plt.text(index, row['Count'], str(row['control_factor']), ha='center', va='bottom')
  1. To change color see the palette argument in seaborn documentation

I'm using palette = 'muted' in the plot below

  1. To change the x-axis labels to control-factors update your set_xticklabels line. I'm using the first control factor for each date, but you might have to change that if you expect duplicates
labs = grouped_df.groupby('DateTime').agg({'control_factor':'first'})['control_factor'].to_list()
ax.set_xticklabels(labs, rotation=45, ha='right')

Resulting plot:

enter image description here

enter image description here