Is there a way to have a highlighted chart as well as have interactivity of selecting elements in R? - r

I have come across a beautiful chart on this webpage: https://ourworldindata.org/coronavirus and interested to know if we can build the same chart in R with functionality of having highlighted series as well as selecting any line on hovering ?
I have build static highlighted charts using gghighlight but those are not interactive.
Plotly can help in interaction but I think they don't work with gghighlight.
So how can we have the combination of both highlight and interactivity in charts as in the link shared on top ?
Is it possible to achieve same results in R ? It would be really helpful if someone could share an example or link that can help.
(UPDATE: May be I can manually highlight lines by creating a factor column instead of using gghighlight and then pass it to ggplotly but then can ggplotly or some other library provide similar results on hover ?)
(NOTE: Not looking for animation. Just need highlighted, hover over interactive chart)
Below is the snapshot of same chart hovered over US (This chart is also similar to the one shared in World Economic Forum many times.)

Using plotly you can use highlight() to achive this.
This is a slightly modified example from here:
library(plotly)
# load the `txhousing` dataset
data(txhousing, package = "ggplot2")
# declare `city` as the SQL 'query by' column
tx <- highlight_key(txhousing, ~city)
# initiate a plotly object
base <- plot_ly(tx, color = I("black")) %>%
group_by(city)
# create a time series of median house price
time_series <- base %>%
group_by(city) %>%
add_lines(x = ~date, y = ~median)
highlight(
time_series,
on = "plotly_hover",
selectize = FALSE,
dynamic = FALSE,
color = "red",
persistent = FALSE
)

Related

Highlight a Specific Section of a Treemap using Treemap package in R

I am using the Treemap package in R to highlight the number of COVID outbreaks in different settings. I am making a number of different reports using R Markdown. Each one describes a different type of settings and I would like to highlight that setting in the treemap for each report, showing what proportion of total outbreaks occur in the setting in question. For example you I am currently working on the K-12 school report and would like to highlight the box representing that category in the figure.
I was previously using an exploded donut pie chart however there were two many subcategories and the graph became hard to read.
I am picturing a way to change the label or border on one specific box, ie. put a yellow border around the box or make the label yellow. I found a way to do both these things for all the boxes but not just one specific box. I made this image using the snipping tool to further illustrate what the desired outcome might look like. The code to generate the treemap can be found in the link below. It looks like this:
# library
library(treemap)
# Build Dataset
group <- c(rep("group-1",4),rep("group-2",2),rep("group-3",3))
subgroup <- paste("subgroup" , c(1,2,3,4,1,2,1,2,3), sep="-")
value <- c(13,5,22,12,11,7,3,1,23)
data <- data.frame(group,subgroup,value)
# treemap
treemap(data,
index=c("group","subgroup"),
vSize="value",
type="index"
)
This is the most straightforward information I can find about the package, this is where I took the sample image and code from: https://www.r-graph-gallery.com/236-custom-your-treemap.html
It looks like the treemap package doesn't have a built-in way to do this. But we can hack it by using the data frame returned by treemap() and adding a rectangle to the appropriate viewport.
# Plot the treemap and save the data used for plotting.
t = treemap(data,
index = c("group", "subgroup"),
vSize = "value",
type = "index"
)
# Add a rectangle around subgroup-2.
library(grid)
library(dplyr)
with(
# t$tm is a data frame with one row per rectangle. Filter to the group we
# want to highlight.
t$tm %>%
filter(group == "group-1",
subgroup == "subgroup-2"),
{
# Use grid.rect to add a rectangle on top of the treemap.
grid.rect(x = x0 + (w / 2),
y = y0 + (h / 2),
width = w,
height = h,
gp = gpar(col = "yellow", fill = NA, lwd = 4),
vp = "data")
}
)

How do you save a Highcharter chart as a gif in R?

I work with financial data that is mostly non-continuous, meaning market closing times and weekends need to be omitted from graphs.
Highcharter seems good at handling such data but how do you convert its charts into gifs? I know how to do this with ggplot and gganimate, but that combination does not handle financial data well.
Below is a simple line chart (of 10-year Treasury yields) done in Highcharter but I'd like to animate it and save it as a gif. Any help would be appreciated.
#load packages -------
library(here)
library(tidyverse)
library(highcharter)
# read in data -------
unemployment <- read_csv(here("data", "US 10-year Treasury.csv"))
# Line chart
data <- data.frame(unemployment)
hc <- data %>% hchart(
'line', hcaes(x = Date, y = Yield),
color = "steelblue"
)
hc
This functionality is not offered in the standard Highcharts library, therefore it has not been implemented in the Highcharter wrapper. Maybe R has some built-in tools for that gif export, unfortunately, I have no experience with it.

Retrieve axis tick information from a plotly figure

I'm plotting a heatmap using R plotly:
set.seed(1)
df <- reshape2::melt(matrix(rnorm(100*20),100,20,dimnames = list(paste0("G",1:100),paste0("S",1:20))))
library(plotly)
library(dplyr)
plot_ly(z=c(df$value),x=df$Var2,y=df$Var1,colors=grDevices::colorRamp(c("darkblue","gray","darkred")),type="heatmap",colorbar=list(title="Scaled Value",len=0.4)) %>%
layout(yaxis=list(title=NULL),xaxis=list(tickangle=90,tickvals=10,ticktext="X-Label"))
As you can see, plotly is not showing all y-axis ticks. My question is whether it is possible, and if so how, to retrieve the y-axis tick labels plotly selected to show?
I saved the plot object:
plotly.obj <- plot_ly(z=c(df$value),x=df$Var2,y=df$Var1,colors=grDevices::colorRamp(c("darkblue","gray","darkred")),type="heatmap",colorbar=list(title="Scaled Value",len=0.4)) %>%
layout(yaxis=list(title=NULL),xaxis=list(tickangle=90,tickvals=10,ticktext="X-Label"))
And looked around and it seems that perhaps plotly.obj$x$layoutAttrs should store this information but it doesn't:
> plotly.obj$x$layoutAttrs
$`102ce55fd393e`
$`102ce55fd393e`$yaxis
$`102ce55fd393e`$yaxis$title
NULL
$`102ce55fd393e`$xaxis
$`102ce55fd393e`$xaxis$tickangle
[1] 90
$`102ce55fd393e`$xaxis$tickvals
[1] 10
$`102ce55fd393e`$xaxis$ticktext
[1] "X-Label"
Any idea?
I don't think you can get the ticks, that are finally rendered. But you can get all the levels of the y-axis, that ploty can choose from.
levels(plotly.obj$x$attrs$`2c4c148651ae`$y)
The ticks that are finally rendered are dynamically chosen and will adapt, depending on your plot size etc.
You can also check out the attributes with plotly_json():
plot_ly(z=c(df$value),x=df$Var2,y=df$Var1,colors=grDevices::colorRamp(c("darkblue","gray","darkred")),type="heatmap",colorbar=list(title="Scaled Value",len=0.4)) %>%
layout(yaxis=list(title=NULL),xaxis=list(tickangle=90,tickvals=10,ticktext="X-Label")) %>%
plotly_json()
I got the answer from a github issue I posted on ropensci/plotly:
set.seed(1)
df <- reshape2::melt(matrix(rnorm(100*20),100,20,dimnames = list(paste0("G",1:100),paste0("S",1:20))))
library(plotly)
library(dplyr)
plot_ly(z=c(df$value),x=df$Var2,y=df$Var1,colors=grDevices::colorRamp(c("darkblue","gray","darkred")),type="heatmap",colorbar=list(title="Scaled Value",len=0.4)) %>%
layout(yaxis=list(title=NULL),xaxis=list(tickangle=90,tickvals=10,ticktext="X-Label")) %>%
htmlwidgets::onRender(
"function(el, x) {
alert(el._fullLayout.yaxis._vals.map(function(i) { return i.text; }));
}"
)
Will pop up a browser window with the tick labels.
The question now is if this can be saved/piped to an R variable or written to a file so it can be done automatically rather than interactively. That's going to be another post.

Optimising Shiny + Leaflet performance for detailed maps with many 'layers'

I want to make a Shiny app where the colouring of a choropleth is based on a numeric value of one of many possible quantitative variables that a user can select from. In simple cases, this is straightforward, but I'm unsure of the best practices when we have 20+ variables, with quite detailed shape files (~2300 polygons).
It might or might not be relevant that the variables might be completely independent to each other such as 'Total Population' or 'Average Temperature' but some of them will have a temporal relationship such as 'Total Population' at 3 or more points in time.
One of the main shapefiles I am using is the ABS Statistical Area 2. Below I give the population density (total population/area) for Australia and a zoomed in view of Sydney to better convey the level of detail I'm interested in.
Australia
Sydney
I have read the shapefile in to R and greatly reduced the complexity/number of points using the ms_simplify() function in the rmapshaper package.
Now as far as Shiny and leaflet go, this is what I have been doing:
Before the server object is defined in server.R, I build a primary map object with all the desired 'layers'. That is, a leaflet with numerous addPolygon() calls to define the colouring of each 'layer' (group).
# Create main map
primary_map <- leaflet() %>%
addProviderTiles(
providers$OpenStreetMap.BlackAndWhite,
options = providerTileOptions(opacity = 0.60)
) %>%
# Layer 0 (blank)
addPolygons(
data = aus_sa2_areas,
group = "blank"
) %>%
# Layer 1
addPolygons(
data = aus_sa2_areas,
fillColor = ~palette_layer_1(aus_sa2_areas$var_1),
smoothFactor = 0.5,
group = "layer_1"
) %>%
...
# Layer N
addPolygons(
data = aus_sa2_areas,
fillColor = ~palette_layer_n(aus_sa2_areas$var_n),
smoothFactor = 0.5,
group = "layer_n"
) %>% ...
All bar the first layer is then hidden using hideGroup() so that the initial rendering of the map doesn't look silly.
hideGroup("layer_1") %>%
hideGroup("layer_2") %>%
...
hideGroup("layer_n")
In the Shiny app, using radio buttons (layer_selection), the user can select the 'layer' they'd like to see. I use observeEvent(input$layer_selection, {}) to watch the status of the radio button options.
To update the plot, I use leafletProxy() and hideGroup() to hide all the groups and then showGroup() to unhide the selected layer.
I apologize for the lack of reproducible example.
Questions
How can I optimise my code? I am eager to make it more performant and/or easy to work with. I've found using hideGroup()'s/showGroup() for each layer selection is far faster than using addPolygon() to a blank map, but this causes the app to take a very significant amount of time to load.
Can I change the variable I am colouring the polygons by, without redrawing or adding those polygons again? To clarify, if I have 2 different variables to plot, both using the same shape data, do I have to do 2 distinct addPolygon() calls?
Is there a more automatic way to sensibly colour the polygons for each layer according to a desired palette (from the viridis package?). Right now I'm finding defining a new palette for each variable, rather cumbersome, eg:
palette_layer_n <- colorNumeric(
palette = "viridis",
domain = aus_sa2_areas$aus_sa2_areas$var_n
)
Side Question
How does this map on the ABS website work? It can be incredibly detailed and yet extremely responsive. Compare the Mesh Block detail to the SA2 (2310 polygons), example below:
Since you haven't gotten any answers yet, I'll post a few things that can maybe help you, based on a simple example.
It would of course be easier if yours was reproducible; and I suppose from looking around you have already seen that there are several related issues / requests (about re-coloring polygons), whereas it doesn't seem that a real solution has made it into any release (of leaflet) yet.
With the below work-around you should be able to avoid multiple addPolygons and can cover an arbitrary number of variables (for now I have just hard-coded a single variable into the modFillCol call though).
library(leaflet)
library(maps)
library(viridis)
mapStates = map("state", fill = TRUE, plot = FALSE)
# regarding Question 3 - the way you set the domain it looks equivalent
# to just not setting it up front, i.e. domain = NULL
myPalette <- colorNumeric(
palette = "viridis",
domain = NULL
)
mp <- leaflet(data = mapStates) %>%
addTiles() %>%
addPolygons(fillColor = topo.colors(10, alpha = NULL), stroke = FALSE)
# utility function to change fill color
modFillCol <- function(x, var_x) {
cls <- lapply(x$x$calls, function(cl) {
if (cl$method == "addPolygons") {
cl$args[[4]]$fillColor <- myPalette(var_x)
}
cl
})
x$x$calls <- cls
x
}
# modify fill color depending on the variable, in this simple example
# I just use the number of characters of the state-names
mp %>%
modFillCol(nchar(mapStates$names))

Disable rCharts animations

I am using rCharts and shiny in order to plot a variety of datasets. These datasets are dynamic and may in some cases be very big (10 000+ points in some cases). In these cases displaying the plot takes a lot of time (40s+).
Is there a way to generate an rCharts plot without the animations. This should significantly reduce the creating and rendering time of the plot.
I have looked trough the documentation (ltle that there is), but haven't found a way to do it.
The only thing that i have found is https://gist.github.com/timelyportfolio/10184829
I am using Polycharts, NVD3 and HighCharts.
EDIT: For highCharts i can do p$tooltip(enabled = F) and p$chart(animation = F). But any additional help would be appreciated, especially for Polycharts and NVD3
I am not a heavy user of Polycharts and Highcharts, so if you could add an example it would be helpful.
For NVD3 the variable is called transitionDuration.
An example of a chart without animations would be as follows:
library(rCharts)
hair_eye = as.data.frame(HairEyeColor)
p2 <- nPlot(Freq ~ Hair, group = 'Eye',
data = subset(hair_eye, Sex == "Female"),
type = 'multiBarChart')
p2$chart(transitionDuration=0)
p2

Resources