external links within a plotly plot? - r

I'm wondering if there is a way to embed external links within a plotly plot (specifically I'm using the plotly package in R, but I don't have to). I want to be able to click on points in a scatter plot and have that take me to an external page with more detailed information about that point. Below is a fake example to demonstrate the idea.
Also, if this is not possible in plotly, but someone knows another library that could do this, I would love to know about that too! Thanks in advance.
THE EXAMPLE:
Imagine we're plotting the distances of each cruise taken by ships owned by two different cruise lines. The code below makes a plot which shows all the voyages and, when you hover over a point, it shows you the name of the ship that took that voyage. What I want is to be able to click on a point and have it take me to some web page with, for example, a detailed log of that particular voyage. (This is all a fake example, these logs don't actually exist.) Another sidenote: I'm using ggplotly because I'm comfortable with ggplot2 but if there's a way to do this in plot_ly I'm happy to use that.
library(ggplot2)
library(plotly)
shipNames <- c("Princess", "Voyager", "Paul Simon", "Dangelo", "Virginia", "Meade", "Capt America", "Naw Dawg")
set.seed(1)
cruise <- data.frame(company = sample(c("Carnival", "Norweigen"), 20, replace = T),
shipName = sample(shipNames, 20, replace=T),
date = sample(seq(from=as.Date('2016-01-01'), to=as.Date('2016-12-31'), by=1), 20),
distance = sample(seq(from=300, to=500, by=1), 20)
)
g <- ggplot(cruise, aes(x=date, y=distance, colour=company, name = shipName)) + geom_point()
# you have to put the geom_line first or it fucks it up
g <- ggplot(cruise, aes(x=date, y=distance)) + geom_line(aes(colour=company)) + geom_point(aes(colour=company, name = shipName))
ggplotly(g, tooltip = c("x", "name"))

Related

Moving image on click in R with gganimate

I just started using the awesome gganimate package, and I managed to create a pretty cool animated gif.
However, I would like the image to move from one state to another on click, not automatically. Is there a way to do that with the gganimate package or with another package?
Thank you,
Sarah
I am 2 short of reputations for commenting hence answering directly, otherwise would have asked for data & code, nevertheless I'll try to answer based on understanding from the linked gif.
Since the main aim of gganimate is to create animations which are simply stitched frames from ggplot output, so to my knowledge there is no option to have a click functionality directly.
This would require a package which has capability for interactive graphics, hence plotly is best option. Not trying to demean gganimate (I am myself a big fan of it).
library(plotly)
library(ggplot2)
df <- data.frame(Dim1 = runif(100,-200,200), Dim2 = rpois(100,5),
Timepoint = rep(c("PRE","4WP"),50), pop = runif(100,1,10))
gg <- ggplot(df, aes(Dim1, Dim2)) +
geom_point(aes(size = pop, frame = Timepoint))
ggplotly(gg) %>%
animation_opts(
frame = 1000,
transition = 1000,
easing = "linear",
redraw = TRUE,
mode = "immediate"
)
you can try more easing options from plotly/animation_attributes.js.
This will directly create a interactive plot:
Another option would be to use same animations from gganimate by first saving each frame generated by it in file system using: (as I dont know how you are creating your animation I will create a basic one)
p <- gg + transition_states(Timepoint, transition_length = 100, state_length = 5)
animate(p, renderer = file_renderer(prefix = "gganim_plot", overwrite = TRUE))
which can then be fed into saveHTML command of animation R package.

Trying to plot in tmap shapefile with attribute

I am trying to work with municipality data in Norway, and I'm totally new to QGIS, shapefiles and plotting this in R. I download the municipalities from here:
Administrative enheter kommuner / Administrative units municipalities
Reproducible files are here:
Joanna's github
I have downloaded QGIS, so I can open the GEOJson file there and convert it to a shapefile. I am able to do this, and read the data into R:
library(sf)
test=st_read("C:/municipality_shape.shp")
head(test)
I have on my own given the different municipalities different values/ranks that I call faktor, and I have stored this classification in a dataframe that I call df_new. I wish to merge this "classification" on to my "test" object above, and wish to plot the map with the classification attribute onto the map:
test33=merge(test, df_new[,c("Kommunekode_str","faktor")],
by=c("Kommunekode_str"), all.x=TRUE)
This works, but when I am to plot this with tmap,
library(tmap)
tmap_mode("view")
tm_shape(test33) +
tm_fill(col="faktor", alpha=0.6, n=20, palette=c("wheat3","red3")) +
tm_borders(col="#000000", lwd=0.2)
it throws this error:
Error in object[-omit, , drop = FALSE] : incorrect number of
dimensions
If I just use base plot,
plot(test33)
I get the picture:
You see I get three plots. Does this has something to do with my error above?
I think the main issue here is that the shapes you are trying to plot are too complex so tmap is struggling to load all of this data. ggplot also fails to load the polygons.
You probably don't need so much accuracy in your polygons if you are making a choropleth map so I would suggest first simplifying your polygons. In my experience the best way to do this is using the package rmapshaper:
# keep = 0.02 will keep just 2% of the points in your polygons.
test_33_simple <- rmapshaper::ms_simplify(test33, keep = 0.02)
I can now use your code to produce the following:
tmap_mode("view")
tm_shape(test_33_simple) +
tm_fill(col="faktor", alpha=0.6, n=20, palette=c("wheat3","red3")) +
tm_borders(col="#000000", lwd=0.2)
This produces an interactive map and the colour scheme is not ideal to tell differences between municipalities.
static version
Since you say in the comments that you are not sure if you want an interactive map or a static one, I will give an example with a static map and some example colour schemes.
The below uses the classInt package to set up breaks for your map. A popular break scheme is 'fisher' which uses the fisher-jenks algorithm. Make sure you research the various different options to pick one that suits your scenario:
library(ggplot2)
library(dplyr)
library(sf)
library(classInt)
breaks <- classIntervals(test_33_simple$faktor, n = 6, style = 'fisher')
#label breaks
lab_vec <- vector(length = length(breaks$brks)-1)
rounded_breaks <- round(breaks$brks,2)
lab_vec[1] <- paste0('[', rounded_breaks[1],' - ', rounded_breaks[2],']')
for(i in 2:(length(breaks$brks) - 1)){
lab_vec[i] <- paste0('(',rounded_breaks[i], ' - ', rounded_breaks[i+1], ']')
}
test_33_simple <- test_33_simple %>%
mutate(faktor_class = factor(cut(faktor, breaks$brks, include.lowest = T), labels = lab_vec))
# map
ggplot(test_33_simple) +
geom_sf(aes(fill = faktor_class), size= 0.2) +
scale_fill_viridis_d() +
theme_minimal()

Merging Legends for both geom Line and Point

I was very new to R Script. If you are able to help my problem that would be really great... Here is my problem...
I am able to create custom visual using R Script and make hover over work in that visual by using this below link Link I think It is displaying legend for both line and point as well. This is how it’s showing me in the graph Both Legends
But I would like to show up something like this…. Which represents both the line and point in the same legend name Same legend.
Please find the R Script below, Please go through that and can you tell me where I was going wrong….
source('./r_files/flatten_HTML.r')
Library Declarations
library(htmlwidgets);library(XML);library(ggplot2);library(plotly);
Values$Storiesgrouping <- as.character(Values$Storiesgrouping)
Cols <- as.character(Values$Color)
names(Cols) <- as.character(Values$Builder_CommunityName)
Sizs <- as.numeric(Values$Size)
names(Sizs) <- as.character(Values$Builder_CommunityName)
Actual code
g <- ggplot(Values, aes(x=BaseSquareFeet, y=BasePriceM,
group=Builder_CommunityName, color=Builder_CommunityName))+
geom_line()+
geom_point(aes(shape=Storiesgrouping), show.legend=FALSE,size=3)+
scale_colour_manual(values = Cols)+
scale_size_manual(values = Sizs)+
scale_shape_manual(values=c("1"=19, "2"=15, "3+"=17))
plot(g)
Create and save widget
p = ggplotly(g); internalSaveWidget(p, 'out.html');

How to create an animation of geospatial / temporal data

I have a set of data which contains around 150,000 observations of 800 subjects. Each observation has: subject ID, latitude, longitude, and the time that the subject was at those coordinates. The data covers a 24-hour period.
If I plot all the data at once I just get a blob. Is anyone able to give me some tips as to how I can animate this data so that I can observe the paths of the subjects as a function of time?
I've read the spacetime vignette but I'm not entirely sure it will do what I want. At this point I'm spending a whole lot of time googling but not really coming up with anything that meets my needs.
Any tips and pointers greatly appreciated!
Here my first use of animation package. It was easier than I anticipated and especially the saveHTML is really amazing. Here my scenario(even I think that my R-code will be clearer:)
I generate some data
I plot a basic plot for all persons as a background plot.
I reshape data to get to a wide format in a way I can plot an arrow between present and next position for each person.
I loop over hours , to generate many plots. I put the llop within the powerful saveHTML function.
You get a html file with a nice animation. I show here one intermediate plot.
Here my code:
library(animation)
library(ggplot2)
library(grid)
## creating some data of hours
N.hour <- 24
dat <- data.frame(person=rep(paste0('p',1:3),N.hour),
lat=sample(1:10,3*N.hour,rep=TRUE),
long=sample(1:10,3*N.hour,rep=TRUE),
time=rep(1:N.hour,each=3))
# the base plot with
base <- ggplot() +
geom_point(data=dat,aes(x=lat, y=long,colour = person),
size=5)+ theme(legend.position = "none")
## reshape data to lat and long formats
library(plyr)
dat.segs <- ddply(dat,.(person),function(x){
dd <- do.call(rbind,
lapply(seq(N.hour-1),
function(y)c(y,x[x$time %in% c(y,y+1),]$lat,
x[x$time %in% c(y,y+1),]$long)))
dd
})
colnames(dat.segs) <- c('person','path','x1','x2','y1','y2')
# a function to create the animation
oopt <- ani.options(interval = 0.5)
saveHTML({
print(base)
interval = ani.options("interval")
for(hour in seq(N.hour-1)){
# a segment for each time
tn <- geom_segment(aes(x= x1, y= y1, xend = x2,
yend = y2,colour = person),
arrow = arrow(), inherit.aes = FALSE,
data =subset(dat.segs,path==hour))
print(base <- base + tn)
ani.pause()
}
}, img.name = "plots", imgdir = "plots_dir",
htmlfile = "random.html", autobrowse = FALSE,
title = "Demo of animated lat/long for different persons",
outdir=getwd())
Your question is a bit vague, but I will share how I have done this kind of animation in the past.
Create a function that plots all the subject locations for one time slice:
plot_time = function(dataset, time_id) {
# make a plot with your favorite plotting package (e.g. `ggplot2`)
# Save it as a file on disk (e.g. using `ggsave`), under a regular name,
# frame001.png, frame002.png, see sprintf('frame%03d', time_index)
}
Call this function on each of your timeslices, e.g. using lapply:
lapply(start_time_id:stop_time_id, plot_time)
leading to a set of graphics files on the hard drive called frame001 to framexxx.
Use a tool to render those frames into a movie, e.g. using ffmpeg, see for example.
This is a general workflow, which has been already implemented in the animation package (thanks for reminding me #mdsummer). You can probably leverage that package to get your animation.

Plotting three densities on the same graph in different line patterns with titles etc

I am very, very new to R so please forgive the basic nature of my question. In short, I have done a lot of Google searching to try to answer this, but I find that even the basic guides available, and simple discussions on forums are assuming more prior knowledge than I have, especially when it comes to outlining what all of the coding terms are and what changing them means for a plot.
In short I have a tab formatted table with three columns of data that I wish to plot densities for on a single graph. I would like the lines to be different patterns (dotted, dashed etc. whatever makes it easy to tell them apart, I cannot use colours as my supervisor is colour blind).
I have code that reads in the data and makes accessible the columns I am interested in:
mydata <- read.table("c:/Users/Demon/Desktop/Thesis/Fst_all_genome.txt", header=TRUE,
sep="\t")
fstdata <- data.frame(Fst_ceu_mkk =rnorm(10),
Fst_ceu_yri =rnorm(10),
Fst_mkk_yri =rnorm(10))
Where do I go from here?
Appendix A of 'An Introduction to R' has a nice walkthrough tutorial you can do in ten minutes; it teaches among other things about line types etc
After that, plotting densities was explained dozens of times here too; search in the search box above for eg '[r] density'. There is also the R Graph Gallery (possibly down right now) and more.
A nice, free guide I often recommend is John Verzani's simpleR which stresses graphs a lot and will teach you what you need here.
Two options for you to explore using high-level graphics.
# dummy data
d = data.frame(x = rnorm(10), y = rnorm(10), z = rnorm(10))
You first need to reshape the data from wide to long format,
require(reshape2)
m = melt(d)
ggplot2 graphics
require(ggplot2)
ggplot(data = m, mapping = aes(x = value, linetype = variable)) +
geom_line(stat = "density")
Lattice graphics
Using the same melt()ed data,
require(lattice)
densityplot( ~ value, data = m, group = variable,
auto.key = TRUE, par.settings = col.whitebg())
If you need something very simple, you could do simply:
plot(density(mydata$col_1))
lines(density(mydata$col_2), lty = 2)
lines(density(mydata$col_2), lty = 3)
If the second and third density curves are far away from the first, you'll need define xy limits of the plotting region explicitly:
dens1 <- density(mydata$col_1)
dens2 <- density(mydata$col_2)
dens3 <- density(mydata$col_3)
plot(dens1, xlim = range(dens1$x, dens2$x, dens3$x),
ylim = range(dens1$y, dens2$y, dens3$y))
lines(density(mydata$col_2), lty = 2)
lines(density(mydata$col_2), lty = 3)
Hope this helps.

Resources