Search code examples
rimageplotly

Interactive display of a 3d object in R


I am still struggling to find a way in R to interactively display successive images.

In the following, I am generating a 3d object mat3d.

mat <- matrix(dnorm(seq(
  from = -10,
  to = 10,
  length.out = 100 * 100
), sd = 5),
c(100, 100))

mat2d <- mat * t(mat)

mat3d <- array(c(mat2d, mat2d * 0.9, mat2d * 0.8), c(100, 100, 3))

image(mat3d[, , 1],
      useRaster = TRUE,
      asp = 1,
      zlim = c(0, 0.01))

I would like to be able to display mat3d[, , 1], mat3d[, , 2], mat3d[, , k] by simply moving a cursor below the 2D image.

I would also like to be able to switch dimensions, so that I could display mat3d[, 1, ], mat3d[, 2, ], mat3d[, j, ], or mat3d[1, , ], mat3d[2, , ], mat3d[i, , ].

Can I obtain this using plotly or javascript in R?

Many thanks in advance for your help.


Solution

  • This is a good job for a Shiny app. Here is a starting point.

    mat <- matrix(dnorm(seq(
      from = -10,
      to = 10,
      length.out = 100 * 100
    ), sd = 5),
    c(100, 100))
    
    mat2d <- mat * t(mat)
    
    mat3d <- array(c(mat2d, mat2d * 0.9, mat2d * 0.8), c(100, 100, 3))
    
    
    library(shiny)
    ui <- fluidPage(
      fluidRow(
        column(
          12,
          radioButtons(
            "index", label = "Choose the index", 
            choices = c("1", "2", "3"), inline = TRUE
          )
        ),
        column(
          12,
          plotOutput("img")
        )    
      )
    )
    
    server <- function(input, output, session) {
      
      output[["img"]] <- renderPlot({
        index <- as.integer(input[["index"]])
        image(mat3d[, , index],
              useRaster = TRUE,
              asp = 1,
              zlim = c(0, 0.01))
      })
    }
    
    shinyApp(ui, server)
    

    enter image description here

    To display the three slices, I would do three images:

    mat <- matrix(dnorm(seq(
      from = -10,
      to = 10,
      length.out = 100 * 100
    ), sd = 5),
    c(100, 100))
    
    mat2d <- mat * t(mat)
    
    mat3d <- array(c(mat2d, mat2d * 0.9, mat2d * 0.8), c(100, 100, 3))
    
    image(mat3d[70, , ],
          useRaster = TRUE,
          asp = 1,
          zlim = c(0, 0.01))
    
    library(shiny)
    ui <- fluidPage(
      fluidRow(
        column(
          4,
          numericInput(
            "ix", label = "Slice x", 
            min = 1, max = 100, step = 1, value = 50
          ),
          br(),
          plotOutput("imgx")
        ),
        column(
          4,
          numericInput(
            "iy", label = "Slice y", 
            min = 1, max = 100, step = 1, value = 20
          ),
          br(),
          plotOutput("imgy")
        ),
        column(
          4,
          radioButtons(
            "iz", label = "Slice z", 
            choices = c("1", "2", "3"), inline = TRUE
          ),
          br(),
          plotOutput("imgz")
        )
      )
    )
    
    server <- function(input, output, session) {
      
      output[["imgx"]] <- renderPlot({
        index <- input[["ix"]]
        image(mat3d[index, , ],
              useRaster = TRUE,
              asp = 1,
              zlim = c(0, 0.01))
      })
      
      output[["imgy"]] <- renderPlot({
        index <- input[["iy"]]
        image(mat3d[, index, ],
              useRaster = TRUE,
              asp = 1,
              zlim = c(0, 0.01))
      })
      
      output[["imgz"]] <- renderPlot({
        index <- as.integer(input[["iz"]])
        image(mat3d[, , index],
              useRaster = TRUE,
              asp = 1,
              zlim = c(0, 0.01))
      })
      
    }
    
    shinyApp(ui, server)
    

    enter image description here