I can change the line style and the item style, but I cannot seem to be able to pass arguments to areaStyle (see areaStyle).
For example:
library(echarts4r)
data.frame(x = seq.int(1, 5, 1),
y = 10) %>%
e_chart(x = x) %>%
e_area(
serie = y,
areaStyle = list(opacity = 0),
lineStyle = list(opacity = 0),
itemStyle = list(opacity = 0)
)
produces an area chart with no points and no line, but the area is still visible. How do I change the color, opacity, etc. of the area itself?
I had a look at the source code of e_area_ (which is called by e_area). and the issue is that e_area_ inits areaStyle as an empty list. See https://github.com/JohnCoene/echarts4r/blob/bf23891749cf42a40656fa87ff04ecb3627a9af5/R/add_.R#L263-L269 . And unfortunately this empty list doesn't gets updated when the user provides his own specs. Not sure whether this is a bug or whether this is intended. Perhaps you should file an issue.
As a possible quick workaround here is "fixed" e_area2_ which updates the default empty list via modifyList:
library(echarts4r)
library(dplyr)
e_area2_ <- function(e, serie, bind = NULL, name = NULL, legend = TRUE,
y_index = 0, x_index = 0, coord_system = "cartesian2d", ...) {
.default <- list(areaStyle = list())
args <- utils::modifyList(.default, list(...))
if (missing(e)) {
stop("must pass e", call. = FALSE)
}
if (missing(serie)) {
stop("must pass serie", call. = FALSE)
}
for (i in seq_along(e$x$data)) {
vector <- echarts4r:::.build_data2(
e$x$data[[i]], e$x$mapping$x,
serie
)
if (!is.null(bind)) {
vector <- echarts4r:::.add_bind2(e, vector, bind, i = i)
}
l <- list(data = vector)
if (coord_system == "cartesian2d") {
if (y_index != 0) {
e <- echarts4r:::.set_y_axis(e, serie, y_index, i)
}
if (x_index != 0) {
e <- echarts4r:::.set_x_axis(e, x_index, i)
}
l$yAxisIndex <- y_index
l$xAxisIndex <- x_index
} else if (coord_system == "polar") {
l$data <- as.list(unname(unlist(dplyr::select(
e$x$data[[i]],
serie
))))
}
if (!e$x$tl) {
nm <- echarts4r:::.name_it(e, serie, name, i)
args
opts <- c(
list(name = nm, type = "line", coordinateSystem = coord_system),
args
)
l <- append(l, opts)
if (isTRUE(legend)) {
e$x$opts$legend$data <- append(
e$x$opts$legend$data,
list(nm)
)
}
e$x$opts$series <- append(e$x$opts$series, list(l))
} else {
e$x$opts$options[[i]]$series <- append(
e$x$opts$options[[i]]$series,
list(l)
)
}
}
if (isTRUE(e$x$tl)) {
if (is.null(name)) {
name <- serie
}
series_opts <- c(
list(
name = name, type = "line", yAxisIndex = y_index,
xAxisIndex = x_index, coordinateSystem = coord_system
),
args
)
if (isTRUE(legend)) {
e$x$opts$baseOption$legend$data <- append(
e$x$opts$baseOption$legend$data,
list(name)
)
}
e$x$opts$baseOption$series <- append(
e$x$opts$baseOption$series,
list(series_opts)
)
}
e
}
data.frame(
x = seq.int(1, 5, 1),
y = 10
) %>%
e_chart(x = x) %>%
e_area2_(
serie = "y",
areaStyle = list(opacity = 0),
lineStyle = list(opacity = 0),
itemStyle = list(opacity = 0)
)
e_area() is going to be deprecated (see this GitHub Issue). Using e_line() and areaStyle (which follows from echarts.js) solves my issue.
library(echarts4r)
library(magrittr)
data.frame(x = seq.int(1, 5, 1),
y = 10) %>%
e_chart(x = x) %>%
e_line(
serie = y,
areaStyle = list(opacity = 0),
lineStyle = list(opacity = 0),
itemStyle = list(opacity = 0)
)
With area areaStyle opactiy = 1:
library(echarts4r)
library(magrittr)
data.frame(x = seq.int(1, 5, 1),
y = 10) %>%
e_chart(x = x) %>%
e_line(
serie = y,
areaStyle = list(opacity = 1),
lineStyle = list(opacity = 0),
itemStyle = list(opacity = 0)
)
Related
How can I set the color of a subset of the graph nodes without also coloring their edges using visNetwork::visIgraph?
Currently, my function vis_graph_prototyping produces the desired plot except that the selected nodes in green also have their associated edges colored in green as well. How can I have these edges appear in the default color, and only have those edges that I separately select via either E(g, P = as.vector(t(linkages)) or E(g, path = pathway, directed = TRUE) colored in red?
An image of the current output is shown below the reproducible example R snippet.
rnd_dag <- function(p = 25, p_edge = 0.2, weighted = FALSE, seed = 123) {
if (seed) set.seed(seed)
A <- matrix(0, p, p)
A[lower.tri(A)] <- sample(c(0, 1), p*(p-1)/2, replace = TRUE,
prob = c(1 - p_edge, p_edge))
if (weighted) {A[A == 1] <- runif(length(A[A == 1]), min = -1, max = 1)}
return(A)
}
linkages <- matrix(c(9, 1,
12, 1,
11, 2), ncol = 2, byrow = TRUE)
vis_graph_prototyping <- function(A, linkages = NULL, pathway = NULL) {
g <- graph_from_adjacency_matrix(A, mode = "directed", weighted = TRUE)
stopifnot(is.null(linkages) || is.null(pathway))
if (!is.null(linkages)) {
g <- set_vertex_attr(g, name = "color",
index = unique(as.vector(linkages)),
value = "green") %>%
set_edge_attr(name = "color",
index = E(g, P = as.vector(t(linkages)), directed = TRUE),
value = "red")
} else if (!is.null(pathway)) {
g <- set_vertex_attr(g, name = "color", index = pathway, value = "green") %>%
set_edge_attr(name = "color",
index = E(g, path = pathway, directed = TRUE), value = "red")
}
visIgraph(g, layout = "layout_with_sugiyama") %>%
visOptions(highlightNearest = list(enabled = TRUE, hover = TRUE),
nodesIdSelection = TRUE)
}
vis_graph_prototyping(rnd_dag(12), linkages = linkages)
You can set the colors so that you have to set them (instead of inheriting them from the nodes).
When you create your graph object, set the color to default before you set the edges that will be red. You can find the default colors here.
The only change I made was in your function. Check it out.
vis_graph_prototyping <- function(A, linkages = NULL, pathway = NULL) {
g <- graph_from_adjacency_matrix(A, mode = "directed", weighted = TRUE)
stopifnot(is.null(linkages) || is.null(pathway))
if (!is.null(linkages)) {
# message(print(edges))
# message(print(linkages))
g <- set_vertex_attr(g, name = "color",
index = unique(as.vector(linkages)),
value = "green") %>%
set_edge_attr(name = "color",
index = E(g), # <----- all edges
value = "#97C2FC") %>% # <----- default blue
set_edge_attr(name = "color",
index = E(g, P = as.vector(t(linkages)), directed = TRUE),
value = "red")
} else if (!is.null(pathway)) {
g <- set_vertex_attr(g, name = "color", index = pathway, value = "green") %>%
set_edge_attr(name = "color",
index = E(g, path = pathway, directed = TRUE), value = "red")
message(" from null path ")
message(E(g))
}
visIgraph(g, layout = "layout_with_sugiyama") %>%
visOptions(highlightNearest = list(enabled = TRUE, hover = TRUE),
nodesIdSelection = TRUE)
}
I am running a loop that assigns a plot to a variable. the code then pulls the variable names with the ls() pattern function
while (i > 0) {
assign(paste("fig", i, sep = ""), plot_ly(tot, y = ~gene, color = ~bx, type = "box", boxpoints = "all") %>% layout(annotations = list(x = 0 , y = 1, xanchor = "left",yanchor = "top",yshift = 20,showarrow = FALSE,font = list(size = 20), text = paste("Data", colnames(total)[i+1]))))
i = i-1
if (i == 0){
the code then pulls the variable names with the ls() pattern function and attempts to pass them as a list to subplot.
...
l <- as.list(ls(pattern = "fig"))
l <- do.call(paste, c(l,sep=", "))
fig <- subplot(l,margin = 0.06,nrows=2) %>% layout(showlegend = FALSE)
fig
}
}'
This is where i am experiencing some errors.
Error in [[: subscript out of bounds
Try the following :
library(plotly)
l <- mget(ls(pattern = "fig"))
fig <- subplot(l,margin = 0.06,nrows=2) %>% layout(showlegend = FALSE)
I have the following code. It selects data and makes a plotly plot. The code loops through the variable "criteria" and at the end of the loop inserts the plot in the appropriate index.
Everything works fine except that all but the last elements of the list are null and only the last plot is included.
How do I include all the plotly charts in the list?
criteria <- c("A", "B", "C")
for(i in 1:length(criteria)){
plotTbl <- dataTbl[Site == criteria[i]]
plotTbl <- unique(plotTbl[ ,N := .N, by = .(Site, Var)])
noexacCols <- unique(c(brewer.pal(name="Set1", n = 9),
brewer.pal(name="Set2", n = 8),
brewer.pal(name="BrBG", n =11),
brewer.pal(name="Paired", n = 12)))
noexacCols <- noexacCols[i]
colMapper <- data.table(Var = sort(unique(plotTbl[,Var])))
colMapper[, colorCodes := noexacCols]
plotTbl <- plotTbl[colMapper, on = .(Var), nomatch = 0]
plotTbl[ ,Percent := round(100*N/sum(N), 1)]
plotTbl[ ,text2display := paste0("Site = ",Site,
"<br>",category, " = ", Var,
"<br>N = ", N, " (", Percent, "%)")]
f1 <- list(
family = "Arial, sans-serif",
size = 14,
color = "black"
)
f2 <- list(
family = "Arial, sans-serif",
size = 12,
color = "black"
)
a <- list(
title = "",
titlefont = f1,
showticklabels = TRUE,
tickangle = 0,
tickfont = f2
)
b <- list(
title = "",
titlefont = f1,
showticklabels = TRUE,
tickangle = 0,
tickfont = f2,
zeroline = TRUE,
showline = TRUE,
mirror = FALSE,
linecolor = toRGB("black"),
linewidth = 1
)
p <- list()
p[[i]] <- plot_ly(data = plotTbl ,
x = ~Var,
y = ~N,
type = 'bar',
marker = list(color = ~colorCodes),
opacity = 0.7,
hoverinfo="text",
text = ~text2display) %>%
layout(xaxis = a, yaxis = b, showlegend = F, margin = list(b = 30))
}
You create p within the loop and thus overwrite it on every revolution. Move line p <- list() before the loop.
I am trying to generate multiple graphs in Plotly for 30 different sales offices. Each graph would have 3 lines: sales, COGS, and inventory. I would like to keep this on one graph with 30 buttons for the different offices. This is the closest solution I could find on SO:
## Create random data. cols holds the parameter that should be switched
l <- lapply(1:100, function(i) rnorm(100))
df <- as.data.frame(l)
cols <- paste0(letters, 1:100)
colnames(df) <- cols
df[["c"]] <- 1:100
## Add trace directly here, since plotly adds a blank trace otherwise
p <- plot_ly(df,
type = "scatter",
mode = "lines",
x = ~c,
y= ~df[[cols[[1]]]],
name = cols[[1]])
## Add arbitrary number of traces
## Ignore first col as it has already been added
for (col in cols[-1]) {
p <- p %>% add_lines(x = ~c, y = df[[col]], name = col, visible = FALSE)
}
p <- p %>%
layout(
title = "Dropdown line plot",
xaxis = list(title = "x"),
yaxis = list(title = "y"),
updatemenus = list(
list(
y = 0.7,
## Add all buttons at once
buttons = lapply(cols, function(col) {
list(method="restyle",
args = list("visible", cols == col),
label = col)
})
)
)
)
print(p)
It works but only on graphs with single lines/traces. How can I modify this code to do the same thing but with graphs with 2 or more traces? or is there a better solution? Any help would be appreciated!
### EXAMPLE 2
#create fake time series data
library(plotly)
set.seed(1)
df <- data.frame(replicate(31,sample(200:500,24,rep=TRUE)))
cols <- paste0(letters, 1:31)
colnames(df) <- cols
#create time series
timeseries <- ts(df[[1]], start = c(2018,1), end = c(2019,12), frequency = 12)
fit <- auto.arima(timeseries, d=1, D=1, stepwise =FALSE, approximation = FALSE)
fore <- forecast(fit, h = 12, level = c(80, 95))
## Add trace directly here, since plotly adds a blank trace otherwise
p <- plot_ly() %>%
add_lines(x = time(timeseries), y = timeseries,
color = I("black"), name = "observed") %>%
add_ribbons(x = time(fore$mean), ymin = fore$lower[, 2], ymax = fore$upper[, 2],
color = I("gray95"), name = "95% confidence") %>%
add_ribbons(x = time(fore$mean), ymin = fore$lower[, 1], ymax = fore$upper[, 1],
color = I("gray80"), name = "80% confidence") %>%
add_lines(x = time(fore$mean), y = fore$mean, color = I("blue"), name = "prediction")
## Add arbitrary number of traces
## Ignore first col as it has already been added
for (col in cols[2:31]) {
timeseries <- ts(df[[col]], start = c(2018,1), end = c(2019,12), frequency = 12)
fit <- auto.arima(timeseries, d=1, D=1, stepwise =FALSE, approximation = FALSE)
fore <- forecast(fit, h = 12, level = c(80, 95))
p <- p %>%
add_lines(x = time(timeseries), y = timeseries,
color = I("black"), name = "observed", visible = FALSE) %>%
add_ribbons(x = time(fore$mean), ymin = fore$lower[, 2], ymax = fore$upper[, 2],
color = I("gray95"), name = "95% confidence", visible = FALSE) %>%
add_ribbons(x = time(fore$mean), ymin = fore$lower[, 1], ymax = fore$upper[, 1],
color = I("gray80"), name = "80% confidence", visible = FALSE) %>%
add_lines(x = time(fore$mean), y = fore$mean, color = I("blue"), name = "prediction", visible = FALSE)
}
p <- p %>%
layout(
title = "Dropdown line plot",
xaxis = list(title = "x"),
yaxis = list(title = "y"),
updatemenus = list(
list(
y = 0.7,
## Add all buttons at once
buttons = lapply(cols, function(col) {
list(method="restyle",
args = list("visible", cols == col),
label = col)
})
)
)
)
p
You were very close!
If for example you want graphs with 3 traces,
You only need to tweak two things:
Set visible the three first traces,
Modify buttons to show traces in groups of three.
My code:
## Create random data. cols holds the parameter that should be switched
library(plotly)
l <- lapply(1:99, function(i) rnorm(100))
df <- as.data.frame(l)
cols <- paste0(letters, 1:99)
colnames(df) <- cols
df[["c"]] <- 1:100
## Add trace directly here, since plotly adds a blank trace otherwise
p <- plot_ly(df,
type = "scatter",
mode = "lines",
x = ~c,
y= ~df[[cols[[1]]]],
name = cols[[1]])
p <- p %>% add_lines(x = ~c, y = df[[2]], name = cols[[2]], visible = T)
p <- p %>% add_lines(x = ~c, y = df[[3]], name = cols[[3]], visible = T)
## Add arbitrary number of traces
## Ignore first col as it has already been added
for (col in cols[4:99]) {
print(col)
p <- p %>% add_lines(x = ~c, y = df[[col]], name = col, visible = F)
}
p <- p %>%
layout(
title = "Dropdown line plot",
xaxis = list(title = "x"),
yaxis = list(title = "y"),
updatemenus = list(
list(
y = 0.7,
## Add all buttons at once
buttons = lapply(0:32, function(col) {
list(method="restyle",
args = list("visible", cols == c(cols[col*3+1],cols[col*3+2],cols[col*3+3])),
label = paste0(cols[col*3+1], " ",cols[col*3+2], " ",cols[col*3+3] ))
})
)
)
)
print(p)
PD: I only use 99 cols because I want 33 groups of 3 graphs
On my highchart plot in an R shiny application I need a delay before the series tooltip is displayed,
i.e. I want the tooltip to wait some time before appearing, instead of appearing instantly when the mouse is hover the element.
Any solutions for this issue?
Thanks in advance:)
library("shiny")
library("highcharter")
ui <- fluidPage(
h1("Highcharter Example"),
fluidRow(
column(width = 8,
highchartOutput("hchart",height = "500px")
)
)
)
server <- function(input, output) {
output$hchart <- renderHighchart({
hc <- highchart() %>%
hc_chart(type = "area", plotBorderWidth = 0.5) %>%
hc_xAxis(lineWidth = 1, gridLineWidth = 0, minorGridLineWidth = 0, labels = list(format = '{value}%')) %>%
hc_add_series(name = 'Dummy', data = list(list(y = 4, z = 2), list(y = 5, z = 0), list(y = 6, z = 1), list(y = 7, z = 1), list(y = 8, z = 1))) %>%
hc_plotOptions(line = list(
dataLabels = list(enabled = TRUE),
enableMouseTracking = TRUE
)
)
return(hc)
})
}
shinyApp(ui = ui, server = server)
I came across this example http://rudovjan.github.io/highcharts-tooltip-delay/ which we can use to solve your problem.we are going to set the delayForDisplay at 2 secs. As a reference I am going to post the JS script here too just in case if he deletes it
rm(list = ls())
library("shiny")
library("highcharter")
ui <- fluidPage(
h1("Highcharter Example"),
fluidRow(
tags$script(src="http://rudovjan.github.io/highcharts-tooltip-delay/tooltip-delay.js"),
column(width = 8,
highchartOutput("hchart",height = "500px")
)
)
)
server <- function(input, output) {
output$hchart <- renderHighchart({
hc <- highchart() %>%
hc_chart(type = "area", plotBorderWidth = 0.5) %>%
hc_xAxis(lineWidth = 1, gridLineWidth = 0, minorGridLineWidth = 0, labels = list(format = '{value}%')) %>%
hc_add_series(name = 'Dummy', data = list(list(y = 4, z = 2), list(y = 5, z = 0), list(y = 6, z = 1), list(y = 7, z = 1), list(y = 8, z = 1))) %>%
hc_plotOptions(line = list(
dataLabels = list(enabled = TRUE),
enableMouseTracking = TRUE
)
)
hc <- hc_tooltip(hc,useHTML = T,delayForDisplay = 2000,hideDelay= 1)
return(hc)
})
}
shinyApp(ui = ui, server = server)
(function(H) {
let timerId = {};
const generatePointsUniqueKey = (points) => {
const generatePointKey = (point) => {
return point.category + " " + point.series.name + ": " + point.x + " " + point.y;
};
const result = points.map(generatePointKey).join(', ');
return result;
}
H.wrap(H.Tooltip.prototype, 'refresh', function(proceed) {
let seriesName;
if (Array.isArray(arguments[ 1 ])) {
// Can be array in case that, it's shared tooltip
seriesName = generatePointsUniqueKey(arguments[ 1 ]);
} else {
seriesName = arguments[ 1 ].series.name;
}
const delayForDisplay = this.chart.options.tooltip.delayForDisplay ? this.chart.options.tooltip.delayForDisplay : 1000;
if (timerId[ seriesName ]) {
clearTimeout(timerId[ seriesName ]);
delete timerId[ seriesName ];
}
timerId[ seriesName ] = window.setTimeout(function() {
let pointOrPoints = this.refreshArguments[ 0 ];
if (pointOrPoints === this.chart.hoverPoint || $.inArray(this.chart.hoverPoint, pointOrPoints) > -1) {
proceed.apply(this.tooltip, this.refreshArguments);
}
}.bind({
refreshArguments: Array.prototype.slice.call(arguments, 1),
chart: this.chart,
tooltip: this
}), delayForDisplay);
});
}(Highcharts));