R: Adding a "tool tip" to interactive plot (plotly) - r

I am using the R programming language. From a previous post (R: Plot not Fully Loading), I learned how to make interactive plots in R using plotly :
library(plotly)
iris %>% plot_ly(type = 'parcoords', line = list(color = ~as.integer(Species),
colorscale = list(c(0,'red'),c(0.5,'green'),c(1,'blue'))),
dimensions = list( list(range = c(2,4.5), label = 'Sepal Width', values = ~Sepal.Width),
list(range = c(4,8), constraintrange = c(5,6), label = 'Sepal Length', values = ~Sepal.Length),
list(range = c(0,2.5), label = 'Petal Width', values = ~Petal.Width),
list(range = c(1,7), label = 'Petal Length', values = ~Petal.Length) ) )
Suppose if I was to add an "id" column to the data set, e.g.
library(dplyr)
df <- iris %>% mutate(id = row_number())
Is it possible so that when you "click" on any of the "lines" on this plot, information from the dataset (i.e. "df") corresponding to row of that line appears?
Thanks

Did not run your code, but you may need to prepare all the text as one string in the column beforehand and use text = ~tooltip_column to display it.
It may work with \n for line splits
fig <- plot_ly(
type = 'scatter3D',
x = -calcDataMeas2$pos_X,
y = calcDataMeas2$pos_Y,
z = z_value,
text = calcDataMeas2$tube_name,
scene = 'scene1',
mode = 'markers',
marker = marker
)

Related

R Markdown not able to display two plots within the same if-statement

I am creating an R-Markdown document to help with reporting final exam results at our school. For the mathematics exam, I need a conditional statement to display appropriate plots, because the students do not need to take an oral exam (Oral = NA) if their written score is above a certain threshold. So I have an if-statement that checks whether the sum of the Oral_Exam variable (1 for those who had to take it, 0 otherwise) is larger than zero, and if so, create a 3D scatterplot where the students who had to take an oral exam are marked with red, followed by another plot of the same type, only with the students who had to go to the oral exam, colored according to oral exam result. If none of the students had to go to an oral exam, it is checked in a later if-statement, and only one plot is produced. My code looks like this:
```{r warning = FALSE, message = FALSE, echo = FALSE, eval = params$subj == "Matematika"}
if(sum(fulldata$Oral_exam) > 0){
fulldata_color = fulldata %>% mutate(Oral_exam, = as.character(Oral_exam), color = recode(Oral_exam, '1' = "red", '0' = "green"))
div(plot_ly(data = fulldata_color, x = ~Long_A_percent, y = ~Long_B_percent, z = ~Short_percent, marker = list(color = ~color), type="scatter3d", mode="markers", text = ~Name, width = 800, height = 800) %>% layout(
scene = list(aspectmode = "cube", xaxis = list(range = c(0,100), title = 'Long A (x)'),yaxis = list(range = c(0,100), title = 'Long B (y)'), zaxis = list(range = c(0,100), title = 'Short (z)'))), align = "center")
enter code here
Oral_data = fulldata %>% filter(!is.na(Oral_percent))
div(plot_ly(data = Oral_data, x = ~Long_A_percent, y = ~Long_B_percent, z = ~Short_percent,color = ~Oral_percent, type="scatter3d", mode="markers", text = ~Name, width = 800, height = 800) %>% layout(
scene = list(aspectmode = "cube", xaxis = list(range = c(0,100), title = 'Long A (x)'),yaxis = list(range = c(0,100), title = 'Long B (y)'), zaxis = list(range = c(0,100), title = 'Short (z)'))), align = "center")
}
This code, when knit, results in only the second plot being created, and it looks like the way I intend it to. However, if I break it up into two if statements with the same condition, and put one plotting command (and the corresponding command for the creation of the data frame), both plots are displayed correctly
I can work around it by having two if-statements instead of two, but it would be good to know why it doesn't work, especially since I have used multiple plots in the same code chunk (although not in the same if-statement) in the same document, and it has always worked as intended.
You can store plotly objets in variables and print them outside if:
```{r}
p1 <- NULL
p2 <- NULL
if(TRUE) {
p1 <- plot_ly(x = 1, y = 1, type = "scatter", mode = "marker")
p2 <- plot_ly(x = 1, y = 10, type = "scatter", mode = "marker")
}
p1
p2
```

Crosstalk interactive slider not working with histogram

I want to create an interactive histogram in R using crosstalk. Specifically, I want to use a slider to select what data appears on a histogram. To do so, I used the following code:
shared_data <- highlight_key(mpg)
widgets <- bscols(
widths = 12,
filter_slider("displ", "displ", shared_data, ~displ))
bscols(widths = 10, widgets,
plot_ly(x = ~mpg$displ, type = "histogram",
histnorm = "probability"))
This creates a histogram as well as an interactive slider. However, the slider doesn't actually do anything.
I've tried an alternate piece of code to do this, but similarly to the previous code, it creates the histogram and a slider which fails to filter the data.
shared_data <- mpg %>%
SharedData$new()
plot_ref <- plot_ly(x = ~mpg$displ, type = "histogram",
histnorm = "probability") %>%
layout(title = "Reference Histogram (Displ)",
xaxis = list(title = "Displ"),
yaxis = list(title = "Percentage (%)"))
bscols(widths = 10,
list(filter_slider(id = "slider_ap", label = "Displ",
sharedData = shared_data, column = ~displ),
plot_ref))
Can anyone explain what is wrong with the code above? I read somewhere that crosstalk interactivity isn't specifically optimized for histograms, could this be the reason it doesn't work? Any help is greatly appreciated!
The purpose of SharedData is to share the data. When you called the plot, you didn't use the shared data, so the filter had no way of matching the plot.
Check it out:
shared_data <- mpg %>%
SharedData$new()
plot_ref <- plot_ly(data = shared_data, # <- share it
x = ~displ, type = "histogram",
histnorm = "probability") %>%
layout(title = "Reference Histogram (Displ)",
xaxis = list(title = "Displ"),
yaxis = list(title = "Percentage (%)"))
bscols(widths = 10,
list(filter_slider(id = "slider_ap", label = "Displ",
sharedData = shared_data, column = ~displ),
plot_ref))

Change title position in plotly R

I created the world map for the dataset I am working with however, the title of the plot is way above the chart and there is a huge space in between.
map_World <- list(
scope = 'world',
lakecolor = toRGB('white'))
Map4 <- plot_geo(regions) %>%
add_trace(
z = ~column1.x, locations = ~`ISO`,
color = ~column1.x, colors = c("red", "blue", "green")
) %>%
colorbar(title = "Legend",x = 1, y = 0.8) %>%
layout(title = "Sub indices for the different dimensions",
geo = map_World)
I expect the title to be right above the chart but it is not working.
I believe you can adjust the chart title attributes:
https://github.com/plotly/plotly.js/pull/3276
Try for your layout something like:
layout(title = list(text = "Sub indices for the different dimensions", y = 0.8),
geo = map_World)

Plotly: Parallel Coordinates Plot: Axis Styling

I really like the parallel coordinates plot available in
Plotly but I just ran into an issue I could use help with.
Is it possible to have log10 based axis for some of the coordinates?
As you can see in the example below performing a log10 transform allows to better distinguish the smaller values. However, by transforming the data we loose the ability to interpret the values. I would prefer to log scale the axis instead of the data but couldn't find a way to do this.
I did find something related to "axis styling" in the github issue https://github.com/plotly/plotly.js/issues/1071#issuecomment-264860379 but
not a solution to this problem.
I would appreciate any ideas/pointer.
library(plotly)
# Setting up some data that span a wide range.
df <- read.csv("https://raw.githubusercontent.com/bcdunbar/datasets/master/iris.csv")
df$sepal_width[1] = 50
df$sepal_width_log10 = log10(df$sepal_width)
p <- df %>%
plot_ly(type = 'parcoords',
line = list(color = ~species_id,
colorscale = list(c(0,'red'),c(0.5,'green'),c(1,'blue'))),
dimensions = list(
list(range = c(~min(sepal_width),~max(sepal_width)),
label = 'Sepal Width', values = ~sepal_width),
list(range = c(~min(sepal_width_log10),~max(sepal_width_log10)),
tickformat='.2f',
label = 'log10(Sepal Width)', values = ~sepal_width_log10),
list(range = c(4,8),
constraintrange = c(5,6),
label = 'Sepal Length', values = ~sepal_length))
)
p
More Parallel Coordinate Examples
Plotly Parallel Coordinates Doc
Since the log projection is not supported (yet) creating tick labels manually seems to be a valid solution.
# Lets create the axis text manually and map the log10 transform
# back to the original scale.
my_tickvals = seq(min(df$sepal_width_log10), max(df$sepal_width_log10), length.out=8)
my_ticktext = signif(10 ^ my_tickvals, digits = 2)
library(plotly)
# Setting up some data that span a wide range.
df <- read.csv("https://raw.githubusercontent.com/bcdunbar/datasets/master/iris.csv")
df$sepal_width[1] = 50
df$sepal_width_log10 = log10(df$sepal_width)
# Lets create the axis text manually and map the log10 transform back to the original scale.
my_tickvals = seq(min(df$sepal_width_log10), max(df$sepal_width_log10), length.out=8)
my_ticktext = signif(10 ^ my_tickvals, digits = 2)
p <- df %>%
plot_ly(type = 'parcoords',
line = list(color = ~species_id,
colorscale = list(c(0,'red'),c(0.5,'green'),c(1,'blue'))),
dimensions = list(
list(range = c(~min(sepal_width),~max(sepal_width)),
label = 'Sepal Width', values = ~sepal_width),
list(range = c(~min(sepal_width_log10),~max(sepal_width_log10)),
tickformat='.2f',
label = 'log10(Sepal Width)', values = ~sepal_width_log10),
list(range = c(~min(sepal_width_log10),~max(sepal_width_log10)),
tickvals = my_tickvals,
ticktext = my_ticktext,
label = 'Sepal Width (log10 axis)', values = ~sepal_width_log10),
list(range = c(4,8),
constraintrange = c(5,6),
label = 'Sepal Length', values = ~sepal_length))
)
p
The underlying plotly.js parcoords doesn't support log projection (scales, axes) at the moment, though as you mention it comes up sometimes and we plan with this functionality. In the meantime, an option is to take the logarithm of the data ahead of time, with the big drawback that axis ticks will show log values, which needs explanation and adds to cognitive burden.

Plotly zerolines at different levels on double axis plot

I'm trying to overlay a line chart and bar chart in plotly (with a vertical line designating an important date) and I'm encountering this issue where the two zero lines are offset instead of on the same line. I've tried messing around with the overlaying = 'y' option within layout and tried changing the order of the three trace components but nothing seems to help. Any ideas how to fix? Below is my code with dummy data:
(Also, bonus points if you can fix my legend-overlapping-y2axis issue)
date <- seq(as.Date("2015/6/1"), by = "month", length.out = 19)
wires_mnth <- c(rep(0,8),100000,750000,1200000,2500000,3100000,5500000,7500000,8000000,9900000,11300000,11000000)
wires_cnt <- c(rep(0,8),100,200,250,325,475,600,750,800,1000,1150,1200)
data <- data.frame(date, wires_mnth)
plot_ly(data) %>%
add_trace(x = ~date, y = ~wires_cnt, type = 'bar', name = 'Wires Count',
yaxis = 'y2', opacity = .5) %>%
add_trace(x = ~date, y = ~wires_mnth, type = 'scatter', mode = 'lines', name
= 'Monthly Wires') %>%
add_trace(x = c(2016,2016), y = c(0, 12000000), type = 'scatter', mode =
"lines", name = 'Sanctions Removed') %>%
layout(title = 'Monthly Aggregate Wire Transfers to Iran',
xaxis = list(title = ''),
yaxis = list(side = 'left', title = 'Wire Amounts (USD)', showgrid =
FALSE, zeroline = FALSE),
yaxis2 = list(side = 'right', overlaying = 'y', title = 'Wires Count',
showgrid = FALSE, zeroline = FALSE)
)
You could add rangemode='nonnegative' to your layout or specify the range manually via range=list(0, max(wires_mnth).
For your bonus question, you can set the x-position of the legend, e.g.
legend = list(x = 1.2)

Resources