본문 바로가기
파이썬으로 배우는 지구과학

파이썬의 원 그래프(pie chart)를 이용하여 해수에 녹아있는 염분비 표현하기

by 0대갈장군0 2023. 4. 16.
반응형

해수에는 염소, 소듐, 황산 등 다양한 물질들이 녹아 있고, 이 물질들이 녹아있는 양은 바다에 따라 다르지만, 녹아있는 비는 어느 바다나 같다는 사실. 지구과학I에서 비교적 중요하게 다루는 내용 중 하나입니다. 여기서는 해수에 녹아있는 염분들의 양을 파이썬을 이용해 원 그래프(또는 파이차트, pie chart)로 나타내는 방법을 알아보고자 합니다.
 

  1. 염분들의 비

우선 녹아있는 염분들의 비를 알아야 합니다. 수 많은 참고서나, 대학 서적, 인터넷 등을 뒤지면 해수 1kg에 녹아있는 평균 염분양을 어렵지 않게 찾을 수 있습니다. 아래 표는 해양학 개론서에서 내용을 참고한 염분비입니다.

염분종류염소이온소듐이온황산이온마그네슘
이온
칼슘이온포타슘이온중탄산이온기타
18.980g10.556g2.649g1.2720.400g0.380g0.140g0.023g

  2. 그래프로 나타내기

가. 라이브러리 추출

그래프 표현 자체는 굉장히 간단합니다. 다만, 우리를 조금 어렵게 하는 부분이 있습니다. 그 부분은 추후 설명하겠습니다.
우선 각 염분 이름을 한글로 표현할 때 필요한 코드와 그래프 그릴때 필수 라이브러리인 matplotlib를 불러오겠습니다.

import matplotlib.pyplot as plt
from matplotlib import font_manager, rc
rc('font', family='HCR Dotum')

나. 데이터 집어넣기

다음으로 필요한 데이터를 리스트 형식으로 불러오겠습니다. 그리고, 그래프의 크기를 적당히 지정해 주겠습니다.

water=[18.980,10.556,2.649,1.272,0.400,0.380,0.140,0.023]
labels=['염소이온','소듐이온','황산이온','마그네슘이온','칼슘이온','포타슘이온','중탄산이온','기타']
plt.figure(figsize=(7,7))

여기까지는 어렵지 않습니다. 하나도.
이제 바로 파이차트로 그려보겠습니다.

다. 그래프 그리기 기초 

plt.pie(water,labels=labels)
plt.savefig(C:\\111\\salanity.jpg", dpi-=300)
plt.show()

라. 그래프 안에 수치 집어넣기 

뭔가 그려지긴 했는데, 너무 허 합니다. 우선 불필요한 여백이 너무 많으니, 여백을 제거하고, 수치가 하나도 없으니 수치도 좀 집어넣겠습니다.
이 때 필요한 코드는 
plt.tight_layout() -> 공백 제거
autopct='%.3f' -> 수치 집어넣기
(여기서 %.3f는 쉽게 생각하면 소숫점 3째 자리까지만 표시하라는 의미입니다. 여기서는 중요하지 않으니 자세히 설명하진 않겠습니다)
 
입니다. 이 아이들을 추가하겠습니다.

import matplotlib.pyplot as plt
from matplotlib import font_manager, rc
rc('font', family='HCR Dotum')
water=[18.980,10.556,2.649,1.272,0.400,0.380,0.140,0.023]
labels=['염소이온','소듐이온','황산이온','마그네슘이온','칼슘이온','포타슘이온','중탄산이온','기타']
plt.figure(figsize=(7,7))
plt.pie(water,labels=labels,autopct='%.3f')
plt.tight_layout()
plt.savefig("C:\\111\\salinity33.jpg",dpi=300)
plt.show()

결과는 아래와 같습니다.

마. 그래프 안의 숫자 퍼센트 말고 실제 숫자 집어넣기 

그래프가 뭔가 그려지긴 했습니다. 근데 가만히 자세히 보면, 수치가 작은 아이들은 칸이 부족해서 글씨가 죄다 겹쳤습니다. 이거야 어떻게 해결이 되겠다만, 문제는 저기 나와있는 수치입니다. 파이썬에서 pie chart로 수치를 표현하면 기본적으로, 실제 데이터를 표현해주지 않고, 저기 나와있는것처럼 비율(퍼센트)로 표현해 줍니다. 이게 사람을 정말 미쳐버리게 합니다. 그렇다면, 실제 수치로 표현할 수 있는 방법은 없는건가? 아닙니다 당연히 있습니다. 이게 좀 복잡합니다.
 
파이썬이 처음에 저렇게 퍼센트로 계산하는과정은 간단합니다. 예를들어 염소 이온의 경우 18.980g이고, 전체 염분 양은 34.4g입니다. 그래서, 염소염분의 퍼센트는 55.174로 나온 겁니다. 이걸 다시 역으로 원래 수치를 넣으라고 해 줘야 합니다.
 
그래서 water와 labels의 리스트형 데이터 다음에 total=sum(water)라는 코드를 추가하고, autopct='%.3f' 대신에 아래 코드를 집어 넣습니다.
autopct=lambda p: '{:.3f}g'.format(p * total / 100)
lambda 함수와 문자열 인덱싱 format에 대한 내용은 잠시 접어두고(글이 산으로 갈 것 같아서) 여기서는 실제 데이터를 파이 차트에 집어넣으려면 저 코드를 집어 넣자는 사실을 공식적으로 외우는 차원에서만 다루겠습니다. 그럼 아래와 같이 됩니다.

import matplotlib.pyplot as plt
from matplotlib import font_manager, rc
rc('font', family='HCR Dotum')
water=[18.980,10.556,2.649,1.272,0.400,0.380,0.140,0.023]
labels=['염소이온','소듐이온','황산이온','마그네슘이온','칼슘이온','포타슘이온','중탄산이온','기타']
total=sum(water)
plt.figure(figsize=(7,7))
plt.pie(water,labels=labels,autopct=lambda p: '{:.3f}g'.format(p * total / 100))
plt.tight_layout()
plt.savefig("C:\\111\\salinity33.jpg",dpi=300)
plt.show()

이렇게 나온 결과는 아래와 같습니다.

오늘 하는것 중 가장 어려운 것이 끝났습니다. 이제 나머지는 단순히 그래프의 시안성을 높이는 단순한 작업들입니다.

반응형

바. 겹치는 부분 해결하기 

기타, 포타슘 이온, 중탄산 이온 등 수치가 너무 작아 겹치는 아이들을 안겹치게 하겠습니다. 겹치는 부분의 데이터에 해당하는 파이 조각을 중심에서 떨어뜨려 해결하겠습니다.
이 때 사용되는 코드는 explode입니다. 데이터가 총 8개이므로, 8개를 각각 중심에서 얼마나 떨어트릴지 결정해야합니다. 기본값은 0입니다. 염소나 소듐, 황산은 중심에서 떨굴 필요가 없으니까 이 아이들은 그대로 0으로 두고, 나머지를 조금씩 떨어뜨리겠습니다. 따라서 explode라는 리스트형 데이터를 하나 만들고, plt.pie의 ()안의 옵션 명령어에 explode를 집어 넣을 겁니다. 그러면 아래와 같습니다.

## 퍼센티지로 표현
import matplotlib.pyplot as plt
from matplotlib import font_manager, rc
rc('font', family='HCR Dotum')
water=[18.980,10.556,2.649,1.272,0.400,0.380,0.140,0.023]
labels=['염소이온','소듐이온','황산이온','마그네슘이온','칼슘이온','포타슘이온','중탄산이온','기타']
explode=[0,0,0,0.2,0.35,0.48,0.59,0.73]
total=sum(water)
plt.figure(figsize=(7,7))
plt.pie(water,labels=labels,explode=explode,autopct=lambda p: '{:.3f}g'.format(p * total / 100))
plt.tight_layout()
plt.savefig("C:\\111\\salinity33.jpg",dpi=300)
plt.show()

사. 시작점 바꾸기

글자 겹침이 완전 해소되진 않았습니다. 그리고 그래프 시작점이 좀 어색하여 이뻐 보이지 않습니다. 시작점만 바꾸어도 글자겹침이 어느정도 해소되기도 합니다. 시작점을 바꾸기 위해 plt.pie()의 괄호안에 아래 코드를 추가합니다.
startangle=30
startangle= 다음에 나오는 숫자를 이리저리 바꾸어 자신에게 보기 좋은 시작점을 찾으시면 됩니다. 코드는 간단하니 생략합니다. 단순히 plt.pie()괄호 안 아무대나 저거 집어넣으면 됩니다. 결과는

이제 좀 봐 줄 만한 모양이 되었습니다. 다 그린거나 마찬가지입니다. 만약 색깔이 좀 칙칙하여 바꾸시고 싶다면, 아래 코드를 추가하면 됩니다. 우선 데이터가 8개니까, 8개의 색상을 하나씩 지정해 줍니다. 만약 8개보다 적게 지정하면 지정해준 색깔을 순차적으로 반복해서 지정해 줍니다. 저는 8개를 모두 달리 지정해 주었습니다.
color=['lightblue', 'deepskyblue','turquoise','cornsilk','tan','mistyrose','lavenderblush','thistle']
plt.pie(water,labels=labels,explode=explode,autopct=lambda p: '{:.3f}g'.format(p * total / 100),startangle=30)
색상표는 구글링하면 엄청나게 쏟아지니 여기서는 생략
어쨌든 결과를 보면

짠 하고 이제 봐 줄 만한 모양새가 나왔습니다.
 
이번 파이썬 코드는 plt.pie만 있었으면 전혀 어렵지 않았습니다. 다만 

  • 글짜가 겹치는 부분을 해결하기
  • 퍼센트가 아닌 실제 수치 사용하기

이 두가지가 어려운 부분이고, 특히 저를 힘들게 한 부분이 퍼센트가 아닌 실제 수치를 사용하는 점이었습니다. 국내 어느 부분을 참조해도 찾기 어려웠는데, 해외 사이트에서 해결책이 나오더군요. 그리고 전세계 사람들이 모두 같은 고민을 했다는 사실..ㅎㅎㅎ 아무튼 저 개인적으로도 문제를 해결하여 뿌듯한 부분이 있었습니다.
 
다음번에는 더 재미있는 파이썬으로 배우는 지구과학을 준비해 보겠습니다.
<전체 코드>

## 퍼센티지로 표현
import matplotlib.pyplot as plt
from matplotlib import font_manager, rc
rc('font', family='HCR Dotum')
water=[18.980,10.556,2.649,1.272,0.400,0.380,0.140,0.023]
labels=['염소이온','소듐이온','황산이온','마그네슘이온','칼슘이온','포타슘이온','중탄산이온','기타']
explode=[0,0,0,0.2,0.35,0.48,0.59,0.73]
color=['lightblue', 'deepskyblue','turquoise','cornsilk','tan','mistyrose','lavenderblush','thistle']
total=sum(water)
plt.figure(figsize=(7,7))
plt.pie(water,colors=color,labels=labels,explode=explode,autopct=lambda p: '{:.3f}g'.format(p * total / 100),startangle=30)
plt.tight_layout()
plt.savefig("C:\\111\\salinity33.jpg",dpi=300)
plt.show()

 

반응형

댓글