Home > Mobile >  Using a for loop to create multiple plots
Using a for loop to create multiple plots

Time:04-15

I am a compete novice at using loops and simplifying my code. I have a dataset of places with accompanying data that I would like to plot on separate maps. The individual plotting of the maps I can do. However I would like to automate the process a little bit, I have new data arriving each day and don't want to repeat the process of cleaning the data and rewriting code. So I thought a for loop might be the answer

What I need are separate plots for each Time in the data below So the loop would pull out all the data for each value of Time and then plot it.

dput(df)  
structure(list(Site = c("O242", "O51", "O59", "O71", "C110", 
"C116", "C120", "C13", "C132", "C134", "C139", "C140", "C29", 
"C30", "C33", "C48", "C56", "C9A", "MP25", "MP67", "B30", "MP2", 
"B101", "B11", "B112", "B15", "B197", "B2", "B217", "B22", "B30", 
"B95", "MP21", "MP25", "MP33", "MP51", "MP56", "MP6", "MP60", 
"MP61", "MP67", "MP77", "EX84", "EX92", "SW130", "O31", "O38", 
"O38B", "O48", "O58", "O59", "O68", "O71", "O72", "O81", "O94", 
"O207", "O209", "O210", "O215"), Time = c(-25, -22, -22, -22, 
-14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, 
-14, -23, -23, -20, -20, -11, -11, -11, -11, -11, -11, -11, -11, 
-11, -11, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, 
-10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, 
-10, -10, -10, -10), Code = c(1L, 1L, 1L, 1L, 2L, 2L, 1L, 1L, 
2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 1L, 1L, 3L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 3L, 2L, 1L, 2L, 1L, 2L, 2L, 2L, 2L, 2L, 
1L, 1L, 1L, 2L, 1L, 2L, 1L, 3L, 2L, 1L, 3L, 1L, 1L, 3L, 2L, 2L, 
3L, 1L, 1L, 2L), lon = c(-1.341280663, -1.343562025, -1.343620358, 
-1.340629756, -1.332551665, -1.329108814, -1.328655294, -1.330835311, 
-1.330715028, -1.33052464, -1.328144549, -1.328287425, -1.329353862, 
-1.329343236, -1.33041446, -1.325353001, -1.327279282, -1.332909331, 
-1.300122834, -1.299148682, -1.310197641, -1.305886812, -1.308725397, 
-1.309505208, -1.309235075, -1.308580716, -1.30959055, -1.308685087, 
-1.309426224, -1.306562029, -1.310197641, -1.307564253, -1.301598673, 
-1.300122834, -1.299510666, -1.299846899, -1.297823339, -1.305388627, 
-1.297220016, -1.297398331, -1.299148682, -1.300378324, -1.333554619, 
-1.338688389, -1.332015649, -1.344951753, -1.344769267, -1.345214102, 
-1.342514477, -1.343145083, -1.343620358, -1.34275518, -1.340629756, 
-1.339067762, -1.338035147, -1.335442485, -1.346461847, -1.34550727, 
-1.34516939, -1.346584124), lat = c(51.76635545, 51.76553293, 
51.76450781, 51.76428383, 51.75689245, 51.75615401, 51.75742817, 
51.75637019, 51.75666667, 51.75740286, 51.7596281, 51.75976378, 
51.75721637, 51.75695556, 51.75701561, 51.75871255, 51.75875955, 
51.75720018, 51.76339382, 51.75986347, 51.76597134, 51.76737513, 
51.76464054, 51.76481595, 51.76542577, 51.76557477, 51.76682149, 
51.7644335, 51.76714421, 51.76681267, 51.76597134, 51.76571265, 
51.76447255, 51.76339382, 51.76268887, 51.76062289, 51.76030512, 
51.76678776, 51.75996884, 51.75968219, 51.75986347, 51.75998767, 
51.76749876, 51.76822905, 51.76474771, 51.76863319, 51.76622254, 
51.7655237, 51.76482531, 51.76430735, 51.76450781, 51.76421526, 
51.76428383, 51.76308822, 51.76434118, 51.76525265, 51.76642077, 
51.7672966, 51.76661139, 51.76598088)), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -60L), groups = structure(list(
    Time = c(-25, -23, -22, -20, -20, -14, -14, -11, -11, -11, 
    -10, -10, -10), Code = c(1L, 1L, 1L, 1L, 3L, 1L, 2L, 1L, 
    2L, 3L, 1L, 2L, 3L), .rows = structure(list(1L, 19:20, 2:4, 
        22L, 21L, c(7L, 8L, 11L, 12L, 13L, 14L, 15L, 16L, 17L
        ), c(5L, 6L, 9L, 10L, 18L), 23:30, 32L, 31L, c(33L, 35L, 
        41L, 42L, 43L, 45L, 47L, 50L, 52L, 53L, 58L, 59L), c(34L, 
        36L, 37L, 38L, 39L, 40L, 44L, 46L, 49L, 55L, 56L, 60L
        ), c(48L, 51L, 54L, 57L)), ptype = integer(0), class = c("vctrs_list_of", 
    "vctrs_vctr", "list"))), class = c("tbl_df", "tbl", "data.frame"
), row.names = c(NA, -13L), .drop = TRUE))

If I was to do this by hand I would use dplyr::filter(Time == "x") then make each plot using leaflet like so

install.packages("leaflet")
library(leaflet)
statecol<- colorFactor(palette = "viridis", df$Code) #create the colour palette

plots<- leaflet() %>% setView(lng = -1.324640, lat = 51.770462, zoom = 13.25)
plots %>% addTiles() %>%
  addCircleMarkers(data = df, label = ~as.character(df$Site), radius = 5, color = ~statecol(Code), stroke = FALSE, fillOpacity = 5) %>%
addLegend('bottomright', pal = statecol, values = df$Code,
          title = 'Codes',
          opacity = 2)

If there is a better solution than a loop I'd be happy to try that too. Hope this is clear and thanks in advance

CodePudding user response:

One approach would be to put the plotting code in a function which takes a the sole argument a dataframe. To make a map for each unique value of Time you could then split your data by Time and loop over the splitted dataset using the plotting function, where instead of a for loop I use lapply. As a result you get a list with plots for each value of Time:

library(leaflet)
library(dplyr)

df_split <- df %>% 
  ungroup() %>% 
  split(.$Time)

statecol<- colorFactor(palette = "viridis", df$Code) #create the colour palette

plot_fun <- function(x) {
  leaflet() %>% 
    setView(lng = -1.324640, lat = 51.770462, zoom = 13.25) |> 
    addTiles() %>%
    addCircleMarkers(data = x, label = ~as.character(x$Site), radius = 5, color = ~statecol(Code), stroke = FALSE, fillOpacity = 5) %>%
    addLegend('bottomright', pal = statecol, values = x$Code,
              title = 'Codes',
              opacity = 2)  
}

plots <- lapply(df_split, plot_fun)

length(plots)
#> [1] 7

plots[[1]]

EDIT In case you want to keep or use the data from previous plots we could basically use the same code with one small change, i.e. loop over an index and combine (rbind) the datasets up to the index value inside the plotting function:

library(leaflet)
library(dplyr)

df_split <- df %>% 
  ungroup() %>% 
  split(.$Time)

statecol<- colorFactor(palette = "viridis", df$Code) #create the colour palette

plot_fun <- function(ix) {
  x <- do.call(rbind, df_split[seq(ix)])
  leaflet() %>% 
    setView(lng = -1.324640, lat = 51.770462, zoom = 13.25) |> 
    addTiles() %>%
    addCircleMarkers(data = x, label = ~as.character(x$Site), radius = 5, color = ~statecol(Code), stroke = FALSE, fillOpacity = 5) %>%
    addLegend('bottomright', pal = statecol, values = x$Code,
              title = 'Codes',
              opacity = 2)  
}

plots <- lapply(seq_along(df_split), plot_fun)

plots[[3]]

plots[[5]]

CodePudding user response:

one approach is to store the Time-wise leaflet maps in a column of your tibble:

## create your base map (only needed once):
base_map <- leaflet() %>% 
               setView(lng = -1.324640, lat = 51.770462, zoom = 13.25) %>%
               addTiles()


all_plots <- 
    df %>% ## df is your tibble given above
    group_by(Time) %>%
    ## compact the data apart from Time as dataframes per Time-group
    ## into column "nested_data"
    nest(nested_data = c(Site, Code, lon, lat)) %>%
    rowwise %>%
    mutate(leaflet_map = list(
               base_map %>%
               addCircleMarkers(data = nested_data, ## the column of dataframes
                                label = ~as.character(Site),
                                radius = 5, 
                                color = ~statecol(Code),
                                stroke = FALSE,
                                fillOpacity = 5
                                )
           )
           ) %>%
           select(Time, leaflet_map)

The resulting tibble can be filtered and iterated (over column leaflet_plot) for automated map display.

## for single map at Time == -25
all_plots %>% 
    filter(Time == -25) %>%
    pull(leaflet_map) %>%
    print


Find solutions to display multiple maps in one go here: Multiple leaflets in a grid

  • Related