draw_korea_raw = pd.read_excel("../data/07_draw_korea_raw.xlsx")
draw_korea_raw
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 철원 | 화천 | 양구 | 고성(강원) | NaN | NaN | NaN |
| 1 | NaN | NaN | NaN | 양주 | 동두천 | 연천 | 포천 | 의정부 | 인제 | 춘천 | 속초 | NaN | NaN | NaN |
| 2 | NaN | NaN | NaN | 고양 덕양 | 고양 일산동 | 서울 도봉 | 서울 노원 | 남양주 | 홍천 | 횡성 | 양양 | NaN | NaN | NaN |
| 3 | NaN | NaN | 파주 | 고양 일산서 | 김포 | 서울 강북 | 서울 성북 | 가평 | 구리 | 하남 | 정선 | 강릉 | NaN | NaN |
| 4 | NaN | NaN | 부천 소사 | 안양 만안 | 광명 | 서울 서대문 | 서울 종로 | 서울 동대문 | 서울 중랑 | 양평 | 태백 | 동해 | NaN | NaN |
| 5 | NaN | 인천 강화 | 부천 원미 | 안양 동안 | 서울 은평 | 서울 마포 | 서울 중구 | 서울 성동 | 서울 강동 | 여주 | 원주 | 삼척 | NaN | NaN |
| 6 | NaN | 인천 서구 | 부천 오정 | 시흥 | 서울 강서 | 서울 동작 | 서울 용산 | 서울 광진 | 서울 송파 | 이천 | 평창 | 울진 | NaN | NaN |
| 7 | NaN | 인천 동구 | 인천 계양 | 안산 상록 | 서울 양천 | 서울 관악 | 서울 서초 | 성남 중원 | 과천 | 광주 | 영월 | 영덕 | NaN | NaN |
| 8 | NaN | NaN | 인천 부평 | 안산 단원 | 서울 영등포 | 서울 금천 | 서울 강남 | 성남 분당 | 성남 수정 | 용인 수지 | 문경 | 봉화 | NaN | 울릉 |
| 9 | NaN | 인천 중구 | 인천 남구 | 화성 | 서울 구로 | 군포 | 의왕 | 수원 영통 | 용인 기흥 | 용인 처인 | 안동 | 영양 | NaN | NaN |
| 10 | 인천 옹진 | 인천 연수 | 인천 남동 | 오산 | 안성 | 수원 권선 | 수원 장안 | 제천 | 예천 | 영주 | 구미 | 청송 | 포항 북구 | NaN |
| 11 | 태안 | 아산 | 천안 동남 | 천안 서북 | 평택 | 음성 | 수원 팔달 | 단양 | 상주 | 김천 | 군위 | 의성 | 포항 남구 | NaN |
| 12 | NaN | 당진 | 홍성 | 예산 | 공주 | 진천 | 충주 | 청주 흥덕 | 괴산 | 칠곡 | 영천 | 경산 | 경주 | NaN |
| 13 | NaN | 서산 | 보령 | 청양 | 세종 | 대전 대덕 | 증평 | 청주 청원 | 보은 | 고령 | 청도 | 성주 | 울산 북구 | NaN |
| 14 | NaN | NaN | 부여 | 논산 | 계룡 | 대전 동구 | 청주 상당 | 청주 서원 | 대구 북구 | 대구 중구 | 대구 수성 | 울산 울주 | 울산 동구 | NaN |
| 15 | NaN | NaN | 서천 | 금산 | 대전 유성 | 대전 중구 | 옥천 | 영동 | 대구 서구 | 대구 남구 | 대구 동구 | 울산 중구 | 울산 남구 | NaN |
| 16 | NaN | NaN | 군산 | 익산 | 대전 서구 | 무주 | 거창 | 합천 | 대구 달서 | 대구 달성 | 부산 금정 | 부산 동래 | 부산 기장 | NaN |
| 17 | NaN | NaN | 부안 | 김제 | 완주 | 장수 | 함양 | 창녕 | 밀양 | 부산 북구 | 부산 부산진 | 부산 연제 | 부산 해운대 | NaN |
| 18 | NaN | 고창 | 정읍 | 전주 덕진 | 진안 | 남원 | 진주 | 의령 | 부산 강서 | 부산 사상 | 부산 동구 | 부산 중구 | NaN | NaN |
| 19 | NaN | 영광 | 장성 | 전주 완산 | 임실 | 산청 | 함안 | 양산 | 창원 합포 | 부산 서구 | 부산 사하 | 부산 남구 | NaN | NaN |
| 20 | NaN | 함평 | 담양 | 순창 | 구례 | 하동 | 창원 의창 | 창원 성산 | 창원 진해 | 김해 | 부산 영도 | 부산 수영 | NaN | NaN |
| 21 | 신안 | 무안 | 광주 광산 | 곡성 | 화순 | 광양 | 사천 | 창원 회원 | 통영 | NaN | NaN | NaN | NaN | NaN |
| 22 | 목포 | 나주 | 광주 서구 | 광주 북구 | 순천 | 고흥 | 남해 | 고성(경남) | 거제 | NaN | NaN | NaN | NaN | NaN |
| 23 | 해남 | 영암 | 광주 남구 | 광주 동구 | 여수 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 24 | 진도 | 강진 | 장흥 | 보성 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 25 | NaN | NaN | 완도 | NaN | NaN | 제주 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 26 | NaN | NaN | NaN | NaN | NaN | 서귀포 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
draw_korea_raw.stack()
0 7 철원
8 화천
9 양구
10 고성(강원)
1 3 양주
...
24 2 장흥
3 보성
25 2 완도
5 제주
26 5 서귀포
Length: 252, dtype: object
draw_korea_raw_stacked = pd.DataFrame(draw_korea_raw.stack())
draw_korea_raw_stacked.reset_index(inplace=True)
draw_korea_raw_stacked
| level_0 | level_1 | 0 | |
|---|---|---|---|
| 0 | 0 | 7 | 철원 |
| 1 | 0 | 8 | 화천 |
| 2 | 0 | 9 | 양구 |
| 3 | 0 | 10 | 고성(강원) |
| 4 | 1 | 3 | 양주 |
| ... | ... | ... | ... |
| 247 | 24 | 2 | 장흥 |
| 248 | 24 | 3 | 보성 |
| 249 | 25 | 2 | 완도 |
| 250 | 25 | 5 | 제주 |
| 251 | 26 | 5 | 서귀포 |
252 rows × 3 columns
# 컬럼 이름 변경
draw_korea_raw_stacked.rename(
columns={
"level_0" : "y",
"level_1" : "x",
0 : "ID"
}, inplace=True)
draw_korea_raw_stacked
| y | x | ID | |
|---|---|---|---|
| 0 | 0 | 7 | 철원 |
| 1 | 0 | 8 | 화천 |
| 2 | 0 | 9 | 양구 |
| 3 | 0 | 10 | 고성(강원) |
| 4 | 1 | 3 | 양주 |
| ... | ... | ... | ... |
| 247 | 24 | 2 | 장흥 |
| 248 | 24 | 3 | 보성 |
| 249 | 25 | 2 | 완도 |
| 250 | 25 | 5 | 제주 |
| 251 | 26 | 5 | 서귀포 |
252 rows × 3 columns
draw_korea = draw_korea_raw_stacked
BORDER_LINES = [
[(5, 1), (5, 2), (7, 2), (7, 3), (11, 3), (11, 0)], # 인천
[(5, 4), (5, 5), (2, 5), (2, 7), (4, 7), (4, 9), (7, 9), (7, 7), (9, 7), (9, 5), (10, 5), (10, 4), (5, 4)], # 서울
[(1, 7), (1, 8), (3, 8), (3, 10), (10, 10), (10, 7), (12, 7), (12, 6), (11, 6), (11, 5), (12, 5), (12, 4), (11, 4), (11, 3)], # 경기도
[(8, 10), (8, 11), (6, 11), (6, 12)], # 강원도
[(12, 5), (13, 5), (13, 4), (14, 4), (14, 5), (15, 5), (15, 4), (16, 4), (16, 2)], # 충청북도
[(16, 4), (17, 4), (17, 5), (16, 5), (16, 6), (19, 6), (19, 5), (20, 5), (20, 4), (21, 4), (21, 3), (19, 3), (19, 1)], # 전라북도
[(13, 5), (13, 6), (16, 6)],
[(13, 5), (14, 5)], # 대전시 # 세종시
[(21, 2), (21, 3), (22, 3), (22, 4), (24, 4), (24, 2), (21, 2)], # 광주
[(20, 5), (21, 5), (21, 6), (23, 6)], # 전라남도
[(10, 8), (12, 8), (12, 9), (14, 9), (14, 8), (16, 8), (16, 6)], # 충청북도
[(14, 9), (14, 11), (14, 12), (13, 12), (13, 13)], # 경상북도
[(15, 8), (17, 8), (17, 10), (16, 10), (16, 11), (14, 11)], # 대구
[(17, 9), (18, 9), (18, 8), (19, 8), (19, 9), (20, 9), (20, 10), (21, 10)], # 부산
[(16, 11), (16, 13)],
[(27, 5), (27, 6), (25, 6)]
]
BORDER_LINES
[[(5, 1), (5, 2), (7, 2), (7, 3), (11, 3), (11, 0)],
[(5, 4),
(5, 5),
(2, 5),
(2, 7),
(4, 7),
(4, 9),
(7, 9),
(7, 7),
(9, 7),
(9, 5),
(10, 5),
(10, 4),
(5, 4)],
[(1, 7),
(1, 8),
(3, 8),
(3, 10),
(10, 10),
(10, 7),
(12, 7),
(12, 6),
(11, 6),
(11, 5),
(12, 5),
(12, 4),
(11, 4),
(11, 3)],
[(8, 10), (8, 11), (6, 11), (6, 12)],
[(12, 5),
(13, 5),
(13, 4),
(14, 4),
(14, 5),
(15, 5),
(15, 4),
(16, 4),
(16, 2)],
[(16, 4),
(17, 4),
(17, 5),
(16, 5),
(16, 6),
(19, 6),
(19, 5),
(20, 5),
(20, 4),
(21, 4),
(21, 3),
(19, 3),
(19, 1)],
[(13, 5), (13, 6), (16, 6)],
[(13, 5), (14, 5)],
[(21, 2), (21, 3), (22, 3), (22, 4), (24, 4), (24, 2), (21, 2)],
[(20, 5), (21, 5), (21, 6), (23, 6)],
[(10, 8), (12, 8), (12, 9), (14, 9), (14, 8), (16, 8), (16, 6)],
[(14, 9), (14, 11), (14, 12), (13, 12), (13, 13)],
[(15, 8), (17, 8), (17, 10), (16, 10), (16, 11), (14, 11)],
[(17, 9), (18, 9), (18, 8), (19, 8), (19, 9), (20, 9), (20, 10), (21, 10)],
[(16, 11), (16, 13)],
[(27, 5), (27, 6), (25, 6)]]
def plot_text_simple(draw_korea):
for idx,row in draw_korea.iterrows():
if len(row["ID"].split()) == 2 :
dispname = "{}\n{}".format(row["ID"].split()[0],row["ID"].split()[1])
elif row["ID"][:2] == "고성":
dispname = "고성"
else:
dispname = row["ID"]
if len(dispname.splitlines()[-1]) >= 3:
fontsize, linespacing = 9.5, 1.5
else:
fontsize, linespacing = 11, 1.2
plt.annotate(# matplotlib 주석 다는 기능
dispname,
(row["x"]+0.5,row["y"]+0.5),
weight="bold",
fontsize=fontsize,
linespacing=linespacing,
ha="center", #수평 정렬
va="center", # 수직 정렬
)
def simpleDraw(draw_korea):
plt.figure(figsize=(8,11))
plot_text_simple(draw_korea)
for path in BORDER_LINES:
ys,xs = zip(*path)
plt.plot(xs, ys, c="black", lw=1.5)
plt.gca().invert_yaxis()
plt.axis("off")
plt.tight_layout()
plt.show()
simpleDraw(draw_korea)

pop.head()
| 광역시도 | 시도 | 20-39세여자 | 20-39세합계 | 65세 이상합계 | 인구수남자 | 인구수여자 | 인구수합계 | 소멸 비율 | 소멸 위기 지역 | ID | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 강원도 | 강릉시 | 23098.0 | 49384.0 | 37679.0 | 106231.0 | 107615.0 | 213846.0 | 1.226041 | False | 강릉 |
| 1 | 강원도 | 고성군 | 2529.0 | 7023.0 | 7151.0 | 15899.0 | 14215.0 | 30114.0 | 0.707314 | True | 고성(강원) |
| 2 | 강원도 | 동해시 | 9753.0 | 21264.0 | 15124.0 | 47166.0 | 46131.0 | 93297.0 | 1.289738 | False | 동해 |
| 3 | 강원도 | 삼척시 | 7115.0 | 15823.0 | 14610.0 | 35253.0 | 34346.0 | 69599.0 | 0.973990 | True | 삼척 |
| 4 | 강원도 | 속초시 | 8752.0 | 18708.0 | 12752.0 | 40288.0 | 41505.0 | 81793.0 | 1.372647 | False | 속초 |
draw_korea.head() # pop 과 draw_korea에 공통된 "ID"
| y | x | ID | |
|---|---|---|---|
| 0 | 0 | 7 | 철원 |
| 1 | 0 | 8 | 화천 |
| 2 | 0 | 9 | 양구 |
| 3 | 0 | 10 | 고성(강원) |
| 4 | 1 | 3 | 양주 |
set(draw_korea["ID"].unique()) - set(pop["ID"].unique()) # 차집합 확인
{'고양 덕양', '고양 일산동', '고양 일산서', '용인 기흥', '용인 수지', '용인 처인'}
set(pop["ID"].unique()) - set(draw_korea["ID"].unique()) # 차집합 확인
{'고양',
'고양 기흥',
'고양 수지',
'고양 처인',
'부천',
'성남',
'수원',
'안산',
'안양',
'용인',
'일산 덕양',
'일산 일산동',
'일산 일산서',
'전주',
'창원',
'천안',
'청주',
'포항'}
tmp_list = list(set(pop["ID"].unique()) - set(draw_korea["ID"].unique()))
for tmp in tmp_list:
pop = pop.drop(pop[pop["ID"]== tmp].index)
print(set(pop["ID"].unique()) - set(draw_korea["ID"].unique()))
set()
tmp2_list = list(set(draw_korea["ID"].unique()) - set(pop["ID"].unique()))
for tmp in tmp2_list:
draw_korea = draw_korea.drop(draw_korea[draw_korea["ID"]== tmp].index)
print(set(draw_korea["ID"].unique()) - set(pop["ID"].unique()))
set()
pop = pd.merge(pop,draw_korea, how="left", on="ID")
pop.head()
| 광역시도 | 시도 | 20-39세여자 | 20-39세합계 | 65세 이상합계 | 인구수남자 | 인구수여자 | 인구수합계 | 소멸 비율 | 소멸 위기 지역 | ID | y | x | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 강원도 | 강릉시 | 23098.0 | 49384.0 | 37679.0 | 106231.0 | 107615.0 | 213846.0 | 1.226041 | False | 강릉 | 3 | 11 |
| 1 | 강원도 | 고성군 | 2529.0 | 7023.0 | 7151.0 | 15899.0 | 14215.0 | 30114.0 | 0.707314 | True | 고성(강원) | 0 | 10 |
| 2 | 강원도 | 동해시 | 9753.0 | 21264.0 | 15124.0 | 47166.0 | 46131.0 | 93297.0 | 1.289738 | False | 동해 | 4 | 11 |
| 3 | 강원도 | 삼척시 | 7115.0 | 15823.0 | 14610.0 | 35253.0 | 34346.0 | 69599.0 | 0.973990 | True | 삼척 | 5 | 11 |
| 4 | 강원도 | 속초시 | 8752.0 | 18708.0 | 12752.0 | 40288.0 | 41505.0 | 81793.0 | 1.372647 | False | 속초 | 1 | 10 |
def get_data_info(targetData, blockedMap):
whitelabelmin = (
max(blockedMap[targetData]) - min(blockedMap[targetData])
) * 0.25 + min(blockedMap[targetData])
vmin = min(blockedMap[targetData])
vmax = max(blockedMap[targetData])
mapData = blockedMap.pivot_table(index='y', columns='x', values=targetData)
return mapData, vmax, vmin, whitelabelmin
def get_data_info_for_zero_center(targetData, blockedMap):
whitelabelmin = 5
tmp_max = max([np.abs(min(blockedMap[targetData])), np.abs(max(blockedMap[targetData]))]
)
vmin, vmax = -tmp_max, tmp_max
mapData = blockedMap.pivot_table(index='y', columns='x', values=targetData)
return mapData, vmax, vmin, whitelabelmin
def plot_text(targetData, blockedMap,whitelabelmin):
for idx,row in blockedMap.iterrows():
if len(row["ID"].split()) == 2 :
dispname = "{}\n{}".format(row["ID"].split()[0],row["ID"].split()[1])
elif row["ID"][:2] == "고성":
dispname = "고성"
else:
dispname = row["ID"]
if len(dispname.splitlines()[-1]) >= 3:
fontsize, linespacing = 9.5, 1.5
else:
fontsize, linespacing = 11, 1.2
annocolor = "white" if np.abs(row[targetData]) > whitelabelmin else "black"
plt.annotate(
dispname,
(row["x"]+0.5,row["y"]+0.5),
weight="bold",
color=annocolor,
fontsize=fontsize,
linespacing=linespacing,
ha="center", #수평 정렬
va="center", # 수직 정렬
)
def drawKorea(targetData, blockedMap, cmapname, zeroCenter=False):
if zeroCenter:
masked_mapdata, vmax, vmin, whitelabelmin = get_data_info_for_zero_center(targetData,blockedMap)
if not zeroCenter:
masked_mapdata, vmax, vmin, whitelabelmin = get_data_info(targetData, blockedMap)
plt.figure(figsize=(8,11))
plt.pcolor(masked_mapdata, vmin=vmin, vmax=vmax, cmap=cmapname, edgecolor="#aaaaaa", linewidth=0.5)
plot_text(targetData, blockedMap, whitelabelmin)
for path in BORDER_LINES:
ys,xs = zip(*path)
plt.plot(xs, ys, c="black", lw=1.5)
plt.gca().invert_yaxis()
plt.axis("off")
plt.tight_layout()
cb = plt.colorbar(shrink=0.1, aspect=10)
cb.set_label(targetData)
plt.show()
drawKorea("인구수합계", pop, "Blues")

pop["소멸 위기 지역"]

pop["소멸 위기 지역"] = [1 if con else 0 for con in pop["소멸 위기 지역"]] # True/False 로 된 데이터 --> 0 /1
drawKorea("소멸 위기 지역", pop, "Reds")

# 여성 비 컬럼 만들기
pop["여성비"] = (pop["인구수여자"] / pop["인구수합계"] - 0.5 ) * 100
drawKorea("여성비", pop, "RdBu", zeroCenter=True)

pop["2030여성비"] = (pop["20-39세여자"] / pop["20-39세합계"] - 0.5 ) * 100
drawKorea("2030여성비", pop, "RdBu", zeroCenter=True)

import folium
import json
pop_folium = pop.set_index("ID") #지도 그릴 때 ID값 기준으로 하기 위해
pop_folium.head()

# 인구수 합계 시각화
geo_path = "../data/07_skorea_municipalities_geo_simple.json"
geo_str = json.load(open(geo_path, encoding="utf-8"))
myMap = folium.Map(location=[36.2002, 127.054], zoom_start=7)
myMap.choropleth(
geo_data=geo_str,
data=pop_folium["인구수합계"],
key_on="feature.id",
columns=[pop_folium.index, pop_folium["인구수합계"]],
fill_color="YlGnBu"
)
myMap

# 소멸위기 지역 시각화
myMap = folium.Map(location=[36.2002, 127.054], zoom_start=7)
myMap.choropleth(
geo_data=geo_str,
data=pop_folium["소멸 위기 지역"],
key_on="feature.id",
columns=[pop_folium.index, pop_folium["소멸 위기 지역"]],
fill_color="PuRd"
)
myMap

# 데이터 저장
draw_korea.to_csv("../data/07_draw_korea2.csv", encoding="utf-8", sep=",")