W niniejszej publikacji zademonstruję wykorzystanie osi czasu jako narzędzia do przedstawienia swojej dotychczasowej historii, którą można pochwalić się w swoim CV.
Pierwszym rozwiązaniem pozwalającym uzyskać wizualizację osi czasu jest zastosowanie pakietu timelineR, który można pobrać z Githuba użytkownika timelyportfolio. Efekt, jaki możemy uzyskać dzięki temu pakietowi, będzie często w wielu przypadkach wystarczający.
Zanim jednak zaczniemy tworzyć nasze osie czasu, zainstalujmy i załadujmy wymagane pakiety.
#install.packages("devtools") #instalacja wymagana, gdy nie posiadamy pakietu devtools
library(devtools)
#devtools::install_github("ramnathv/htmlwidgets")
#devtools::install_github("timelyportfolio/timelineR")
library(timelineR)
library(RColorBrewer)
Wpierw zdefiniujmy sobie dane, które chcielibyśmy zwizualizować. W tym celu do zmiennej osczasu_data przypisałem dataframe składający się z 3 kolumn (dat, wydarzeń i kolorów). Dwie pierwsze kolumny - time i name są wymagane, zaś trzecia (kolory) posłuży mi w późniejszym etapie do zastosowania odpowiednich kolorystyk.
osczasu_data <- data.frame(
time = c(
"30-Apr-10", "14-Febr-14", "29-Febr-16", "4-Oct-16", "5-Sept-19",
"4-Jul-17", "20-Febr-17", "7-Nov-16", "14-May-19"
),
name = c(
'Ukończenie I LO w Łodzi z wyróżnieniem',
'Inżynier budownictwa',
'Magister inżynier budownictwa',
'Rozpoczęcie nauki na WNE UW',
'Licencjat z ekonomii (?)',
'Rozpoczęcie pracy w Linkcity Poland S.A.',
'Wolontariat w Fundacji EY',
'Praca w Komisji UW HERE',
'Ukończenie ścieżki MS Excel i VBA na WNE UW'
),
stringsAsFactors = FALSE,
kolory = c("yellowgreen","steelblue","steelblue","deeppink","deeppink",
"deepskyblue", "darkorchid","slateblue","sienna"
)
)
W celu zilustrowania naszych danych posłużymy się komendą d3kit_timeline jest to element htmlwidget z pojedynczą osią i ładnymi dla oka labelkami.
d3kit_timeline(
osczasu_data, # nasze dane
direction = "right", # orientacja osi, tutaj pionowa + opisy z prawej strony
timeFn = ~time, # dane czasowe, argument niewymagany, jeśli mamy kolumnę time w naszym dataframe
textFn = htmlwidgets::JS( # opisy labeli, tutaj ustawione za pomocą funkcji: "rok - nazwa wydarzenia"
"
function(d){
return new Date(d.time).getFullYear() + ' - ' + d.name;
}
"
),
width = 500, # szerokość naszej wizualizacji
height = 300, # wysokość naszej wizualizacji
labelBgColor = "darkorchid", # kolorystyka labeli (jeden kolor do wszystkich)
dotColor = "coral" # kolor zaznaczeń na osi
)
Powyższy efekt jest ok, ale można by spróbować wyśrodkować nasz wykres, zrobić parę usprawnień.
Tym razem będziemy mieć zewnętrzną oś, do której dodamy nasze dane z d3kit_timeline.
add_axis(
d3kit_timeline( # obróbka naszych danych - "funkcja" d3kit_timeline
osczasu_data, # nasze wyjściowe dane
direction = "left", # orientacja osi
labelBgColor = '#377', # kolor labelek (tu w postaci kodu)
linkColor = '#727', # kolor linii łączącej
textFn = htmlwidgets::JS( # opisy na labelkach
"
function(d){
return new Date(d.time).getFullYear() + ' - ' + d.name;
}
"
),
margin = list(left=20, right=250, top=20, bottom=20), # marginesy
width = 800, # szerokość
height = 450, # wysokość
dotColor = "magenta" # kolor zaznaczeń na osi
),
ticks = 10, # liczba podziałek na osi
tickSize = 5 # wielkość podziałek
)
Wersja druga wydaje się być stosunkowo przystępna. Zobaczmy jeszcze, jaki efekt uzyskamy jeśli zdecydujemy się na orientację poziomą i zechcemy posiadać labelki w różnych kolorach.
Przydadzą nam się tutaj pakiety scales i dplyr oraz definicje palet kolorów, z których będziemy chcieli skorzystać.
library(scales)
wlasnekolory <- htmlwidgets::JS( # paleta odwołująca się do samodzielnie zdefiniowanych kolorów w dataframe'ie
"function(d)
{ return d.kolory;
}")
d3kit_timeline(
osczasu_data,
direction = "down", # orientacja pozioma: labelki pod osią
layerGap = 50, # odległość pierwszego rzędu labelek od osi
labella = list(maxPos = 500, # reguły określające rozmieszczenie labelek
algorithm = "simple", # algorytm określający jak powinny się układać labelki w kolejnych rzędach
stubWidth = 20), # szerokość odstępy między liniami łączącymi w danym rzędzie labelek
textFn = ~name,
dotColor = wlasnekolory, # w tym przypadku definiujemy wspólne kolory dla zaznaczeń, linii i labelek
labelBgColor = wlasnekolory,
linkColor = wlasnekolory,
margin = list(left=20, right=20, top=40, bottom=20),
width = 900,
height = 400
)
Orientacja pozioma jest z pewnością bardziej naturalna w odbiorze, niemniej należy mieć na uwadze, że wymaga ona stosunkowo krótkich opisów bo wtedy nasz rysunek staje się kolokwialnie mówiąc “rozlazły” i “pływające” linie łączące nie najlepiej wyglądają.
Zobaczmy jeszcze jak wyglądałby wykres z wykorzystaniem wbudowanej palety kolorów R.
library(dplyr)
colorJS <- htmlwidgets::JS("function(d){ return d.color; }") # paleta korzystająca z Rcolors
d3kit_timeline(
osczasu_data %>% # korzystamy z operatora przetwarzania potokowego, by przetransformować nasz wyjściowy dataframe i dodać kolumnę z daną paletą kolorów (tutaj skorzystano z palety Paired)
mutate( color = col_factor( palette = "Paired", domain = NULL)(.$name)),
direction = "right", # orientacja pionowa, labele z prawej strony
layerGap = 50, # odległość między osią a labelami
textFn = ~name, # nazwy do labeli
dotColor = colorJS, # jednolite kolory do zaznaczeń
labelBgColor = colorJS, # jednolite kolory do labeli
linkColor = colorJS, # jednolite kolory do linii łączących
margin = list(left=300, right=20, top=30, bottom=20), # marginesy
width = 800, # szerokość
height = 425 # wysokość
)
Na powyższych przykładach widać, że pakiet timelineR jest przydatny i pozwala w łatwy i szybki sposób zwizualizować niezbyt skomplikowane osie czasowe. Jednak pakiet ten nie daje aż takiego efektu wow, czego niektórzy użytkownicy mogliby się spodziewać. Dlatego w kolejnej części zostanie przedstawiony drugi przydatny pakiet do wizualizji osi czasowych.
Jak już wspomniano, w tej części przyjrzymy się innemu pakietowi do wizualizacji osi czasu. Tym razem jest to narzędzie głównie dedykowane do prezentacji w Curriculum Vitae (wszystkim dobrze znanym jako CV), stąd jego prosta do zapamiętania nazwa VisualResume i podobnie jak pierwszy pakiet, ten również pochodzi z Githuba (autorstwa użytkownika ndphillips). Niemniej oczywiście jest możliwe zilustrowanie samej osi czasu.
Zastosowany pakiet daje dodatkowe możliwości wizualizacji. Umożliwia wizualizację czynności/zadań, które trwają pewny okres czasu. Ponadto VisualResume pomoże nam zobrazować proste minigrafy drzewkowe, które można wykorzystać do przedstawienia swoich zainteresowań. Każdą z tych funkcji postarano się zademonstrować w niniejszej publikacji.
devtools::install_github("ndphillips/VisualResume")
library(VisualResume)
VisualResume::VisualResume(
titles.left = c( # Nagłówki lewostronne
"Janusz Fortuniak", # Nagłówek 1 rzędu
"", # Nagłówek 2 rzędu
"Zwycięzcy robią to, czego przegranym się nie chciało."), # Nagłówek 3 rzędu
titles.left.cex = c(3, 1, 1.1), # Wielkości nagłówków lewostronnych
titles.right = c( # Nagłówki prawostronne
"jfortuniak26[at]gmail.com", "", "tel. 500-653-xxx"),
titles.right.cex = c(1.8, 1, 1.8), # Wielkości nagłówków prawostronnych
timeline.labels = c("Dotychczasowa kariera", "Zainteresowania"), # Nazwy sekcji
timeline = data.frame( # Dataframe z danymi do osi czasu
title = c( # Tytuły poszczególnych etapów
"I LO w Łodzi", "PŁ WBAIŚ", "PŁ WBAIŚ", "WNE UW", "Fundacja EY", "ULMA",
"Linkcity Poland S.A.", "Linkcity Poland S.A.", "EC Industria", "Inbud"),
sub = c( # Podtytuły
"Profil mat-fiz", "Studia inż.", "Studia II stop.", "Studia licenjackie", "Wolontariat", "Staż",
"Praktyka", "Junior Officer", "Asystent Projektanta", "Inżynier budowy"),
start = c(2007.8, 2010.85, 2014.25, 2016.8, 2017.2, 2013.52, 2017.6, 2017.9, 2016.5, 2015.6), # początek wydarzenia
end = c(2010.5, 2014.2, 2016.25, 2019.9, 2019.6, 2013.8, 2017.82, 2019.7, 2016.78,2015.7), # koniec wydarzenia
side = c(1, 1, 1, 1, 0, 0, 0, 0, 1, 1)), # Położenie nad (1) lub pod (0) osią czasu
milestones = data.frame( # Kamienie milowe (dataframe)
title = c("", "", ""), # Tytuły nagłówków
sub = c("inż. budownictwa", "mgr inż. budownictwa", "lic. nauk ekonom."), # Tytuły nagłówków 2 rzędu
year = c(2014.01, 2016.2, 2019.7)), # Moment zajścia w czasie (rok z częściami dziesiętnymi)
events = data.frame( # Wydarzenia, które są ponumerowane na osi czasu (Kamienie milowe 2 rzędu)
year = c(2008.4, 2010.4, 2014.15, 2016.2, 2019), # Moment zajścia (rok z częsciami dziesiętnymi)
title = c("Finalista XXXIV Olimpiady Geograficznej", # Nazwy wydarzeń
"Finalista XXXVI Olimpiady Geograficznej",
"Praca inżynierska: Projekt budowlany z elementami projektu \nwykonawczego domu jednorodzinnego w technologii tradycyjnej",
"Praca magisterska: Projekt stalowej konstrukcji wsporczej \nbanera reklamowego",
"Ukończona ścieżka Ekonomiczna analiza danych w programie \nMicrosoft Excel i języku programowania VBA.")),
events.cex = 1.3, # Wielkość czcionki nazw wydarzeń
interests = list( # "Zainteresowania" = Lista max 4 obszarów, w których możemy dodatkowo zobrazować 5 pozycji (im częściej dana rzecz występuje tym bardziej jest ona uwydatniona)
"Piłka nożna" = c(rep("La Liga", 3), rep("Liga Mistrzów", 3), rep("Biało-czerwoni", 1.5), rep("Premier League", 1.2)),
"Programowanie" = c(rep("R", 3), rep("VBA", 4), rep("HTML & CSS", 1.5), rep("Python", 1)),
"Japonia" = c(rep("Sudoku", 2), rep("Manga", 4), rep("Kultura", 1.3))),
#font.family = "TeX Gyre Heros", # Rodzina czcionek (tylko jeśli publikujemy do pdf)
year.steps = 1, # Krok (liczba lat) na osi czasu
col = "basel", # Kolorystyka zaznaczeń na osi czasu (można zastosować paletę z pakietu yarrr albo zdefiniować własny wektor
trans = 0.35 # Przezroczystość poszczególnych zaznaczeń (0 - brak)
)
Ładne? Na pewno nie jest źle. Zwizualizowanie procesów nachodzących na siebie i biegnących równolegle w czasie z pewnością jest satysfakcjonujące. Możliwość zastosowania kamieni milowych z legendą, również jest mocno na plus. Wiadomo, końcowy efekt wymaga pewnych dopracowań, stosowania pewnych skrótów/uproszczeń.
Ale uwaga! Przedstawienie tak bogatego w treści wykresu może być kłopotliwe. Domyślne ustawienia wydruku wyniku w pakiecie VisualResume (8.5 x 11 cala) nie pokażą w Markdownie czytelnego obrazka. Dlatego tutaj autor zastosował sztuczkę, że powyższy kod zapuścił “normalnie” w RStudio, a następnie uzyskany output zapisał do obrazka, który to obrazek został umieszczony w kodzie. Stąd brak responsywności w tym outcomie (#aledziała).
Zapraszam do przetestowania i życzę jak najfajniejszych wizualizacji w przyszłości :).
Publikacja została wykonana w ramach zaliczenia przedmiotu Raportowanie i Wizualizacja danych w R na Wydziale Nauk Ekonomicznych (WNE) Uniwersytetu Warszawskiego.