이전 내용
[파이썬] 프로젝트 : 대시보드 웹 페이지 구축하기 - 8
이전 내용 [파이썬] 프로젝트 : 대시보드 웹 페이지 구축하기 - 7이전 내용 [파이썬] 프로젝트 : 대시보드 웹 페이지 구축하기 - 6이전 내용 [파이썬] 프로젝트 : 대시보드 웹 페이지 구축하기 - 5
puppy-foot-it.tistory.com
오프라인 수정하기
레이아웃 수정하기
오프라인 데이터도 온라인 데이터처럼 탭을 세 개로 나누고 (지표 / 분석 / 예측), 데이터 조회 버튼과 지역 선택 버튼을 사이드바로 옮긴다.
# 지역 선택하는 멀티 셀렉트 버튼 생성
city_options = ['All_CITIES'] + df['CITY'].unique().tolist() # 전체 선택 및 지역의 유니크 값
selected_city = st.sidebar.multiselect(
"**:violet[조회하고자 하는 지역을 선택해 주세요.(중복가능)]**",
options=city_options,
default=['All_CITIES'],
placeholder='도시 선택'
)
# 탭 생성하기
tab1, tab2, tab3 = st.tabs(['데이터(지표)', '분석', '예측'])
# 데이터 출력
with tab1:
# 데이터 조회 버튼
if st.sidebar.button("데이터 조회"):
'이하 생략'
with tab2: # 데이터 시각화
# 'DATE'를 월 단위로 그룹화하고 각 도시별 방문자 수를 합산
# 차트를 생성하는 함수
def create_monthly_bar_chart(data, value_col, title):
'이하 생략'
with tab3: # 머신러닝 모델 구현
# 1. 일별 데이터 집계
daily_data = filtered_selected_df.groupby('DATE').agg({'VISITORS':'sum', 'PART':'sum'}).reset_index()
'이하 생략'

멀티 페이지 만들기
멀티페이지를 만들기 위해서
1. home.py 파일 만들고 코드 넣어주기
import streamlit as st
st.set_page_config(
page_title="재활용 이벤트 성과 지표",
page_icon= "📋"
)
st.title(":recycle: :rainbow[재활용 이벤트 성과 지표] :recycle:")
st.sidebar.success("페이지를 선택해 주세요.")
st.markdown(
"""
재활용 관련 오프라인 캠페인과 온라인 마케팅을
2023년 1월 1일부터 2024년 12월 31일까지 2년간 진행한 결과를
집계 및 분석한 페이지 입니다.
필요한 데이터를 해당 사이트로 이동하셔서 조회하시면 됩니다.
**👈 이동하려는 페이지 선택하기**
### 어떤 데이터를 보고싶으세요?
- 오프라인 캠페인 진행 관련 데이터
- 온라인 마케팅 진행 관련 데이터
"""
)
2. 각 파일이 연동되도록 하나의 파일에 넣고, pages(소문자) 폴더를 만들기
3. 해당 폴더에 집어넣고자 하는 파일의 이름을 '숫자_파일명'의 형태로 넣어주기
4. DB정보를 불러올 수 있도록 '.streamlit' 폴더를 생성하고, 안에 secrets.toml 파일 복사 붙여넣기

이제 home.py 파일의 터미널에서 파일을 실행하면
streamlit run home.py

이렇게 페이지가 연동된다.
실제로 잘 작동할까?


▶ 모두 문제없이 잘 작동한다.
summary 페이지 추가하기
+ 오프라인 데이터 꾸미기
원래는 오프라인 데이터셋에 있는 지역 정보를 가지고 위도, 경도를 받아 지도에 매핑하는 작업을 하려고 했다.
그런데, 오프라인 페이지는 지역으로 데이터 필터링이 되기 때문에 전체 지역이 아닌 다른 지역을 선택할 때 데이터가 꼬여버릴 거 같아서 필터링 기능이 없는 페이지를 추가하여 해당 페이지에서 지도 정보를 매핑 후 시각화하려고 한다.
대략적인 시각화 결과물은 아래와 같은데, 필터링 기능은 제외하려고 한다.

1. 기본 셋팅
먼저 pages 폴더 내에 summary 파일을 추가하는 데, 순서가 다른 파일에 비해 앞에 나와야 하므로 숫자를 1로 지정하고 기존 파일들의 숫자를 다 1씩 미룬다.

2. 오프라인데이터 각 지역의 위도 경도 받기
summary 파일에서 필요한 라이브러리를 import 하고, 이번엔 csv 파일을 받아와서 지역별로 방문자수와 참여자수를 각각 합하고 각 지역의 위도와 경도를 받아 데이터프레임으로 출력한다.
cities = off_df['지역'].unique().tolist()
st.write(cities)
각 지역 리스트를 받아서 챗gpt에 각 도시의 위도와 경도 정보를 달라고 하여 이를 딕셔너리 형태로 저장한다.
# 각 지역에 대한 위도와 경도 정보를 포함한 사전 생성
coordinates = {
"인천": (37.4563, 126.7052),
"강원": (37.8228, 128.1555),
"충북": (36.6351, 127.4915),
"경기": (37.4138, 127.5183),
"울산": (35.5373, 129.3167),
"제주": (33.4997, 126.5318),
"전북": (35.7210, 127.1454),
"대전": (36.3504, 127.3845),
"대구": (35.8714, 128.6014),
"서울": (37.5665, 126.9780),
"충남": (36.6887, 126.7732),
"경남": (35.2345, 128.6880),
"세종": (36.4805, 127.2898),
"경북": (36.1002, 128.6295),
"부산": (35.1796, 129.0756),
"광주": (35.1595, 126.8526),
"전남": (34.7802, 126.1322)
}
이제 지역별 방문자수와 참여자수 합계 데이터를 구하고, 참여율을 계산한 뒤 앞서 저장해둔 위도 경도 정보를 각 지역과 매핑하여 데이터프레임으로 출력한다.
off_data_by_city = off_df.groupby('지역').agg({'방문자수':'sum', '참여자수':'sum'}).reset_index()
off_data_by_city = off_data_by_city.dropna(subset=['방문자수', '참여자수']) # NaN 제거
# 참여율 계산
off_data_by_city['참여율'] = off_data_by_city.apply(
lambda row: (row['참여자수'] / row['방문자수'] * 100) if row['방문자수'] > 0 else 0,
axis=1
)
# 위도와 경도 열 추가
off_data_by_city['위도'] = off_data_by_city['지역'].map(lambda x: coordinates[x][0] if x in coordinates else None)
off_data_by_city['경도'] = off_data_by_city['지역'].map(lambda x: coordinates[x][1] if x in coordinates else None)
st.dataframe(off_data_by_city) # 오프라인 지역별 데이터

3. 지도 시각화하기 (Folium)
먼저 Folium을 사용하기 위해 라이브러리를 설치하고
pip install folium
필요한 라이브러리를 import
import folium
from folium.plugins import MarkerCluster
folium을 사용해 지도를 그리고 그 위에 참여율을 CircleMarker로 표시한 뒤, Marker를 사용하여 각 도시와 참여율을 표시한다.
# 비어있는 데이터가 없는지를 확인
valid_data = off_data_by_city.dropna(subset=['위도', '경도'])
# Map 추가
my_map = folium.Map(
location=[valid_data['위도'].mean(), valid_data['경도'].mean()],
zoom_start=7
)
# 지도 커스텀 - 원형 마커와 값 추가
for index, row in valid_data.iterrows():
folium.CircleMarker(
location=[row['위도'], row['경도']],
radius=row['참여율'], # 반지름은 참여율에서 가져옴
color='#3186cc',
fill_color='#3186cc',
fill_opacity=0.6 # 적절한 투명도로 설정
).add_to(my_map)
# 마커 추가
folium.Marker(
location=[row['위도'], row['경도']],
icon=folium.DivIcon(
html=f"<div style='font-size: 11pt'><b>{row['지역']} {(row['참여율']):.1f}%</b></div>" # 값 표시 방식
)
).add_to(my_map)
# Streamlit으로 지도 표시
st.title(":rainbow[지역별 참여율]")
st.caption("## 지역별 참여율 데이터")
st.components.v1.html(my_map._repr_html_(), height=600) # Streamlit에서 지도를 표시

summary 페이지 추가하기
+ 온라인 데이터 꾸미기
온라인 데이터로는 유입경로별 유입수를 시각화하는 데, 키워드 검색의 유입수가 월등히 높으므로, 해당 수치는 제외한다.
또한, 키워드별 전환수를 수평 막대차트로 시각화한다.
st.title('**:rainbow[온라인 마케팅 데이터]**')
on_by_route = on_df.groupby('유입경로').agg({'노출수':'sum', '유입수':'sum', '체류시간(min)':'sum', '페이지뷰':'sum', '이탈수':'sum',
'회원가입':'sum', '앱 다운':'sum', '구독':'sum'}).reset_index()
on_by_route = on_by_route.dropna(subset=['노출수', '유입수', '체류시간(min)', '페이지뷰', '이탈수', '회원가입', '앱 다운', '구독']) # NaN 제거
on_by_route_ex = on_by_route[on_by_route['유입경로']!='키워드 검색'] # 키워드 검색 제외
st.dataframe(on_by_route, use_container_width=True)
# 산점도 생성을 위한 Plotly 시각화
fig = go.Figure()
# 산점도 추가
fig.add_trace(go.Scatter(
x=on_by_route_ex['유입수'],
y=on_by_route_ex['유입경로'],
mode='markers+text',
name='유입수 데이터',
text=on_by_route_ex['유입수'],
textposition='top center', # 텍스트 표시 위치
marker=dict(color='#d00000', size=10)
))
# 레이아웃 설정
fig.update_layout(
title='유입경로별 유입수 Scatter Plot',
xaxis_title='유입수',
yaxis_title='유입경로',
boxmode='group', # 그룹화된 박스 플롯
height=600,
showlegend=True
)
# 결과 출력
st.plotly_chart(fig, use_container_width=True)
st.divider()
# 키워드별 전환수
act_by_keyword = on_df[on_df['유입경로'] =='키워드 검색']
act_by_keyword = act_by_keyword.groupby('키워드').agg({'노출수':'sum', '유입수':'sum', '체류시간(min)':'sum', '페이지뷰':'sum', '이탈수':'sum',
'회원가입':'sum', '앱 다운':'sum', '구독':'sum', '전환수':'sum'}).reset_index()
act_by_keyword = act_by_keyword.dropna(subset=['노출수', '유입수', '체류시간(min)', '페이지뷰', '이탈수', '회원가입', '앱 다운', '구독', '전환수']) # NaN 제거
# 바 레이스 차트 생성
fig = px.bar(act_by_keyword,
x='전환수',
y='키워드',
range_x=[0, act_by_keyword['전환수'].max() + 100], # x축 범위 설정
title='전환수 바 레이스 차트',
orientation='h', # 수평 바 차트
labels={'키워드': '키워드', '전환수': '전환수'},
color='전환수', # 색상 기준 설정
template='plotly_white' # 템플릿 설정
)
# 결과 출력
st.plotly_chart(fig, use_container_width=True)


이제 이 파일을 Streamlit 클라우드에 올려서 인터넷에서 확인할 수 있도록 해 본다.
다음 내용
[파이썬] 프로젝트 : 대시보드 웹 페이지 구축하기 - 10
이전 내용 [파이썬] 프로젝트 : 대시보드 웹 페이지 구축하기 - 9이전 내용 [파이썬] 프로젝트 : 대시보드 웹 페이지 구축하기 - 8이전 내용 [파이썬] 프로젝트 : 대시보드 웹 페이지 구축하기 - 7
puppy-foot-it.tistory.com
'[파이썬 Projects] > <파이썬 웹개발>' 카테고리의 다른 글
[파이썬] 프로젝트 : 웹 페이지 구축 - 10(Cloud에 배포하기) (0) | 2025.03.24 |
---|---|
[파이썬] 프로젝트 : 웹 페이지 구축 - 8 (온라인 페이지 구현) (1) | 2025.03.24 |
[파이썬] 프로젝트 : 웹 페이지 구축 - 7 (Streamlit 레이아웃 구현) (0) | 2025.03.21 |
[파이썬] 프로젝트 : 웹 페이지 구축 - 6(DB 연동) (0) | 2025.03.21 |
[파이썬] Faker 라이브러리로 가짜 데이터 생성하기 (2) | 2025.03.20 |