rrworldmap

See unmatched countries for joinCountryData2Map in rworldmap?


I'm using the joinCountryData2Map function in rworldmap to match my data to the countries in the world map.

I get this result:

230 codes from your data successfully matched countries in the map
11 codes from your data failed to match with a country code in the map
11 codes from the map weren't represented in your data

I cannot figure out how to view those two lists of 11 countries. I am guessing that those 11 countries have issues with their ISO2 codes that I need to correct, but am not sure which ones to check without being able to view those two lists.

I'm guessing there's a solution along the lines of just View(SomeObject$Countries) but I haven't been able to find anything that works.


Solution

  • Set joinCountryData2Map(...,verbose=TRUE) to print the names of the countries that failed to match in the console.

    From the FAQ: "You can see that a summary of how many countries are successfully joined is output to the console. You can specify verbose=TRUE to get a full list of countries"

    library(rworldmap)
    
    data(countryExData)
    
    # Set Angola to fail
    countryExData[countryExData$ISO3V10 == "AGO", "ISO3V10"] <- "AGO_FAIL"
    
    # Attempt to join
    # With verbose=TRUE, failed joins (ie Angola) are printed in the console
    sPDF <- joinCountryData2Map(
      countryExData[,c("ISO3V10", "Country")],
      joinCode = "ISO3",
      nameJoinColumn = "ISO3V10",
      verbose = TRUE)
    
    # > 148 codes from your data successfully matched countries in the map
    # > 1 codes from your data failed to match with a country code in the map
    # >      failedCodes failedCountries
    # > [1,] "AGO_FAIL"  "Angola"       
    # > 95 codes from the map weren't represented in your data
    

    But what if you want to get the information on failed joins programmatically? I may have missed something, but I don't see an option for that (i.e., str(sPDF) or function arguments). However, looking at the internals of joinCountryData2Map(), the object failedCountries contains the info you want, so it should be easy enough to include it in the returned object.

    Here's how you could modify joinCountryData2Map() to return a list with two elements: the first element is the default object, and the second element is failedCountries.

    # Modify the function to return the failed joins in the environment
    joinCountryData2Map_wfails <- function(
      dF, joinCode = "ISO3", nameJoinColumn = "ISO3V10",
      nameCountryColumn = "Country", suggestForFailedCodes = FALSE, 
      mapResolution = "coarse", projection = NA, verbose = FALSE) {
      
      # Retain successful join as first element and failed join as second element
      ll <- list() # MODIFIED
      mapWithData <- getMap(resolution = mapResolution)
      if (!is.na(projection)) 
        warning("the projection argument has been deprecated, returning Lat Lon, use spTransform from package rgdal as shown in help details or the FAQ")
      listJoinCodesNew <- c("ISO_A2", "ISO_A3", "FIPS_10_", 
                            "ADMIN", "ISO_N3")
      listJoinCodesOld <- c("ISO2", "ISO3", "FIPS", 
                            "NAME", "UN")
      listJoinCodes <- c(listJoinCodesOld, listJoinCodesNew)
      if (joinCode %in% listJoinCodes == FALSE) {
        stop("your joinCode (", joinCode, ") in joinCountryData2Map() is not one of those supported. Options are :", 
             paste(listJoinCodes, ""), "\n")
        return(FALSE)
      }
      joinCodeOld <- joinCode
      if (joinCode %in% listJoinCodesOld) {
        joinCode <- listJoinCodesNew[match(joinCode, listJoinCodesOld)]
      }
      if (is.na(match(nameJoinColumn, names(dF)))) {
        stop("your chosen nameJoinColumn :'", nameJoinColumn, 
             "' seems not to exist in your data, columns = ", 
             paste(names(dF), ""))
        return(FALSE)
      }
      dF[[joinCode]] <- as.character(dF[[nameJoinColumn]])
      dF[[joinCode]] <- gsub("[[:space:]]*$", "", dF[[joinCode]])
      if (joinCode == "ADMIN") {
        dF$ISO3 <- NA
        for (i in 1:nrow(dF)) dF$ISO3[i] = rwmGetISO3(dF[[joinCode]][i])
        joinCode = "ISO3"
        nameCountryColumn = nameJoinColumn
      }
      matchPosnsInLookup <- match(as.character(dF[[joinCode]]), 
                                  as.character(mapWithData@data[[joinCode]]))
      failedCodes <- dF[[joinCode]][is.na(matchPosnsInLookup)]
      numFailedCodes <- length(failedCodes)
      numMatchedCountries <- nrow(dF) - numFailedCodes
      cat(numMatchedCountries, "codes from your data successfully matched countries in the map\n")
      failedCountries <- dF[[nameCountryColumn]][is.na(matchPosnsInLookup)]
      failedCountries <- cbind(failedCodes, failedCountries = as.character(failedCountries))
      cat(numFailedCodes, "codes from your data failed to match with a country code in the map\n")
      if (verbose) 
        print(failedCountries)
      matchPosnsInUserData <- match(as.character(mapWithData@data[[joinCode]]), 
                                    as.character(dF[[joinCode]]))
      codesMissingFromUserData <- as.character(mapWithData@data[[joinCode]][is.na(matchPosnsInUserData)])
      countriesMissingFromUserData <- as.character(mapWithData@data[["NAME"]][is.na(matchPosnsInUserData)])
      numMissingCodes <- length(codesMissingFromUserData)
      cat(numMissingCodes, "codes from the map weren't represented in your data\n")
      mapWithData@data <- cbind(mapWithData@data, dF[matchPosnsInUserData, 
      ])
      invisible(mapWithData)
      
      ll[[1]] <- mapWithData # MODIFIED
      ll[[2]] <- failedCountries # MODIFIED
      return(ll) # MODIFIED
    }
    

    Usage:

    sPDF_wfails <- joinCountryData2Map_wfails(
      countryExData[,c("ISO3V10", "Country")],
      joinCode = "ISO3",
      nameJoinColumn = "ISO3V10",
      verbose = TRUE)
    
    # This is the result of the original function
    # sPDF_wfails[[1]]
    
    # This is info on the failed joins
    sPDF_wfails[[2]]
    
    # >     failedCodes failedCountries
    # > [1,] "AGO_FAIL"  "Angola"