Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the x y coordinates from a line of a png image and use it in a shiny app

This is a follow-up question to this Color an area with a sliderInput in a shiny app

Suppose I have this image:

enter image description here

How could I apply this solution by @ismirsehregal to this picture. I think I have to put the x and y from the esophagus to the code, but I don't know how to get the x and y of the esophagues (green in the picture):

Code from Color an area with a sliderInput in a shiny app

library(shiny)
library(plotly)
library(shinyWidgets)

DF <- data.frame(
    x = c(cos(seq(0.01, 10, 0.01)) * 1000:1 + 1000, cos(seq(0.01, 10, 0.01)) * 1000:1 + 1500),
    y = rep(1:1000, 2),
    id = c(rep("trace_1", 1000), rep("trace_2", 1000))
  )

ui <- fluidPage(
  br(),
  column(
    2,
    noUiSliderInput(
      inputId = "noui2",
      label = "Slider vertical:",
      min = 0,
      max = 1000,
      step = 50,
      value = c(100, 400),
      margin = 100,
      orientation = "vertical",
      direction = c("rtl"),
      width = "100px",
      height = "350px"
    )
  ),
  column(4, plotlyOutput("plot")),
  verbatimTextOutput(outputId = "res2")
)

server <- function(input, output, session) {
  output$res2 <- renderPrint(input$noui2)
  
  plotDF <- reactive({
    plotDF <- DF[DF$y %in% input$noui2[1]:input$noui2[2], ]
    plotDF$id <- paste0("filtered_", plotDF$id)
    plotDF
  })
  
  output$plot <- renderPlotly({
    fig <- plot_ly(
        rbind(DF, plotDF()),
        x = ~ x,
        y = ~ y,
        split = ~ id,
        type = "scatter",
        mode = "lines",
        color = I("black"),
        fillcolor = 'red',
        showlegend = FALSE
      ) |> style(fill = 'tonexty', traces = 2)
  })
}

shinyApp(ui, server)

enter image description here

like image 946
TarJae Avatar asked Oct 30 '25 12:10

TarJae


1 Answers

The following approach doesn't meet the title of your question, but it shows the procedure I mentioned in your previous post.

You will need to save a modified png file (transparent esophagus - edited with gimp's "fuzzy select tool") in your apps www folder for this to work (please find it below).

I'm now using plotlyProxyInvoke to update the data without re-rendering the plot:

library(shiny)
library(plotly)
library(shinyWidgets)

slider_min <- 0
slider_max <- 45
lower_slider_value <- 5
upper_slider_value <- 18
x_position_trace_1 <- 40
x_position_trace_2 <- 50

DF <- data.frame(
  x = c(rep(x_position_trace_1, 2), rep(x_position_trace_2, 2)),
  y = rep(c(lower_slider_value, upper_slider_value), 2),
  id = c(rep("trace_1", 2), rep("trace_2", 2))
)

ui <- fluidPage(
  br(),
  column(
    2,
    noUiSliderInput(
      inputId = "noui2",
      label = "Slider vertical:",
      min = slider_min,
      max = slider_max,
      step = 1L,
      value = c(lower_slider_value, upper_slider_value),
      margin = 1,
      orientation = "vertical",
      width = "100px",
      height = "350px"
    )
  ),
  column(4, plotlyOutput("myPlot", height = "800px")),
  verbatimTextOutput(outputId = "res2")
)

server <- function(input, output, session) {
  output$res2 <- renderPrint(input$noui2)
  
  output$myPlot <- renderPlotly({
    fig <- plot_ly(
      DF,
      x = ~ x,
      y = ~ y,
      split = ~ id,
      type = "scatter",
      mode = "lines",
      color = I("white"),
      fillcolor = 'red',
      showlegend = FALSE
    ) |> layout(
      images = list(
        list(
          source =  "/esophagus.png",
          xref = "x",
          yref = "y",
          x = 0,
          y = -16,
          sizex = 93,
          sizey = 93,
          sizing = "stretch",
          opacity = 1,
          layer = "above"
        )
      ),
      plot_bgcolor  = "rgba(0, 0, 0, 0)",
      paper_bgcolor = "rgba(0, 0, 0, 0)",
      xaxis = list(
        zerolinecolor = '#ffff',  
        zerolinewidth = 2,  
        gridcolor = 'ffff',
        range = list(0, 100)),  
      yaxis = list(
        zerolinecolor = '#ffff',  
        zerolinewidth = 2,  
        gridcolor = 'ffff',
        range = list(80, -20)
        # or autorange = "reversed"
        )  
    ) |> style(fill = 'tonexty', traces = 2)
  })
  
  myPlotProxy <- plotlyProxy("myPlot", session)
  
  observe({
    plotlyProxyInvoke(myPlotProxy, "restyle", list(x = list(rep(x_position_trace_1, 2), rep(x_position_trace_2, 2)), y = list(input$noui2, input$noui2)), list(0, 1))
  })
}

shinyApp(ui, server)

result


Image for the www folder - save as "esophagus.png".

To visualize the transparent area (grey) open the image in a new browser tab (chrome):

transparent_esophagus


Edit: Here is another lightweight approach without using {plotly}.

This isn't perfectly aligned yet and it might make sense to work wit % instead of px, however it shows the principle:

We can simply provide the esophagus image with a red background image and modify the css properties background-size and background-position-y:

library(shiny)
library(shinyjs)
library(shinyWidgets)

ui <- fluidPage(
  useShinyjs(),
  br(),
  column(
    2,
    noUiSliderInput(
      inputId = "noui2",
      label = "Slider vertical:",
      min = 0,
      max = 1000,
      step = 50,
      value = c(100, 400),
      margin = 100,
      orientation = "vertical",
      direction = c("rtl"),
      width = "100px",
      height = "350px"
    )
  ),
  column(
    4,
    tags$img(
      id = "esophagus",
      height = 1000,
      width = "100%",
      src = "/esophagus.png",
      style = "background-image: url(red_background.png); background-repeat: no-repeat; background-size: 100% 30%; background-position-y: 40%;"
    )
  ),
  verbatimTextOutput(outputId = "res2")
)

server <- function(input, output, session) {
  output$res2 <- renderPrint(input$noui2)
  
  observeEvent(input$noui2, {
    runjs(paste0('$("#esophagus").css("background-size", "100% ', input$noui2[2] - input$noui2[1], 'px");'))
    runjs(paste0('$("#esophagus").css("background-position-y", "', 1000 - input$noui2[2], 'px");'))
  })
}

shinyApp(ui, server)

Save as "red_background.png" in your www folder:

red_background

like image 158
ismirsehregal Avatar answered Nov 02 '25 02:11

ismirsehregal