Intersecting Circles on a Map

Hello all,

I am trying to build an app where I show circles that represent the radiuses of workers from certain coordinates. However, I would like to also include categorical variables like the customer that the worker can do and the day of the week in which the work is to be done (So Mon through Fri)

One way I was thinking about doing this is by finding the combinations between the different variables: So if I have 5 customers * and 5 days of the week then I have 25 different cases. However, I have so many categories under each variable, so my UI will look really bad.

Within my app I want to be able to select days say ( Mon and Wed) and the customers (say X, and Z) and thus see the circles of all workers that can do customers X and Z on Mon and Wed.

Here is my code:

#Show days Monday and Tuesday 

coverage_Monday_XXXXX_Roberts <- coverage_data %>%
  filter(Days == "Monday", Manager == 'XXXXX Roberts')
coverage_Tuesday_XXXXX_Roberts <- coverage_data %>%
  filter(Days == 'Tuesday', Manager == 'XXXXX Roberts')

coverage_Monday_YYYY_Gutierrez <- coverage_data %>%
  filter(Days == "Monday", Manager == 'YYYY Gutierrez')
coverage_Tuesday_YYYY_Gutierrez <- coverage_data %>%
   filter(Days == 'Tuesday', Manager == 'YYYY Gutierrez')

# #Create label for Monday cases

# #Create label for Monday cases
 coverage_Monday_XXXXX_Roberts$label <- paste("<p>", coverage_Monday_XXXXX_Roberts$Inspector.Name, "</p>",
                                "<p>", coverage_Monday_XXXXX_Roberts$Day, " ", coverage_Monday_XXXXX_Roberts$Region, "</p>",
                                "<p>", coverage_Monday_XXXXX_Roberts$City, ", ", coverage_Monday_XXXXX_Roberts$Postcode, "</p>",
                                "<p>", coverage_Monday_XXXXX_Roberts$State, "</p>",
                                "<p>", coverage_Monday_XXXXX_Roberts$Manager, "</p>",
                                "<p>", coverage_Monday_XXXXX_Roberts$Customer, "</p>",
                                "<p>", coverage_Monday_XXXXX_Roberts$Inspector.Skill, "</p>",
                                "<p>", coverage_Monday_XXXXX_Roberts$Days, "</p>",
                                "<p>", coverage_Monday_XXXXX_Roberts$Radius, "</p>",

# #Create label for Tuesday cases
 coverage_Tuesday_XXXXX_Roberts$label <- paste("<p>", coverage_Tuesday_XXXXX_Roberts$Inspector.Name, "</p>",
                                 "<p>", coverage_Tuesday_XXXXX_Roberts$Day, " ", coverage_Tuesday_XXXXX_Roberts$Region, "</p>",
                                 "<p>", coverage_Tuesday_XXXXX_Roberts$City, ", ", coverage_Tuesday_XXXXX_Roberts$Postcode, "</p>",
                                 "<p>", coverage_Tuesday_XXXXX_Roberts$State, "</p>",
                                 "<p>", coverage_Tuesday_XXXXX_Roberts$Manager, "</p>",
                                 "<p>", coverage_Tuesday_XXXXX_Roberts$Customer, "</p>",
                                 "<p>", coverage_Tuesday_XXXXX_Roberts$Inspector.Skill, "</p>",
                                 "<p>", coverage_Tuesday_XXXXX_Roberts$Days, "</p>",
                                 "<p>", coverage_Tuesday_XXXXX_Roberts$Radius, "</p>",

 coverage_Monday_YYYY_Gutierrez$label <- paste("<p>", coverage_Monday_YYYY_Gutierrez$Inspector.Name, "</p>",
                                "<p>", coverage_Monday_YYYY_Gutierrez$Day, " ", coverage_Monday_YYYY_Gutierrez$Region, "</p>",
                                "<p>", coverage_Monday_YYYY_Gutierrez$City, ", ", coverage_Monday_YYYY_Gutierrez$Postcode, "</p>",
                                "<p>", coverage_Monday_YYYY_Gutierrez$State, "</p>",
                                "<p>", coverage_Monday_YYYY_Gutierrez$Manager, "</p>",
                                "<p>", coverage_Monday_YYYY_Gutierrez$Customer, "</p>",
                                "<p>", coverage_Monday_YYYY_Gutierrez$Inspector.Skill, "</p>",
                                "<p>", coverage_Monday_YYYY_Gutierrez$Days, "</p>",
                                "<p>", coverage_Monday_YYYY_Gutierrez$Radius, "</p>",

# Create label for Tuesday cases
 coverage_Tuesday_YYYY_Gutierrez$label <- paste("<p>", coverage_Tuesday_YYYY_Gutierrez$Inspector.Name, "</p>",
                                 "<p>", coverage_Tuesday_YYYY_Gutierrez$Day, " ", coverage_Tuesday_YYYY_Gutierrez$Region, "</p>",
                                 "<p>", coverage_Tuesday_YYYY_Gutierrez$City, ", ", coverage_Tuesday_YYYY_Gutierrez$Postcode, "</p>",
                                 "<p>", coverage_Tuesday_YYYY_Gutierrez$State, "</p>",
                                 "<p>", coverage_Tuesday_YYYY_Gutierrez$Manager, "</p>",
                                 "<p>", coverage_Tuesday_YYYY_Gutierrez$Customer, "</p>",
                                 "<p>", coverage_Tuesday_YYYY_Gutierrez$Inspector.Skill, "</p>",
                                 "<p>", coverage_Tuesday_YYYY_Gutierrez$Days, "</p>",
                                 "<p>", coverage_Tuesday_YYYY_Gutierrez$Radius, "</p>",

pal <- colorFactor(
  palette = 'Dark2',
  domain = coverage_data$Inpector.Name

map11 <- leaflet(coverage_data) %>%
  setView(lng = -95.7129, lat = 34.0902, zoom = 4.499) %>%
  addProviderTiles(providers$Esri.DeLorme) %>%

  ###### DAYS #######
addCircles(lng = coverage_Monday_XXXXX_Roberts$Longitude,
           lat = coverage_Monday_XXXXX_Roberts$Latitude,
           color = ~pal(coverage_Monday_XXXXX_Roberts$Inspector.Name),
           weight = 1,
           radius = coverage_Monday_XXXXX_Roberts$radius,
           opacity = 0.05,
           label = lapply(coverage_Monday_XXXXX_Roberts$label, HTML),
           fillOpacity = 0.05,
           group = "Monday: XXXXX Roberts") %>%
  addCircles(lng = coverage_Tuesday_XXXXX_Roberts$Longitude,
             lat = coverage_Tuesday_XXXXX_Roberts$Latitude,
             color = ~pal(coverage_Tuesday_XXXXX_Roberts$Inspector.Name),
             weight = 1,
             radius = coverage_Tuesday_XXXXX_Roberts$radius,
             opacity = 0.05,
             fillOpacity = 0.05,
             label = lapply(coverage_Tuesday_XXXXX_Roberts$label, HTML),
             group = "Tuesday: XXXXX Roberts") %>%
  addCircles(lng = coverage_Monday_YYYY_Gutierrez$Longitude,
             lat = coverage_Monday_YYYY_Gutierrez$Latitude,
             color = ~pal(coverage_Monday_YYYY_Gutierrez$Inspector.Name),
             weight = 1,
             radius = coverage_Monday_YYYY_Gutierrez$radius,
             opacity = 0.05,
             label = lapply(coverage_Monday_YYYY_Gutierrez$label, HTML),
             fillOpacity = 0.05,
             group = "Monday: YYYY Gutierrez") %>%
  addCircles(lng = coverage_Tuesday_YYYY_Gutierrez$Longitude,
             lat = coverage_Tuesday_YYYY_Gutierrez$Latitude,
             color = ~pal(coverage_Tuesday_YYYY_Gutierrez$Inspector.Name),
             weight = 1,
             radius = coverage_Tuesday_YYYY_Gutierrez$radius,
             opacity = 0.05,
             fillOpacity = 0.05,
             label = lapply(coverage_Tuesday_YYYY_Gutierrez$label, HTML),
             group = "Tuesday: YYYY_Gutierrez") %>%
    overlayGroups= c("Monday: XXXXX Roberts", "Tuesday: XXXXX Roberts",# "Wednesday: XXXXX Roberts", "Thursday: XXXXX Roberts", "Friday: XXXXX Roberts",
                     "Monday: YYYY Gutierrez", "Tuesday: YYYY Gutierrez"), # "Wednesday: YYYY Gutierrez", "Thursday: YYYY Gutierrez", "Friday: YYYY Gutierrez"),
    options = layersControlOptions(collapsed = FALSE))


Please note that I also tried the function baseGroups and overlayGroups and I can't seem to be able to intersect the different variables. I appreciate any help.

You seem to be putting a lot of information in a single map; the risk of overwhelming your users is real.

In your case I would consider the baseGroups() option of addLayersControl() call - it is usually associated with changing basemaps, but it is not restricted to them and can be used whenever a radio button functionality is desired.

This should enable you to switch between circle markers with color mapped to employee name to circles names with colors mapped to day of week and / or customer names.

In theory you should be able to map all three colour legends to groups, though I sort of recall I have struggled with legends with baseGroups (overlayGroups were better behaved in this manner).

Lastly, and not really related to the subject, I would suggest to avoid having your employee names (Roberts, Gutierrez etc.) hardcoded in your app. People come & go, but code remains. Better keep it as a parametrization...

I have used baseGroups() and overlayGroups() together before, but I was not able to find the intersection of variables based on the categories I pick.

Say the baseGroups contains Monday, Tuesday, Wednesday, Thursday, Friday
and overlayGroups contains customers X, Y, and Z
For example, if I selected Monday and customer X, I wasn't able to find the circles of ONLY customers X on a Monday.

Are you saying that if I add a radio button functionality with overlayGroups, I can achieve this intersection? (i.e. I can see only the circles of workers with whatever combinations I select? )

Thanks jlacko!

Hi I created a reprex to show how I used overlayGroups and baseGroups. I can give some data, but I am not allowed to provide this data for some reason because this doesn't accept a csv file :/)

As you can see when I select Monday and Andrew XXXXX, you still see some Tuesday data on my map.
So how can I just have the Monday data and Andrew XXXXX on my map when I select Monday and Andrew XXXXX?

# Add both days and manager

# packages load

library(tibble) # to use add_column

# Load unpivoted file
coverage_data <- read.csv('reprex.csv', stringsAsFactors = FALSE,
                          strip.white = TRUE)
# Convert to miles

coverage_data <- coverage_data %>%
  mutate(radius = coverage_data$Max.Distance.from.C.or.HB * 1609.34)

#Show  days Monday to Friday
coverage_Monday <- coverage_data %>%
  filter(Days == "Monday")
coverage_Tuesday <- coverage_data %>%
  filter(Days == 'Tuesday')

#Create label for Monday cases
coverage_Monday$label <- paste("<p>", coverage_Monday$Inspector.Name, "</p>",
                               "<p>", coverage_Monday$Day, " ", coverage_Monday$Region, "</p>",
                               "<p>", coverage_Monday$City, ", ", coverage_Monday$Postcode, "</p>",
                               "<p>", coverage_Monday$State, "</p>",
                               "<p>", coverage_Monday$Manager, "</p>",
                               "<p>", coverage_Monday$Customer, "</p>",
                               "<p>", coverage_Monday$Inspector.Skill, "</p>",
                               "<p>", coverage_Monday$Days, "</p>",
                               "<p>", coverage_Monday$Radius, "</p>",

#Create label for Tuesday cases
coverage_Tuesday$label <- paste("<p>", coverage_Tuesday$Inspector.Name, "</p>",
                                "<p>", coverage_Tuesday$Day, " ", coverage_Tuesday$Region, "</p>",
                                "<p>", coverage_Tuesday$City, ", ", coverage_Tuesday$Postcode, "</p>",
                                "<p>", coverage_Tuesday$State, "</p>",
                                "<p>", coverage_Tuesday$Manager, "</p>",
                                "<p>", coverage_Tuesday$Customer, "</p>",
                                "<p>", coverage_Tuesday$Inspector.Skill, "</p>",
                                "<p>", coverage_Tuesday$Days, "</p>",
                                "<p>", coverage_Tuesday$Radius, "</p>",

####### map 2  Managers ########

#Show  Managers coverage

coverage_Andrew_XXXXX<- coverage_data %>%
  filter(Manager == "Andrew XXXXX")
coverage_Andy_YYYY <- coverage_data %>%
  filter(Manager == 'Andy YYYY')

#Create label for Managers
coverage_Andrew_XXXXX$label <- paste("<p>", coverage_Andrew_XXXXX$Inspector.Name, "</p>",
                                       "<p>", coverage_Andrew_XXXXX$Day, " ", coverage_Andrew_XXXXX$Region, "</p>",
                                       "<p>", coverage_Andrew_XXXXX$City, ", ", coverage_Andrew_XXXXX$Postcode, "</p>",
                                       "<p>", coverage_Andrew_XXXXX$State, "</p>",
                                       "<p>", coverage_Andrew_XXXXX$Manager, "</p>",
                                       "<p>", coverage_Andrew_XXXXX$Customer, "</p>",
                                       "<p>", coverage_Andrew_XXXXX$Inspector.Skill, "</p>",
                                       "<p>", coverage_Andrew_XXXXX$Days, "</p>",
                                       "<p>", coverage_Andrew_XXXXX$Radius, "</p>",

coverage_Andy_YYYY$label <- paste("<p>", coverage_Andy_YYYY$Inspector.Name, "</p>",
                                       "<p>", coverage_Andy_YYYY$Day, " ", coverage_Andy_YYYY$Region, "</p>",
                                       "<p>", coverage_Andy_YYYY$City, ", ", coverage_Andy_YYYY$Postcode, "</p>",
                                       "<p>", coverage_Andy_YYYY$State, "</p>",
                                       "<p>", coverage_Andy_YYYY$Manager, "</p>",
                                       "<p>", coverage_Andy_YYYY$Customer, "</p>",
                                       "<p>", coverage_Andy_YYYY$Inspector.Skill, "</p>",
                                       "<p>", coverage_Andy_YYYY$Days, "</p>",
                                       "<p>", coverage_Andy_YYYY$Radius, "</p>",

pal <- colorFactor(
  palette = 'Dark2',   #Dark2 is another palette option
  domain = coverage_data$Inpector.Name


#add checkbox control.

map10 <- leaflet(coverage_data) %>%
  setView(lng = -95.7129, lat = 34.0902, zoom = 4.499) %>%
  addProviderTiles(providers$OpenStreetMap.France, group = 'Monday') %>%
  addProviderTiles(providers$OpenStreetMap.France, group = 'Tuesday') %>%

  ###### DAYS #######
addCircles(lng = coverage_Monday$Longitude,
           lat = coverage_Monday$Latitude,
           color = ~pal(coverage_Monday$Inspector.Name),
           weight = 1,
           radius = coverage_Monday$radius,
           opacity = 0.05,
           label = lapply(coverage_Monday$label, HTML),
           fillOpacity = 0.05,
           group = "Monday") %>%
  addCircles(lng = coverage_Tuesday$Longitude,
             lat = coverage_Tuesday$Latitude,
             color = ~pal(coverage_Tuesday$Inspector.Name),
             weight = 1,
             radius = coverage_Tuesday$radius,
             opacity = 0.05,
             fillOpacity = 0.05,
             label = lapply(coverage_Tuesday$label, HTML),
             group = "Tuesday") %>%
  ####### MANAGERS ######
addCircles(lng = coverage_Andrew_XXXXX$Longitude,
           lat = coverage_Andrew_XXXXX$Latitude,
           color = ~pal(coverage_Andrew_XXXXX$Inspector.Name),
           weight = 1,
           radius = coverage_Andrew_XXXXX$radius,
           opacity = 0.05,
           label = lapply(coverage_Andrew_XXXXX$label, HTML),
           fillOpacity = 0.05,
           group = "Andrew XXXXX") %>%
  addCircles(lng = coverage_Andy_YYYY$Longitude,
             lat = coverage_Andy_YYYY$Latitude,
             color = ~pal(coverage_Andy_YYYY$Inspector.Name),
             weight = 1,
             radius = coverage_Andy_YYYY$radius,
             opacity = 0.05,
             fillOpacity = 0.05,
             label = lapply(coverage_Andy_YYYY$label, HTML),
             group = "Andy YYYY") %>%
   overlayGroups= c("Andrew XXXXX", "Andy YYYY"),
    baseGroups   = c("Monday", "Tuesday"),
    options = layersControlOptions(collapsed = FALSE))


Ah, I feel I understand your question better now: you need to filter the circles based on two criteria, joined by an AND condition (employee == "Andy" & day == "Monday"). Excuse my being slow :sob:

I don't think this operation is doable in plain leaflet, as it supports only a single group for an object. With two employees and seven days a week you would end up with 14 groups, completely overwhelming the user interface.

You will need to have to use shiny, take the name and day selection fields out of the leaflet UI and use leafletProxy to update the map on the fly.

Doable, but not quite easy - do check out the demo on the link above.


Thank you! I managed to get the circles to intersect based on the link you sent. However, being new to shiny, there is a bit of a struggle. Not sure how much you are familiar with Shiny, but would you please look at this if you have some time?

It feels like I am very close, but not quite yet.

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.