Spaces:
Configuration error
Configuration error
| import streamlit as st | |
| import pandas as pd | |
| from datetime import datetime | |
| import plotly.express as px | |
| import plotly.graph_objects as go | |
| # Set page config | |
| st.set_page_config( | |
| page_title="License Plate Detection Results", | |
| page_icon="🚗", | |
| layout="wide" | |
| ) | |
| # Custom CSS | |
| st.markdown(""" | |
| <style> | |
| .metric-container { | |
| background-color: #f0f2f6; | |
| border-radius: 10px; | |
| padding: 15px; | |
| margin: 10px 0; | |
| } | |
| .stMetric { | |
| background-color: white !important; | |
| border-radius: 5px; | |
| padding: 10px; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.1); | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # Title and description | |
| st.title("📊 License Plate Detection Dashboard") | |
| st.markdown(""" | |
| This dashboard shows the results of license plate detections from video surveillance. | |
| """) | |
| # Load and process data | |
| def load_data(): | |
| try: | |
| df = pd.read_csv("car_plate_data_stored.csv") | |
| # Handle different column names | |
| if 'NumberPlate' in df.columns: | |
| df = df.rename(columns={'NumberPlate': 'ID'}) | |
| elif 'ImageFile' in df.columns: | |
| df = df.rename(columns={'ImageFile': 'ID'}) | |
| # Ensure we have all required columns | |
| if 'Confidence' not in df.columns: | |
| df['Confidence'] = 'N/A' | |
| # Convert dates | |
| df['DateTime'] = pd.to_datetime(df['Date'] + ' ' + df['Time'], | |
| format='%d-%m-%Y %H:%M:%S', | |
| dayfirst=True) | |
| return df | |
| except Exception as e: | |
| st.error(f"Error loading data: {str(e)}") | |
| return pd.DataFrame(columns=['ID', 'Date', 'Time', 'Confidence', 'DateTime']) | |
| # Load data | |
| df = load_data() | |
| # Dashboard layout | |
| col1, col2 = st.columns([2, 1]) | |
| with col1: | |
| # Statistics cards in a grid | |
| st.markdown('<div class="metric-container">', unsafe_allow_html=True) | |
| stat_col1, stat_col2, stat_col3 = st.columns(3) | |
| with stat_col1: | |
| st.metric("Total Detections", len(df)) | |
| with stat_col2: | |
| if not df.empty: | |
| numeric_conf = pd.to_numeric(df['Confidence'].replace('N/A', float('nan')), errors='coerce') | |
| avg_confidence = numeric_conf.mean() | |
| if pd.notnull(avg_confidence): | |
| st.metric("Average Confidence", f"{avg_confidence:.2f}%") | |
| else: | |
| st.metric("Average Confidence", "N/A") | |
| with stat_col3: | |
| if not df.empty: | |
| today = datetime.now().date() | |
| today_detections = df[pd.to_datetime(df['Date']).dt.date == today].shape[0] | |
| st.metric("Today's Detections", today_detections) | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| # Timeline chart | |
| if not df.empty: | |
| st.subheader("Detection Timeline") | |
| detections_by_time = df.groupby(df['DateTime'].dt.floor('H')).size().reset_index(name='count') | |
| fig = go.Figure() | |
| fig.add_trace(go.Scatter( | |
| x=detections_by_time['DateTime'], | |
| y=detections_by_time['count'], | |
| mode='lines+markers', | |
| line=dict(color='#1f77b4', width=2), | |
| marker=dict(size=6), | |
| name='Detections' | |
| )) | |
| fig.update_layout( | |
| title="Detections Over Time", | |
| xaxis_title="Time", | |
| yaxis_title="Number of Detections", | |
| height=400, | |
| hovermode='x unified', | |
| plot_bgcolor='white', | |
| paper_bgcolor='white', | |
| xaxis=dict( | |
| showgrid=True, | |
| gridcolor='#f0f0f0', | |
| ), | |
| yaxis=dict( | |
| showgrid=True, | |
| gridcolor='#f0f0f0', | |
| ) | |
| ) | |
| st.plotly_chart(fig, use_container_width=True) | |
| with col2: | |
| st.subheader("Recent Detections") | |
| if not df.empty: | |
| recent = df.tail(5) | |
| for _, row in recent.iterrows(): | |
| with st.container(): | |
| st.markdown(f""" | |
| <div style="padding: 10px; background-color: #f0f2f6; border-radius: 5px; margin: 5px 0;"> | |
| <p><strong>ID:</strong> {row['ID']}</p> | |
| <p><strong>Time:</strong> {row['Time']}</p> | |
| <p><strong>Confidence:</strong> {row['Confidence'] if row['Confidence'] != 'N/A' else 'N/A'}</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Data table with filters | |
| st.subheader("Detection Records") | |
| if not df.empty: | |
| col1, col2 = st.columns([1, 2]) | |
| with col1: | |
| date_filter = st.date_input( | |
| "Filter by date", | |
| pd.to_datetime(df['Date']).min() | |
| ) | |
| with col2: | |
| confidence_filter = st.slider( | |
| "Minimum confidence", | |
| 0.0, 100.0, 0.0, | |
| help="Filter detections by minimum confidence score" | |
| ) | |
| # Apply filters | |
| filtered_df = df[df['DateTime'].dt.date == date_filter] | |
| if confidence_filter > 0: | |
| numeric_conf = pd.to_numeric(filtered_df['Confidence'].replace('N/A', -1), errors='coerce') | |
| filtered_df = filtered_df[numeric_conf >= confidence_filter] | |
| # Display the filtered dataframe | |
| st.dataframe( | |
| filtered_df[['ID', 'Date', 'Time', 'Confidence']].style.format({ | |
| 'Confidence': lambda x: f"{x:.2f}%" if isinstance(x, (int, float)) else x | |
| }), | |
| use_container_width=True | |
| ) | |
| # Add summary statistics | |
| if not df.empty: | |
| st.subheader("Detection Statistics") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| # Detections by hour | |
| hourly_stats = df.groupby(df['DateTime'].dt.hour).size() | |
| fig = px.bar( | |
| x=hourly_stats.index, | |
| y=hourly_stats.values, | |
| labels={'x': 'Hour of Day', 'y': 'Number of Detections'}, | |
| title='Detections by Hour of Day' | |
| ) | |
| fig.update_layout(bargap=0.2) | |
| st.plotly_chart(fig, use_container_width=True) | |
| with col2: | |
| # Confidence distribution | |
| confidence_values = pd.to_numeric(df['Confidence'].replace('N/A', float('nan')), errors='coerce') | |
| confidence_values = confidence_values.dropna() | |
| if not confidence_values.empty: | |
| fig = px.histogram( | |
| confidence_values, | |
| nbins=20, | |
| labels={'value': 'Confidence Score', 'count': 'Number of Detections'}, | |
| title='Distribution of Confidence Scores' | |
| ) | |
| fig.update_layout(bargap=0.2) | |
| st.plotly_chart(fig, use_container_width=True) |