Интерактивное построение растра R: значения при наведении курсора

Я хотел бы сделать небольшую программу в R для интерактивной визуализации и модификации некоторых наборов растровых данных, видимых как цветные изображения. Пользователь должен открыть файл (из терминала можно), начертить его, выбрать точки для редактирования щелчками мыши и вставить новые значения.

До сих пор я достиг этого легко. Я использую функцию plot() из пакета raster для визуализации графика, затем click() для выбора точек и редактирования их значения через терминал.

Я хотел бы добавить возможность показывать значения при наведении курсора мыши. Я искал способы, как это сделать, но это невозможно со стандартными пакетами R. Это правильно?

В этом случае я могу быть вынужден использовать внешние пакеты, такие как gGobi, iPlots, Shiny или Plotly. Однако я бы предпочел KISS и использовать только "стандартные" графические инструменты, такие как растровая функция plot() или, возможно, объекты решетчатой ​​графики (например, из rasterVis).

Я понимаю, что приложение Shiny, вероятно, было бы лучшим, но для его изучения и совершенствования требуется много времени.


person AF7    schedule 08.06.2015    source источник
comment
Возможно, это будет полезно для вас oscarperpinan.github.io/rastervis/#interaction   -  person Oscar Perpiñán    schedule 08.06.2015
comment
@OscarPerpiñán: спасибо, но я уже рассмотрел возможности взаимодействия rasterVis (поэтому я упомянул об этом в вопросе), и, насколько я вижу, identifyRaster() не имеет много дополнительных функций по сравнению с raster::click, которые я уже использую. В частности, нет возможности отображать данные при наведении курсора мыши, что я и пытаюсь сделать. Пожалуйста, поправьте меня, если я ошибаюсь, я был бы очень рад использовать такое хорошее решение (я люблю rasterVis и часто его использую).   -  person AF7    schedule 08.06.2015
comment
Ты прав. identifyRaster и click более или менее одинаковы (для решетчатой ​​и базовой графики соответственно). Насколько я знаю, то, что вы пытаетесь сделать, невозможно с графическим устройством, созданным R. Боюсь, вам понадобится код javascript.   -  person Oscar Perpiñán    schedule 09.06.2015
comment
@Оскар: я тоже этого боюсь. Если у вас есть какие-либо предложения о том, какой метод (я думаю, какой-нибудь интерфейс D3.js) был бы наиболее целесообразным, то есть какой из них проще всего адаптировать к моим потребностям, они были бы очень кстати.   -  person AF7    schedule 09.06.2015
comment
У меня нет информации о решении, объединяющем javascript с растровыми данными. Вы можете попробовать пакет gridSVG для создания собственного решения. Возможно, вам будут полезны эти примеры (с точечными данными). : . Кроме того, пакет htmlwidgets создает привязки R к библиотекам javascript, но, насколько мне известно, ни один из них работают с растровыми данными.   -  person Oscar Perpiñán    schedule 09.06.2015
comment
Я вижу, что версия отличного ggiraph на гитхабе теперь содержит функцию geom_sf_interactive, которая работает с пакетом sf. Если я правильно понимаю ваши потребности, я думаю, что это может сработать для вас и обеспечить взаимодействие без Shiny.   -  person p0bs    schedule 24.06.2018
comment
@pObs спасибо за вклад! С тех пор, как я опубликовал этот вопрос, дела пошли очень быстро: теперь у нас есть sf, leaflet, mapview, mapedit и т. д. Я думаю, что вопрос немного устарел. Во всяком случае, я не знал, что ggiraph уже реализовал sf объектов, здорово!   -  person AF7    schedule 25.06.2018
comment
почему бы не добавить свое решение в список ниже?   -  person Adrian Tompkins    schedule 27.06.2018
comment
@AdrianTompkins то, что я сделал тогда, было очень похоже на то, что реализовал @SeGa, что дополнительно подразумевало многократное перерисовывание растрового изображения (я думаю, что sf еще не было). Это было медленно и неуклюже.   -  person AF7    schedule 28.06.2018


Ответы (2)


С помощью leaflet, mapview и leafem вы можете добиться чего-то вроде этого:

library(raster)
library(mapview)
library(leaflet)
library(leafem)

f <- system.file("external/test.grd", package="raster")
r <- raster(f)

leaflet() %>% 
  addRasterImage(r, layerId = "values") %>% 
  addMouseCoordinates() %>%
  addImageQuery(r, type="mousemove", layerId = "values")

Поместив это в блестящее приложение, вы получите:

library(raster)
library(mapview)
library(leaflet)
library(shiny)

f <- system.file("external/test.grd", package="raster")
r <- raster(f)

ui <- fluidPage(
  leafletOutput("map")
)

server <- function(input, output){
  output$map <- renderLeaflet({
    leaflet() %>% 
      addRasterImage(r, layerId = "values") %>% 
      addMouseCoordinates() %>%
      addImageQuery(r, type="mousemove", layerId = "values")
  })
}

shinyApp(ui, server)

Следующий пример иллюстрирует идею преобразования растра в простые объекты/шейп-файлы. Это не очень удобно для больших файлов, но метки могут быть разработаны индивидуально, данные редактируются и могут быть легко отображены в таблице.

library(raster)
library(leaflet)
library(shiny)
library(sf)
library(DT)
library(dplyr)

## DATA
f <- system.file("external/test.grd", package="raster")
r <- raster(f)
r1 = aggregate(r, 30)

sp = st_as_sf(rasterToPolygons(r1))
cn = st_coordinates(st_transform(st_centroid(sp),4326))
sp = st_transform(sp, 4326)
sp = cbind(sp, cn)
sp$id <- 1:nrow(sp)
colnames(sp)[1] <- "value"


## UI
ui <- fluidPage(
  leafletOutput("map"),
  uiOutput("newValueUI"),
  textInput("newVal", label = "Enter new value"),
  actionButton("enter", "Enter new value"),
  hr(),
  dataTableOutput("table")
)


## SERVER
server <- function(input, output){

  ## Reactive Shapefile
  sp_react <- reactiveValues(sp = sp)
  
  ## Leaflet Map
  output$map <- renderLeaflet({
    pal= colorNumeric(topo.colors(25), sp_react$sp$value)
    leaflet() %>% 
      addPolygons(data = sp_react$sp, label= paste(
        "Lng: ", as.character(round(sp_react$sp$X,4)),
        "Lat: ", as.character(round(sp_react$sp$Y,4)),
        "Val: ", as.character(round(sp_react$sp$value,4))),
        color = ~pal(sp_react$sp$value), 
        layerId = sp_react$sp$id
      )
  })
  
  ## Observe Map Clicks
  observeEvent(input$map_shape_click, {
    
    click_id = input$map_shape_click$id
    
    click_grid <- sp_react$sp[sp_react$sp$id == click_id,]

  })
  
  ## Observe Action Button
  observeEvent(input$enter, {
    click_id <- input$map_shape_click$id
    sp_react$sp[sp_react$sp$id == click_id,]$value <- as.numeric(input$newVal)
  })

  ## Data Table
  output$table <- DT::renderDataTable({
    sp_react$sp %>% st_set_geometry(NULL) %>% 
      dplyr::select(id,X,Y,value)
  })
  proxy = dataTableProxy('table')
  
  ## Table Proxy
  observeEvent(input$map_shape_click$id, {
    req(input$map_shape_click$id)
    proxy %>% selectRows(as.numeric(input$map_shape_click$id))
  })
}

shinyApp(ui, server)
person SeGa    schedule 25.06.2018
comment
Я знаю, что это не совсем ответ на мой вопрос, но я все равно приму этот ответ. Я считаю, что с сегодняшними пакетами R можно было бы подумать о том, чтобы сделать это в листовке / блестящем, а не с использованием базы raster или аналогичной. - person AF7; 26.06.2018
comment
Я не знаю, поддерживает ли addRasterImage события мыши, я ничего не нашел в руководствах. Таким образом, 1 идея состоит в том, чтобы создать сетку с тем же разрешением, что и растр, и выполнять события мыши на основе этого шейп-файла. Либо делайте все только с шейп-файлами, либо получайте только центральные точки выбранной сетки и фильтруйте растр для этой ячейки, чтобы включить значения/координаты в метки. - person SeGa; 26.06.2018
comment
Да, я бы тоже так сделал. Но это становится неуклюжим с большими шейп-файлами. - person AF7; 26.06.2018
comment
Я думаю, что mapview::addImageQuery делает то, что вы ищете. - person TimSalabim; 27.06.2018
comment
Действительно .. Спасибо @TimSalabim. Надеюсь, вы не возражаете, что я включил это в свой ответ. - person SeGa; 27.06.2018
comment
Нисколько! Это делает ответ более актуальным, ИМО - person TimSalabim; 27.06.2018
comment
Это точно! Но редактирование значений по-прежнему невозможно с растрами или? Я мог бы придумать несколько способов для шейп-файлов, хотя - person SeGa; 27.06.2018
comment
Никакое редактирование в настоящее время невозможно. Хотя мы работаем над этим в mapedit. Может быть, мы также можем предоставить что-то для растровых данных. Я буду иметь это в виду. - person TimSalabim; 27.06.2018
comment
Я только что изменил пример шейп-файла. Ячейки сетки теперь можно редактировать, но это неэффективно, так как весь шейп-файл перерисовывается при вводе нового значения. - person SeGa; 27.06.2018
comment
Да, это очень похоже на то, что я делал в прошлом. Я перерисовывал растровое изображение несколько раз, каждый раз, когда редактировалось значение. Это было некрасиво. Возможно, используя sf полигонов, можно было бы достичь более аккуратного решения. В целом гораздо приятнее использовать полигоны, так как вам не нужно интерполировать растр. - person AF7; 28.06.2018

Я привожу вам простой пример того, как это сделать в R без внешних библиотек Java, если вам нужны функции Javan, вы можете адаптировать его, но каждая графическая библиотека java отличается, и я никогда не делал ничего подобного.

set.seed(123)
mydata <- data.frame(x = runif(10), y = runif(10))

edit_plot <- function(data) {
  plot(data)

  sel <- locator(n = 1)
  if(is.null(sel)) return(TRUE)
  dd <- (data$x - sel$x)^2 + (data$y - sel$y)^2

  data[which.min(dd),] <- edit(data[which.min(dd),])
  r <- edit_plot(data)
  if(r) return(TRUE)
}
edit_plot(mydata)

Для выхода нажмите Esc, когда локатор активен.

person Juan Antonio Roldán Díaz    schedule 25.06.2018