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!
Related
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 wrote a code to make a subplots with scatterplots using my data. Here is a graph:
This is hours on x axis. As you see, not all of them appear on x axis. How could i make all 24 hours be on axis? Even if for example in dataframe there is no value for 23 o'clock, i want it to be on x axis. How to do that?
Here is my code:
plot <- function(df) {
subplotList <- list()
for(metric in unique(df$metrics)){
subplotList[[metric]] <- df[df$metrics == metric,] %>%
plot_ly(
x = ~ hr,
y = ~ actual,
name = ~ paste(metrics, " - ", time_pos),
colors = ~ time_pos,
hoverinfo = "text",
hovertemplate = paste(
"<b>%{text}</b><br>",
"%{xaxis.title.text}: %{x:+.1f}<br>",
"%{yaxis.title.text}: %{y:+.1f}<br>",
"<extra></extra>"
),
type = "scatter",
mode = "lines+markers",
marker = list(
size = 7,
color = "white",
line = list(width = 1.5)
),
width = 700,
height = 620
) %>% layout(autosize = T,legend = list(font = list(size = 8)))
}
subplot(subplotList, nrows = length(subplotList), margin = 0.05)
}
This could be achieved in layout via the attribute xaxis like so. The ticks or breaks can be set via tickvals, the tick labels via ticktext.
This is illustrasted using some random data in the reproducible example below:
library(plotly)
set.seed(42)
d <- data.frame(
x = sort(sample(24, 15)),
y = 1:15 + runif(15),
z = 1:15 + runif(15)
)
plot_ly(d) %>%
add_trace(x = ~x, y = ~y, type = "scatter", mode = "lines+markers") %>%
add_trace(x = ~x, y = ~z, type = "scatter", mode = "lines+markers") %>%
layout(xaxis = list(tickvals = 1:24, ticktext = paste0(1:24, "h")))
I have the following code producing a scatter plot and I would like to add both vertical and horizontal lines representing the mean values of the y axis and x axis, how could I do that?
f <- list(
family = "Courier New, monospace",
size = 18,
color = "#7f7f7f"
)
x <- list(
title = "Age of Buildings",
titlefont = f,
zeroline = FALSE,
showline = FALSE,
showticklabels = TRUE,
showgrid = TRUE
)
y <- list(
title = "Total Violations",
titlefont = f,
zeroline = FALSE,
showline = FALSE,
showticklabels = TRUE,
showgrid = TRUE
)
fig2 <- plot_ly(final, x=~agebuilding, y=~violationstotal, mode= "markers", color = ~INdexrehabless6, size = ~totalvalue)
fig2 <- fig2 %>% layout(xaxis = x, yaxis = y, legend=list(title=list(text='<b> Housing Conditions </b>'))) #chaging name legend
fig2
Here is the plot I get
Using some random data for your df final. I don't know whether plotly provides some kind of geom_h/vline ... Instead I constructed the lines using dataframes which contain the start and the end point of the lines. Have a look:
set.seed(50)
final <- data.frame(
agebuilding = 150 * runif(50),
violationstotal = 30 * runif(50),
INdexrehabless6 = factor(sample(0:1, 50, replace = TRUE)),
totalvalue = 100 * runif(50)
)
mean_x <- data.frame(x = rep(mean(final$agebuilding), 2), y = c(0, ceiling(10* max(final$violationstotal))/10))
mean_y <- data.frame(y = rep(mean(final$violationstotal), 2), x = c(0, ceiling(10* max(final$agebuilding))/10))
library(plotly)
fig2 <- plot_ly(final) %>%
add_markers(x=~agebuilding, y=~violationstotal, color = ~INdexrehabless6, size = ~totalvalue) %>%
add_lines(x = ~x, y = ~y, data = mean_x, name = "Mean x") %>%
add_lines(x = ~x, y = ~y, data = mean_y, name = "Mean y")
fig2 <- fig2 %>% layout(xaxis = x, yaxis = y, legend=list(title=list(text='<b> Housing Conditions </b>'))) #chaging name legend
fig2
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
I want to create a flight path map using plotly. When following the plotly tutorial called 'Lines on Maps', I do not get the expected output. While all flight paths are indeed drawn, for some reason, a lot of lines seems to connect to the origin (longitude==0, latitude==0). . What is wrong?
library(plotly)
library(dplyr)
# airport locations
air <- read.csv('https://raw.githubusercontent.com/plotly/datasets/master/2011_february_us_airport_traffic.csv')
# flights between airports
flights <- read.csv('https://raw.githubusercontent.com/plotly/datasets/master/2011_february_aa_flight_paths.csv')
flights$id <- seq_len(nrow(flights))
# map projection
geo <- list(
scope = 'world',
projection = list(type = 'azimuthal equal area'),
showland = TRUE,
landcolor = toRGB("gray95"),
countrycolor = toRGB("gray80")
)
p <- plot_geo(locationmode = 'USA-states', color = I("red")) %>%
add_markers(
data = air, x = ~long, y = ~lat, text = ~airport,
size = ~cnt, hoverinfo = "text", alpha = 0.5
) %>%
add_segments(
data = group_by(flights, id),
x = ~start_lon, xend = ~end_lon,
y = ~start_lat, yend = ~end_lat,
alpha = 0.3, size = I(1), hoverinfo = "none"
) %>%
layout(
title = 'Feb. 2011 American Airline flight paths<br>(Hover for airport names)',
geo = geo, showlegend = FALSE, height=800
)
ggplotly(p)
You can use the split argument with your id variable to stop drawing between each line of you data.frame :
add_segments(
data = group_by(flights, id),
x = ~start_lon, xend = ~end_lon,
y = ~start_lat, yend = ~end_lat, split=~id,
alpha = 0.3, size = I(1), hoverinfo = "none"
) %>%