← 메인 화면프로젝트 자료·코드
← 자료 목록

map_sejong.py

프로그램·코드 · 4.5 KB원본 다운로드

원본 내용을 읽기 전용으로 표시합니다.

  1. # 세종 전체 업종 구조 + 상권 유형 지도
  2. # sejong_analysis.py 에서는 세종지도() 함수만 가져다 씀 ^^
  3. import json
  4. import os
  5. import numpy as np
  6. import folium
  7. from common import *
  8. def 세종지도(now, CATS, dong, comp, cell, prof, BEST_K):
  9. # 세종 전체 지도 (과제 요구사항: 지역별 업종 구조와 상권 유형을 지도에 시각화)
  10. log("\n" + "=" * 70)
  11. log("4. 지도 시각화 ①: 세종 전역 (output/map1_세종_업종구조_상권유형.html)")
  12. log("=" * 70)
  13. geo = json.load(open(os.path.join(데이터폴더, "sejong_admdong.geojson"), encoding="utf-8"))
  14. 최다업종 = comp.idxmax(axis=1) # 동마다 제일 많은 업종
  15. # 지도에 마우스 올리면 나오는 정보 넣기
  16. for f in geo["features"]:
  17. 동이름 = f["properties"]["adm_nm"].split()[-1]
  18. f["properties"]["동"] = 동이름
  19. if 동이름 in dong.index:
  20. f["properties"]["업소수"] = int(dong.loc[동이름, "업소수"])
  21. f["properties"]["최다업종"] = f"{최다업종[동이름]} ({comp.loc[동이름, 최다업종[동이름]]:.0%})"
  22. f["properties"]["소멸률"] = f"{dong.loc[동이름, '소멸률']:.1%}"
  23. f["properties"]["체인비율"] = f"{dong.loc[동이름, '체인비율']:.1%}"
  24. 구성 = []
  25. for c in CATS[:5]:
  26. 구성.append(f"{c} {comp.loc[동이름, c]:.0%}")
  27. f["properties"]["업종구성"] = " / ".join(구성)
  28. m1 = 지도만들기([36.53, 127.27], 11)
  29. # 행정동별 업소 수 색칠
  30. ch = folium.Choropleth(
  31. geo_data=geo, data=dong.reset_index(), columns=["행정동명", "업소수"],
  32. key_on="feature.properties.동", fill_color="Blues", fill_opacity=0.6, line_opacity=0.6,
  33. legend_name="행정동별 업소 수", name="행정동별 업소 수(단계구분도)",
  34. ).add_to(m1)
  35. folium.GeoJsonTooltip(fields=["동", "업소수", "최다업종", "업종구성", "소멸률", "체인비율"],
  36. aliases=["행정동", "업소 수", "최다 업종", "상위5 업종 구성", "1년 소멸률", "체인 비율"]
  37. ).add_to(ch.geojson)
  38. # 격자별 상권 유형 (네모 칸)
  39. 격자레이어 = folium.FeatureGroup(name="격자별 상권 유형(K-Means)", show=True)
  40. dlat = GRID_M / 110540
  41. dlon = GRID_M / (111320 * np.cos(np.radians(LAT0)))
  42. for (gx, gy), r in cell.iterrows():
  43. lat0 = LAT0 + gy * dlat
  44. lon0 = LON0 + gx * dlon
  45. top3 = r[CATS].sort_values(ascending=False).head(3)
  46. 글 = f"<b>{r['유형명']}</b><br>{r['대표동']} / 업소 {int(r['업소수'])}개<br>"
  47. for k, v in top3.items():
  48. 글 += f"{k} {v:.0%}<br>"
  49. 글 += f"1층비율 {r['1층비율']:.0%}, 체인 {r['체인비율']:.0%}"
  50. folium.Rectangle([[lat0, lon0], [lat0 + dlat, lon0 + dlon]], color="white", weight=1,
  51. fill=True, fill_color=COLORS[int(r["군집"]) % 8], fill_opacity=0.75,
  52. tooltip=글).add_to(격자레이어)
  53. 격자레이어.add_to(m1)
  54. # 업종별 업소 위치 (처음엔 꺼놓음)
  55. for i in range(8):
  56. c = CATS[i]
  57. 레이어 = folium.FeatureGroup(name=f"업소 위치: {c}", show=False)
  58. 업종업소 = now[now["상권업종대분류명"] == c]
  59. for _, r in 업종업소.iterrows():
  60. folium.CircleMarker([r["위도"], r["경도"]], radius=2, color=COLORS[i], fill=True,
  61. fill_opacity=0.7, weight=0).add_to(레이어)
  62. 레이어.add_to(m1)
  63. # 범례 (html로 직접 넣음)
  64. 범례 = "<div style='position:fixed;bottom:30px;left:10px;z-index:9999;background:white;padding:8px 10px;" \
  65. "border:1px solid #ccc;font-size:12px;border-radius:4px'><b>격자 상권 유형</b>"
  66. for c in range(BEST_K):
  67. 범례 += f"<div><span style='display:inline-block;width:12px;height:12px;background:{COLORS[c % 8]};" \
  68. f"margin-right:6px'></span>{prof.loc[c, '유형명']}</div>"
  69. 범례 += "</div>"
  70. m1.get_root().html.add_child(folium.Element(범례))
  71. folium.LayerControl(collapsed=False).add_to(m1)
  72. m1.save(os.path.join(결과폴더, "map1_세종_업종구조_상권유형.html"))
  73. log("저장 완료")
  74. if __name__ == "__main__":
  75. from sejong_area import 탐색분석, 상권유형군집
  76. now, prev, CATS = 데이터준비()
  77. dong, comp = 탐색분석(now, prev, CATS)
  78. cell, prof, BEST_K = 상권유형군집(now, prev, CATS)
  79. 세종지도(now, CATS, dong, comp, cell, prof, BEST_K)
파일 확인 정보

SHA-256: c08d6e44d2766ff47dcbc0101a015585bbabe9ee977458c2a4bb21f3477c6fc6