[제로베이스] 7주차_EDA 11

해오름·2023년 3월 17일
0

[zb]

목록 보기
17/18

📌3/15 영상 강의 인구분석 3 , MYSQL 기초 1,2

4. 지도 그리기(카르토그램)

(1) 엑셀에서 그린 지도 읽어오기

draw_korea_raw=pd.read_excel("../data/07_draw_korea_raw.xlsx")
draw_korea_raw


# 인덱스로 나타난 좌표를 데이터로 사용하기 위해 reset_index

draw_korea_raw_stack = pd.DataFrame(draw_korea_raw.stack())
draw_korea_raw_stack

stack & unstack

  • stack : 컬럼 레벨에서 인덱스 레벨(row 레벨)로 dataframe 변경
    즉, 데이터를 쌓아올리는 개념으로 이해하면 쉬움
  • unstack : 인덱스 레벨에서 컬럼 레벨로 dataframe 변경
    stack의 반대 operation 둘은 역의 관계에 있음

(2) 경계선 그리기

# 엑셀 좌표 한땀한땀 적기

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]) # id 두글자씩개행하기
        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)  # ys, xs 변수 순서가 바뀌면 모인 숫자 위치가 달라져서 지도가 다르게 그려진다
        plt.plot(xs, ys, c="black", lw=1.5)
        
    plt.gca().invert_yaxis()
    plt.axis("off")
    plt.tight_layout()
    plt.show()
    
simpleDraw(draw_korea)

(3) 데이터검증

(4) merge

(5) 그림을 그리기 위한 데이터를 계산하는 함수

  • 색상을 만들 때, 최소값을 흰색
  • 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): 
    
    # 값이 음수, 양수 들어왔을 센터(0,화이트색상) 범위 다시 잡아주기
    
    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]) # id 두글자씩개행하기
        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)  # ys, xs 변수 순서가 바뀌면 모인 숫자 위치가 달라져서 지도가 다르게 그려진다
        plt.plot(xs, ys, c="black", lw=1.5)
        
    plt.gca().invert_yaxis()
    plt.axis("off")    
    cb = plt.colorbar(shrink=0.1, aspect=10)
    cb.set_label(targetData)
    plt.tight_layout()
    plt.show()



(6) 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

👍마무리
지도그리기 함수 ..넘 복잡하다
나중에 내가 이런걸 뚝딱 한다고? 세상에나.. 넘 멋잇는걸
갈 길이 한~참 멀지만 뚝딱뚝딱 일하는 내 모습을 상상하며 힘을 내본다

profile
study note

0개의 댓글