poniedziałek, 2 lutego 2015

Wizualizacja sił drużyn serie-A w latach 1994-2014 - d3.js w akcji.

Problem

Doszliśmy do momentu, w którym odstawiamy R na bok, klepiąc przyjacielsko po ramieniu mówiąc "zrobiłeś wszystko co w Twojej mocy, dziękuję". Pakiety do wizualizacji danych takie jak ggplot2 czy lattice są świetnym asystentem w trakcie pracy z danymi, pozwalają na szybki podgląd w trakcie wyjaśniania jakiegoś zjawiska. Statyczność, brak możliwości interakcji, ograniczone możliwości animacyjne raczej ograniczają R do wizualizacji na użytek własny lub prezentacje na mniejszą skalę. Być może wspomniana "wizualizacja na mniejszą skalę" jest dla wielu wystarczająca, bowiem seria dostępnych pakietów robi dobre wrażenie - ggplot2, lattice, plotly, shiny, animation, iplot, svgGrid i coś co mi podoba się najbardziej, czyli połączenie slidify i rCharts. Prawdopodobnie nie wymieniłem wszystkich pakietów i być może są gdzieś dobrze skrojone biblioteki pozwalające na dosyć dużą swobodę w kształtowaniu formy. Wątpię jednak żeby była biblioteka dająca pełną swobodę. Ja sam jestem zwolennikiem rozszerzania horyzontów i uważam, że lepiej nawet dla czystego sportu nauczyć się JavaScript, HTML5 oraz CSS3 i tworzyć od podstaw szalone wizualizacje, niż ograniczać się do granic narzuconych przez biblioteki R. Wpis jest pewną propozycją, próbą zainteresowania, a nie koniecznie wskazaniem bezwarunkowego rozwiązania. Zapewniam również, że zestaw R-owych pakietów, które wymieniłem wystarczą mistrzom danych do sprawnego prezentowania wyników analiz czy nawet schludnego dziennikarstwa.
Zaletą JavaScript jest to, że jest językiem przeglądarek internetowych, oznacza to, że każdy może otworzyć Naszą wizualizację nawet na urządzeniach mobilnych. Jak dotąd nie zanosi się żeby JavaScript miał stracić monopol na przeglądarki. Z pewnością JS to technologia, która będzie powszechna jeszcze przez wiele lat, co więc stoi na przeszkodzie żeby przeznaczyć kilka dni na naukę nowego środowiska? 
JavaScript nie koniecznie można uznać za trudny język, jest on jednak zupełnie inaczej skonstruowany niż R i trzeba po prostu przez to przebrnąć. Do rozpoczęcia programowania w JS wystarczy notatnik i przeglądarka np. z dodatkiem firebug. Być może duża część z Was już kiedyś pisała strony w HTML i CSS, dodając czasem jakieś drobne funkcjonalności używając JavaScript (np. "onclick"). Spora część z pewnością zjadła zęby na WebScrapingu . Być może ktoś już korzystał z jQuery, jeżeli tak - nie ma przeszkód żeby użyć d3.js i sprawić żeby Nasza usługa cieszyła oko odbiorcy.


Rozwiązanie

Siły drużyn Serie-A w sezonach 1994-2014 to sporo danych do zaprezentowania. Wrzucenie całego stosu na wykres i prezentacja w formie statycznej powoduje chaos informacyjny, dlatego wprowadzimy elementy interakcji. Przed każdą większą wizualizacją warto przemyśleć sobie formę jaką zaserwujemy odbiorcy i zanotowanie wszystkich detali. Najlepiej narysować sobie owoc Naszej wyobraźni, a następnie przystąpić do kodowania zgodnie z planem.


W planie mamy skonstruowanie wykresu czasowego parametrów beta dla każdej z drużyn. Wszystkie drużyny wrzucamy do pola wykresu o jednakowej, słabej wyrazistości. Legenda, która znajdować się będzie ponad wykresem będzie alfabetyczną listą drużyn, na których najechanie myszką ma spowodować wyróżnienie danego szeregu na wykresie. Szerokość wykresu powinna wynieść 700px żeby zmieścił się w granicy tekstu mojego bloga.
Na początku tworzymy plik .html, w którym umieszczamy podstawy takie jak zdefiniowane style poszczególnych elementów, jeden <div> z tytułem i dwa puste <div>, w których umieścimy legendę i wykres (id="legenda", id="chart"). Skoro będziemy skryptować z użyciem d3.js to musimy wskazać miejsce biblioteki <script src="...">.
Mamy już podstawę w postaci html, teraz możemy przejść do skryptowania. W pierwszej kolejności określamy odstępy (margins) i wymiary obszaru wykresu. Następnie do elementu o id="chart" dodajemy element <svg> oraz element <g> o zadanych atrybutach (tutaj więcej o tworzeniu nowych obiektów).
Tworzymy zmienną kolor z 10 kolorami dla odróżnienia drużyn. Podobnie jak w R musimy sformatować datę żeby była poprawnie interpretowana. Zmienna sezon to rok rozpoczęcia rozgrywek, dlatego określamy format daty jako "%Y". parseDate możemy uznać za funkcję, którą użyjemy w dalszej części do formatowania zmiennej x. W d3.js musimy sami zdefiniować zakres zmienności na wykresie (domain) oraz określić na jakim obszarze mają  się wyświetlać dane (range) - dokładniejszy opis tutaj. Następnie definiujemy osie X (czasowa) i Y(liczbowa). Na koniec pierwszej sekcji definiujemy funkcję rysującą linie, która pomija missingi (!isNaN). Kształt linii będzie bardziej zaokrąglony, bez ostrych kątów. Położenie linii będzie uzależnione od parametru (.y) i od sezonu (.x). Na koniec pierwszej części skryptu dodajemy puste wektory sezon i parametry, do których załadujemy danę z pliku .csv.
Teraz przechodzimy do najważniejszego punktu czyli danych - możemy zaciągać dane z różnych źródeł. My skorzystamy z pliku .csv, który zapisałem w R i wrzuciłem tutaj do sieci. Skryptowanie w JS wygląda zupełnie inaczej niż w R. W R przypisujemy cały zbiór do określonej zmiennej, do której możemy dalej się odwoływać. W JS odwołujemy się do danych z pliku .csv i w granicach klamry {} musimy wykonać wszystkie operacje dokonywane przy użyciu zbioru. Przyznam, że miałem zawroty głowy jak próbowałem zrozumieć jak pracować z danymi w JS ale szczególnie pomocny okazał się blog jeromecukier.com z wpisem "manupulating data like a boss with d3" 8-).

W pierwszej kolejności po przeczytaniu pliku.csv musimy zadbać o poprawność danych. Przy pomocy pętli na zbiorze formatujemy kolumnę sezon jako datę (użycie parseDate) i parametr jako zmienną liczbową. Wstawienie znaku dodawania +przed_zmienną sprawia, że jest ona interpretowana jako liczbowa - przypadku gdy w kolumnie liczbowej znajduje się tekst np. pochodzące z R "NA", automatycznie jest zamieniane na NaN, o czym warto pamiętać przy rysowaniu linii. Przy okazji również demonstruję jak zapisać dane z dowolnych kolumny do zmiennych (sezon i parametr), dodając w pętli jedną obserwację po drugiej do wektora (odpowiednik append w pythonie).
Na podstawie minimum i maksimum z wektorów sezon i parametry ustawiamy .domain dla x i y, czyli zakres zmienności zmiennych. Następnie rysowane są osi x i y.

Mamy już narysowane osie, zdefiniowane pole wykresu (svg wraz z .domain i .range), zdefiniowaną funkcję rysującą linie (var linia) zatem możemy przejść do finałowych linijek skryptu. Musimy dane pogrupować po danej drużynie, tak żeby linia nie była ciągła na całym zbiorze. Służy do tego funkcja d3.nest gdzie .key() to zmienna po której grupujemy, a .entries() do zbiór, którego grupowanie dotyczy. Po zdefiniowaniu grup uruchamiamy pętle .foreach osobno dla każdej z grup. W pętli do zdefiniowanego pola wykresu (svg) dodajemy element "path", rysując linię. Sposób w jakim dochodzi do rysowania linii może być dla niektórych mylący, tutaj metoda2 dokładniej to demonstruje. Każda z linii ma swój unikalny id='tag'+d.key.
Kolejna cześć pętli poświęcona została rysowaniu legendy. Dodano tyle elementów <span> ile jest drużyn dodając odpowiadający nazwie danej drużyny (d.key). Część odpowiedzialna za interakcje oskryptowana jest na końcu:
  • Gdy kursor myszy jest ponad .on("mouseover") obiektem legendy uruchamiana zostaje funkcja zaznaczająca obiekty przypisane do danej drużyny selectAll("#tag"+d.key), zmieniając grubość linii z 1 na 3, opacity (wyrazistość) z 0.5 na 1 oraz zmienia kolor czcionki na czarną.
  • Gdy zdejmujemy mysz z obiektu .("onmouseout") wracamy do domyślnych ustawień.

Zlepiając wszystko w całość powstaje taki wykres jak poniżej zgodnie z wcześniej wyrysowanym planem działania. Linie, które wyglądają przerywają się na dole reprezentują drużyny, które spadły z ligii do niższej klasy rozgrywkowej. Wyjątkiem jest Juventus, który w 2005 roku pomimo zwycięstwa w lidze został zdegradowany w wyniku afery korupcyjnej.

See the Pen D3.js serie-A teams strength (1994-2015) by Dawid 'Gonzo' Kałędkowski (@elo2zero) on CodePen.

8 komentarzy:

  1. Thanks for your personal marvelous posting! I quite enjoyed reading it,you could be a great author.I will always bookmark your blog. I am sharing related topic which is mostly important for How does the PSN code generator works?

    OdpowiedzUsuń
  2. I like how you think and the way you represent your views in this article. I agree with your way of thinking. Thank you for sharing this. I shared useful topic which is important to everything visit how to get free Robux

    OdpowiedzUsuń
  3. Enjoyed reading the article above, really explains everything in detail, the article is very interesting and effective. Thank you and good luck for the upcoming articles. If you have time you can check What Are Credit Card Generators?

    OdpowiedzUsuń
  4. Thank you for posting such a great article! I found your website perfect essay writing service of needs. It contains wonderful and helpful posts. Keep up the good work !. Thank you for this wonderful Article! And also for great content about minecraft skin
    how to use Minecraft

    OdpowiedzUsuń
  5. Your posts are really helpful to me. Its easy to understand and informative. And you can also check software for Creating self-extract files and Backup your files. You can check Winrar.

    OdpowiedzUsuń
  6. I always like and such a super contents of these post. Excellent and very cool idea and great content of different kinds of the valuable information's. Very nice post here and thanks for it. I also have something for you to Compress and archive files and data. Winrar
    visit here

    OdpowiedzUsuń
  7. I am loving this blog. I met this blog for a long time. I have found this blog by asking. I have got a good information.
    I really appreciate meeting it and I emphasize on this blog. I am curious to learn more and more on this blog.Earlier, such related information was seen on Desmume.

    OdpowiedzUsuń
  8. Hello sir, i read every page of your site.I really like the content that you post on your site.thanks for such helpfull contents.
    Good afternoon guys ,Here you can know about Digital marketing
    I'm sure you will like it

    OdpowiedzUsuń