Spaces:
Sleeping
Sleeping
Spencer525
commited on
Commit
•
05ac7fe
1
Parent(s):
b5168c5
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import pandas as pd
|
3 |
+
import plotly.graph_objects as go
|
4 |
+
import plotly.express as px
|
5 |
+
|
6 |
+
# Load data function
|
7 |
+
def load_data(uploaded_file):
|
8 |
+
if uploaded_file is not None:
|
9 |
+
df = pd.read_csv(uploaded_file)
|
10 |
+
df.fillna(0, inplace=True)
|
11 |
+
if '出表日期' in df.columns:
|
12 |
+
df['出表日期'] = df['出表日期'].astype(str)
|
13 |
+
if '公司代號' in df.columns:
|
14 |
+
df['公司代號'] = df['公司代號'].astype(str)
|
15 |
+
return df
|
16 |
+
else:
|
17 |
+
st.warning("請上傳檔案。")
|
18 |
+
return None
|
19 |
+
|
20 |
+
# Merge dataframes
|
21 |
+
def merge_dataframes(df1, df2, on_columns):
|
22 |
+
if df1 is None or df2 is None:
|
23 |
+
return None
|
24 |
+
for col in on_columns:
|
25 |
+
if col in df1.columns and col in df2.columns:
|
26 |
+
df1[col] = df1[col].astype(str)
|
27 |
+
df2[col] = df2[col].astype(str)
|
28 |
+
return pd.merge(df1, df2, on=on_columns, how="outer")
|
29 |
+
|
30 |
+
# Filter dataframe
|
31 |
+
def filter_dataframe(df, prefix):
|
32 |
+
return df[df['公司代號'].astype(str).str.startswith(prefix)]
|
33 |
+
|
34 |
+
# Get specific company data
|
35 |
+
def get_specific_company(df, company_code):
|
36 |
+
return df[df['公司代號'] == company_code]
|
37 |
+
|
38 |
+
# Plot radar chart
|
39 |
+
def plot_radar_chart(avg_values, specific_company_values, categories, prefix, specific_company_name):
|
40 |
+
fig = go.Figure()
|
41 |
+
|
42 |
+
fig.add_trace(go.Scatterpolar(
|
43 |
+
r=avg_values,
|
44 |
+
theta=categories,
|
45 |
+
fill='toself',
|
46 |
+
name=f"股號前兩位『{prefix}』的族群"
|
47 |
+
))
|
48 |
+
|
49 |
+
fig.add_trace(go.Scatterpolar(
|
50 |
+
r=specific_company_values,
|
51 |
+
theta=categories,
|
52 |
+
fill='toself',
|
53 |
+
name=f'{specific_company_name}'
|
54 |
+
))
|
55 |
+
|
56 |
+
fig.update_layout(
|
57 |
+
polar=dict(radialaxis=dict(visible=True, range=[0, 100])),
|
58 |
+
showlegend=True,
|
59 |
+
title="董事會和投資人溝通指標比較"
|
60 |
+
)
|
61 |
+
|
62 |
+
st.plotly_chart(fig)
|
63 |
+
|
64 |
+
# Plot emission chart
|
65 |
+
def plot_emission_chart(filtered_df, avg_emissions, prefix):
|
66 |
+
emission_columns = ['範疇一排放量(噸CO2e)', '範疇二排放量(噸CO2e)', '範疇三排放量(噸CO2e)']
|
67 |
+
fig = go.Figure()
|
68 |
+
|
69 |
+
for scope, color in zip(emission_columns, ['blue', 'green', 'red']):
|
70 |
+
fig.add_trace(go.Bar(
|
71 |
+
x=filtered_df['公司名稱'],
|
72 |
+
y=filtered_df[scope],
|
73 |
+
name=scope,
|
74 |
+
marker_color=color
|
75 |
+
))
|
76 |
+
|
77 |
+
fig.add_trace(go.Scatter(
|
78 |
+
x=filtered_df['公司名稱'],
|
79 |
+
y=[avg_emissions[scope]] * len(filtered_df),
|
80 |
+
mode='lines',
|
81 |
+
line=dict(color=color, dash='dash'),
|
82 |
+
name=f'{scope}平均值'
|
83 |
+
))
|
84 |
+
|
85 |
+
fig.update_layout(
|
86 |
+
title=f"代號前兩位『{prefix}』的族群 - 各範疇排放量",
|
87 |
+
barmode='group',
|
88 |
+
xaxis_title="公司名稱",
|
89 |
+
yaxis_title="排放量(噸CO2e)"
|
90 |
+
)
|
91 |
+
|
92 |
+
st.plotly_chart(fig)
|
93 |
+
|
94 |
+
# Plot energy usage
|
95 |
+
def plot_energy_usage(filtered_df, avg_energy_usage):
|
96 |
+
fig_energy = px.bar(filtered_df, x='公司名稱', y='使用率(再生能源/總能源)', title="再生能源使用率")
|
97 |
+
|
98 |
+
fig_energy.add_trace(go.Scatter(
|
99 |
+
x=filtered_df['公司名稱'],
|
100 |
+
y=[avg_energy_usage] * len(filtered_df),
|
101 |
+
mode='lines',
|
102 |
+
line=dict(color='red', dash='dash'),
|
103 |
+
name='群體平均值'
|
104 |
+
))
|
105 |
+
|
106 |
+
fig_energy.update_layout(
|
107 |
+
yaxis_title="再生能源使用率 (%)",
|
108 |
+
xaxis_title="公司名稱"
|
109 |
+
)
|
110 |
+
|
111 |
+
st.plotly_chart(fig_energy)
|
112 |
+
|
113 |
+
# Main function
|
114 |
+
def main():
|
115 |
+
st.title("公司數據分析儀表板")
|
116 |
+
|
117 |
+
# File upload
|
118 |
+
st.sidebar.header("上傳 CSV 檔案")
|
119 |
+
investor_file = st.sidebar.file_uploader("上傳 投資人溝通.csv", type=["csv"])
|
120 |
+
board_file = st.sidebar.file_uploader("上傳 董事會.csv", type=["csv"])
|
121 |
+
emission_file = st.sidebar.file_uploader("上傳 溫室氣體排放.csv", type=["csv"])
|
122 |
+
energy_file = st.sidebar.file_uploader("上傳 能源管理.csv", type=["csv"])
|
123 |
+
waste_file = st.sidebar.file_uploader("上傳 廢棄物管理.csv", type=["csv"])
|
124 |
+
|
125 |
+
# Load data
|
126 |
+
investor_df = load_data(investor_file)
|
127 |
+
board_df = load_data(board_file)
|
128 |
+
emission_df = load_data(emission_file)
|
129 |
+
energy_df = load_data(energy_file)
|
130 |
+
waste_df = load_data(waste_file)
|
131 |
+
|
132 |
+
# Merge data
|
133 |
+
merged_df1 = merge_dataframes(investor_df, board_df, ["公司代號", "公司名稱", "出表日期", "報告年度"])
|
134 |
+
merged_df2 = merge_dataframes(emission_df, energy_df, ["公司代號", "公司名稱", "出表日期", "報告年度"])
|
135 |
+
|
136 |
+
# User input
|
137 |
+
prefix = st.sidebar.text_input("輸入公司代號前兩位")
|
138 |
+
specific_company_code = st.sidebar.text_input("輸入四位數字公司代號")
|
139 |
+
|
140 |
+
# Handle 投資人溝通和董事會資料
|
141 |
+
if merged_df1 is not None and prefix and specific_company_code:
|
142 |
+
columns_of_interest = ['董事出席董事會出席率', '董事進修時數符合進修要點比率', '公司年度召開法說會次數(次)']
|
143 |
+
for col in ['董事出席董事會出席率', '董事進修時數符合��修要點比率']:
|
144 |
+
merged_df1[col] = merged_df1[col].replace({'%': ''}, regex=True).astype(float)
|
145 |
+
|
146 |
+
filtered_df1 = filter_dataframe(merged_df1, prefix)
|
147 |
+
avg_values = filtered_df1[columns_of_interest].mean()
|
148 |
+
specific_company_df1 = get_specific_company(merged_df1, specific_company_code)
|
149 |
+
|
150 |
+
if not specific_company_df1.empty:
|
151 |
+
specific_company_name = specific_company_df1['公司名稱'].iloc[0]
|
152 |
+
specific_company_values = specific_company_df1[columns_of_interest].iloc[0]
|
153 |
+
plot_radar_chart(avg_values, specific_company_values, ['董事出席率', '董事進修時數符合比率', '年度法說會次數'], prefix, specific_company_name)
|
154 |
+
else:
|
155 |
+
st.warning(f"找不到公司代號 {specific_company_code} 的資料")
|
156 |
+
|
157 |
+
# Handle 溫室氣體排放和能源管理資料
|
158 |
+
if merged_df2 is not None and prefix:
|
159 |
+
emission_columns = ['範疇一排放量(噸CO2e)', '範疇二排放量(噸CO2e)', '範疇三排放量(噸CO2e)']
|
160 |
+
energy_column = '使用率(再生能源/總能源)'
|
161 |
+
merged_df2[energy_column] = merged_df2[energy_column].replace({'%': ''}, regex=True).astype(float)
|
162 |
+
|
163 |
+
filtered_df2 = filter_dataframe(merged_df2, prefix)
|
164 |
+
specific_company_df2 = get_specific_company(merged_df2, specific_company_code)
|
165 |
+
|
166 |
+
if not filtered_df2.empty:
|
167 |
+
avg_emissions = filtered_df2[emission_columns].mean()
|
168 |
+
plot_emission_chart(filtered_df2, avg_emissions, prefix)
|
169 |
+
|
170 |
+
avg_energy_usage = filtered_df2[energy_column].mean()
|
171 |
+
plot_energy_usage(filtered_df2, avg_energy_usage)
|
172 |
+
|
173 |
+
if not specific_company_df2.empty:
|
174 |
+
specific_energy_usage = specific_company_df2[energy_column].iloc[0]
|
175 |
+
comparison_data = {
|
176 |
+
'公司名稱': [specific_company_df2['公司名稱'].iloc[0], f"{prefix} 母群體平均"],
|
177 |
+
'再生能源使用率 (%)': [specific_energy_usage, avg_energy_usage]
|
178 |
+
}
|
179 |
+
comparison_df = pd.DataFrame(comparison_data)
|
180 |
+
st.write("\n再生能源使用率比較表格:")
|
181 |
+
st.write(comparison_df)
|
182 |
+
else:
|
183 |
+
st.warning(f"找不到公司代號 {specific_company_code} 的能源管理數據")
|
184 |
+
else:
|
185 |
+
st.warning(f"找不到前兩碼為 {prefix} 的公司數據")
|
186 |
+
|
187 |
+
if __name__ == "__main__":
|
188 |
+
main()
|