standard app name
This commit is contained in:
		
							
								
								
									
										214
									
								
								app.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								app.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,214 @@ | |||||||
|  | import pandas as pd  | ||||||
|  | import vobject | ||||||
|  | import requests | ||||||
|  | from datetime import datetime, date | ||||||
|  | import matplotlib.pyplot as plt | ||||||
|  | import calmap | ||||||
|  | import streamlit as st  | ||||||
|  | import plotly.express as px | ||||||
|  | import plotly.graph_objects as go | ||||||
|  | import json | ||||||
|  | import os | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Function to load data from a JSON file | ||||||
|  | def load_data(file_path): | ||||||
|  |     try: | ||||||
|  |         with open(file_path, 'r') as file: | ||||||
|  |             if os.path.getsize(file_path) == 0: return {} | ||||||
|  |             return json.load(file) | ||||||
|  |     except FileNotFoundError: | ||||||
|  |         print("settings file not found") | ||||||
|  |         return {} | ||||||
|  |     except : | ||||||
|  |         print("settings file invalid") | ||||||
|  |         return {} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Function to save data to a JSON file | ||||||
|  | def save_data(file_path, data): | ||||||
|  |     with open(file_path, 'w') as file: | ||||||
|  |         json.dump(data, file) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Function to create a calendar heatmap for a specific year | ||||||
|  | def create_calendar_heatmap(event_series, year): | ||||||
|  |     # Filter the series to include only the specific year | ||||||
|  |     event_series_year = event_series[event_series.index.year == year] | ||||||
|  |  | ||||||
|  |     # Create a complete date range for the year | ||||||
|  |     all_dates_year = pd.date_range(start=f'{year}-01-01', end=f'{year}-12-31') | ||||||
|  |  | ||||||
|  |     # Reindex the Series to include all dates in the year and fill missing dates with zero | ||||||
|  |     event_series_year = event_series_year.reindex(all_dates_year, fill_value=0) | ||||||
|  |  | ||||||
|  |     # Create a DataFrame for Plotly | ||||||
|  |     df_year = pd.DataFrame({'Date': event_series_year.index, 'Events': event_series_year.values}) | ||||||
|  |  | ||||||
|  |     # Generate day of the week and week of the year | ||||||
|  |     df_year['DayOfWeek'] = df_year['Date'].dt.dayofweek | ||||||
|  |     df_year['WeekOfYear'] = df_year['Date'].dt.isocalendar().week | ||||||
|  |     df_year['Month'] = df_year['Date'].dt.strftime('%b') | ||||||
|  |  | ||||||
|  |     # Create the Plotly figure | ||||||
|  |     fig = go.Figure(data=go.Heatmap( | ||||||
|  |         z=df_year['Events'], | ||||||
|  |         x=df_year['WeekOfYear'], | ||||||
|  |         y=df_year['DayOfWeek'], | ||||||
|  |         colorscale='YlGn', | ||||||
|  |         showscale=True, | ||||||
|  |         colorbar=dict( | ||||||
|  |             title='# of Events', | ||||||
|  |             orientation='h',  # Set the color scale to horizontal | ||||||
|  |             len=0.3,  # Adjust the length of the color scale | ||||||
|  |             thickness=10, | ||||||
|  |             x=0.98, | ||||||
|  |             y=1, | ||||||
|  |             xanchor="right", | ||||||
|  |             yanchor="bottom",  # Position the color scale at the bottom | ||||||
|  |         ), | ||||||
|  |         hoverinfo='z+x+y' | ||||||
|  |     )) | ||||||
|  |  | ||||||
|  |     # Set the aspect ratio to ensure square boxes | ||||||
|  |     fig.update_yaxes(scaleanchor="x", scaleratio=1, constrain="domain") | ||||||
|  |  | ||||||
|  |     # Update the layout with the axes | ||||||
|  |     fig.update_layout( | ||||||
|  |         title=f'Calendar Heatmap for {year}', | ||||||
|  |         yaxis=dict( | ||||||
|  |             tickmode='array', | ||||||
|  |             tickvals=[0, 1, 2, 3, 4, 5, 6], | ||||||
|  |             ticktext=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'], | ||||||
|  |             range=[-1.2, 6.5], # Adjust the range to eliminate space | ||||||
|  |             automargin=True, # Adjust margins automatically  | ||||||
|  |             domain=[0.1,0.95] # Use available space effectively | ||||||
|  |         ), | ||||||
|  |         xaxis=dict( | ||||||
|  |             tickmode='array', | ||||||
|  |             tickvals=list(range(1, 54)), | ||||||
|  |             ticktext=list(range(1, 54)), | ||||||
|  |             title=dict( | ||||||
|  |                 text='Weeks of the Year', | ||||||
|  |                 standoff=0 | ||||||
|  |             ), | ||||||
|  |             title_standoff=0,  # Adjust the distance of the title from the axis | ||||||
|  |             tickangle=-90,  # Adjust the angle of the week numbers | ||||||
|  |             ticklen=2, | ||||||
|  |             side='top', # Display x-axis ticks above the heatmap | ||||||
|  |             automargin=True, # Adjust margins automatically | ||||||
|  |         ), | ||||||
|  |         autosize=True, | ||||||
|  |         margin=dict( | ||||||
|  |             l=50, | ||||||
|  |             r=50, | ||||||
|  |             b=30,  # Increase bottom margin to fit month names | ||||||
|  |             t=30,  # Increase top margin to fit week numbers | ||||||
|  |             pad=0 | ||||||
|  |         ), | ||||||
|  |         height=450, # Fixed height to avoid excessive space | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     # Add month annotations with arrows at the bottom | ||||||
|  |     month_starts = df_year.iloc[:-10].groupby('Month')['WeekOfYear'].min().to_dict() | ||||||
|  |     for month, week in month_starts.items(): | ||||||
|  |         fig.add_annotation( | ||||||
|  |             x=week, | ||||||
|  |             y=-0.5,  # Position below the x-axis | ||||||
|  |             text=month, | ||||||
|  |             showarrow=False, | ||||||
|  |             arrowhead=2, | ||||||
|  |             ax=week, | ||||||
|  |             ay=0,  # Position the arrow closer | ||||||
|  |             xref="x", | ||||||
|  |             yref="y", | ||||||
|  |             #font=dict(size=12, color="black"), | ||||||
|  |             xanchor='left', | ||||||
|  |             yanchor='top' | ||||||
|  |         ) | ||||||
|  |      | ||||||
|  |     return fig | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def save_load(): | ||||||
|  |     st.session_state['options'].pop("New") | ||||||
|  |     save_data(settings_file, st.session_state['options']) | ||||||
|  |     st.session_state['options'] = load_data(settings_file) | ||||||
|  |      | ||||||
|  | def update_params(): | ||||||
|  |     st.session_state['cal_url'] = st.session_state['options'][st.session_state['setup']]['cal_url'] | ||||||
|  |     st.session_state['number_of_years'] = st.session_state['options'][st.session_state['setup']]['number_of_years'] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # set webpage title | ||||||
|  | st.title("Yearly Activity Heatmaps") | ||||||
|  |  | ||||||
|  | # File path for data storage | ||||||
|  | settings_file = 'settings.json' | ||||||
|  | # Load persisted data if it exists; set default values otherwise | ||||||
|  | st.session_state['options'] = load_data(settings_file) | ||||||
|  | st.session_state['options']["New"] = { | ||||||
|  |     'cal_url':"https://canada-holidays.ca/ics?cd=true", | ||||||
|  |     'number_of_years': 3 | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | # Get the Calendar Export link and number of years from sidebar menu | ||||||
|  | st.sidebar.header("Settings") | ||||||
|  | st.session_state['setup'] = st.sidebar.selectbox("Choose a Setup:", st.session_state['options'].keys()) | ||||||
|  | st.session_state['cal_url'] = st.sidebar.text_input("Enter The Calendar Export Link:", value=st.session_state['options'][st.session_state['setup']]['cal_url']) | ||||||
|  | st.session_state['number_of_years'] = st.sidebar.number_input("Enter the number of years:", min_value=1, max_value=10, value=st.session_state['options'][st.session_state['setup']]['number_of_years']) | ||||||
|  | update_params() | ||||||
|  | if(st.session_state['setup'] == "New"): | ||||||
|  |     setup_save_name = st.sidebar.text_input("Setup Save Name:", value='yahoo') | ||||||
|  |     st.session_state['options'][setup_save_name] = { | ||||||
|  |         'cal_url': st.session_state['cal_url'], | ||||||
|  |         'number_of_years': st.session_state['number_of_years'] | ||||||
|  |     } | ||||||
|  |     st.sidebar.button("Save",on_click=save_load) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | response = requests.get(st.session_state['cal_url']) | ||||||
|  | if response.status_code == 200: | ||||||
|  |     # Parse the .ics file | ||||||
|  |     cal = vobject.readOne(response.text) | ||||||
|  | else: | ||||||
|  |     print("Failed to download the file") | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Create a dictionary to store event counts by date | ||||||
|  | event_counts = {} | ||||||
|  | for component in cal.components(): | ||||||
|  |     if component.name == "VEVENT": | ||||||
|  |         event_date = component.dtstart.value | ||||||
|  |         if isinstance(event_date, datetime): | ||||||
|  |             event_date = event_date.date() | ||||||
|  |         if event_date in event_counts: | ||||||
|  |             event_counts[event_date] += 1 | ||||||
|  |         else: | ||||||
|  |             event_counts[event_date] = 1 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Convert the dictionary to a pandas Series | ||||||
|  | event_series = pd.Series(event_counts) | ||||||
|  | # Ensure the index is in datetime format | ||||||
|  | event_series.index = pd.to_datetime(event_series.index) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Get the current year | ||||||
|  | current_year = datetime.now().year | ||||||
|  | # Create a list of years to plot | ||||||
|  | years_to_plot = [current_year - i for i in range(st.session_state['number_of_years'])] | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Plot each year's data | ||||||
|  | for year in years_to_plot: | ||||||
|  |     fig = create_calendar_heatmap(event_series, year) | ||||||
|  |     st.plotly_chart(fig) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user