Search code examples
rshinygisr-leaflet

Why does adding markers in a Shiny app work for one map but not the other?


I downloaded two separate, similar but distinct shape files. They can be found here and here. The first file has filename "FED_A_FINAL_REPORT_BC.shp" and the second has filename "lfed000b21a_e". Using Shiny, I am able to place markers on one map (the second) but not the other(the first), and this is where I have my problem.

I have been able to reproduce this without adding any external data, in fact.

Once downloaded, you can read in the shape files as below:

new_bc_fed = sf::st_read("/Downloads/shapefile_folder_feds_canada/lfed000b21a_e.shp")

bc_fed_nova = sf::st_read("/Downloads/FED_A_FINAL_REPORT_BC.shp")

I am particularly interested in being able to use the first file, bc_fed_nova, which is the one which does not work.

I then define a centroid for each of the polygons (federal electoral districts) within each of the two maps in exactly the same way:

bc_centroids = data.frame(st_coordinates(st_centroid(bc_fed_nova$geometry)))
bc_fed_nova$X = bc_centroids[,1]
bc_fed_nova$Y = bc_centroids[,2]

...and also:

bc_centroids = data.frame(st_coordinates(st_centroid(new_bc_fed$geometry)))
new_bc_fed$X = bc_centroids[,1]
new_bc_fed$Y = bc_centroids[,2]

Up to this point, everything I did was the same for both maps. I also checked that they are the same class of object:

> class(new_bc_fed_C)
[1] "sf"         "data.frame"
> class(bc_fed_nova)
[1] "sf"         "data.frame"

For the map called "bc_fed_nova," I added some data from a data frame which contains some census data (basically, I want to modify this to be able to show the population of each FED). This is how I did that:

census_data_file = ("/Downloads/98-401-X2021029_English_CSV_data.csv")
#Starting on line 807719
#Ending on line 923482
#We found this from the associated metadata, we want to 
starting_line = 807719
ending_line = 923482
number_of_rows = ending_line - starting_line 
census_data_BC = read.csv(census_data_file, nrows = number_of_rows, skip = (starting_line - 1), header = FALSE)
census_metadata = read.csv(census_data_file, nrows = 1)

#Remove the white space
census_data_BC_copy = census_data_BC
for(j in 1:ncol(census_data_BC_copy))
{
  census_data_BC_copy[,j] = str_remove_all(census_data_BC_copy[,j], " ")
}

#Assign this column name so that we can merge with the DF in the map 
#file
colnames(census_data_BC_copy)[5] = "FED"

#Find total population in each FED
totalpop_in_bc_feds = census_data_BC_copy[which(census_data_BC_copy$V10 == "Population,2021"),]

#We only need the following columns
totalpop_in_bc_cropped = totalpop_in_bc_feds[,c(2, 5, 12, 13, 14, 15)]

colnames(totalpop_in_bc_cropped)[3] = "TotalPop"

#To avoid double counting, remove the first row
totalpop_in_bc_cropped = totalpop_in_bc_cropped[-1,]

#Make sure that the column name has an equivalent in the target 
# sf object
colnames(new_bc_fed)[4] = "FED"
#The original name was "FEDENAME"

#We merge this data with the sf/dataframe from above
bc_fed_nova = dplyr::left_join(bc_fed_nova, totalpop_in_bc_cropped, by = "FED")

#Confirm that the data has been merged with the data frame from the map

What I want is to use these maps as the basis for a Shiny app in R which does something very simple: as you move around, you should see markers on the centroid of a district and to be able to see the surface area of the federal electoral district when clicking on the marker. I did this code twice, but only one version of the code works:

library(shiny)
library(WikidataQueryServiceR)
library(leaflet)

ui <- fluidPage(
    # Application title
    titlePanel("BC Electoral Districts--Selected data"),
    
    mainPanel(leafletOutput("BCFEDS"))
)

# Define server logic required to draw a histogram
server <- function(input, output) {
  
  output$BCFEDS <- renderLeaflet(
    {
      #This code works
      BCFEDS <- leaflet()
      BCFEDS <- addTiles(BCFEDS)
      BCFEDS <- setView(BCFEDS, lng = -122.8, lat = 49.3, zoom = 8)
      BCFEDS <- addPolygons(data = new_bc_fed_C, map = BCFEDS)
      BCFEDS <- addMarkers(map = BCFEDS, lng = new_bc_fed_C$X , lat = new_bc_fed_C$Y, popup = as.character(new_bc_fed_C$LANDAREA))
      
      #This code does not work 
      BCFEDS <- leaflet()
      BCFEDS <- addTiles(BCFEDS)
      BCFEDS <- setView(BCFEDS, lng = -122.8, lat = 49.3, zoom = 8)
      BCFEDS <- addPolygons(data = bc_fed_nova, map = BCFEDS)
      BCFEDS <- addMarkers(map = BCFEDS, lng = bc_fed_nova$X , lat = bc_fed_nova$Y, popup = as.character(bc_fed_nova$Shape_Area))
      
    }
  )

}

# Run the application 
shinyApp(ui = ui, server = server)

Obviously, I comment out one of the two blocks of code as needed when I run it.

This is what it looks like when it's working:

The working version

This is what it looks like when it's not working:

No markers this time??

Is the reason that one works and not the other that I added columns to the data frame using the left_join function from dplyr?


Solution

  • Okay, I've figured it out. It was actually a simple mistake all along: I forgot to transform the coordinate system of the map I wanted to use with the sf::st_transform() function. As a result, the coordinate system was all over the place and that's why I couldn't see the markers.

    Sorry about the confusion and thank you to @Jan.