import streamlit as st import pandas as pd from datetime import datetime import matplotlib.pyplot as plt import seaborn as sns import matplotlib.dates as mdates from matplotlib.patches import Patch # Set page configuration without the 'theme' argument st.set_page_config( page_title="Task Manager", page_icon="✅", layout="wide", initial_sidebar_state="expanded" ) st.text(" ") st.write("#") st.image("st.PNG", width=280) # Initialize session state to store tasks if 'tasks' not in st.session_state: st.session_state.tasks = [] # Function to add a new task def add_task(game_name, company, start_date, end_date, status, notes): st.session_state.tasks.append({ 'Game Name': game_name, 'Company': company, 'Start': start_date, 'Finish': end_date, 'Status': status, 'Notes': notes }) # Function to remove a task def remove_task(task_index): if 0 <= task_index < len(st.session_state.tasks): if st.sidebar.button(f"Confirm Delete Task {task_index}"): st.session_state.tasks.pop(task_index) st.success(f"Task {task_index} deleted permanently!") # Function to update a task def update_task(index, game_name, company, start_date, end_date, status, notes): if 0 <= index < len(st.session_state.tasks): st.session_state.tasks[index] = { 'Game Name': game_name, 'Company': company, 'Start': start_date, 'Finish': end_date, 'Status': status, 'Notes': notes } # Function to load tasks from a CSV file def load_tasks_from_csv(uploaded_file): df = pd.read_csv(uploaded_file) for _, row in df.iterrows(): add_task( row['Game Name'], row['Company'], pd.to_datetime(row['Start']), pd.to_datetime(row['Finish']), row['Status'], row['Notes'] ) # Function to clear tasks from session state def clear_tasks(): if st.sidebar.button("Confirm Clear All Tasks"): st.session_state.tasks = [] st.success("All tasks cleared permanently!") # Sidebar for adding new tasks with st.sidebar: st.header("Add New Task") game_name = st.text_input("Game Name", key="add_game_name") company = st.text_input("Company", key="add_company") start_date = st.date_input("Start Date", min_value=datetime.now(), key="add_start_date") end_date = st.date_input("End Date", min_value=start_date, key="add_end_date") status = st.selectbox( "Status", ["Not Started", "In Progress", "Completed", "Hold", "Delayed"], key="add_status" ) notes = st.text_area("Notes", key="add_notes") if st.button("Add Task", key="add_task_button"): add_task(game_name, company, start_date, end_date, status, notes) st.success("Task added successfully!") # Sidebar for uploading tasks from a file with st.sidebar: st.header("Upload Tasks from File") uploaded_file = st.file_uploader("Upload a CSV file", type=["csv"], key="file_uploader") if uploaded_file is not None: load_tasks_from_csv(uploaded_file) st.success("Tasks loaded successfully!") # Sidebar for managing tasks with st.sidebar: st.header("Manage Tasks") task_action = st.radio("Choose Action", ("None", "Edit Task", "Delete Task"), key="task_action") if task_action != "None" and st.session_state.tasks: task_names = [ f"{task['Game Name']} - {task['Start'].strftime('%b %Y')} to {task['Finish'].strftime('%b %Y')}" for task in st.session_state.tasks ] selected_task_index = st.selectbox( "Select Task", range(len(task_names)), format_func=lambda x: task_names[x], key="select_task" ) if task_action == "Edit Task": st.write("Editing Task:", task_names[selected_task_index]) edit_game_name = st.text_input( "Game Name", value=st.session_state.tasks[selected_task_index]['Game Name'], key="edit_game_name" ) edit_company = st.text_input( "Company", value=st.session_state.tasks[selected_task_index]['Company'], key="edit_company" ) edit_start_date = st.date_input( "Start Date", value=st.session_state.tasks[selected_task_index]['Start'], key="edit_start_date" ) edit_end_date = st.date_input( "End Date", value=st.session_state.tasks[selected_task_index]['Finish'], key="edit_end_date" ) edit_status = st.selectbox( "Status", ["Not Started", "In Progress", "Completed", "Hold", "Delayed"], index=["Not Started", "In Progress", "Completed", "Hold", "Delayed"].index( st.session_state.tasks[selected_task_index]['Status'] ), key="edit_status" ) edit_notes = st.text_area( "Notes", value=st.session_state.tasks[selected_task_index]['Notes'], key="edit_notes" ) if st.button("Update Task", key="update_task_button"): update_task( selected_task_index, edit_game_name, edit_company, edit_start_date, edit_end_date, edit_status, edit_notes ) st.success("Task updated successfully!") elif task_action == "Delete Task": st.write("Deleting Task:", task_names[selected_task_index]) remove_task(selected_task_index) # Clear the selection selected_task_index = None elif not st.session_state.tasks: st.write("No tasks available to edit or delete.") # Button to clear tasks from memory with st.sidebar: if st.button("Clear All Tasks"): clear_tasks() # Create DataFrame for the Gantt chart if st.session_state.tasks: df = pd.DataFrame(st.session_state.tasks) df['Start'] = pd.to_datetime(df['Start']) df['Finish'] = pd.to_datetime(df['Finish']) # Custom color map for task statuses color_discrete_map = { "Not Started": "lightblue", "In Progress": "blue", "Completed": "green", "Hold": "tan", "Delayed": "red" } # Create Gantt chart with Matplotlib fig, ax = plt.subplots(figsize=(12, 6), facecolor='black') # Set figure background to dark # Set axes background to dark ax.set_facecolor('black') # Plot each task as a horizontal bar for i, task in df.iterrows(): ax.barh( task['Game Name'], (task['Finish'] - task['Start']).days, left=task['Start'].to_pydatetime(), color=color_discrete_map.get(task['Status'], 'gray'), edgecolor='white' # Optional: add edge color for better separation ) # Set labels and title with white color and clear font ax.set_xlabel('Time', color='white', fontsize=14, fontweight='bold') ax.set_ylabel('Game Name', color='white', fontsize=14, fontweight='bold') ax.set_title('Project Timelines', color='white', fontsize=18, fontweight='bold') # Format the x-axis to show month and year ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y')) ax.xaxis.set_major_locator(mdates.MonthLocator(interval=1)) # Set the interval of the ticks # Rotate x-axis labels for better readability and set color to white plt.xticks(rotation=45, color='white') # Set y-axis tick labels to white plt.yticks(color='white', fontsize=12) # Set x-axis tick labels to white ax.tick_params(axis='x', colors='white', labelsize=12) ax.tick_params(axis='y', colors='white', labelsize=12) # Set the spine colors to white for spine in ax.spines.values(): spine.set_color('white') # Add gridlines (optional: customize as needed) ax.grid(True, which='both', axis='x', color='gray', linestyle='--', linewidth=0.5) # Add a legend with white font legend_elements = [Patch(facecolor=color_discrete_map[status], edgecolor='white', label=status) for status in color_discrete_map] ax.legend(handles=legend_elements, title="Status", title_fontsize='13', fontsize='12', loc='upper right', facecolor='black', edgecolor='white', labelcolor='white') # Adjust layout for better spacing plt.tight_layout() # Display the Gantt chart st.write("Progress Updates") st.pyplot(fig) # Convert DataFrame to CSV csv = df.to_csv(index=False) st.sidebar.download_button( label="Download CSV", data=csv, file_name='tasks.csv', mime='text/csv', key="download_csv_button" ) else: st.write("No tasks to display in the timeline chart.") # Bar chart of task statuses using Seaborn if st.session_state.tasks: status_counts = df['Status'].value_counts().reset_index() status_counts.columns = ['Status', 'Count'] fig, ax = plt.subplots(figsize=(10, 5), facecolor='black') # Set figure background to dark ax.set_facecolor('black') sns.barplot( x='Status', y='Count', data=status_counts, palette=[color_discrete_map.get(status, 'gray') for status in status_counts['Status']], ax=ax ) # Set labels and title with white color and clear font ax.set_title('Task Status Distribution', color='white', fontsize=16, fontweight='bold') ax.set_ylabel('Game Count', color='white', fontsize=14, fontweight='bold') ax.set_xlabel('Status', color='white', fontsize=14, fontweight='bold') # Set tick parameters for better readability ax.tick_params(axis='x', colors='white', labelsize=12) ax.tick_params(axis='y', colors='white', labelsize=12) # Set the spine colors to white for spine in ax.spines.values(): spine.set_color('white') # Add a legend with white font legend_elements = [Patch(facecolor=color_discrete_map[status], edgecolor='white', label=status) for status in color_discrete_map] ax.legend(handles=legend_elements, title="Status", title_fontsize='13', fontsize='12', loc='upper right', facecolor='black', edgecolor='white', labelcolor='white') # Adjust layout for better spacing plt.tight_layout() # Display the bar chart st.pyplot(fig) # Final save and load buttons st.write("Save files, edit and load from sidebar") st.info("Built by dw 8-27-24")