지도 그리기 (카르토그램)
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(
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()
|
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()
공통 컬럼 "ID"로 merge`
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 |
그림을 그리기 위한 데이터를 계산하는 함수
- 색상을 만들 때, 최소값을 흰색으로
- blockedMap : 인구현황 (pop)
- targetData : 그리고싶은 컬럼
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["소멸 위기 지역"]]
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)
folium으로 지도 시각화
import folium
import json
pop_folium = pop.set_index("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=",")