Having trouble mapping highcharter aesthetics to reactive object elements - r

I have a large shiny app that allows users to filter through an API and spark table aggregate (dumped to an .Rdata) simultaneously using the same set of initially selectized parameters. Fitting all this into a reproducible example is going to be tough, but, this is the function that is grouping and summming my metric of interest (try to resist asking me to paste in partitionFiltered()):
df <- reactive({partitionFiltered() %>%
dplyr::group_by(updatedTimeHour, direction) %>%
dplyr::mutate(count_dir = sum(n_flows)) %>%
dplyr::ungroup() %>%
dplyr::select(updatedTimeHour, direction, count_dir) %>%
dplyr::arrange(updatedTimeHour) %>%
unique()})
(Eventually, updatedTimeHour and direction will be replaced by input$periodicity and input$dimension, respectively, but that is beyond the scope of this question.)
The df() object looks like:
updatedTimeHour direction count_dir
6 1 525071.00
6 2 3491.00
6 0 498816.00
6 3 5374.00
7 2 2432.00
7 0 303818.00
7 1 340768.00
7 3 4852.00
8 1 1969048.00
My highcharter calls do not seem to be grouping and coloring the aesthetics as I would expect:
hc <- highchart() %>%
hc_add_series(data = df()$count_dir,
type = input$plot_type,
name = factor(df()$direction)
showInLegend = TRUE,
# ??group = df()$direction,
# ??color = df()$direction,
# ??x = df()$updatedTimeHour, y = df()$count_dir, color = df()$direction,
# ??hcaes(x = df()$updatedTimeHour, y = df()$count_dir, color = df()$direction)
) %>%
hc_xAxis(type = 'datetime',
# ??group = factor(df()$direction),
categories = df()$updatedTimeHour,
tickmarkPlacement = "on",
opposite = FALSE) %>%
hc_title(text = "NetFlows, by Hour",
style = list(fontWeight = "bold")) %>%
hc_exporting(enabled = TRUE, filename = "threat_extract")
As you can probably tell, I'm very confused about where/how to map the x-grouping udpatedTimeHour, or color the different direction levels appropriately and make sure their group ends up mapped correctly to the labels in the legend and hover.
I have also attempted to map these aesthetics using the hcaes() call I see included as an argument to hc_add_series() in some of the documentation, but I get errors thrown saying that that argument is not (any longer?) named in that hc_ function...
Any help is appreciated, and a related question is here.

You are trying to add as one series multiple objects that's the reason why is not working. Just changing a little bit your code and using the "magic" function hchart it should work:
df = data_frame(updatedTimeHour = c(6,6,6,6,7,7,7,7,8), direction = c(1,2,0,3,2,0,1,3,1), count_dir = rnorm(9))
type = "line"
hchart(df, type, hcaes(x = updatedTimeHour, y = count_dir, group = as.factor(direction))) %>%
hc_title(text = "NetFlows, by Hour",
style = list(fontWeight = "bold")) %>%
hc_exporting(enabled = TRUE, filename = "threat_extract")

Related

geom_label() equivalent in {echarts4r}

Issue
I'm trying to produce a visualisation using {echarts4r} that involves plotting points with labels displayed on the chart itself, where the labels are unrelated to the position of the points. This sounds like it should be simple, but so far I haven't found any viable method of doing this and I'm beginning to wonder if it's even possible.
Desired output
Here is a minimal example. I will use {ggplot2} to demonstrate what I'd (roughly) like to reproduce:
data <- data.frame(
date_eaten = as.Date(c("2020-01-01", "2020-01-02", "2020-01-03")),
tastiness = c(5, 7, 10),
fruit = c("apple", "orange", "mango")
)
data
#> date_eaten tastiness fruit
#> 1 2020-01-01 5 apple
#> 2 2020-01-02 7 orange
#> 3 2020-01-03 10 mango
library(ggplot2)
ggplot(data, aes(x = date_eaten, y = tastiness, label = fruit)) +
geom_point() +
geom_text(nudge_y = 0.2)
Attempt using e_labels()
This method is visually exactly what I want, however, it seems that there is no option to specify which columns to take the labels from.
library(echarts4r)
data %>%
e_chart(date_eaten) %>%
e_scatter(tastiness, symbol_size = 10) %>%
e_labels()
Attempt using e_mark_point()
This option allows for more customisation, however this is not really a viable solution as it is very clunky and doesn't strictly 'link back' to the original data:
data %>%
e_chart(date_eaten) %>%
e_scatter(tastiness, symbol_size = 10) %>%
e_mark_point(data = list(
xAxis = as.Date("2020-01-01"),
yAxis = 5,
value = "apple"
)) %>%
e_mark_point(data = list(
xAxis = as.Date("2020-01-02"),
yAxis = 7,
value = "orange"
)) %>%
e_mark_point(data = list(
xAxis = as.Date("2020-01-03"),
yAxis = 10,
value = "mango"
))
I think this is the solution. Currently I'm not sure exactly how it works as documentation is a bit limited, but it seems to work:
data %>%
e_chart(date_eaten) %>%
e_scatter(tastiness, symbol_size = 10, bind = fruit) %>%
e_labels(formatter = htmlwidgets::JS("
function(params) {
return(params.name)
}
"))

Plotly gauge graph and crosstalk filtering for flexdashboard

I am trying the create a plotly gauge graph for a flexdashboard which should change value depending on the chosen filter in crosstalk::filter_select().
I have tried and tried but cannot get the filter to work. This is an example with mtcars of what I am trying to do. I noticed that if the SharedData object has only one value, then it works, but otherwise plotly does not show any data.
mtcars_data <- tibble::rownames_to_column(mtcars, "Car")
shared_mtcars <- SharedData$new(mtcars_data)
row1 <- bscols(filter_select("Car", "Car", shared_mtcars, ~Car, multiple = F)
)
fig <- plot_ly(shared_mtcars,
domain = list(x = c(0, 1), y = c(0, 1)),
value = ~mpg,
title = list(text = "MPG"),
type = "indicator",
mode = "gauge+number")
bscols(row1, fig, widths = 12)
This code results in a graph with no data. If I subset mtcars_data to take the first row or the first two rows (which happen to have the same value for mpg) then it works. If I subset rows 1 and 3, it doesn't.
I might be missing something - in that case would really appreciate any feedback.

dynamical plot using plot_ly from R-plotly package

I am using shiny and plot_ly to plot a data frame.
The Goal: to implement a dynamical plot depending on the choice of users in GUI.
Consider the following data.table named pl.d
Group OS NP own.OS own.SCR HY9 WS8
A 34 54 27 76 56 82
B 15 45 0 84 89 48
C 0 36 7 92 91 22
in the server.R I used
plot_ly(pl.d, x = ~Group, y = ~OS, type = 'bar', name = "OS" ) %>%
layout(showlegend = TRUE)
The user should be able to expand the plot in the way that y could be an arbitrary choice of c(OS, NP, own.OS, own.SCR, HY9, WS8).
One not smart possible approach is to expand the plot_ly function with
if (input$choice of user =="NP"){
add_trace(y = ~NP, name = "NP")
}
and if conditionsand so on.
Is there any smart possibility to write an smart dynamical code to do that?
It has not to do with "NP". I mean plot_ly or add_trace should be in principle able to show one or many of c(OS, NP, own.OS, own.SCR,HY9,WS8).
I can write it as follows:
plot_ly(pl.d, x = ~Group, y = ~OS, type = 'bar', name = "OS" ) %>%
add_trace(y = ~NP, name = "NP") %>%
add_trace(y = ~own.OS, name = "own.OS") %>%
add_trace(y = ~own.SCR, name = "own.SCR") %>%
add_trace(y = ~HY9, name = "HY9") %>%
add_trace(y = ~WS8, name = "WS8")%>%
layout(showlegend = TRUE)
Problem: If you omit one of c(OS, NP, own.OS, own.SCR,HY9,WS8) you get an error!
One possible solution: to split the data frame into vectors! Using melt function makes it possible, however I do not get vectors just another shape of data table! Please take into account my outgoing point is pl.d and not data.frame(Group =c(...), ....)!
So, I tried the following
pl.d<-data.frame(Group =melt(setDT(d.plot), id.var = 'Group ')[,1],
model=melt(setDT(d.plot), id.var = 'Group ')[,2],
value=melt(setDT(d.plot), id.var = 'Group ')[,3])
and then,
plot_ly(pl.d, x = ~Group, y = ~value, type = 'bar', color= ~model ) %>%
add_trace(y = ~value, name = "NP")
However, I do not get for example the bars belonging to A close to each other.
Addendum: My mistake was, that I used color= ~model I had to use color=~Variable as mentioned in the answer! BUT why? I set it in my data frame asmodel`!!
Sounds like you are on the right track. You can use melt and filter to create a dataframe with the desired column names, like the following code.
data = data.frame(Group = c("a","b","c"),os = c(1,2,3),np = c(4,5,6), ws = c(7,8,9))
plot_cols = function(data, column_names = colnames(data)){
data%>%
melt()%>%
filter(variable %in% column_names) %>%
plot_ly(x = ~Group,y = ~value,color = ~variable,type = "bar")
}
You can plot all columns by calling plot_cols(data) or any select column like plot_cols(data,"os") or plot_cols(data,c("os","ws"))

Highcharts X axis categories name gets only shows 1 character

I created a column and line chart with highcharts.
X axis category names have been appearing fine in other charts created with the same code but now I encounter an issue where the entire category name gets cut short with only the first letter only displayed in the chart.
For example a category should read 'Run' but it only shows up as 'R'.
I also noted that this occurs in charts where there is only 1 category to display (so like a lone column chart with only one column displayed).
Would appreciate some help here :)
highchart() %>%
hc_title(text = "Creative Performance") %>%
hc_yAxis_multiples(
list(title = list(text = "Spend"),labels=list(format ='${value:,.2f}'), min=0, max=max(data_creative_trueview$Spend), showFirstLabel= TRUE,showLastLabel=TRUE,opposite = FALSE),
list(title = list(text = "TrueView: CPCV"),min=0,max = max(data_creative_trueview$`TrueView: CPCV`)+0.5, labels = list(format = "${value:,.2f}"),showLastLabel = FALSE, opposite = TRUE)) %>%
hc_add_series(data = data_creative_trueview, type= "column", hcaes(y=Spend), name="Spend") %>%
hc_add_series(data = data_creative_trueview, type = "line", hcaes(y=`TrueView: CPCV`), name="TrueView: CPCV", yAxis=1) %>%
hc_xAxis(title="Creative", categories=data_creative_trueview$Creative) %>%
hc_tooltip(pointFormat = '${point.y:,.2f}') %>%
emphasized text hc_legend(align = "right", verticalAlign = "top")
I found an answer right after I posted this. Apparently this is a common issue. Categories must be provided as a list when there is only one category. Refer to: https://github.com/jbkunst/highcharter/issues/173
In my case xlabel={{"64"}} showed only 6 where as xlabel={{"64",}} gave me 64 which was what I have wanted.

Multiple y-axes in shiny app w/ highcharter

I'm trying to render a graph in a shiny app using highcharter that shares an x-axis (days) but has multiple y-axes (a percent and a count). After some research it seems like I should use the 'hc_yAxis_multiples' method. On the left y-axis, I have % displayed. On the right y-axis, I want the count displayed. There is a line graph that is based on the left y-axis (%), and a stacked bar graph that is displayed based on the right y-axis.
I have been able to overlay the two graphs, but the bar chart portion based on the right y-axis is not formatted to the corresponding y-axis. Based on what I have been looking at, it seems like something like this would produce a result that I want:
##This first block is to show what the data types of the variables I'm using are and what the structure of my df looks like
df$inbox_rate <- df$total_inbox / df$total_volume
df$inbox_rate <- round((df$inbox_rate*100),0)
df$received_dt <- as.character(df$received_dt)
df$received_dt <- as.Date(df$received_dt, "%Y%m%d")
df <- df[order(df$received_dt),]
## This second block here is where I'm trying to build the chart with two Y-axes
hc <- highchart()%>%
hc_title(text = paste(domain_name,sep=""),align = "center") %>%
hc_legend(align = "center") %>%
hc_xAxis(type = "datetime", labels = list(format = '{value:%m/%d}')) %>%
hc_yAxis_multiples(list(title = list(text = "IPR"),labels=list(format = '{value}%'),min=0,
max=100,showFirstLabel = TRUE,showLastLabel=TRUE,opposite = FALSE),
list(title = list(text = "Total Subscribers"),min=0,max = max(df$total_users),
labels = list(format = "{value}"),showLastLabel = FALSE, opposite = TRUE)) %>%
hc_plotOptions(column = list(stacking = "normal")) %>%
hc_add_series(df,"column",hcaes(
x=received_dt,y=total_users,group=isp,yAxis=total_users)) %>%
hc_add_series(df,type="line",hcaes(
x=received_dt,y=inbox_rate,group=isp,yAxis=inbox_rate)) %>%
hc_exporting(enabled = TRUE) %>%
hc_add_theme(thm)
hc
However this produces something that looks like this.
To give more insight about the data I'm using, the domain_name is a string variable that looks like this: example.com. The total_users variable is a number that varies from 0 to about 50000. The received_dt variable is a date, formatted using as.Date(df$received_dt, "%Y%m%d"). The inbox_rate variable is a percent, from 0 to 100.
The bar counts are all displaying to the full height of the graph, even though the values of the bars vary widely. To reiterate, I want the right y-axis that the bar chart heights are based on to be the count of the df$total_users. Within the hc_yAxis_multiples function, there are two lists given. I thought that the first list gives the left y-axis, and the second gives the right. The closest answer to my question that I could find was given by this stackoverflow response
If anyone has any insight, it would be very much appreciated!
Your use of the yAxis statement in hc_add_series seems to be off. First, it should not be inside hcaes and second, it's a number specifying which axis (in order of appearance in hy_yAxis_multiple call) the series belongs to. So hc_add_series(..., yAxis = 1) should be used to assign a series to the second (right) axis.
Below is a (fully self-explaining, independent, minimal) example that shows how it should work.
library(highcharter)
df <- data.frame(
total_inbox = c(2, 3, 4, 5, 6),
total_volume = c(30, 30, 30, 30, 30),
total_users = c(300, 400, 20, 340, 330),
received_dt = c("20180202", "20180204", "20180206", "20180210", "20180212"),
isp = "ProviderXY"
)
df$inbox_rate <- df$total_inbox / df$total_volume
df$inbox_rate <- round((df$inbox_rate*100),0)
df$received_dt <- as.character(df$received_dt)
df$received_dt <- as.Date(df$received_dt, "%Y%m%d")
df <- df[order(df$received_dt),]
hc <- highchart()%>%
hc_xAxis(type = "datetime", labels = list(format = '{value:%m/%d}')) %>%
hc_yAxis_multiples(list(title = list(text = "IPR"),labels=list(format = '{value}%'),min=0,
max=100,showFirstLabel = TRUE,showLastLabel=TRUE,opposite = FALSE),
list(title = list(text = "Total Subscribers"),min=0,max = max(df$total_users),
labels = list(format = "{value}"),showLastLabel = FALSE, opposite = TRUE)) %>%
hc_plotOptions(column = list(stacking = "normal")) %>%
hc_add_series(df,type="column",hcaes(x=received_dt,y=total_users,group=isp),yAxis=1) %>%
hc_add_series(df,type="line",hcaes(x=received_dt,y=inbox_rate,group=isp))
hc
Maybe take this as an example how code in questions should be like. Copy-Paste-Runnable, no outside variables and minus all the things that dont matter here (like the theme and legend for example).

Resources