Out of curiosity I am trying to reconstruct a ggplot graph with plotly.
It is an example of a simple linear regression. The graph shows the observed data, the regression line and vertical lines showing the errors.
The ggplot looks like this:
The reconstructed plotly graph looks like this:
Is there a way to push the vertical lines showing the errors to the back of the points?
Is there a better approach?
The data may be found here:
Advertising.csv
This is the code used to make the plots:
library(ggplot2)
library(plotly)
#### prepare data ####
adv <- read.csv("Advertising.csv")
fit_tv <- lm(sales ~ TV, data = adv)
adv_plot <- data.frame(adv, fit = fit_tv$fitted.values)
#### ggplot ####
p1 <- ggplot(adv_plot, aes(x = TV, y = sales)) +
geom_segment(aes(x = TV, xend = TV, y = sales, yend = fit), size = 0.5, color = "lightgrey") +
geom_point(color = "red") +
geom_point(aes(y = fit), color = "blue")
p1
#### Plotly ####
p2 <- plot_ly(adv_plot, x = ~TV, y = ~sales, type = "scatter", mode = "markers", marker = list(color = "red", size = 5)) %>%
add_trace(x = ~TV, y = ~fit, type = "scatter", mode = "markers", marker = list(color = "blue", size = 5))
line <- list(
type = "line",
line = list(color = "lightgrey"),
xref = "x",
yref = "y"
)
lines <- list()
for (i in 1:length(adv_plot$sales)) {
line[["x0"]] <- adv_plot$TV[i]
line[["x1"]] <- adv_plot$TV[i]
line[["y0"]] <- adv_plot$sales[i]
line[["y1"]] <- adv_plot$fit[i]
lines <- c(lines, list(line))
}
p2 <- layout(p2, shapes = lines, showlegend = FALSE)
p2
At the end managed to find the answer myself. The order of the segments and traces keep the error lines in the background.
The data is here: Advertising.csv
This is the code:
library(ggplot2)
library(plotly)
adv <- read.csv("Advertising.csv")
fit_tv <- lm(sales ~ TV, data = adv)
adv_plot <- data.frame(adv, fit = fit_tv$fitted.values)
p <- plot_ly(adv_plot, x = ~TV) %>%
add_segments(x = ~TV, y = ~fit, xend = ~TV, yend = ~sales, mode = 'line', line = list(color = "lightgrey")) %>%
add_trace(y = ~sales, name = 'trace 0', type = "scatter", mode = 'markers', marker = list(color = "red", size = 5)) %>%
add_trace(y = ~fit, name = 'trace 1', type = "scatter", mode = 'markers', marker = list(color = "blue", size = 5)) %>%
layout(showlegend = FALSE)
p
Related
I just started using plotly in R, and I've made a plot like this
with a syntax like this:
maximum <- rnorm(30, mean = 20)
datasource <- rnorm(30, mean = 15)
minimum <- rnorm(30, mean = 10)
x <- c(1:30)
data <- data.frame(x,datasource,maximum,minimum)
fig <- plot_ly(data, x = ~x, y = ~datasource, name = 'trace 1', type = 'scatter', mode = 'lines+markers', marker = list(size = 10))
fig <- fig %>% add_trace(y = ~maximum, name = 'maximum', mode = 'markers', marker = list(size = 10))
fig <- fig %>% add_trace(y = ~minimum, name = 'minimum', mode = 'markers', marker = list(size = 10))
fig <- fig %>% layout(title = "XBAR CHART",
xaxis = list(title = "ID"),
yaxis = list (title = "Measurement Value (mm)"))
fig
I want to add a line connecting the minimum and maximum markers like the following.
I've been trying but haven't found the solution.
I hope I find a solution here.
thanks
calculate the points that defined the lines
v_lines <- mutate(rowwise(data),
vline=list(list(type="line",
x0=x,
x1=x,
y0=minimum,
y1=maximum,
line=list(color="blue")))) |> pull(vline)
add them to the layout
fig <- fig %>% layout(title = "XBAR CHART",
shapes= v_lines,
xaxis = list(title = "ID"),
yaxis = list (title = "Measurement Value (mm)"))
Like this?
ggplot(data=data, aes(x,datasource))+
geom_segment(data = data, aes(x = x, y = minimum, xend = x, yend = maximum), color = "light blue", size = 1)+
geom_line(data = data, aes(x = x, y = datasource), color= "blue", size = 1)+
geom_point(data=data, aes(x, minimum), color = "green", size=3)+
geom_point(data=data, aes(x, maximum), color = "orange", size=3)+
geom_point(color = "blue", size=3)+
xlab("X - axis text")+ylab("Y - axis text")+
theme_light(base_size = 18, base_rect_size = 1)
Consider the following code
set.seed(1234)
r = rnorm(200)
ir = cumsum(r)
df = data.frame(low = ir - 2*abs(r), high = ir + 2*abs(r), mid = ir, x = 1:200)
df[90:110,] <- NA
plot_ly(data = df) |>
add_lines(x = ~x, y = ~high, line = list(width = 2), name = "high") |>
add_lines(x = ~x, y = ~low, fillcolor='rgba(0,100,80,0.2)', fill = "tonexty", line = list(width = 2), name = "low") |>
add_lines(x = ~x, y = ~mid, line = list(color = "black"), name = "mid")
which generates the following chart
I want to have a break in the chart where the data is missing, and I want to fill the area between the lines, but I don't want this weird artifact you can see. Any ideas?
I am working with the R Programming language.
Using the following link as a tutorial (https://plotly.com/r/lines-on-maps/), I was able to make an interactive plot:
#load libraries
library(dplyr)
library(leaflet)
library(plotly)
library(data.table)
#generate data for example (longitude and latitude of cities)
lat = rnorm(100, 43, 3)
long = rnorm(100, -79, 3)
map_data = data.frame(lat, long)
map_data$type = as.factor(1:100)
#change format of the data so that it is compatible for this example
result = rbind(
cbind(map_data[1:nrow(map_data)-1,c(1,2)], map_data[-1,c(1,2)]),
cbind(map_data[nrow(map_data), c(1,2)], map_data[1,c(1,2)])
)
colnames(result) <- c("start_lat", "start_long", "end_lat", "end_long")
my_data = result
my_data$type = as.factor(1:nrow(my_data))
my_data$type1 = as.character(1:100)
my_data$count = as.integer(1)
my_data$id = 1:100
#### begin visualization
# map projection
geo <- list(
scope = 'north america',
projection = list(type = 'azimuthal equal area'),
showland = TRUE,
landcolor = toRGB("gray95"),
countrycolor = toRGB("gray80")
)
fig <- plot_geo(locationmode = 'USA-states', color = I("red"))
fig <- fig %>% add_markers(
data = my_data, x = ~start_long, y = ~start_lat, alpha = 0.5
)
fig <- fig %>% add_markers(
data = my_data, x = ~start_long, y = ~start_lat, hoverinfo = "text", alpha = 0.5
)
fig <- fig %>% add_segments(
data = group_by(my_data, type),
x = ~start_long, xend = ~end_long,
y = ~start_lat, yend = ~end_lat,
alpha = 0.3, size = I(1), hoverinfo = "none"
)
fig <- fig %>% layout(
title = 'Plot 1',
geo = geo, showlegend = FALSE, height=800
)
#final result
fig
This produces the following result:
Now, I am trying to get the "interactive text" to work:
# map projection
geo <- list(
scope = 'north america',
projection = list(type = 'azimuthal equal area'),
showland = TRUE,
landcolor = toRGB("gray95"),
countrycolor = toRGB("gray80")
)
fig <- plot_geo(locationmode = 'USA-states', color = I("red"))
fig <- fig %>% add_markers(
data = my_data, x = ~start_long, y = ~start_lat, alpha = 0.5
)
fig <- fig %>% add_markers(
data = my_data, x = ~start_long, y = ~start_lat, text = ~type1, size = ~count, hoverinfo = "text", alpha = 0.5
)
fig <- fig %>% add_segments(
data = group_by(my_data, type),
x = ~start_long, xend = ~end_long,
y = ~start_lat, yend = ~end_lat,
alpha = 0.3, size = I(1), hoverinfo = "none"
)
fig <- fig %>% layout(
title = 'Plot 1',
geo = geo, showlegend = FALSE, height=800
)
fig
The interactive text is now working, but the data points are appearing "much bulkier".
My Question: Is it possible to make the interactive text work, but have the data points appear the same way they do in the first picture?
I originally tried to do this without a "count" variable:
fig <- fig %>% add_markers(
data = my_data, x = ~start_long, y = ~start_lat, text = ~type1, hoverinfo = "text", alpha = 0.5
)
But when I do this, the interactive text isn't working - the interactive text only works when a "count" variable is added.
Is this "count" variable necessary? Can someone please show me how to fix this?
Thanks!
You don't need to use count. However, there is something odd here with the segments. Either way, this achieves what I think you're looking for.
I have provided two examples because you didn't say what you wanted to have in the hover text. In the first example, I just use the x and y (lat and long). In the second, I used custom hover content.
Everything that precedes the creation of fig was left unchanged.
Notable changes:
the order the fig elements are assembled; segments seems to only work if it is before the markers
hoverinfo for the segments add is now set to text--this didn't add hover content, but for some reason none here was a problem...odd
I dropped a call to fig or two, that seemed to be doing nothing...
in add_markers, this changed differently in the two options
in one, hovertext = "text" was changed to hovertext = "lat+lon"
in the other, there were multiple changes--you'll have to look at the code for this one
in layout, I deleted the height argument; it's ignored
fig <- plot_geo(locationmode = 'USA-states', color = I("red"))
fig <- fig %>% add_segments( # add segments
data = group_by(my_data, type),
x = ~start_long, xend = ~end_long,
y = ~start_lat, yend = ~end_lat,
alpha = 0.3, size = I(1), hoverinfo = "text" # changed hoverinfo
)
fig <- fig %>% add_markers(
data = my_data, x = ~start_long, y = ~start_lat,
alpha = 0.5, hoverinfo = "lat+lon" # changed hoverinfo
)
fig <- fig %>% layout(
title = 'Plot 1',
geo = geo, showlegend = FALSE # removed height argument
)
#final result
fig
Here's the custom text version
fig <- plot_geo(locationmode = 'USA-states', color = I("red"))
fig <- fig %>% add_segments( # add segments
data = group_by(my_data, type),
x = ~start_long, xend = ~end_long,
y = ~start_lat, yend = ~end_lat,
alpha = 0.3, size = I(1), hoverinfo = "text" # changed hoverinfo
)
fig <- fig %>% add_markers(
data = my_data, x = ~start_long, y = ~start_lat,
alpha = 0.5, hoverinfo = "text", # hoverinfo unchanged
text = ~paste0("Longitude: ", # text changed here**
round(my_data$start_long, 2),
"<br>Latitude: ",
round(my_data$start_lat, 2))
)
fig <- fig %>% layout(
title = 'Plot 1',
geo = geo, showlegend = FALSE # removed height argument
)
#final result
fig
Let me know if you have any questions!
I am plotting some plot with plotly. So everything is ok but I am not satisfied with font appearance. Namely in legend I have one font while for x and y-axis I have other. So can anybody help how to fix this problem and have same font like font in legend ?
x1 = lcBR$p
y1 = lcBR$L
x2 = lcAR$p
y2 = lcAR$L
fig <- plot_ly(x = ~ x1, y = ~ x1, name = '45ยบ', type = 'scatter', mode = 'lines',
line = list(color = "black", width = 2))
fig <- fig %>% add_trace(x = ~ x1, y = ~ y1, name = 'Before reform', mode = 'lines',
line = list(color = "red", width = 2, dash = "solid"))
fig <- fig %>% add_trace(x ~ x2, y = ~ y2, name = 'After reform', mode = 'lines',
line = list(color = "blue", width = 2, dash = "dash"))
f <- list(
family = "Courier New, monospace",
size = 18,
color = "#7f7f7f")
x <- list(
title = "Share of Population",
titlefont = f)
y <- list(
title = "Share of income",
titlefont = f)
fig <- fig %>% layout(xaxis = x, yaxis = y)
fig
Your code looks a bit different than what "normal" python code in plotly looks like; is this R-code? However, you can use fig.update_layout to update the layout throughout your figure and fig.update_xaxes to change the appearance of the x-axis including text; have a look at https://plotly.com/python/figure-labels/#global-and-local-font-specification
I would like to add the regression line to my correlation scatter plot. Unfortunately this doesn't really work with plot_ly(). I've already tried some solutions from other posts in this forum, but it doesn't work.
My data frame looks like the following (only a smart part of it):
My code for the plot and the actual plot-output look like the following:
CorrelationPlot <- plot_ly(data = df.dataCorrelation, x = ~df.dataCorrelation$prod1,
y = ~df.dataCorrelation$prod2, type = 'scatter', mode = 'markers',
marker = list(size = 7, color = "#FF9999", line = list(color = "#CC0000", width = 2))) %>%
layout(title = "<b> Correlation Scatter Plot", xaxis = list(title = product1),
yaxis = list(title = product2), showlegend = FALSE)
What I want to have is something like this:
which I have produced with the ggscatter() function:
library(ggpubr)
ggscatter(df.dataCorrelation, x = "prod1", y = "prod2", color = "#CC0000", shape = 21, size = 2,
add = "reg.line", add.params = list(color = "#CC0000", size = 2), conf.int = TRUE,
cor.coef = TRUE, cor.method = "pearson", xlab = product1, ylab = product2)
HOW do I get the regression line with plot_ly()??
CODE EDITING:
CorrelationPlot <- plot_ly(data = df.dataCorrelation, x = ~df.dataCorrelation$prod1,
y = ~df.dataCorrelation$prod2, type = 'scatter', mode = 'markers',
marker = list(size = 7, color = "#FF9999",
line = list(color = "#CC0000", width = 2))) %>%
add_trace(x = ~df.dataCorrelation$fitted_values, mode = "lines", type = 'scatter',
line = list(color = "black")) %>%
layout(title = "<b> Correlation Scatter Plot", xaxis = list(title = product1),
yaxis = list(title = product2), showlegend = FALSE)
GIVES:
How do I get here a line for the regression line??
I don't think there's a ready function like ggscatter, most likely you have to do it manually, like first fitting the linear model and adding the values to the data.frame.
I made a data.frame that's like your data:
set.seed(111)
df.dataCorrelation = data.frame(prod1=runif(50,20,60))
df.dataCorrelation$prod2 = df.dataCorrelation$prod1 + rnorm(50,10,5)
fit = lm(prod2 ~ prod1,data=df.dataCorrelation)
fitdata = data.frame(prod1=20:60)
prediction = predict(fit,fitdata,se.fit=TRUE)
fitdata$fitted = prediction$fit
The upper and lower bounds of the line are simply 1.96* standard error of prediction:
fitdata$ymin = fitdata$fitted - 1.96*prediction$se.fit
fitdata$ymax = fitdata$fitted + 1.96*prediction$se.fit
We calculate correlation:
COR = cor.test(df.dataCorrelation$prod1,df.dataCorrelation$prod2)[c("estimate","p.value")]
COR_text = paste(c("R=","p="),signif(as.numeric(COR,3),3),collapse=" ")
And put it into plotly:
library(plotly)
df.dataCorrelation %>%
plot_ly(x = ~prod1) %>%
add_markers(x=~prod1, y = ~prod2) %>%
add_trace(data=fitdata,x= ~prod1, y = ~fitted,
mode = "lines",type="scatter",line=list(color="#8d93ab")) %>%
add_ribbons(data=fitdata, ymin = ~ ymin, ymax = ~ ymax,
line=list(color="#F1F3F8E6"),fillcolor ="#F1F3F880" ) %>%
layout(
showlegend = F,
annotations = list(x = 50, y = 50,
text = COR_text,showarrow =FALSE)
)
Another option is using ggplotly as
library(plotly)
ggplotly(
ggplot(iris, aes(x = Sepal.Length, y = Petal.Length))+
geom_point(color = "#CC0000", shape = 21, size = 2) +
geom_smooth(method = 'lm') +
annotate("text", label=paste0("R = ", round(with(iris, cor.test(Sepal.Length, Petal.Length))$estimate, 2),
", p = ", with(iris, cor.test(Sepal.Length, Petal.Length))$p.value),
x = min(iris$Sepal.Length) + 1, y = max(iris$Petal.Length) + 1, color="steelblue", size=5)+
theme_classic()
)