Spaces:
Sleeping
Sleeping
import streamlit as st | |
import pandas as pd | |
import requests | |
import plotly.express as px | |
import io | |
# 設置顏色主題 | |
theme = px.colors.qualitative.Bold | |
# 下載並載入 CSV 數據 | |
def download_and_load_csv(url): | |
response = requests.get(url) | |
response.encoding = 'utf-8' | |
df = pd.read_csv(io.StringIO(response.text), encoding='utf-8') | |
df = df.fillna(0) # 避免 NaN 錯誤 | |
return df | |
# 美化圖表 | |
def beautify_chart(fig): | |
fig.update_layout( | |
font_family="Arial", | |
font_color="#444", | |
title_font_family="Arial", | |
title_font_color="#000", | |
legend_title_font_color="#000", | |
plot_bgcolor='rgba(0,0,0,0)', | |
paper_bgcolor='rgba(0,0,0,0)', | |
) | |
fig.update_xaxes(showline=True, linewidth=2, linecolor='lightgray', gridcolor='lightgray') | |
fig.update_yaxes(showline=True, linewidth=2, linecolor='lightgray', gridcolor='lightgray') | |
return fig | |
# **生成 Plotly 圖表** | |
def generate_plots(df, df_name, selected_columns, chart_type): | |
selected_columns = list(selected_columns) # 確保是列表 | |
if not selected_columns: | |
st.error("❌ 沒有選擇數據欄位,請至少選擇一個!") | |
return | |
if "公司名稱" not in df.columns: | |
st.error("❌ 缺少 公司名稱 欄位,請確認數據格式!") | |
return | |
# ✅ **確保所有 y 軸數據與 x 軸 (公司名稱) 長度一致** | |
df = df.dropna(subset=["公司名稱"] + selected_columns) # **移除 NaN 確保長度相同** | |
df[selected_columns] = df[selected_columns].apply(pd.to_numeric, errors='coerce') # **轉換數據類型** | |
valid_columns = [col for col in selected_columns if col in df.columns and len(df[col]) == len(df["公司名稱"])] | |
if not valid_columns: | |
st.error(f"❌ 選擇的欄位長度與 公司名稱 不匹配,請檢查數據!\n" | |
f"📊 公司名稱 長度: {len(df['公司名稱'])}\n" | |
f"🟢 可用欄位: {valid_columns}") | |
return | |
with st.expander(f"📊 顯示 {df_name} 圖表"): | |
st.subheader(f"{df_name} - {chart_type} 圖") | |
# **根據選擇的圖表類型來繪製** | |
if chart_type == "折線圖": | |
fig = px.line(df, x="公司名稱", y=valid_columns, title=f"{df_name} - 折線圖", color_discrete_sequence=theme) | |
elif chart_type == "散點圖": | |
fig = px.scatter(df, x="公司名稱", y=valid_columns, title=f"{df_name} - 散點圖", color_discrete_sequence=theme) | |
elif chart_type == "長條圖": | |
fig = px.bar(df, x="公司名稱", y=valid_columns, title=f"{df_name} - 長條圖", color_discrete_sequence=theme) | |
elif chart_type == "餅圖": | |
total_emissions = df.groupby("公司名稱")[valid_columns].sum().reset_index() | |
total_emissions = total_emissions.melt(id_vars=["公司名稱"], value_vars=valid_columns, var_name="排放類型", value_name="總排放量") | |
fig = px.pie(total_emissions, values='總排放量', names='公司名稱', title=f"{df_name} - 餅圖", color_discrete_sequence=theme, hole=0.3) | |
fig.update_traces(textposition='inside', textinfo='percent+label') | |
fig = beautify_chart(fig) | |
st.plotly_chart(fig, use_container_width=True) # ✅ **讓圖表自適應畫面** | |
# **下載數據** | |
urls = [ | |
"https://mopsfin.twse.com.tw/opendata/t187ap46_L_1.csv", | |
"https://mopsfin.twse.com.tw/opendata/t187ap46_O_2.csv", | |
"https://mopsfin.twse.com.tw/opendata/t187ap46_L_6.csv" | |
] | |
dfs = [download_and_load_csv(url) for url in urls] | |
combined_df = pd.concat(dfs, ignore_index=True).fillna(0) # 合併數據並填充 NaN 值 | |
# **再次填充 NaN 值** | |
combined_df = combined_df.fillna(0) | |
# **只顯示前300筆數據** | |
combined_df = combined_df.head(300) | |
# **Streamlit UI** | |
st.title("📊 台灣企業 ESG 數據分析") | |
st.subheader("📂 數據預覽") | |
st.dataframe(combined_df) | |
# **選擇數據欄位** | |
emission_columns = ["範疇一排放量(噸CO2e)", "範疇二排放量(噸CO2e)", "範疇三排放量(噸CO2e)"] | |
selected_columns = st.multiselect("選擇要顯示的排放類別", emission_columns, default=emission_columns[:1]) | |
# **選擇圖表類型** | |
chart_type = st.selectbox("選擇圖表類型", ["折線圖", "散點圖", "長條圖", "餅圖"]) | |
# **生成圖表** | |
if selected_columns: | |
generate_plots(combined_df, "綜合數據", selected_columns, chart_type) | |
else: | |
st.write("⚠️ 請選擇至少一個排放類別來顯示圖表。") | |