Plotly markers to appear in a bar chart - r

I am new to plotly and want to make my own bullet chart (a bit like http://bl.ocks.org/mbostock/4061961) that has markers/traces to show the values of the relevant values when comparing actual vs expected.
Below is my attempt:
q <- ggplot(data.frame(measure='',actual=25),aes(x=measure,y=actual))+
geom_bar(stat='identity')+
ylim(c(0,35))+
geom_hline(yintercept = 30,color='red')+
geom_text(y=30,label='Expected',angle=270,vjust=0)+
coord_flip()+
ylab('Num. of carrots')
q
q1 <- ggplotly(q) %>% add_markers()
q1
When converting it to plotly using ggplotly, the text looks like it has not rotated correctly, and the markers/traces do not show for the bar chart...Any help here would be much appreciated.
Kindest regards,
HLM

I do not think that plotly supports rotating text for type="scatter" (which is how ggplotly is interpreting your geom_text). You can delete the geom_text line from the ggplot graph, then add text to the plotly one using annotations:
q1 <- ggplotly(q) %>% add_markers() %>%
layout(annotations = list(x = 30, y = 1, text = "Expected", textangle=270))
q1
update
The 2nd part of your question (how to also get hover info on the bar) is slightly trickier. To get the hover info, we can create the bars using the plotly API directly like this
p.bars = plot_ly(data = data.frame(measure='', actual=25)) %>%
add_bars(y=~measure, x=~actual, orientation="h")
we can add the text annotation to it like this
p.bars.text = p.bars %>%
layout(annotations = list(x = 30, y = 0, text = "Expected", textangle=270,
showarrow=F, xanchor="center"))
But the problem is that adding a line also to this plot by
p.bars.text %>% add_segments(x=30, xend=30, y=-0.5, yend=0.5)
gives an error
Error in populate_categorical_axes(p) : Can't display both discrete & non-discrete data on same axis
I.e. we can only specify the y values of the line with respect to categorical values of y. So, for example we can do
dat1 = data.frame(measure=letters[1:2], actual=c(25,20))
plot_ly(data = dat1) %>%
add_bars(y=~measure, x=~actual, orientation="h") %>%
layout(annotations = list(x = 29, y = 0, text = "Expected", textangle=270,
showarrow=F, xanchor="center")) %>%
add_segments(x=30, xend=30, y='a', yend='b')
which gives the following in which the line is aligned with the category labels rather than with the width of the bars
The only solution I have to this at the moment is to use a numeric axis for the categories, and then set the axis labels using ticktext:
plot_ly(data = data.frame(measure=c(0,1), actual=c(25,20))) %>%
add_bars(y=~measure, x=~actual, orientation="h", showlegend=F) %>%
add_segments(x=30, xend=30, y=-0.4, yend=0.4, showlegend=F) %>%
layout(annotations = list(x = 29.5, y = 0, text = "Expected", textangle=270, showarrow=F, xanchor="center"),
yaxis = list(tickmode="array", tickvals=c(0,1), ticktext=c("", "") ))

Related

Placing Spaces Between the Titles of Plots

I made this pie chart in R:
# https://plotly.com/r/text-and-annotations/
df <- read.csv("https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv", stringsAsFactors = FALSE)
df <- df[which(df$year==2007 & df$continent=='Asia'),]
fig <- plot_ly(df, type='pie', labels = ~country, values = ~pop, textposition = 'inside')
fig1 <- fig %>% layout(uniformtext=list(minsize=12, mode='hide'))
fig1 <- fig1 %>% add_annotations(
y=1.05,
x=0.5,
text="Countries of the World",
showarrow=F,
font=list(size=15)
)
Everything works fine here, but I notice that when I am working with my real data, the title of the pie chart and the actual pie chart always come very close to intersecting with each other - I would like to try and change this.
I was thinking if there might be a way to avoid this problem. I thought that perhaps I could add more space between the title and the actual pie chart to avoid this problem from happening. I found this post here (how to adjust title space and plot plotly in r) and tried to apply the advice that was suggested in the answer:
mrg <- list(l = 50, r = 50,
b = 50, t = 50,
pad = 20)
fig1 %>% layout(margin = mrg)
However, this has not seemed to add any space between the pie chart and the title of the pie chart.
Can someone please show me how to do this correctly?
Thank you!
Here is one option making use of layout for the title and adjusting the spacing. Then, you can just adjust the margins to get the desired spacing.
library(plotly)
plot_ly(df, type='pie', labels = ~country, values = ~pop, textposition = 'inside') %>%
layout(uniformtext=list(minsize=12, mode='hide')) %>%
layout(title = list(text = 'Countries of the World',
y=1.25,
x=0.43, font=list(size = 30)),
autosize = T,
margin=list( l = 50, r = 50, b = 100, t = 100, pad = 4))
Output

R Plotly rotation of text in add_text

I can't seem to get the text to rotate in Plotly, in a scatter plot, using add_text().
I'm just trying to get the same result that the angle argument yields in ggplot. In plotly, the output needs to have the hovertext if that's of consequence.
Example -
library(dplyr)
library(plotly)
data <- data.frame(
x = 1:10,
y = runif(10,0,10),
lab = LETTERS[1:10]
)
# base output needed in ggplot
p <- data %>%
ggplot(aes(x,y)) +
geom_text(aes(label = lab, angle = 90))
# doesn't respect angle arg - not that I'm looking to use ggplotly
ggplotly(p)
# plotly version
plot_ly(data) %>%
add_text(
x = ~x,
y = ~y,
text = ~lab,
hovertext = ~paste0("Label is ", lab),
# things I've tried (generally one at a time..)
textfont = list(angle = 90, textangle = 90, orientation = 90, rotate = 90)
)
I'm sure I'm missing something obvious, but I can't track it down.. Help pls!
It appears the solution is to use add_annotations() rather than add_text(). A textangle arg is then accpeted.
Edit - turns out you need two traces - annotations to achieve the text rotation, then markers for the hovertext. Setting opacity = 0 for the markers seems OK.

R Plotly linked subplot with percentage histogram and categories coloured

The Background
I am using the plotly API in R to create two linked plots. The first is a scatter plot and the second is a bar chart that should show the percentage of data belonging to each category, in the current selection. I can't make the percentages behave as expected.
The problem
The plots render correctly and the interactive selection works fine. When I select a set of data points in the top scatter plot, I would like to see the percentage of that selection that belongs to each category. Instead what I see is the percentage of points in that selection in that category that belong to that category, in other words always 100%. I guess this is because I set color = ~c which applies a grouping to the category.
The Example
Here is a reproducible example to follow. First create some dummy data.
library(plotly)
n = 1000
make_axis = function(n) c(rnorm(n, -1, 1), rnorm(n, 2, 0.25))
data = data.frame(
x = make_axis(n),
y = make_axis(n),
c = rep(c("A", "B"), each = n)
)
Create a sharedData object and supply it to plot_ly() for the base plot.
shared_data = data %>%
highlight_key()
baseplot = plot_ly(shared_data)
Make the individual panels.
points = baseplot %>%
add_markers(x = ~x, y = ~y, color = ~c)
bars = baseplot %>%
add_histogram(x = ~c, color = ~c, histnorm = "percent", showlegend = FALSE) %>%
layout(barmode = "group")
And put them together in a linked subplot with selection and highlighting.
subplot(points, bars) %>%
layout(dragmode = "select") %>%
highlight("plotly_selected")
Here is a screenshot of this to illustrate the problem.
An Aside
Incidentally when I set histnorm = "" in add_histogram() then I get closer to the expected behaviour but I do want percentages and not counts. When I remove color = ~c then I get closer to the expected behaviour but I do want the consistent colour scheme.
What have I tried
I have tried manually supplying the colours but then some of the linked selection breaks. I have tried creating a separate summarised data set from the sharedData object first and then plotting that but again this breaks the linkage between the plots.
If anyone has any clues as to how to solve this I would be very grateful.
To me it seems the behaviour you are looking for isn't implemented in plotly.
Please see schema(): object ► traces ► histogram ► attributes ► histnorm ► description
However, here is the closest I was able to achive via add_bars and perprocessing the data (Sorry for adding data.table, you will be able to do the same in base R, just personal preference):
library(plotly)
library(data.table)
n = 1000
make_axis = function(n) c(rnorm(n, -1, 1), rnorm(n, 2, 0.25))
DT = data.table(
x = make_axis(n),
y = make_axis(n),
c = rep(c("A", "B"), each = n)
)
DT[, grp_percent := rep(100/.N, .N), by = "c"]
shared_data = DT %>%
highlight_key()
baseplot = plot_ly(shared_data)
# Make the individual panels.
points = baseplot %>%
add_markers(x = ~x, y = ~y, color = ~c)
bars = baseplot %>%
add_bars(x = ~c, y = ~grp_percent, color = ~c, showlegend = FALSE) %>%
layout(barmode = "group")
subplot(points, bars) %>%
layout(dragmode = "select") %>%
highlight("plotly_selected")
Unfortunately, the resulting hoverinfo isn't really desirable.

Bar-plot does not show bar for only one x value

I am having an issue with a plotly bar plot when I define the date range for the x-axis.
When there is one or more data points with the same x-value, the bars do not show in the plot. If there is at least two different x-values or if I do not use a x-axis range, then the bars show as they should.
Below follows an example (I am currently using lubridate to deal with dates).
library(lubridate)
library(plotly)
# Same x-value: bar does not show
plot_ly(x = c(ymd("2019-08-25"), ymd("2019-08-25")), y = c(1, 2), type = "bar") %>%
layout(xaxis = list(range = ymd(c("2019-08-20", "2019-08-30"))))
# Different x-values: bars are shown
plot_ly(x = c(ymd("2019-08-25"), ymd("2019-08-26")), y = c(1, 2), type = "bar") %>%
layout(xaxis = list(range = ymd(c("2019-08-20", "2019-08-30"))))
# No x-axis range defined, same x-values: the bar is shown
plot_ly(x = c(ymd("2019-08-25"), ymd("2019-08-25")), y = c(1, 2), type = "bar")
Any solution?
Edit: For comparison, ggplot2 does not have the same issue:
# ggplot works like expected
library(lubridate)
library(ggplot2)
ggplot(NULL, aes(x = ymd(c("2019-08-25", "2019-08-25")), y = c(1, 2))) +
geom_col() +
xlim(ymd(c("2019-08-20", "2019-08-30")))
Your code is actually being understood in your first version, but you need to set the width of the bars so they show up in the end.
I'm not sure what the units are (maybe miliseconds???) so you may need to play around with it or do research to get a good width for your actual scenario.
plot_ly() %>%
add_bars(x = c(ymd("2019-08-25"), ymd("2019-08-25")), y = c(1, 2), type = "bar",width=100000000)%>%
layout(xaxis = list(range = ymd(c("2019-08-20", "2019-08-30"))))

Adding a horizontal line to a plotly bar graph

I'm trying to use R plotly's bar type plot to generate a plot with horizontally laid out boxes and add to that a horizontal line which is in their background (rather than goes on top of them). In addition, I would like the line to extend symmetrically one box unit in each direction.
Here's what I'm doing:
plot.df <- data.frame(x = paste0("LONG NAME ",1:6),y = 0.2,width=0.75,group = c("A","B","B","B","C","A"),stringsAsFactors = F)
plot.df$group <- factor(plot.df$group)
plotly::plot_ly(plot.df) %>%
plotly::add_trace(x=~x,y=~y/2,type='scatter',mode='lines',line=list(color='black'),showlegend=F) %>%
plotly::add_bars(x=~x,y=~y,width=~width,color=~group) %>%
plotly::layout(xaxis=list(title=NA,zeroline=F,tickangle=45),yaxis=list(title=NA,zeroline=F,showgrid=F,range=c(0,1),showticklabels=F))
Which gives:
My questions are:
How to extend the the line in both directions
How to put the line in the background so it does not run over the boxes
I specified plot.df$y as 0.2 but the yaxis range to be c(0,1) so that the boxes don't look like long bars. But then the legend appears too high. Any better way to get square boxes with the legend appearing lower than it currently is?
For the horizontal line you can see Horizontal/Vertical Line in plotly
with
layout(legend =list(x = 1 ,y =0 ))
you can solve the legend problem
I could not solve your second point (put the bar in the background). I hope it helps:
hline <- function(y = 0, color = "blue") {
list(
type = "line",
x0 = 0,
x1 = 1,
xref = "paper",
y0 = y,
y1 = y,
line = list(color = color)
)
}
plot_ly(plot.df) %>%
add_bars(x=~x,y=~y,width=~width,color=~group, hoverinfo = "text") %>%
layout(shapes = list(hline(0.1)))%>%
layout(legend =list(x = 1 ,y =0 ))%>%
layout(xaxis=list(title=NA,zeroline=F,tickangle=45),yaxis=list(title=NA,zeroline=F,showgrid=F,range=c(0,1),showticklabels=F))

Resources