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))
Related
I am outputting a scatterplot in R using plotly with the code below:
library(tidyverse)
library(plotly)
set.seed(1)
data.frame(state = c(rep(state.name, 2)),
value = sample(1:100, 100)) %>%
plot_ly(x = ~value,
y = ~state,
type = "scatter",
mode = "markers") %>%
layout(title = list(text = "State Information"))
The issue that I am running into is that the code above renders a plot with an excessive amount of space between the y-axis and the plot title and x-axis ticks respectively:
Can anyone tell me how I can shrink this space so that the plot margins are tighter?
Edit: I know that a similar question was asked here, but this relates to a numeric y-axis, not a categorical one:
R Plotly - Large unused space on top and bottom of graph when setting height
We can use the same procedure for a categorical axis.
Please run schema() and navigate: object ► layout ► layoutAttributes ► yaxis ► range:
[...] If the axis type is category, it should be numbers, using
the scale where each category is assigned a serial number from zero in
the order it appears.
library(plotly)
library(datasets)
set.seed(1)
DF <- data.frame(state = c(rep(state.name, 2)),
value = sample(1:100, 100))
plot_ly(
data = DF,
x = ~ value,
y = ~ state,
type = "scatter",
mode = "markers"
) %>%
layout(
title = list(text = "State Information"),
xaxis = list(
range = ~ c(-1, length(unique(value)) + 1)
),
yaxis = list(
range = ~ c(-1, length(unique(state))),
title = list(text = "state", standoff = 0L)) # maybe needed? sets distance between title and labels
)
Context & problem:
I am trying to show the evolution of a value over time and some events that occured during the same period. One x-axis shows dates and I would like to get another x-axis, on top of the plot, that shows alternative tick-labels for dates i.e. events.
Here is a ggplot version of this plot:
library(ggplot2)
# here is a dummy dataset
df <- data.frame(
timeaxis = seq.Date(from = as.Date.character("2020-01-01"),
to = as.Date.character("2020-02-01"),
by = "days"),
avalue = runif(32)
)
# now I want to add a secondary axis to show events that occured during this time period
df_event <- data.frame(
eventdate = as.Date.character(c("2020-01-05", "2020-01-17", "2020-01-20", "2020-01-25")),
eventlabel = c("diner", "exam", "meeting", "payday")
)
# and the basic plot related to it
p <- ggplot(data = df, aes(x = timeaxis, y = avalue)) +
geom_line()
# I can add a new axis like so:
p <- p + scale_x_date(sec.axis = sec_axis(
~ .,
breaks = df_event$eventdate,
labels = df_event$eventlabel
))
print(p)
Created on 2022-02-11 by the reprex package (v2.0.1)
I need to use plotly for the awesome rangeslider that adds a very nice to use way to zoom in specific time periods.
Demo:
library(dplyr)
library(plotly)
plotly::ggplotly(p) %>%
plotly::layout(
# as you can see the rangeslider is linked to xaxis, is it possible to link it to xaxis2?
xaxis = list(rangeslider = list(visible = TRUE))
)
# note that using rangeslider() does not show the plot right...
As you can see, the second x-axis is not showing. Problem is that plotly does not have, yet, a good handling of secondary axis. First, if you use ggplot2::scale_x_date(sec.axis = ggplot2::sec_axis() to get a secondary x-axis, it is not transfered to the plotly plot by using plotly::ggplotly(). Second, if you manually define a secondary x-axis using plotly functions (as proposed here or there, this axis does not change according to the rangeslider (I guess because the rangeslider is actually bound to xaxis and should de defined for xaxis2 as well). Not to mention, I was not able to change the labels of the breaks to get the "events" displayed (even the example on
Demo:
plotly::ggplotly(p) %>%
# making an invisible trace
plotly::add_lines(
data = df_event,
x = ~ eventdate,
y = 0,
color = I("transparent"),
hoverinfo = "skip",
showlegend = FALSE,
xaxis = "x2"
) %>%
plotly::layout(
xaxis = list(rangeslider = list(visible = TRUE)),
xaxis2 = list(overlaying = "x", side = "top")
)
And with the actual event labels:
plotly::ggplotly(p) %>%
# making an invisible trace
plotly::add_lines(
data = df_event,
x = ~ eventdate,
y = 0,
color = I("transparent"),
hoverinfo = "skip",
showlegend = FALSE,
xaxis = "x2"
) %>%
plotly::layout(
xaxis = list(rangeslider = list(visible = TRUE)),
xaxis2 = list(overlaying = "x",
side = "top",
tickvals = df_event$eventdate,
ticktext = df_event$eventlabel)
)
I tried to add matches = "x", anchor = "x", scaleanchor = "x" to xaxis2 list but nothing changed.
Question:
How to make a second axis in a plotly plot that reacts to "zoom" using rangeslider?
If you think there is a better way of achieving this, please go ahead! Any idea is very welcome, I am quite new to plotly and I certainly have overlooked its functionalities.
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
)
I am trying to get another plot to react to both legend (select/deselect levels of a factor) and drag select. In the following toy example drag select works as intended: the violin and boxplot are re-rendered to depict the points that are selected using the mouse. The legend works for the scatterplot, but not for the boxplot and violin that don't seem to share the legend. I read many posts about shared legend, but nothing worked for subplots of different types.
Even more surprisingly, when deplying to plotly cloud, the plot also loses it's drag select feature (altough I don't need the plotly cloud, I thought I should mention this).
Just to be clear, I'd like the boxplot and violin to be re-rendered based both on selecting on legend and drag-select on scatterplot. As these features theoretically work, the legend should provide the full data or subsets based on levels of the factor used for legend from which the drag selection could be carried out afterwards.
library(plotly)
d <- mtcars
d$cyl <- as.factor(d$cyl)
d <- highlight_key(mtcars)
sp <- plot_ly(d, x = ~mpg, y = ~disp,
color = ~factor(cyl), colors = c("red", "green", "blue"),
legendgroup = ~factor(cyl), showlegend = T) %>%
add_markers()
box <-
plot_ly(d, y = ~disp,
color = I("black"),
legendgroup = ~factor(cyl), showlegend = F) %>%
add_boxplot(name = " ")
violin <-
plot_ly(d, y = ~disp,
color = I("black"),
legendgroup = ~factor(cyl), showlegend = F) %>%
add_trace(type = "violin", name = " ")
p <-
subplot(sp, box, violin, shareY = TRUE, titleX = TRUE, titleY = TRUE) %>%
layout(
dragmode = "select",
barmode = "overlay",
title = "Click and drag scatterplot",
showlegend = TRUE
) %>%
highlight(on = "plotly_selected", off = "plotly_deselect")
p
Any help is greatly appreciated.
I am trying to produce a dumbell plot in R. In this case, there are four rows, and they need to have different and specific colors each. I define the colors as part of the dataset using colorRampPalette(). Then when I produce the plot, the colors get mixed in inappropriate ways. See the image below, and in particular the legend.
As you can see, the orange is supposed to be #7570B3 according to the legend. But this is not correct. The color 7570B3 is purple ! For this reason, the colors that I had defined in the dataset are mixed in the plot. "Alt 2" sound be in orange and "Alt 3" should be in purple.
Does anyone know how to fix this ? Any help would be very appreciated.
Here is a simple version of the code:
table_stats_scores <- data.frame(alt=c("alt1","alt2","alt3","alt4"),
average=c(15,20,10,5),
dumb_colors= colorRampPalette(brewer.pal(4,"Dark2"))(4),
min=c(10,15,5,0),max=c(20,25,15,10)
)
table_stats_scores # This is the dataset
table_stats_scores <- table_stats_scores[order(-
table_stats_scores$average),] # ordering
table_stats_scores$alt <- factor(table_stats_scores$alt,
levels = table_stats_scores$alt[order(table_stats_scores$average)])
# giving factor status to alternatives so that plot_ly() picks up on this
p <- plot_ly(table_stats_scores, x=table_stats_scores$average, color = ~
dumb_colors,
y=table_stats_scores$alt,text=table_stats_scores$alt) %>%
add_segments(x = ~min, xend = ~max, y = ~alt, yend = ~alt,name = "Min-Max
range", showlegend = FALSE, line = list(width = 4)) %>%
add_markers(x = ~average, y = ~alt, name = "Mean",
marker=list(size=8.5),showlegend = FALSE) %>%
add_text(textposition = "top right") %>%
layout(title = "Scores of alternatives",
xaxis = list(title = "scores"),
yaxis = list(title = "Alternatives")
)
p
Yes color can be an issue in plotly, because there are several ways to specify it, and the assignment order of the various elements from the dataframe can be hard to keep in sync.
The following changes were made:
added a list of brighter colors to your dataframe because I couldn't easily visualize the brewer.pal colors. Better to debug with something obvious.
changed the color parameter to the alt column, because it is really just used only indirectly to set the color, and mostly it determines the text in the legend.
added the colors to the text parameter (instead of alt) so I could see if it was assigning the colors correctly.
changed the sort order to the default "ascending" on the table_stat_scores sort because otherwise it assigned the colors in the incorrect order (don't completely understand this - seems like there is some mysterious sorting/re-ordering going on internally)
added a colors parameter to the add_segments and add_markers so that they set the color in the same way using the same column.
I think this gets you want you want:
library(plotly)
library(RColorBrewer)
table_stats_scores <- data.frame(alt=c("alt1","alt2","alt3","alt4"),
average=c(15,20,10,5),
dumb_colors= colorRampPalette(brewer.pal(4,"Dark2"))(4),
min=c(10,15,5,0),max=c(20,25,15,10)
)
table_stats_scores # This is the dataset
table_stats_scores$bright_colors <- c("#FF0000","#00FF00","#0000FF","#FF00FF")
table_stats_scores <- table_stats_scores[order(table_stats_scores$average),] # ordering
table_stats_scores$alt <- factor(table_stats_scores$alt,
levels = table_stats_scores$alt[order(table_stats_scores$average)])
# giving factor status to alternatives so that plot_ly() picks up on this
p <- plot_ly(table_stats_scores, x=~average, color = ~alt, y=~alt,text=~bright_colors) %>%
add_segments(x = ~min, xend = ~max, y = ~alt, yend = ~alt,name = "Min-Max range",
colors=~bright_colors, showlegend = FALSE, line = list(width = 4)) %>%
add_markers(x = ~average, y = ~alt, name = "Mean",
marker=list(size=8.5,colors=~bright_colors),showlegend = FALSE) %>%
add_text(textposition = "top right") %>%
layout(title = "Scores of alternatives",
xaxis = list(title = "scores"),
yaxis = list(title = "Alternatives")
)
p
yielding this: