Skip to content
This repository was archived by the owner on Jun 20, 2023. It is now read-only.

Commit e45d9f4

Browse files
authored
Initial Commit
1 parent dfc0200 commit e45d9f4

File tree

64 files changed

+1635
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1635
-0
lines changed

5 - Julia/gitpersist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
gitpersist
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import streamlit as st
2+
3+
# ---- HEADER ----
4+
st.header(':mailbox: Get in Touch With Me!')
5+
6+
# ---- FORM ----
7+
# documentation: https://formsubmit.co
8+
contact_form = """
9+
<form action="https://formsubmit.co/[email protected]" method="POST">
10+
<input type="hidden" name="_captcha" value="false">
11+
<input type="text" name="name" placeholder="Your name" required>
12+
<input type="email" name="email" placeholder="Your email" required>
13+
<textarea name="message" placeholder="Details of your message" required></textarea>
14+
<button type="submit">Send</button>
15+
</form>
16+
"""
17+
18+
st.markdown(contact_form, unsafe_allow_html=True)
19+
20+
# ---- FORM STYLE ----
21+
def local_css(file_name):
22+
with open(file_name) as f:
23+
st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
24+
25+
local_css('./style/style.css')
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
input[type=text], input[type=email], textarea {
2+
width: 100%;
3+
padding: 12px;
4+
border: 1px solid #ccc;
5+
border-radius: 4px;
6+
box-sizing: border-box;
7+
margin-top: 6px;
8+
margin-bottom: 16px;
9+
resize: vertical;
10+
}
11+
12+
button[type=submit] {
13+
background-color: #0a394d;
14+
color: white;
15+
padding: 12px 20px;
16+
border: none;
17+
border-radius: 4px;
18+
cursor: pointer;
19+
transition: all 0.3s ease;
20+
}
21+
22+
button[type=submit]:hover {
23+
opacity: 0.75;
24+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
# Interactive Dashboard with Python – Streamlit
3+
4+
Sales Dashboard built in Python and the Streamlit library to visualize Excel data.
5+
6+
## Run the app
7+
```Powershell
8+
# vanilla terminal
9+
streamlit run app.py
10+
11+
# quit
12+
ctrl-c
13+
```
14+
15+
## Demo
16+
Sales Dashboard: https://www.salesdashboard.pythonandvba.com/
17+
18+
## Screenshot
19+
20+
![Dashboar Screenshot](https://content.screencast.com/users/jubbel3/folders/Snagit/media/64b4d64a-4e59-4bec-9f16-771eb1a99005/08.18.2021-19.50.jpg)
21+
22+
23+
## Author
24+
25+
- Sven from Coding Is Fun
26+
- YouTube: https://youtube.com/c/CodingIsFun
27+
- Website: https://pythonandvba.com
28+
29+
30+
31+
## Feedback
32+
33+
If you have any feedback, please reach out to me at [email protected]
34+
35+
36+
![Logo](https://www.pythonandvba.com/banner-img)
37+
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import pandas as pd # pip install pandas openpyxl
2+
import streamlit as st # pip install streamlit
3+
import plotly.express as px # pip install plotly-express
4+
5+
# Setting up the page
6+
#
7+
# Emojis: https://www.webfx.com/tools/emoji-cheat-sheet
8+
st.set_page_config(
9+
page_title='Sales Dashboard'
10+
, page_icon=':bar_chart:'
11+
, layout='wide'
12+
)
13+
14+
# Saving the dataframe into cache in order to
15+
# do not make streamlit reads the entire excel file
16+
# every time
17+
@st.cache
18+
def get_data_from_excel():
19+
# Reading the file
20+
df = pd.read_excel(
21+
io='supermarkt_sales.xlsx'
22+
, engine='openpyxl'
23+
, sheet_name='Sales'
24+
, skiprows=3
25+
, usecols='B:R'
26+
, nrows=1000
27+
)
28+
# Adding 'hour' column to dataframe
29+
df['hour'] = pd.to_datetime(df['Time'], format='%H:%M:%S').dt.hour
30+
31+
return df
32+
33+
df = get_data_from_excel()
34+
35+
# ---- SIDEBAR ----
36+
st.sidebar.header('Please Filter Here:')
37+
38+
city = st.sidebar.multiselect(
39+
'Select the City:'
40+
, options=df['City'].unique()
41+
, default=df['City'].unique()
42+
)
43+
44+
customer_type = st.sidebar.multiselect(
45+
'Select the Customer Type:'
46+
, options=df['Customer_type'].unique()
47+
, default=df['Customer_type'].unique()
48+
)
49+
50+
gender = st.sidebar.multiselect(
51+
'Select the Gender:'
52+
, options=df['Gender'].unique()
53+
, default=df['Gender'].unique()
54+
)
55+
56+
df_selection = df.query(
57+
'City == @city & Customer_type == @customer_type & Gender == @gender'
58+
)
59+
60+
#st.dataframe(df_selection)
61+
62+
# ---- MAIN PAGE ----
63+
st.title(':bar_chart: Sales Dashboard')
64+
st.markdown('##')
65+
66+
# TOP KPI's
67+
total_sales = int(df_selection['Total'].sum())
68+
average_rating = round(df_selection['Rating'].mean(), 1)
69+
star_rating = ':star:' * int(round(average_rating, 0))
70+
average_sales_by_transaction = round(df_selection['Total'].mean(), 2)
71+
72+
left_column, middle_column, right_column = st.columns(3)
73+
74+
with left_column:
75+
st.subheader('Total Sales:')
76+
st.subheader(f'US ${total_sales:,}')
77+
78+
with middle_column:
79+
st.subheader('Average Rating:')
80+
st.subheader(f'{average_rating} {star_rating}')
81+
82+
with right_column:
83+
st.subheader('Average Sales Per Transaction:')
84+
st.subheader(f'US ${average_sales_by_transaction}')
85+
86+
st.markdown('----')
87+
88+
# ---- SALES BY PRODUCT LINE [BAR CHART] ----
89+
sales_by_product_line = (
90+
df_selection.groupby(by=['Product line']).sum()[['Total']].sort_values(by='Total')
91+
)
92+
93+
fig_product_sales = px.bar(
94+
sales_by_product_line
95+
, x='Total'
96+
, y=sales_by_product_line.index
97+
, orientation='h'
98+
, title='<b>Sales by Product Line</b>'
99+
, color_discrete_sequence=['#0083b8'] * len(sales_by_product_line)
100+
, template='plotly_white'
101+
)
102+
103+
fig_product_sales.update_layout(
104+
plot_bgcolor='rgba(0, 0, 0, 0)' # turning the background transparent
105+
, xaxis=(dict(showgrid=False))
106+
)
107+
108+
# st.plotly_chart(fig_product_sales)
109+
110+
# ---- SALES BY HOUR [BAR CHART] ----
111+
sales_by_hour = df_selection.groupby(by=['hour']).sum()[['Total']]
112+
fig_hourly_sales = px.bar(
113+
sales_by_hour
114+
, x=sales_by_hour.index
115+
, y='Total'
116+
, title='<b>Sales by Hour</b>'
117+
, color_discrete_sequence=['#0083b8'] * len(sales_by_hour)
118+
, template='plotly_white'
119+
)
120+
fig_hourly_sales.update_layout(
121+
xaxis=dict(tickmode='linear')
122+
, plot_bgcolor='rgba(0,0,0,0)'
123+
, yaxis=(dict(showgrid=False))
124+
)
125+
126+
# st.plotly_chart(fig_hourly_sales)
127+
128+
# ---- Adding the Charts ----
129+
left_column, right_column = st.columns(2)
130+
left_column.plotly_chart(fig_hourly_sales, use_container_width=True)
131+
right_column.plotly_chart(fig_product_sales, use_container_width=True)
132+
133+
# ---- Adding DataFrame ----
134+
st.markdown('----')
135+
st.markdown('**DataSet**')
136+
st.dataframe(df_selection)
137+
138+
# ---- HIDE STREAMLIT STYLE ----
139+
# hide_st_style = """
140+
# <style>footer {visibility: hidden;}</style>
141+
# """
142+
hide_st_style = """
143+
<style>
144+
#MainMenu {visibility: hidden;}
145+
header {visibility: hidden;}
146+
footer {visibility: hidden;}
147+
</style>
148+
"""
149+
150+
st.markdown(hide_st_style, unsafe_allow_html=True)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
openpyxl==3.0.10
2+
plotly==4.14.3
3+
pandas==1.4.3
4+
streamlit==1.12.0
Binary file not shown.
956 Bytes
Binary file not shown.

6 - Streamlit/10 - Web App/app.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import calendar
2+
from datetime import datetime
3+
4+
import streamlit as st # pip install streamlit
5+
from streamlit_option_menu import option_menu # pip install streamlit-option-menu
6+
import plotly.graph_objects as go # pip install plotly
7+
8+
import database as db # local import
9+
10+
# ---- SETTINGS ----
11+
incomes = ['Salary', 'Blog', 'Other Income']
12+
expenses = ['Rent', 'Utilities', 'Groceries', 'Car', 'Other Expense', 'Saving']
13+
currency = 'USD'
14+
page_title = 'Income and Expense Tracker'
15+
page_icon = ':money_with_wings:'
16+
layout = 'centered'
17+
18+
st.set_page_config(
19+
page_title=page_title
20+
, page_icon=page_icon
21+
, layout=layout
22+
)
23+
24+
st.title(f'{page_title} {page_icon}')
25+
26+
# ---- DROP DOWN VALUES FOR SELECTING THE PERIOD ----
27+
years = [datetime.today().year, datetime.today().year + 1]
28+
months = list(calendar.month_name[1:])
29+
30+
# ---- DATABASE INTERFACE ----
31+
def get_all_periods():
32+
items = db.fetch_all_periods()
33+
periods = [item['key'] for item in items]
34+
return periods
35+
36+
# ---- HIDE STREAMLIT STYLE ----
37+
hide_st_style = """
38+
<style>
39+
#MainMenu {visibility: hidden;}
40+
footer {visibility: hidden;}
41+
header {visibility: hidden;}
42+
</style>
43+
"""
44+
st.markdown(hide_st_style, unsafe_allow_html=True)
45+
46+
# ---- NAVIGATION MENU ----
47+
selected = option_menu(
48+
menu_title=None
49+
, options=['Data Entry', 'Data Visualization']
50+
, icons=['pencil-fill', 'bar-chart-fill'] # https://icons.getbootstrap.com/
51+
, orientation='horizontal'
52+
)
53+
54+
# ---- INPUT & SAVE PERIODS ----
55+
if selected == 'Data Entry':
56+
st.header(f'Data Entry in {currency}')
57+
58+
with st.form('entry_form', clear_on_submit=True):
59+
col1, col2 = st.columns(2)
60+
col1.selectbox('Select Month:', months, key='month')
61+
col2.selectbox('Select Year:', years, key='year')
62+
63+
st.markdown('----')
64+
65+
with st.expander('Income'):
66+
for income in incomes:
67+
st.number_input(f'{income}:', min_value=0, format='%i', step=10, key=income)
68+
69+
with st.expander('Expenses'):
70+
for expense in expenses:
71+
st.number_input(f'{expense}:', min_value=0, format='%i', step=10, key=expense)
72+
73+
with st.expander('Comment'):
74+
comment = st.text_area('', placeholder='Enter a comment here ...')
75+
76+
77+
st.markdown('----')
78+
79+
submitted = st.form_submit_button('Save Data')
80+
if submitted:
81+
period = str(st.session_state['year']) + '_' + str(st.session_state['month'])
82+
incomes = {income: st.session_state[income] for income in incomes}
83+
expenses = {expense: st.session_state[expense] for expense in expenses}
84+
db.insert_period(period, incomes, expenses, comment)
85+
st.success('Data Saved!')
86+
87+
# ---- PLOT PERIODS ----
88+
elif selected == 'Data Visualization':
89+
st.header('Data Visualization')
90+
with st.form('saved_periods'):
91+
period = st.selectbox('Select a Period', get_all_periods())
92+
submitted = st.form_submit_button('Plot Period')
93+
if submitted:
94+
period_data = db.get_period(period)
95+
comment = period_data.get('comment')
96+
expenses = period_data.get('expenses')
97+
incomes = period_data.get('incomes')
98+
99+
# Metrics
100+
total_income = sum(incomes.values())
101+
total_expense = sum(expenses.values())
102+
remaining_budget = total_income - total_expense
103+
col1, col2, col3 = st.columns(3)
104+
col1.metric('Total Income:', f'{total_income} {currency}')
105+
col2.metric('Total Expense:', f'{total_expense} {currency}')
106+
col3.metric('Remaining Budget:', f'{remaining_budget} {currency}')
107+
st.text(f'Comment: {comment}')
108+
109+
# Sankey Plot
110+
label = list(incomes.keys()) + ['Total Income'] + list(expenses.keys())
111+
source = list(range(len(incomes))) + [len(incomes)] * len(expenses)
112+
target = [len(incomes)] * len(incomes) + [label.index(expense) for expense in expenses]
113+
value = list(incomes.values()) + list(expenses.values())
114+
115+
# Data to dict, dict to sankey
116+
link = dict(source=source, target=target, value=value)
117+
node = dict(label=label, pad=20, thickness=30, color='#e694ff')
118+
data = go.Sankey(link=link, node=node)
119+
120+
# Plotting
121+
fig = go.Figure(data)
122+
fig.update_layout(margin=dict(l=0, r=0, t=5, b=5))
123+
st.plotly_chart(fig, use_container_width=True)

0 commit comments

Comments
 (0)