My example includes sample data, my function and two examples of how it can be used.
Sample DataI created the following data frame in Python:Input data can be accessed here: https://gist.
github.
com/claudiasolar/77d5bd6f59d18ea708a3ef31f3351f28site_id: our location identification column representing different sites that we monitor.
lon, lat: GPS coordinates of this site.
NOTE: I have added noise to these fields for privacy purposes.
t_stamp: 5-minute time stamps for each site between 7am and 8pm on the 2/3/2018.
energy _norm: normalised values of energy produced in each time stamp on a scale of 0 to 1.
over_voltage: Whether or not the network voltage at the site was above the specification (voltage > 253 V) in that time stamp.
Required Packageslibrary(readr)library(dplyr)library(ggplot2)library(ggthemes)library(gganimate)Main Aspects of FunctionArgumentsdf: data frame with all required informationlocation_id (column reference): indicates column to order df by, such that the animation recognises which points correspond to one another.
E.
g.
df$site_idtime_stamp (column reference): indicates column of time to iterate frames overcolour_col (column reference): indicates column which point colour is based off, this is what we are trying to graph e.
g.
df$energy_norm or df$over_voltageselected_title (string): title of animated map e.
g.
‘Energy Generated’ or ‘Over Voltage’point_colours (vector): gives colours of points on map or colours to define a colour scale e.
g.
c(‘#7a4eb7’, ‘#FF6100’) or c(‘#000000’, ‘#fec533’, ‘#fec533’, ‘#fec533’, ‘#f99f1e’, ‘#f99f1e’, ‘#f99f1e’, ‘#FF6100’, ‘#FF6100’, ‘#F90707’, ‘#F90707’)num_frames (integer): The number of frames to render (default 100), e.
g.
280dur (integer): The length of the animation in seconds (unset by default) e.
g.
50.
Note: Decreasing num_frames or duration can result in clipping off animation so that you don’t see all required frames!longitude_lim (vector of length = 2): governs longitude shown on map e.
g.
c(-150, -140)latitude_lim (vector of length = 2): governs longitude shown on map e.
g.
c(20, 40)Note: If longitude_lim and latitude_lim are not preferenced the function will take these limits from df$lon and df$latOrder dfIt is extremely important to correctly order your data frame.
I have included the argument location_id in the function so that the df input is appropriately ordered:df = df[order(location_id),]Without this you could get the following result:Here I have setlocation_id = df$energy_normInstead of what is required:location_id = df$site_idRather than demonstrating a site’s transition in energy_norm we are seeing each energy_norm’s transition around the map.
Create MapChoose general map locationdictate colour of mapChoose gps coordinates to determine area covered by map,Add and edit titles and legend aestheticsbase_map <- ggplot() + borders("world", region = 'Australia', colour = "gray85", fill = "gray80") + theme_map() + coord_fixed(xlim = longitude_lim, ylim = latitude_lim) + labs(title = selected_title, subtitle = '{closest_state}') + theme(plot.
title = element_text(hjust = 0, size = 14, lineheight = .
5), plot.
subtitle = element_text(hjust = 0, size = 12, lineheight = 0), legend.
position = c(0,.
1), legend.
title = element_blank(), legend.
text = element_text(size = 12))Determine colouring of points on mapIf colour_level is a column of characters than point_colours should contain as many distinct colours as there are distinct entries in this column so that it may map a colour to each unique entry.
the first and last colour in vector point_colours are used to create a colour scale if colour_level is a column of integerscolour_length = length(point_colours)if (typeof(colour_col) == 'character') { coloured <- scale_color_manual(values = point_colours)}else { coloured <- scale_color_gradientn(colours = point_colours)}Animate Mapcombine base_map, coloured, geom_point from ggplot2 and transition_states from gganimate to create our animationalpha argument in geom_point specifies transparency of pointstransition_length argument in transition_states determines the relative length of the transition.
animate from gganimate controls animation speed and lengthanim <- base_map + coloured + geom_point(aes(x = lon, y = lat, color = colour_col), data = df, alpha = .
5) + transition_states(state_col, transition_length = 0)anim <- animate(anim, nframes = num_fr, duration = durExamplesMelbourne Over Voltageanimated_map(df = be, order_col = be$site_id, state_col = be$t_stamp, colour_col = be$over_voltage, selected_title = 'Over Voltage', point_colours = c('#7a4eb7', '#FF6100'), num_fr = 280, dur = 50)Melbourne Solar Generationanimated_map(df = be, order_col = be$site_id, state_col = be$t_stamp, colour_col = be$energy_norm, selected_title = 'Solar Generation', point_colours = c('#000000', '#fec533', '#fec533', '#fec533', '#f99f1e', '#f99f1e', '#f99f1e', '#FF6100', '#FF6100', '#F90707', '#F90707'), num_fr = 280, dur = 50)Saving AnimationSave the last animation created as a gif:anim_save(‘/example.
gif’)Entire Functionanimated_map = function(df, order_col, state_col, colour_col, selected_title, point_colours, num_fr, dur, longitude_lim, latitude_lim) { # ensure df is ordered correctly df = df[order(order_col),] # Check for longitude and latitude limits # if missing automatically set them if (missing(longitude_lim)) { longitude_lim = sort(c(max(df$lon), min(df$lon))) } if (missing(latitude_lim)) { latitude_lim = sort(c(max(df$lat), min(df$lat))) } # create basic map, dictate colour of map, area covered by map, # labels and label aesthetics base_map <- ggplot() + borders("world", region = 'Australia', colour = "gray85", fill = "gray80") + theme_map() + coord_fixed(xlim = longitude_lim, ylim = latitude_lim) + labs(title = selected_title, subtitle = '{closest_state}') + theme(plot.
title = element_text(hjust = 0, size = 14, lineheight = .
5), plot.
subtitle = element_text(hjust = 0, size = 12, lineheight = 0), legend.
position = c(0,.
1), legend.
title = element_blank(), legend.
text = element_text(size = 12)) # determine colouring of points on map colour_length = length(point_colours) if (typeof(colour_col) == 'character') { coloured <- scale_color_manual(values = point_colours) } else { coloured <- scale_color_gradientn(colours = point_colours) #low = point_colours[1], high = point_colours[colour_length]) } # combine previous map lists, add points to map and animate anim <- base_map + coloured + geom_point(aes(x = lon, y = lat, color = colour_col), data = df, alpha = .
5) + transition_states(state_col, transition_length = 0) # animate map anim <- animate(anim, nframes = num_fr, duration = dur) return(anim)}.