JohnCoene / echarts4r

🐳 ECharts 5 for R
http://echarts4r.john-coene.com/
Other
601 stars 81 forks source link

Timeline VS Categorical groupby | Potential limitation [scatter3d/scatter/area etc] #593

Open MrMisc opened 11 months ago

MrMisc commented 11 months ago

From all the examples I have seen so far regarding timeline, I have seen timeline being used to groupby one variable, and each frame being one homogeneous set of points, usually with little to no distinction between them in terms of grouping. Considering the following dataset

3D Scatterplot Example | ECharts

library(echarts4r)
# library(echarts4r.assets)
library(dplyr)
library(pandoc)
library(rjson)
library(echarty)

N<-300
df <- data.frame(x = runif(N,1,20),
                 y = runif(N,10,25),
                 z = rnorm(N,100,50),
                 Time = runif(N,5,500),
                 label = sample(c("interaction1", "interaction2", "interaction3", "interaction4", "interaction5"), N, replace = TRUE),
                 zone = sample(c("zone0", "zone1", "zone3"), N, replace = TRUE))

df_toadd<-data.frame(x = runif(N,80,100),
                     y = runif(N,10,25),
                     z = rnorm(N,100,50),
                     Time = runif(N,5,500),
                     label = sample(c("interaction1", "interaction2", "interaction3", "interaction4", "interaction5"), N, replace = TRUE),
                     zone = sample(c("zone0", "zone1", "zone3"), N, replace = TRUE))
df<-rbind(df,df_toadd)

df|>group_by(label)|>e_charts(x)|>
  e_scatter_3d(y,z,Time)|>
  e_visual_map(Time,inRange = list(symbol = "diamond",symbolSize = c(25,5)),scale = my_scale)|>
  e_tooltip()|>
  e_theme("westeros")|>
  e_legend(show = TRUE)

So far this part works just fine, but the moment I want to use timeline to "scroll" through the zone column, I am forced to turn label into a numerical variable and do this

##Timeline
df$mylabel<-as.numeric(substr(df$label,12,12))
my_scale <- function(x) scales::rescale(x, to = c(min(df$Time),max(df$Time)))

df|>group_by(zone)|>e_charts(x,timeline = TRUE)|>
  e_scatter_3d(y,z,Time,mylabel,label)|>
  e_visual_map(Time,inRange = list(symbol = "diamond",symbolSize = c(35,5)),scale = my_scale,dimension = 3)|>
  e_visual_map(mylabel,inRange = list(colorLightness = c(0.5,0.8), colorHue = c(180,260),colorSaturation = c(120,200)),dimension = 4,bottom = 300)|>
  e_tooltip()|>
  e_theme("westeros")|>
  e_legend(show = TRUE)

Is there a way to do a categorical form of grouping WITHIN each frame?

Scatterplot Timeseries Across Timeline WITH categories | Plotly

I find this issue popping up for me a number of times. For example, say we had a dataset like so: output.csv

and the columns meant the following

data<-read.csv("output.csv",header = FALSE)
colnames(data) <- c(
  "ContaminantPct1","TotalSamples1_","ContaminantSamples1",
  "HitPct1", "TotalSamples1", "HitSamples1",
  "HitPct2", "TotalSamples2", "HitSamples2","HitPct3","HitSamples3","HitPct4", "TotalSamples4", "HitSamples4","Zone"
)

In plotly, I can make a frame-by-frame plot for each zone, where each of the HitPct{i} & ContaminantPct1 numbers are a category of their own (totalling to 5 categories of time series, for each zone). I can use plotly to make a plot that looks like this

#Round up values
data$ContaminantSamples1<-ceiling(data$ContaminantSamples1) #Contaminated Hosts
data$HitSamples1<-ceiling(data$HitSamples1) #Infected Hosts
data$HitSamples2<-ceiling(data$HitSamples2) #Eggs
data$HitSamples3<-ceiling(data$HitSamples3) #Colonized Hosts
data$HitSamples4<-ceiling(data$HitSamples4) #Faeces
# Scatter plot for the first 2 sets of data
# Define custom theme colors
thematic_on(bg = "#FCE9D7", fg = "orange", accent = "purple",font = "Yu Gothic")
# 

# Create a unique identifier for each time unit
no_of_zones<-length(unique(data$Zone))
data$TimeUnit <- rep(seq_len(nrow(data) / no_of_zones), each = no_of_zones)

# Farm

fig_dots <- data %>%
  plot_ly(type = "scatter",
          mode = "markers+lines", line = list(width = 0.35))%>%
  add_trace(x = ~TimeUnit,
            y = ~ContaminantPct1,
            frame = ~Zone,  # Use TimeUnit for animation frames
            color = "Contaminated Hosts",
            colors = c("#2A6074", "#00C9B1"),
            size = ~TotalSamples1_,
            customdata = ~{
              zone_data <- data[data$TimeUnit == TimeUnit, ]
              paste(zone_data$ContaminantSamples1, "out of ", zone_data$TotalSamples1_, " hosts @ ",zone_data$TimeUnit," hours")
            },
            hovertemplate = "%{y} % of motile hosts <br> are contaminated  <br> ie %{customdata}") %>%
  add_trace(x = ~TimeUnit,
            y = ~HitPct1,
            frame = ~Zone,  # Use TimeUnit for animation frames
            color = "Infected Hosts",
            colors = c("#2A6074", "#00C9B1"),
            size = ~TotalSamples1,
            customdata = ~{
              zone_data <- data[data$TimeUnit == TimeUnit, ]
              paste(zone_data$HitSamples1, "out of ", zone_data$TotalSamples1, " hosts @ ",zone_data$TimeUnit," hours")
            },
            hovertemplate = "%{y} % of motile hosts <br> are infected  <br> ie %{customdata}") %>%
  add_trace(x = ~TimeUnit,
            y = ~HitPct3,
            frame = ~Zone,  # Use TimeUnit for animation frames
            color = "Colonized Hosts",
            colors = c("#2A6074", "#00C9B1"),
            size = ~TotalSamples1,
            customdata = ~{
              zone_data <- data[data$TimeUnit == TimeUnit, ]
              paste(zone_data$HitSamples3, "out of ", zone_data$TotalSamples1, " colonized hosts @ ",zone_data$TimeUnit," hours")
            },
            hovertemplate = "%{y} % of motile hosts <br> are colonized  <br> ie %{customdata}") %>%            
  add_trace(
    x = ~TimeUnit,
    y = ~HitPct2,
    frame = ~Zone,  # Use TimeUnit for animation frames
    color = "Deposits",
    colors = c("#FFF184", "#FFDD80"),
    size = ~TotalSamples2,
    customdata = ~{
              zone_data <- data[data$TimeUnit == TimeUnit, ]
              paste(zone_data$HitSamples2, "out of ", zone_data$TotalSamples2, " edible/consumable deposits @ ",zone_data$TimeUnit," hours")
            },
    hovertemplate = "%{y} % of sessile deposits <br> are infected  <br> ie %{customdata}",
    line = list(width = 0.35)
  )%>%
  add_trace(x = ~TimeUnit,
            y = ~HitPct4,
            frame = ~Zone,  # Use TimeUnit for animation frames
            color = "Faeces",
            colors = c("#2A6074", "#00C9B1"),
            size = ~TotalSamples4,
            customdata = ~{
              zone_data <- data[data$TimeUnit == TimeUnit, ]
              paste(zone_data$HitSamples4, "out of ", zone_data$TotalSamples4, " faecal matter @ ",zone_data$TimeUnit," hours")
            },
            hovertemplate = "%{y} % of faecal matter <br> are infected  <br> ie %{customdata}") %>%
  layout(title = "Infection Trend within cultivation",
         plot_bgcolor = '#FFF8EE',
         xaxis = list(
           title = "Time (Hours)",
           zerolinecolor = '#ffff',
           zerolinewidth = 0.5,
           gridcolor = '#F4F2F0'),
         yaxis = list(
           title = "Percentage of Infected",
           zerolinecolor = '#ffff',
           zerolinewidth = 0.5,
           gridcolor = '#F4F2F0')) %>%
  animation_slider(
    currentvalue = list(font = list(color = "darkgreen"))
  ) %>%
  animation_opts(mode = "next",
                 easing = "exp-in", redraw = FALSE
  )

plotlyoutput

I have tried doing something similar with ECharts but I end up forced to remove the valuable distinction between said categories here. I have the same issue within other charts too such as e_area etc. I can't seem to split between categorical groups within each frame when timeline gets involved. (PS: I find visual map to also be quite confusing sometimes too, especially with my other concurrent issue with e_geo/e_scatter not apparently following my colouring instructions like here)

Symbols per group

Small note here, but in the couple of visualization libraries I have dabbled with, I noticed that all the ones I have tried seem to not have the capability to intuitively allow the user to have different symbols for each group. In plotly, if you categorise scatterpoints via colour for group1 for instance, you are never going to be able to allocate separate symbols successfully for those same scatterpoints via a different group2 for example.

In echarts4r it seems, you can use different "icons" for scatterpoints if you want across the different groups. I have not checked to see if this is still possible within each frame in the timeline, however. Nevertheless, you can't quite do it for scatterpoint symbols at all. As far as I am aware, there is no direct way to have the scatterpoints randomly be given a different symbols per group. Is there any chance of this being incorporated into echarts4r in the near future perhaps? Or maybe someone knows of a way to currently give different symbols for each group (including within a timeline)?

Any help would be greatly appreciated. Thank you for your time.

rdatasculptor commented 11 months ago

Just a thought: have you considered to experiment with e_morph()? Maybe not ideal, and I could be mistaken (haven't tried out your seemingly excellent reproducible code yet), but I used it for cases like yours before.

MrMisc commented 11 months ago

Just a thought: have you considered to experiment with e_morph()? Maybe not ideal, and I could be mistaken (haven't tried out your seemingly excellent reproducible code yet), but I used it for cases like yours before.

Since your comment I have actually been looking into how to use e_morph to work for a number of scenarios. Unfortunately I am still very much in a learning phase for that. I have trouble even replicating simple emorphs for 2 scatterplots for example.

Additionally, I wonder if it is even possible to do e_morphs exhaustively or if it is possible to ascribe morphing to a button, instead of it being automatic as I have seen from the example here

rdatasculptor commented 11 months ago

The good news: yes you can ascribe the morphing to a button! @JohnCoene put some very helpful examples in this issue: https://github.com/JohnCoene/echarts4r/issues/440. I experimented a lot with it. It's simply great!

Morphing between two scatter plots should be definitely possible using echarts4r. Can you give an example script? Maybe I can take a look. I have not much time lately though.

Also, Thank you for all your finds and questions! In the end it will help us improve echarts4r.