R Shiny -> Аргумент FillOpacity в функции AddCircles игнорируется - PullRequest
1 голос
/ 04 августа 2020

Я работаю над проектом R Shiny по визуализации всех аэропортов мира. Приведенный ниже код является образцом моего проекта. Функционально приложение работает должным образом - таблица данных и карта обновляются, когда вы выбираете другую страну. Однако у меня возникла проблема с точками на картах. Поскольку у меня радиус точек зависит от количества маршрутов из аэропорта, в густонаселенных районах, где может быть несколько крупных аэропортов (например: Чика go), некоторые большие точки перекрывают меньшие. Я использовал аргумент FillOpacity в функции AddCircles, чтобы сделать его более прозрачным, чтобы вы могли видеть потенциально замаскированные точки. Однако кажется, что этот аргумент игнорируется, когда я использую его в приведенном ниже коде:

#Dataset 1: Routes
routes=read.csv(url("https://raw.githubusercontent.com/jpatokal/openflights/master/data/routes.dat"))
dim(routes)
#67662  9
str(routes)

#Dataset #2: Airports
airports=read.csv(url("https://raw.githubusercontent.com/jpatokal/openflights/master/data/airports-extended.dat"))
dim(airports)
#12667 14

#Rename columns
colnames(routes)=c("Airline","AirlineID","IATA","SourceAP_ID","DestinationAirport","DestAP_ID","Codeshare","Stops","Equipment")
colnames(airports)=c("AirportID","Name","City","Country","IATA","ICAO","Latitude","Longitude","Altitude","Timezone","DST","TzDatabaseTz","Type","Source")

#Join datasets on Source Airport
#-------------------------------#
#IATA in airports
#SourceAirport in routes (IATA)

fullair=merge(x=routes,y=airports,by="IATA",all.x=TRUE)

fullair2=subset(fullair,fullair$Type=="airport")

library(dplyr)

#Make a new unique ID by combining IATA and Destination Airport
fullair2$UniqueID=paste0(fullair2$IATA,"_",fullair2$DestinationAirport)

#Create column that assigns number of unique routes to single airport
fullair3=fullair2 %>%
  group_by(IATA) %>%
  mutate(Count=n_distinct(UniqueID)) %>%
  ungroup()
fullair3=as.data.frame(fullair3)



#Get rid of duplicates
fullair3=fullair3[!duplicated(fullair3[c("UniqueID")]),]


library(rowr)
library(sqldf)
library(RSQLite)


#-----------Number of Routes from Destination------------#
SpitOutNum=sqldf("select IATA,count(*)
                 from fullair3
                 group by IATA")
SpitOutNum=as.data.frame(SpitOutNum)
colnames(SpitOutNum)=c("IATA","DestinationCount")
fullair3=merge(x=fullair3,y=SpitOutNum,by="IATA",all.x=TRUE)



#Create the full name
fullair3$NamePart1=paste("(",fullair3$IATA,")",sep ="")
fullair3$FullName=paste(fullair3$Name, fullair3$NamePart1)
fullair3$NamePart1=NULL

fullair3$Name2Part1=paste("(",fullair3$DestinationAirport,")",sep ="")
fullair3$DestFullName=paste(fullair3$DestAirportName, fullair3$Name2Part1)

fullair3$Name2Part1=paste("(",fullair3$DestinationAirport,")",sep ="")
fullair3$DestFullName=paste(fullair3$DestAirportName, fullair3$Name2Part1)


table2=sqldf("select Country, FullName as 'Airport Name', City, count(*) as 'Number of Routes'
             from fullair3
             group by Country, FullName, City
             order by count(*) desc")


#Sort by FullName
fullair3= fullair3[order(fullair3$FullName),]

#-----------------------------------------------------
library(shinydashboard)
library(shiny)
library(leaflet)
library(leaflet.extras)
library(rgdal)
library(sp)
library(raster)
library(DT)
library(markdown)
library(geosphere)
library(htmltools)


airportchoices=unique(fullair3$FullName)
countrychoices=unique(fullair3$Country)

countrychoices=as.character(countrychoices)
countrychoices=sort(countrychoices)


# Define UI for application
ui <- fluidPage(
  dashboardPage(
    dashboardHeader(title="Airport Analysis"),
    dashboardSidebar(
      sidebarMenu(
        menuItem("Country Maps",
                 tabName = "CountryMaps",
                 icon=icon("flag")
        ))
    ),
    dashboardBody(
      tabItems(
        tabItem(
          tabName = "CountryMaps",
          tags$style(type="text/css","#country_airports {height:calc(100vh - 80px) !important;}"),
          fluidRow(column(4),
                   column(8, selectInput(inputId = "countryselect",label="Select a country:",choices=countrychoices)
                   )),
          DTOutput("countrydata"),
          leafletOutput("country_airports")
          
        )
      )
    )
  )
)
# Define server logic 
server <- function(input, output) {
  
  #----------COUNTRY FILTERING---------#  
  
  CountryData=reactive({
    filteredData=subset(fullair3,Country == input$countryselect)
    return(filteredData)
  })
  
  CountryDataTable=reactive({
    filteredDataTable=subset(table2,Country==input$countryselect)
    filteredDataTable$Country=NULL
    return(filteredDataTable)
  })
  
  
  #-------------------COUNTRY PLOTS-------------------#
  output$countrydata=renderDT({
    
    data_table = CountryDataTable()
    
    
    datatable(data_table,options=list(pageLength=5,
                                      lengthMenu=c(5,10,15,20)
    ),rownames = FALSE)
  })
  
  output$country_airports=renderLeaflet({
    
    data=CountryData()
    
    pal=colorNumeric("Yellow",data$DestinationCount)
    
    
    leaflet(data=data) %>% 
      addTiles(group="CartoDB.Positron")  %>%
      
      addProviderTiles(providers$CartoDB.Positron,
                       options = tileOptions(minZoom =0, maxZoom = 13),
                       group = "CartoDB.Positron") %>%
      
      
      addCircles(radius = ~data$DestinationCount*1000, 
                 weight = 1, 
                 color = "black", 
                 fillColor = ~pal(data$DestinationCount),
                 fillOpacity = 0.4,
                 popup = paste0("Airport Name: ", data$Name, "<br>",
                                "City: ", data$City, "<br>",
                                "Destination Count: ",data$DestinationCount,"<br>"
                 ),
                 label = ~as.character(data$IATA),
                 group = "Points") 
    
  })
}

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

Есть ли у кого-нибудь предложения, как исправить эту проблему? Любая помощь будет оценена по достоинству! Спасибо!

1 Ответ

2 голосов
/ 08 августа 2020

Я думаю, что fillOpacity = 0.4 слишком велико, чтобы получить прозрачность для точек около Chica go, например. Я получил прозрачность на изображении ниже, установив fillOpacity = 0.01. При более низком значении альфа требуется большее количество точек, чтобы сделать точку полностью непрозрачной. И я думаю, что, например, с 0,4 и более 200 строк для ORD аэропорта вы достигнете этого порога.

enter image description here

You could try to solve this plotting only one point per airport (that is, only one row in your dataset).

For example with fillOpacity = 0.4 and adding this code before leaflet function

data <- data %>% 
  dplyr::distinct(IATA, Latitude, Longitude, DestinationCount, Name, City)

I got the map in the image below

enter image description here

Answering your further question in the comment, it seemed that a possible way was playing with the z-index parameter, but I found that SVGs (like Circles) do not support z-index and the order is based on the order in which the elements were added to the map. So I tried to change the code above in the following way:

data <- data %>% 
  dplyr::distinct(IATA, Latitude, Longitude, DestinationCount, Name, City) %>% 
  dplyr::arrange(desc(DestinationCount))

And got this result

введите описание изображения здесь

Вы также можете попробовать использовать addCircleMarkers вместо addCircles, изменив только radius = ~data$DestinationCount*0.3. Если вы увеличите масштаб достаточно, вы увидите, что ORD и MDW не перекрываются.

...