Animating time series on a map using Solar Analytic data and R’s gganimate package!

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)}.

. More details

Leave a Reply