|
import streamlit as st |
|
import pandas as pd |
|
import plotly.express as px |
|
import plotly.graph_objects as go |
|
from comparison import ModelEvaluator, ModelComparison |
|
import matplotlib.pyplot as plt |
|
import seaborn as sns |
|
import io |
|
import os |
|
import base64 |
|
|
|
st.set_page_config( |
|
page_title="Nexar Dashcam Leaderboard", |
|
page_icon="nexar_logo.png", |
|
layout="wide" |
|
) |
|
|
|
st.markdown(""" |
|
<style> |
|
.main { padding: 2rem; } |
|
.stTabs [data-baseweb="tab-list"] { gap: 8px; } |
|
.stTabs [data-baseweb="tab"] { |
|
padding: 8px 16px; |
|
border-radius: 4px; |
|
} |
|
.metric-card { |
|
background-color: #f8f9fa; |
|
padding: 20px; |
|
border-radius: 10px; |
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1); |
|
} |
|
</style> |
|
""", unsafe_allow_html=True) |
|
|
|
col1, col2 = st.columns([0.15, 0.85]) |
|
with col1: |
|
st.image("nexar_logo.png", width=600) |
|
with col2: |
|
st.title("Nexar Dashcam Leaderboard") |
|
|
|
@st.cache_data |
|
def load_data(directory='results', labels_filename='Labels.csv'): |
|
labels_path = os.path.join(directory, labels_filename) |
|
df_labels = pd.read_csv(labels_path) |
|
|
|
evaluators = [] |
|
|
|
for filename in os.listdir(directory): |
|
if filename.endswith('.csv') and filename != labels_filename: |
|
model_name = os.path.splitext(filename)[0] |
|
df_model = pd.read_csv(os.path.join(directory, filename)) |
|
evaluator = ModelEvaluator(df_labels, df_model, model_name) |
|
evaluators.append(evaluator) |
|
|
|
model_comparison = ModelComparison(evaluators) |
|
|
|
return model_comparison |
|
|
|
if 'model_comparison' not in st.session_state: |
|
st.session_state.model_comparison = load_data() |
|
st.session_state.leaderboard_df = st.session_state.model_comparison.transform_to_leaderboard() |
|
st.session_state.combined_df = st.session_state.model_comparison.combined_df |
|
|
|
tab1, tab2, tab3, tab4 = st.tabs([ |
|
"π Leaderboard", |
|
"π― Category Analysis", |
|
"π Class Performance", |
|
"π Detailed Metrics" |
|
]) |
|
|
|
def style_dataframe(df): |
|
numeric_cols = df.select_dtypes(include=['float64']).columns |
|
|
|
def background_gradient(s): |
|
normalized = (s - s.min()) / (s.max() - s.min()) |
|
normalized = normalized.fillna(0) |
|
return ['background: linear-gradient(90deg, rgba(52, 152, 219, 0.2) {}%, transparent {}%)'.format( |
|
int(val * 100), int(val * 100)) for val in normalized] |
|
|
|
def highlight_max(s): |
|
is_max = s == s.max() |
|
return ['font-weight: bold; color: #2ecc71' if v else '' for v in is_max] |
|
|
|
styled = df.style\ |
|
.format({col: '{:.2f}%' for col in numeric_cols})\ |
|
.apply(background_gradient, subset=numeric_cols)\ |
|
.apply(highlight_max, subset=numeric_cols)\ |
|
.set_properties(**{ |
|
'background-color': '#f8f9fa', |
|
'padding': '10px', |
|
'border': '1px solid #dee2e6', |
|
'text-align': 'center' |
|
})\ |
|
.set_table_styles([ |
|
{'selector': 'th', 'props': [ |
|
('background-color', '#4a90e2'), |
|
('color', 'white'), |
|
('font-weight', 'bold'), |
|
('padding', '10px'), |
|
('text-align', 'center') |
|
]}, |
|
{'selector': 'tr:hover', 'props': [ |
|
('background-color', '#edf2f7') |
|
]} |
|
]) |
|
|
|
return styled |
|
|
|
with tab1: |
|
st.subheader("Model Performance Leaderboard") |
|
|
|
sort_col = st.selectbox( |
|
"Sort by metric:", |
|
options=[col for col in st.session_state.leaderboard_df.columns if col not in ['Rank', 'Model']], |
|
key='leaderboard_sort' |
|
) |
|
|
|
sorted_df = st.session_state.leaderboard_df.sort_values(by=sort_col, ascending=False) |
|
st.dataframe( |
|
style_dataframe(sorted_df), |
|
use_container_width=True, |
|
height=400 |
|
) |
|
|
|
|
|
metrics = ['F1 Score', 'Precision', 'Recall'] |
|
selected_metric = st.selectbox("Select Metric for Category Analysis:", metrics) |
|
|
|
category_data = st.session_state.combined_df[ |
|
st.session_state.combined_df['Class'].str.contains('Overall') |
|
] |
|
|
|
fig = px.bar( |
|
category_data, |
|
x='Category', |
|
y=selected_metric, |
|
color='Model', |
|
barmode='group', |
|
title=f'Category-level {selected_metric} by Model', |
|
) |
|
|
|
fig.update_layout( |
|
xaxis_title="Category", |
|
yaxis_title=selected_metric, |
|
legend_title="Model" |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
with tab2: |
|
st.subheader("Category-level Analysis") |
|
|
|
categories = st.session_state.combined_df['Category'].unique() |
|
selected_category = st.selectbox("Select Category:", categories) |
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
category_data = st.session_state.combined_df[ |
|
st.session_state.combined_df['Class'].str.contains('Overall') |
|
] |
|
|
|
fig = px.bar( |
|
category_data, |
|
x='Category', |
|
y=selected_metric, |
|
color='Model', |
|
barmode='group', |
|
title=f'{selected_metric} by Category' |
|
) |
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
with col2: |
|
cat_data = st.session_state.combined_df[ |
|
(st.session_state.combined_df['Category'] == selected_category) & |
|
(~st.session_state.combined_df['Class'].str.contains('Overall')) |
|
] |
|
|
|
fig = go.Figure() |
|
|
|
for model in cat_data['Model'].unique(): |
|
model_data = cat_data[cat_data['Model'] == model] |
|
fig.add_trace(go.Scatterpolar( |
|
r=model_data[selected_metric], |
|
theta=model_data['Class'], |
|
name=model, |
|
fill='toself' |
|
)) |
|
|
|
fig.update_layout( |
|
polar=dict( |
|
radialaxis=dict( |
|
visible=True, |
|
range=[0, 1] |
|
) |
|
), |
|
showlegend=True, |
|
title=f'{selected_metric} Distribution for {selected_category}' |
|
) |
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
with tab3: |
|
st.subheader("Class-level Performance") |
|
|
|
col1, col2, col3 = st.columns(3) |
|
with col1: |
|
selected_category = st.selectbox( |
|
"Select Category:", |
|
categories, |
|
key='class_category' |
|
) |
|
with col2: |
|
selected_metric = st.selectbox( |
|
"Select Metric:", |
|
metrics, |
|
key='class_metric' |
|
) |
|
with col3: |
|
selected_models = st.multiselect( |
|
"Select Models:", |
|
st.session_state.combined_df['Model'].unique(), |
|
default=st.session_state.combined_df['Model'].unique() |
|
) |
|
|
|
class_data = st.session_state.combined_df[ |
|
(st.session_state.combined_df['Category'] == selected_category) & |
|
(~st.session_state.combined_df['Class'].str.contains('Overall')) & |
|
(st.session_state.combined_df['Model'].isin(selected_models)) |
|
] |
|
|
|
fig = px.bar( |
|
class_data, |
|
x='Class', |
|
y=selected_metric, |
|
color='Model', |
|
barmode='group', |
|
title=f'{selected_metric} by Class for {selected_category}' |
|
) |
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
fig = px.scatter( |
|
class_data, |
|
x='Precision', |
|
y='Recall', |
|
color='Model', |
|
size='Support', |
|
hover_data=['Class'], |
|
title=f'Precision vs Recall for {selected_category}' |
|
) |
|
fig.update_traces(marker=dict(sizeref=2.*max(class_data['Support'])/40.**2)) |
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
with tab4: |
|
st.subheader("Detailed Metrics Analysis") |
|
|
|
selected_model = st.selectbox( |
|
"Select Model for Detailed Analysis:", |
|
st.session_state.combined_df['Model'].unique() |
|
) |
|
|
|
model_data = st.session_state.combined_df[ |
|
st.session_state.combined_df['Model'] == selected_model |
|
] |
|
|
|
st.markdown("### Detailed Metrics Table") |
|
detailed_metrics = model_data.pivot_table( |
|
index='Category', |
|
columns='Class', |
|
values=['F1 Score', 'Precision', 'Recall'] |
|
).round(4) |
|
|
|
st.dataframe(style_dataframe(detailed_metrics), use_container_width=True) |
|
|
|
csv = detailed_metrics.to_csv().encode() |
|
st.download_button( |
|
"Download Detailed Metrics", |
|
csv, |
|
f"detailed_metrics_{selected_model}.csv", |
|
"text/csv", |
|
key='download-csv' |
|
) |
|
|
|
st.markdown("---") |
|
st.markdown("Dashboard created for model evaluation and comparison.") |