{"id":122,"date":"2017-09-09T19:57:38","date_gmt":"2017-09-09T17:57:38","guid":{"rendered":"http:\/\/cwiok.pl\/?p=122"},"modified":"2018-05-23T15:46:53","modified_gmt":"2018-05-23T13:46:53","slug":"loty-podczas-burzy","status":"publish","type":"post","link":"https:\/\/cwiok.pl\/index.php\/pl\/2017\/09\/09\/loty-podczas-burzy\/","title":{"rendered":"Loty podczas burzy"},"content":{"rendered":"<p style=\"text-align: left;\">Stworzenie tej wizualizacji zaj\u0119\u0142o mi znacznie wi\u0119cej czasu ni\u017c s\u0105dzi\u0142em. Pomys\u0142 pojawi\u0142 si\u0119 29. czerwca gdy siedzia\u0142em w biurze Microsoft przy lotnisku w Warszawie. Burza tego dnia by\u0142a ogromna. Podczas sprawdzania ruchu lotniczego na Flightradar24, zacz\u0105\u0142em zastanawia\u0107 si\u0119 jak wygl\u0105da\u0142yby loty na jednym wykresie z map\u0105 i chmurami. Po 3(!) miesi\u0105cach pracy, oto i on:\n<\/p>\n<div style=\"width: 640px;\" class=\"wp-video\"><video class=\"wp-video-shortcode\" id=\"video-122-1\" width=\"640\" height=\"475\" loop autoplay preload=\"metadata\" controls=\"controls\"><source type=\"video\/mp4\" src=\"http:\/\/cwiok.pl\/wp-content\/uploads\/2017\/09\/0-478_ready.mp4?_=1\" \/><a href=\"http:\/\/cwiok.pl\/wp-content\/uploads\/2017\/09\/0-478_ready.mp4\">http:\/\/cwiok.pl\/wp-content\/uploads\/2017\/09\/0-478_ready.mp4<\/a><\/video><\/div>\n<p style=\"text-align: left;\">Poni\u017cej znajdziecie szczeg\u00f3\u0142owy opis, jak zosta\u0142 stworzony.<br \/>\n<!--more--><\/p>\n<p style=\"text-align: left;\">1. Dane lot\u00f3w<\/p>\n<p style=\"text-align: left;\">Po bardzo dok\u0142adnych poszukiwaniach stwierdzi\u0142em, \u017ce na danych z Flightradar24 mo\u017cna polega\u0107 najbardziej, wi\u0119c wzi\u0105\u0142em kart\u0119 do r\u0119ki i rozpocz\u0105\u0142em okres pr\u00f3bny. Na stronie wyfiltrowa\u0142em interesuj\u0105ce mnie loty i pobra\u0142em pliki csv z kolumnami: Timestamp, UTC, Callsign, Position, Altitude ,Speed, Direction. Wszystkie pliki s\u0105 dost\u0119pne <a href=\"http:\/\/cwiok.pl\/wp-content\/uploads\/2017\/09\/Flights.7z\">tutaj.<\/a><\/p>\n<p style=\"text-align: left;\">G\u0142\u00f3wnym problemem z danymi by\u0142 fakt, \u017ce r\u00f3\u017cnice czasu mi\u0119dzy obserwacjami (wierszami) nie by\u0142y sta\u0142e. Przyk\u0142adowo podczas startu i l\u0105dowanie w danych znajdowa\u0142o si\u0119 oko\u0142o 10 obserwacji na minut\u0119, a na wysoko\u015bci przelotowej 1 lub 2. Z tego powodu musia\u0142em interpolowa\u0107 &#8220;brakuj\u0105ce&#8221; obserwacji zak\u0142adaj\u0105c, \u017ce zmiana mi\u0119dzy dwoma obserwacjami by\u0142a liniowa.<\/p>\n<p style=\"text-align: left;\">Kod, u\u017cyty do przygotowania danych jest dost\u0119pny poni\u017cej:<\/p>\n<pre>import re\r\nfrom numpy import genfromtxt\r\nimport numpy as np\r\nimport os.path\r\nfrom distribution import uniform_distribution #the function I have written\r\n\r\n#Get list of all the CSV\r\npath = '.'\r\nr = re.compile(\".*csv\")\r\ncsv_list = list(filter(r.match,os.listdir(path)))\r\ncsv_count = len(csv_list)\r\n\r\ndef data_extract(file1):\r\n    #Rename files and write them to a separate folder\r\n    file2 = file1.replace('Flight_','')[:5] + '.csv'\r\n    fin = open(file1)\r\n    data = fin.read().splitlines(True)\r\n    fout = open('source files\/'+ file2,\"w+\")\r\n    for line in data[1:]:\r\n        line = line.replace('\"','')\r\n        fout.write(line)\r\n    fin.close()\r\n    fout.close()\r\n    \r\n    #Create arrays from the data and filter it by time\r\n    data = genfromtxt('source files\/'+ file2, delimiter=\",\",  dtype = None, names=\"timestamp, utc, callsigb, pos1, pos2, att, speed, direction\")\r\n    data = data[::-1]\r\n    data = data[data['timestamp']&gt;1498731036]\r\n\r\n    #Interpolate the data\r\n    coords = uniform_distribution (data)\r\n    return coords\r\n<\/pre>\n<pre>#Interpolate the coords\r\nfrom numpy import genfromtxt\r\nimport numpy as np\r\nimport math\r\nimport bisect\r\n\r\ndef uniform_distribution (data):\r\n    #Get min and max time from the data\r\n    max_t = max(data['timestamp'])\r\n    min_t = min(data['timestamp'])\r\n    \r\n    #Divide it by 12 seconds, because this is my aim\r\n    diff = (max_t-min_t)\/\/12\r\n    rounded = math.ceil(diff)\r\n    \r\n    #Create new array with time distributed by 12 seconds\r\n    new_data = np.arange(min_t, max_t, 12)\r\n    pos1 = np.empty(len(new_data))\r\n    pos2 = np.empty(len(new_data))\r\n\r\n    for i,timestamp in enumerate(new_data):\r\n        #Find next timestamp bigger than current\r\n        index = bisect.bisect(data['timestamp'], timestamp)\r\n        \r\n        #Smaller\r\n        smaller = data['timestamp'][index-1]\r\n        smaller_pos1 = data['pos1'][index-1]\r\n        smaller_pos2 = data['pos2'][index-1]\r\n        #Bigger\r\n        bigger = data['timestamp'][index]\r\n        bigger_pos1 = data['pos1'][index]\r\n        bigger_pos2 = data['pos2'][index]\r\n        #Linear interpolation\r\n        pos1[i]=smaller_pos1 + ((bigger_pos1-smaller_pos1)\/(bigger - smaller))*(timestamp-smaller)\r\n        pos2[i]=smaller_pos2 + ((bigger_pos2-smaller_pos2)\/(bigger - smaller))*(timestamp-smaller)\r\n    \r\n    #Merge columns and return them  \r\n    new_coords = np.column_stack((pos1, pos2))\r\n    \r\n    return new_coords\r\n<\/pre>\n<p style=\"text-align: left;\">2.Mapa i chmury<\/p>\n<p style=\"text-align: left;\">Dane chmur zdoby\u0142em od portalu <a href=\"http:\/\/radar-opadow.pl\" target=\"_blank\" rel=\"noopener\">radar-opadow<\/a>, kt\u00f3rego ekipa dosta\u0142a od IMGW. Pliki sa dost\u0119pne <a href=\"https:\/\/radar-opadow.pl\/\/data\/imgw\/cappi\/201706291150.png\" target=\"_blank\" rel=\"noopener\">tutaj.<\/a>\u00a0Pliki te musia\u0142y zosta\u0107 przetworzone u\u017cywaj\u0105c proj4. Ca\u0142y proces jest opisany na <a href=\"https:\/\/openlayers.org\/en\/master\/examples\/reprojection-image.html\" target=\"_blank\" rel=\"noopener\">tej stronie<\/a>. Ta cz\u0119\u015b\u0107 projektu by\u0142a najwolniejsza i ostatecznie zapisywa\u0142em wycinku ekranu z plik\u00f3w HTML, kt\u00f3re stworzy\u0142em. Tym sposobem otrzyma\u0142em kilkana\u015bcie plik\u00f3w, kt\u00f3re mia\u0142y pos\u0142u\u017cy\u0107 jako t\u0142o dla wykresu. Przyk\u0142adowy html jest do pobrania pod <a href=\"http:\/\/cwiok.pl\/wp-content\/uploads\/2017\/09\/Clouds_over_gmaps.html\">tym linkiem<\/a>\u00a0(kliknij zapisz jako).<\/p>\n<p>3. Tworzenie wykresu<br \/>\nPocz\u0105tkowo planowa\u0142em stworzy\u0107 animacj\u0119 korzystaj\u0105c z Matplotlib i zapisa\u0107 j\u0105 jako gif\/mp4. Niestety nie by\u0142em w stanie znale\u017a\u0107 sposobu na zmian\u0119 t\u0142a razem z kolejnymi klatkami. Aby rozwi\u0105za\u0107 ten problem napisa\u0142em p\u0119tl\u0119, kt\u00f3ra tworzy\u0142a poszczeg\u00f3lne klatki. Ca\u0142y kod jest poni\u017cej:<\/p>\n<pre>import re\r\nfrom numpy import genfromtxt\r\nimport numpy as np\r\nimport os.path\r\nfrom distribution import uniform_distribution\r\n\r\n#Find all the backgrounds\r\npath1 = '.'\r\nr1 = re.compile(\".*png\")\r\npng_list = list(filter(r1.match,os.listdir(path1)))\r\npng_count = len(png_list)\r\n\r\npath = '.'\r\nr = re.compile(\".*csv\")\r\ncsv_list = list(filter(r.match,os.listdir(path)))\r\ncsv_count = len(csv_list) \r\n\r\nfig = plt.figure(figsize = (50,80))\r\nlines = [plt.plot([], [], 'r-',  markersize=10,linewidth=5)[0] for _ in range(csv_count)]\r\n\r\nextracted_data = []\r\nfor i in range(csv_count):\r\n extracted_data.append(data_extract(csv_list[i]))\r\n\r\nif __name__ == '__main__':\r\n    for line in lines:\r\n        line.set_data([], [])\r\n    #Loop all the frames\r\n    for i in range(0,475):\r\n        \r\n        for index, line in enumerate(lines):\r\n            line.set_data(((extracted_data[index][1+i:10+i,1]-13)*(600\/13)-45)*(1326\/531), (392-(extracted_data[index][1+i:10+i,0]-49)*(430\/6)+40)*(983\/392))\r\n       \r\n        l = i\/\/50\r\n        img = plt.imread(png_list[l])\r\n        plt.imshow(img, zorder = 1,interpolation='nearest') #extent=[14, 27, 49, 55])\r\n        plt.axis('off')\r\n        plt.savefig('final_gif\/' + str(i) + \"_ready.jpg\", bbox_inches='tight', dpi=40)\r\n        print('Frame {}'.format(i))\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Za pomoc\u0105 tego skryptu wygenerowa\u0142em 476 klatek, kt\u00f3re p\u00f3\u017aniej zosta\u0142y zapisane w MP4. W pierwszym podej\u015bciu chcia\u0142em u\u017cy\u0107 pythona do stworzenia animacji, ale po kilku eksperymentach zawsze ko\u0144czy\u0142em z plikiem o rozmiarze 500+. Z tego powodu poprosi\u0142em o pomoc <a href=\"http:\/\/kgrabowski.com\">koleg\u0119<\/a>, kt\u00f3ry jest mistrzem Photoshopa. On da\u0142 rad\u0119 stworzy\u0107 znacznie mniejszy plik.<\/p>\n<div style=\"width: 640px;\" class=\"wp-video\"><video class=\"wp-video-shortcode\" id=\"video-122-2\" width=\"640\" height=\"475\" loop autoplay preload=\"metadata\" controls=\"controls\"><source type=\"video\/mp4\" src=\"http:\/\/cwiok.pl\/wp-content\/uploads\/2017\/09\/0-478_ready.mp4?_=2\" \/><a href=\"http:\/\/cwiok.pl\/wp-content\/uploads\/2017\/09\/0-478_ready.mp4\">http:\/\/cwiok.pl\/wp-content\/uploads\/2017\/09\/0-478_ready.mp4<\/a><\/video><\/div>\n<p>Czekam na feedback, to s\u0105 moje pierwsze kroki w Pythonie i pewnie da\u0142oby si\u0119 zrobi\u0107 to lepiej. Ka\u017cda sugestia jest mile widziana \ud83d\ude42<\/p>\n<p>Dzi\u0119ki!<\/p>\n","protected":false},"excerpt":{"rendered":"<p style=\"text-align: left;\">Stworzenie tej wizualizacji zaj\u0119\u0142o mi znacznie wi\u0119cej czasu ni\u017c s\u0105dzi\u0142em. Pomys\u0142 pojawi\u0142 si\u0119 29. czerwca gdy siedzia\u0142em w biurze Microsoft przy lotnisku w Warszawie. Burza tego dnia by\u0142a ogromna. Podczas sprawdzania ruchu lotniczego na Flightradar24, zacz\u0105\u0142em zastanawia\u0107 si\u0119 jak wygl\u0105da\u0142yby loty na jednym wykresie z map\u0105 i chmurami. <\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/cwiok.pl\/wp-content\/uploads\/2018\/05\/artyku\u0142_02_loty-podczas-burzy.jpg\" alt=\"\" width=\"1200\" height=\"628\" class=\"alignnone size-full wp-image-228\" srcset=\"https:\/\/cwiok.pl\/wp-content\/uploads\/2018\/05\/artyku\u0142_02_loty-podczas-burzy.jpg 1200w, https:\/\/cwiok.pl\/wp-content\/uploads\/2018\/05\/artyku\u0142_02_loty-podczas-burzy-300x157.jpg 300w, https:\/\/cwiok.pl\/wp-content\/uploads\/2018\/05\/artyku\u0142_02_loty-podczas-burzy-768x402.jpg 768w, https:\/\/cwiok.pl\/wp-content\/uploads\/2018\/05\/artyku\u0142_02_loty-podczas-burzy-1024x536.jpg 1024w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/p>\n<div class=\"tech_read_more\"><a href=\"https:\/\/cwiok.pl\/index.php\/pl\/2017\/09\/09\/loty-podczas-burzy\/\">Read More<\/a><\/div>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[34],"tags":[],"class_list":["post-122","post","type-post","status-publish","format-standard","hentry","category-python-pl"],"_links":{"self":[{"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/posts\/122","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/comments?post=122"}],"version-history":[{"count":0,"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/posts\/122\/revisions"}],"wp:attachment":[{"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/media?parent=122"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/categories?post=122"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cwiok.pl\/index.php\/wp-json\/wp\/v2\/tags?post=122"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}