standard app name
This commit is contained in:
214
habits.py
214
habits.py
@ -1,214 +0,0 @@
|
|||||||
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