본문 바로가기

데이터분석 및 프로젝트

위도 경도 값을 이용하여 거리를 구하고 그래프를 그려보자 :)

 

 

 

 

 

위도 경도 값을 이용하여 거리를 구하고 그래프를 그려보자.

 

안녕하세요 :) 좌표값을 haversine이라는 공식을 이용하여 지구 반경등을 사용하여 거리를 구해보고, 여기에 해당 좌표들의 고도 값을 이용하여 그래프를 그려보도록 하겠습니다.

In [94]:
import matplotlib.pyplot as plt

%matplotlib inline

import platform
from matplotlib import font_manager, rc
plt.rcParams['axes.unicode_minus']=False

if platform.system() == 'Darwin':
    rc('font', family='AppleGothic')
elif platform.system() == 'Windows':
    path = "c:/Windows/Fonts/malgun.ttf"
    font_name = font_manager.FontProperties(fname = path).get_name()
    rc('font', family = font_name)
else:
    print('Unkown system... sorry~~~~')
 

그래프를 그릴 때 한글이 깨지지 않도록 사용하는 코드입니다. 자주 사용하게 되니 알아두세요.

In [95]:

 

import numbers
import math
from geopy.geocoders import Nominatim
geolocator = Nominatim()

class GeoUtil:
    """
    Geographical Utils
    """
    @staticmethod
    def degree2radius(degree):
        return degree * (math.pi/180)
    
    @staticmethod
    def get_harversion_distance(x1, y1, x2, y2, round_decimal_digits=5):
        """
        경위도 (x1,y1)과 (x2,y2) 점의 거리를 반환
        Harversion Formula 이용하여 2개의 경위도간 거래를 구함(단위:Km)
        """
        if x1 is None or y1 is None or x2 is None or y2 is None:
            return None
        assert isinstance(x1, numbers.Number) and -180 <= x1 and x1 <= 180
        assert isinstance(y1, numbers.Number) and  -90 <= y1 and y1 <=  90
        assert isinstance(x2, numbers.Number) and -180 <= x2 and x2 <= 180
        assert isinstance(y2, numbers.Number) and  -90 <= y2 and y2 <=  90

        R = 6371 # 지구의 반경(단위: km)
        dLon = GeoUtil.degree2radius(x2-x1)    
        dLat = GeoUtil.degree2radius(y2-y1)

        a = math.sin(dLat/2) * math.sin(dLat/2) \
            + (math.cos(GeoUtil.degree2radius(y1)) \
              *math.cos(GeoUtil.degree2radius(y2)) \
              *math.sin(dLon/2) * math.sin(dLon/2))
        b = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
        return round(R * b, round_decimal_digits)
 
C:\Users\Wonkim\Anaconda33\lib\site-packages\ipykernel_launcher.py:4: DeprecationWarning: Using Nominatim with the default "geopy/1.20.0" `user_agent` is strongly discouraged, as it violates Nominatim's ToS https://operations.osmfoundation.org/policies/nominatim/ and may possibly cause 403 and 429 HTTP errors. Please specify a custom `user_agent` with `Nominatim(user_agent="my-application")` or by overriding the default `user_agent`: `geopy.geocoders.options.default_user_agent = "my-application"`. In geopy 2.0 this will become an exception.
  after removing the cwd from sys.path.
 

haversine 공식은 좌표계 변환과 삼각함수를 이용하여 거리를 구하는 공식입니다. 소스는 제가 원하는 형태로 짜집기 해온 코드입니다. 좌표를 이용해서 어떤 프로젝트를 하거나 할때 유용하게 쓰일 수 있습니다.

In [96]:
Route_LatLng = [[37.5764873, 126.9854266], [37.57684, 126.98618], [37.577516, 126.9858367], [37.5778665, 126.9856691], [37.5781121, 126.9855516], [37.5782186, 126.985506], [37.5790391, 126.9851173], [37.5792618, 126.9849995], [37.5796173, 126.984966], [37.5800671, 126.984992], [37.5801629, 126.9849962], [37.5805961, 126.9850118], [37.5809155, 126.9850293], [37.5812312, 126.9850139], [37.5814686, 126.9850111], [37.5818577, 126.9843257], [37.5821692, 126.9836089], [37.5823256, 126.983551], [37.5824217, 126.9836735], [37.5829857, 126.9834767], [37.5834721, 126.98306], [37.5834848, 126.9829258], [37.5839766, 126.9829677], [37.5839889, 126.9826768], [37.5839907, 126.9825698], [37.5840336, 126.9826416], [37.5843184, 126.9822764], [37.5844481, 126.9820227], [37.5845466, 126.9820455], [37.5846562, 126.9820518], [37.5848361, 126.9820462], [37.5850625, 126.9820218], [37.5851596, 126.9820188], [37.5852425, 126.9820106], [37.5857697, 126.9818111], [37.5862357, 126.9816655]]
ele = [45.155, 43.766, 42.196, 41.018, 40.381, 40.578, 43.174, 43.691, 44.423, 45.329, 45.725, 48.678, 50.726, 52.532, 53.93, 57.716, 63.152, 64.438, 64.618, 68.689, 69.221, 68.371, 68.622, 65.147, 63.865, 64.564, 59.612, 56.666, 56.637, 56.475, 56.209, 56.313, 56.467, 56.648, 58.841, 60.125]

print(len(Route_LatLng),len(ele))
 
36 36
 

예시를 보여 드리기 위해 임의의 길에 대한 좌표값들(출발지에서 도착지까지의 좌표값들)과 그 해당 좌표에서의 고도값들을 설정해주었습니다.

In [97]:
Lat=[]
for i in range(len(Route_LatLng)):
    lat = Route_LatLng[i][0]
    a = [lat]
    
    Lat.append(a)
    
len(Lat)
Out[97]:
36
In [98]:
Lng=[]
for i in range(len(Route_LatLng)):
    lng = Route_LatLng[i][1]
    a = [lat]
    
    Lng.append(a)
    
len(Lng)
Out[98]:
36
In [115]:
def What_Km(route):
    add=[]
    for i in range(len(route)-1):
            lng1 = route[i][0]
            lat1 = route[i][1]
            lng2 = route[i+1][0]
            lat2 = route[i+1][1]

            result =GeoUtil.get_harversion_distance(lat1,lng1,lat2,lng2)
            add.append(result)

    return '총 거리는 ' + str(round(sum(add),2)) + 'KM 입니다.'
In [100]:
Route_LatLng[0][1]
Out[100]:
126.9854266
In [101]:
def Not_sum_What_Km(route):
    add=[0] #0을 넣어줘서 출발점 생성.
    for i in range(len(route)-1):
            lng1 = route[i][0]
            lat1 = route[i][1]
            lng2 = route[i+1][0]
            lat2 = route[i+1][1]

            result =GeoUtil.get_harversion_distance(lat1,lng1,lat2,lng2)
            c=add[i]+result
            add.append(c)

    return add
 

그래프를 그리는데 필요한 함수들을 만들어줍니다.

In [116]:
def godograph():
    # from Numeric import asarray
    %matplotlib inline
    P1 = Route_LatLng[0] #start
    P2 = Route_LatLng[len(Route_LatLng)-1] #end

    lat0=P1[0]
    lon0=P1[1]

    lat_list=Lat
    lon_list=Lng

    leng=Not_sum_What_Km(Route_LatLng)

    mean_elev=round((sum(ele)/len(ele)),3)
    min_elev=min(ele)
    max_elev=max(ele)
    distance=leng[-1]

    plt.figure(figsize=(14,5))
    plt.xlim(0, leng[len(leng)-1])
    plt.ylim(30, max(ele)+5)

    plt.plot(leng,ele)
    plt.plot([0,distance],[min_elev,min_elev],'--g',label='최저: '+str(min_elev)+' m')
    plt.plot([0,distance],[max_elev,max_elev],'--r',label='최고: '+str(max_elev)+' m')
    plt.plot([0,distance],[mean_elev,mean_elev],'--y',label='평균: '+str(mean_elev)+' m')
    plt.fill_between(leng,ele,30,alpha=0.3)

    plt.annotate('출발',size='18',xy=(leng[0],ele[0]),xytext=(leng[0],ele[0]+5),arrowprops={'color':'black'})

    plt.text(leng[-1],ele[-1],"도착",size='18',color='black')
    plt.xlabel("Distance(km)",size='16',color='darkblue')
    plt.ylabel("Elevation(m)",size='16',color='darkblue')
    plt.grid()
    plt.legend(fancybox=True, framealpha=1, shadow=True, borderpad=0.6,loc=2,fontsize='10')

    print(What_Km(Route_LatLng))

    return plt.show()
In [118]:
godograph()
 
총 거리는 1.31KM 입니다.
 
 

이렇게 결과물이 나왔습니다. 보기좋게 좀 꾸며봤는데요. 응용하여 잘 쓰일 수 있는 코드들이라고 생각합니다:)