简体   繁体   中英

Plot many differnt lines; base legend on column A (visibility); base color on column B

I try to visualize certain data in a HTML file using R. Enviroment:

  • R: version 4.2.2
  • R Studio: version 2022.07.2+576
  • librarys: tidyverse, plotly

I have 100 CSV-Files named 00_Trace to 99_Trace. Each file has three columns (time, Cylinder_0, Cylinder_1) and 500 data plus one 1 title lines. The lines represent the trace of two positions over time.

Importing the CSV-Files leads to a big data of the following form:

time       filename              Cylinder_0  Cylinder_1
...
979.971    00_Trace_Retract.csv   1.9        9.0    
981.967    00_Trace_Retract.csv   2.0        5.0    
984.062    00_Trace_Retract.csv   1.7        9.0    
985.964    00_Trace_Retract.csv   1.7        1.0    
987.995    00_Trace_Retract.csv   1.3        1.0    
989.978    00_Trace_Retract.csv   1.6        9.0    
991.973    00_Trace_Retract.csv   1.6        1.0    
994.091    00_Trace_Retract.csv   1.6        1.0    
995.960    00_Trace_Retract.csv   1.7        1.1    
997.986    00_Trace_Retract.csv   1.7        1.0
...

I can mutate the values to numeric, pivot_longer the data set to one value and additional column for Position_A or Position_B.

What I want is basically to have a legend in order to choose which file(s) (00_Trace... 99_Trace) shall be shown; always two traces. The color of the line should be based on Position_A (blue) and Position_B (grey).

I tried:

data <- readAllCsvData("data") %>% 
  rename(time = `time..s.`) %>% 
  select(-X) %>% 
  mutate(time = as.numeric(time)) %>% 
  mutate(Cylinder_0 = as.numeric(Cylinder_0)) %>% 
  mutate(Cylinder_1 = as.numeric(Cylinder_1)) %>% 
  mutate(Dev_new = Cylinder_0 - Cylinder_1) %>% 
  mutate(Deviation = as.numeric(Deviation)) %>% 
  pivot_longer(cols = c(Cylinder_0, Cylinder_1), names_to = "Cylinder")

gg <- data %>% 
  filter(grepl(".*Advance.*", filename)) %>% 
  ggplot() +
  geom_line(aes(x = time, y = value, group = filename, color = Cylinder)) 

ggplotly(gg)

But I only do get the following. Colors are basically allright, just need to change the actually used color. But I can only select Cylinder_0 or Cylinder_1, not for example 50_Trace.

Can this be solved in an easy way?

I tried several different ways where the plot was initiated as a ggplot object, but couldn't get any of them to work.

However, I did come up with a few different methods that work in Plotly without starting in ggplot .

This answer really shows one method of making this happen in Plotly and a few methods to customize it further. This uses buttons. I did come up with a method that would allow you to have something like a legend to click on to change files, but it was ugly and not something that would be all that easy to implement.

Creating the Buttons

By use of buttons, you can have individual buttons for each file. Alternatively, you can have a drop-down menu to choose the file-- which may be better if you have 99 files.

First, here's a function that will create a single button, considering how you've set your data up.

btn <- function(lab, x, y){   # lab: (string) button label
  # x: (int) number of traces; y: (vector) traces to make visible
  v = rep(F, x)  
  v[y] = T
  list(method = "restyle",          # make the button
       label = lab,
       args = list(list(visible = unlist(v))))
}

To use this btn function, we need a list of unique file names and something that will call this function to create a list of buttons—one for each file name.

filenames <- unique(dta$filename) # unique files

btns <- lapply(                   # create button for each file name
  1:length(filenames),
  function(j) {
    btn(filenames[j], 
        length(filenames)*2,         # 2 <-- 1 for each color
        c(j, j + length(filenames))) # <- all blue traces created first
  }
)

Using the Buttons; Creating the Plot

Now all that's left to do is create the plot. This plot version uses individual buttons (not a dropdown). I only used 3 'files' in my sample data since your question isn't reproducible.

plot_ly(dta2, x = ~time, y = ~value, split = ~filename, color = ~Cylinder,
        type = 'scatter', mode = 'lines', 
        colors = ~c("Cylinder_0" = "blue", "Cylinder_1" = "grey")) %>% 
  layout(updatemenus = list(
    list(type = "buttons", buttons = btns)   # <--- type changed!
  ))

在此处输入图像描述

This plot uses a dropdown menu instead.

在此处输入图像描述

Updating the Legend Names

I thought that the 'cylinder...file' in the legend was ugly and rather cumbersome, so I also came up with a workaround to rid yourself of that, too.

fixer <- function(plt) {
  plt <- plotly_build(plt)
  lapply(1:length(plt$x$data),
         function(k) {
           plt$x$data[[k]]$name <<- str_extract(plt$x$data[[k]]$name,
                                                "^.*(?=\\<)")
         })
  plt
}

This is how you use it.

plot_ly(dta2, x = ~time, y = ~value, split = ~filename, color = ~Cylinder,
        type = 'scatter', mode = 'lines', 
        colors = ~c("Cylinder_0" = "blue", "Cylinder_1" = "grey")) %>% 
  layout(updatemenus = list(
    list(type = "dropdown", buttons = btns)
  )) %>% fixer()                               # <-- I'm new!

在此处输入图像描述

All the Code in One Chunk

Since there are a lot of separate chunks of code, here's all the code you need to create a drop-down menu and updated legend names version altogether.

library(tidyverse)
library(plotly)

btn <- function(lab, x, y){   # lab: (string) button label
  # x: (int) number of traces; y: (vector) traces to make visible
  v = rep(F, x)  
  v[y] = T
  list(method = "restyle",          # make the button
       label = lab,
       args = list(list(visible = unlist(v))))
}

filenames <- unique(dta$filename)

btns <- lapply(                   # create button for each file name
  1:length(filenames),
  function(j) {
    btn(filenames[j], 
        length(filenames)*2,         # 2 <-- 1 for each color
        c(j, j + length(filenames))) # <- all blue traces created first
  }
)

fixer <- function(plt) {
  plt <- plotly_build(plt)
  lapply(1:length(plt$x$data),
         function(k) {
           plt$x$data[[k]]$name <<- str_extract(plt$x$data[[k]]$name,
                                                "^.*(?=\\<)")
         })
  plt
}

plot_ly(dta2, x = ~time, y = ~value, split = ~filename, color = ~Cylinder,
        type = 'scatter', mode = 'lines', 
        colors = ~c("Cylinder_0" = "blue", "Cylinder_1" = "grey")) %>% 
  layout(updatemenus = list(
    list(type = "dropdown", buttons = btns)
  )) %>% fixer()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM