I'm attempting to create a map graph with highlighted tiles using highcharter in R.
I managed to retrieve a JSON map, create a dataframe with my data, and generate a highcharter map graph. I'm now customizing the toolip, which should display the country name, region and the number integer in my dataframe's count column. Using the hc_tooltip() function returns the name and region, but doesn't find the values. I suspect this is due to the tooltip function looking in the map data rather than my dataframe. I'm unsure how to change that. Here's an example:
map <- "https://code.highcharts.com/mapdata/custom/world-highres.geo.json" %>%
GET() %>%
content() %>%
jsonlite::fromJSON(simplifyVector = FALSE)
sample_table <- data.frame(name = c("Spain","France","China"),
continent = c("Europe","Europe","Asia"),
occurences = c(150,70,120))
cols3 <- scales::viridis_pal(option = "turbo",
begin = 0.4,
direction = 1)(length(unique(sample_table$name)))
highchart(type = "map") %>%
hc_title(text = "Map Title") %>%
hc_subtitle(text = "Map Subtitle") %>%
hc_add_series_map(map = map, df = sample_table, joinBy = "name", value = "occurences",
dataLabels = list(enabled = TRUE
,format = "{point.properties.hc-a2}")
) %>%
hc_colors(cols3) %>%
hc_colorAxis(stops = color_stops(colors = cols3)) %>%
hc_tooltip(
useHTML = TRUE,
formatter = JS(
"
function(){
outHTML = '<b>' + this.point.name + '</b> <br>' + this.point.continent +
'</b> <br>' + this.point.occurences
return(outHTML)
}
"
))%>%
hc_mapNavigation(enabled = TRUE)
Where the table contains the following
name continent occurences
1 Spain Europe 150
2 France Europe 70
3 China Asia 120
As you can see from the image, I get the country and continent name as intended, but I do not get the number of occurrences. Is there a way to get the tooltip values from both the map data and the dataframe?
When you included hc_add_series_map you defined the value of the variable to chart as "occurences". To include this column in your formatter, try using:
this.point.value
instead of referencing the column name.
Here is the complete example:
library(highcharter)
library(httr)
map <- "https://code.highcharts.com/mapdata/custom/world-highres.geo.json" %>%
GET() %>%
content()
sample_table <- data.frame(name = c("Spain","France","China"),
continent = c("Europe","Europe","Asia"),
occurences = c(150,70,120))
cols3 <- scales::viridis_pal(option = "turbo",
begin = 0.4,
direction = 1)(length(unique(sample_table$name)))
highchart(type = "map") %>%
hc_title(text = "Map Title") %>%
hc_subtitle(text = "Map Subtitle") %>%
hc_add_series_map(map = map,
df = sample_table,
joinBy = "name",
value = "occurences",
dataLabels = list(enabled = TRUE,format = "{point.properties.hc-a2}")
) %>%
hc_colors(cols3) %>%
hc_colorAxis(stops = color_stops(colors = cols3)) %>%
hc_tooltip(
useHTML = TRUE,
formatter = JS(
"
function(){
outHTML = '<b>' + this.point.name + '</b> <br>' + this.point.continent +
'</b> <br>' + this.point.value;
return(outHTML)
}
"
)) %>%
hc_mapNavigation(enabled = TRUE)
Map
Related
I use Leaflet with R quite frequently, but I've not used addPolylines before.
I have a series of lines with origin and destination locations that I'm attempting to plot on a map, and I'm noticing some weird behaviour:
Polylines and markers mapped to the same dataframe are not appearing in the same location.
Labels are not mapping at all to the dataframe, instead only returning the values in the last row for all lines.
Line weight mapping is not working.
I'm not entirely sure what I'm doing wrong here - any help would be appreciated. I've included a reproducible example below.
dummy <- data.frame(
Line_name = c("line1", "line2", "line3"),
origin_lng = c(145.1234, 147.223, 153.225),
origin_lat = c(-17, -19.4, -27.6),
Destination_lng = c(147.223, 153.225, 156.1123),
Destination_lat = c(-19.4, -27.6, -30.5),
Line_weight = c(1, 2, 5)
)
leaflet() %>%
addProviderTiles(provider = providers$Esri.WorldImagery) %>%
setView(lng = 146.612020, lat = -21.628836, zoom = 5) %>%
addMarkers(lng = dummy$origin_lng, lat = dummy$origin_lat, label = "origins") %>%
addPolylines(
lng = c(dummy$origin_lng, dummy$Destination_lng),
lat = c(dummy$Origin_lat, dummy$Destination_lat),
weight = dummy$Line_weight,
label = paste0(
"Line name: ", dummy$Line_name, "<br>",
"Origin coords: ", dummy$origin_lng, " ", dummy$origin_lat, "<br>",
"Destination coords: ", dummy$Destination_lng, " ", dummy$Destination_lat
) %>% lapply(htmltools::HTML)
)
You have to group the lines. You used the columns of dummy as independent vectors but sent no groups. Leaflet doesn't 'know' which labels go with which line segments. Additionally, you did get a popup, but you have to hover. (You only had one, as well.)
So, in short—grouping the data... There is probably an easier way of doing this, but this works. I pivoted longer to going the lat/long. Then I pivoted wider. Essentially, I needed the longs in a column and the lats in a column.
library(leaflet)
library(tidyverse)
dum2 <- dummy %>% pivot_longer(cols = names(.)[2:5], names_to = c("ft", "val"),
names_sep = "_", values_to = "lng_lat") %>%
pivot_wider(id_cols = c("Line_name", "ft", "Line_weight"),
names_from = "val", values_from = "lng_lat")
Then I separated the call for addPolyLines. You need one call for each group.
mp <- leaflet() %>%
addProviderTiles(provider = providers$Esri.WorldImagery) %>%
setView(lng = 146.612020, lat = -21.628836, zoom = 5) %>%
addMarkers(lng = dummy$origin_lng, lat = dummy$origin_lat, label = "origins")
map(dummy$Line_name,
function(group){
mp <<- addPolylines(
mp,
data = dum2[dum2$Line_name == group, ],
lng = ~lng,
lat = ~lat,
weight = ~Line_weight,
labelOptions = list(noHide = T, sticky = T, permanent = T),
label = paste0(
"Line name: ", group, "<br>",
"Origin coords: ", dummy[dummy$Line_name == group, ]$origin_lng,
" ", dummy[dummy$Line_name == group, ]$origin_lat, "<br>",
"Destination coords: ", dummy[dummy$Line_name == group, ]$Destination_lng,
" ", dummy[dummy$Line_name == group, ]$Destination_lat) %>%
lapply(htmltools::HTML))
}
)
I am mapping out zip code areas in leaflet and coloring the polygon based on the Dealer.
Dealer Zipcodes geometry
A 32505 list(list(c(.....)))
B 32505 ....
This code is used to create the colors, labels, and the map.
factpal <- colorFactor(topo.colors(5), data$Dealer)
labels <- paste0("Zip Code: ",data$Zipcodes, ", Dealer: ", data$Dealer)
leaflet(data) %>%
addTiles() %>%
addPolygons( color = ~factpal(Dealer),),
label = labels) %>%
leaflet.extras::addSearchOSM(options = searchOptions(collapsed = FALSE)) %>%
addLegend(pal = factpal, values = ~Dealer,
opacity = 0.7,
position = "bottomright")
When the zip code (and thus the geometry) are the same between two dealers, only one label is visible, though it is clear colors are overlapping. All I want is for that label to somehow show the info for both dealers in that zip code. Please let me know if there is code missing you need, or clarification needed.
Not sure whether you could have multiple tooltips but to show all Dealers in the tooltip you could change your labels such that they include all dealer names per zip code, e.g. making use of dplyr you could do:
library(leaflet)
library(dplyr)
factpal <- colorFactor(topo.colors(5), data$Dealer)
data <- data %>%
group_by(Zipcodes) %>%
mutate(labels = paste(Dealer, collapse = ", "),
labels = paste0("Zip Code: ", Zipcodes, ", Dealer: ", labels))
leaflet(data) %>%
addTiles() %>%
addPolygons(
color = ~factpal(Dealer),
label = ~labels,
weight = 1
) %>%
# leaflet.extras::addSearchOSM(options = searchOptions(collapsed = FALSE)) %>%
addLegend(
pal = factpal, values = ~Dealer,
opacity = 0.7,
position = "bottomright"
)
DATA
nycounties <- rgdal::readOGR("https://eric.clst.org/assets/wiki/uploads/Stuff/gz_2010_us_050_00_20m.json")
nycounties_sf <- sf::st_as_sf(nycounties)
nycounties_sf_n <- nycounties_sf %>%
filter(STATE == "01") %>%
select(Zipcodes = COUNTY, geometry)
data <- list(
A = sample_n(nycounties_sf_n, 40),
B = sample_n(nycounties_sf_n, 40),
C = sample_n(nycounties_sf_n, 40),
D = sample_n(nycounties_sf_n, 40)
)
data <- purrr::imap(data, ~ mutate(.x, Dealer = .y))
data <- do.call("rbind", data)
Maybe it's duplicated with mapbubble does not work with highcharter highmaps but there was no answer to the question...
From the example taken at https://jkunst.com/highcharter/articles/maps.html with a map of type "mappoint", I try to achieve the same with "mapbubble". I created for this a column z
library(httr)
library(jsonlite)
library(geojsonio)
library(highcharter)
library(dplyr)
ausgeojson <- GET("https://raw.githubusercontent.com/johan/world.geo.json/master/countries/AUS.geo.json") %>%
content() %>%
fromJSON(simplifyVector = FALSE) %>%
as.json()
ausmap <- highchart(type = "map") %>%
hc_add_series(mapData = ausgeojson, showInLegend = FALSE)
ausmap
airports <- read.csv("https://raw.githubusercontent.com/ajdapretnar/datasets/master/data/global_airports.csv")
airports <- airports %>%
filter(country == "Australia", name != "Roma Street Railway Station")
airports <- airports %>%
mutate(z=runif(n=nrow(airports),min=1,max=20))
airp_geojson <- geojson_json(airports, lat = "latitude", lon = "longitude")
# works with mappoint
ausmap %>%
hc_add_series(
data = airp_geojson,
type = "mappoint",
dataLabels = list(enabled = FALSE),
name = "Airports",
tooltip = list(pointFormat = "{point.name}")
)
# doesn't work with mapbubble
ausmap %>%
hc_add_series(
data = airp_geojson,
type = "mapbubble",
value = "z",
dataLabels = list(enabled = FALSE),
name = "Airports",
tooltip = list(pointFormat = "{point.name}")
)
The problem is probably due to the fact that {highcharter} cannot access the other columns of the geojson file.
Example if I add another column to the tooltip argument in the mappoint case :
ausmap %>%
hc_add_series(
data = airp_geojson,
type = "mappoint",
dataLabels = list(enabled = FALSE),
name = "Airports",
tooltip = list(pointFormat = "{point.name} : {point.altitude}")
)
I don't see altitude :
I posted this in the plotly community forum but got absolutely no activity! Hope you can help here:
I have map time-series data, some countries don’t have data and plotly does not plot them at all. I can have them outlined and they look different but it appears nowhere that the data is missing there (i.e. I want a legend entry). How can I achieve this? Here is a reprex:
library(plotly)
library(dplyr)
data = read.csv('https://github.com/lc5415/COVID19/raw/master/data.csv')
l <- list(color = toRGB("grey"), width = 0.5)
g <- list(
scope = 'world',
countrycolor = toRGB('grey'),
showframe = T,
showcoastlines = TRUE,
projection = list(type = 'natural earth')
)
map.time = data %>%
plot_geo() %>%
add_trace(z = ~Confirmed, color = ~Confirmed, frame = ~Date, colors = 'Blues',
text = ~Country, locations = ~Alpha.3.code, marker = list(line = l)) %>%
colorbar(title = 'Confirmed') %>%
layout(
title = 'Number of confirmed cases over time',
geo = g
) %>%
animation_opts(redraw = F) %>%
animation_slider(
currentvalue = list(
prefix = paste0("Days from ",
format(StartDate, "%B %dnd"),": "))) %>%
plotly_build()
map.time
Note that the countries with missing data (e.g. Russia) have as many data points as all other countries, the issue is not that they do not appear in the dtaframe passed to plotly.
The obvious way to handle this is to create a separate labels column for the tooltip that reads "No data" for NA values (with the actual value otherwise), then make your actual NA values 0. This will give a uniform appearance to all the countries but correctly tells you when a country has no data.
map.time = data %>%
mutate_if(is.numeric, function(x) {x[is.na(x)] <- -1; x}) %>%
plot_geo() %>%
add_trace(z = ~Confirmed, color = ~Confirmed, frame = ~Date, colors = 'Blues',
text = ~Country, locations = ~Alpha.3.code,
marker = list(line = l)) %>%
colorbar(title = 'Confirmed') %>%
layout(
title = 'Number of confirmed cases over time',
geo = g
) %>%
animation_opts(redraw = F) %>%
animation_slider(
currentvalue = list(
prefix = paste0("Days from ",
format(StartDate, "%B %dnd"),": "))) %>%
plotly_build()
Which gives:
I am trying to draw line chart using Highchart . I need data format in Million format . Ex for the First point in screenshot 2423175 should be shown as 2.42 Million .How do i change format = "{point.y}" to show in Millions
highchart() %>%
hc_add_series(data, hcaes(x = data$Month, y = data$Total, color = data$Total), type = "line",dataLabels = list(
enabled = TRUE,
format = "{point.y} " )
) %>%
hc_tooltip(cros[![enter image description here][1]][1]shairs = TRUE, borderWidth = 1.5,headerFormat= "",
pointFormat = paste("Year: <b>{point.x:%b-%y}</b> <br> Population: <b>{point.y}</b>")) %>%
hc_title(text = "Population by year") %>%
hc_subtitle(text = "2016-2020") %>%
hc_xAxis(type = "datetime", title = list(text = "Year")) %>%
hc_yAxis(title = list(text = "count per year")) %>%
hc_legend(enabled = FALSE) %>%
hc_add_theme(custom_theme)
Here is a 2 step way of doing it:
First, you need to format your numbers from looking like 2423175 to 2.42 before you create your plot.
data$Total <- format(round(data$Total / 1e6, 1), trim = TRUE)
Next, in order to add 'Million' after your numbers in Highcharter, change format from format = "{point.y} " to format = paste("{point.y} Million") while creating your plot. Your numbers should now be displayed in the format "X.XX Million".
You can use dataLabels.formatter: https://api.highcharts.com/highcharts/series.line.dataLabels.formatter to format your dataLabels. I know how to do it in JavaScript and inject this code inside JS() function in R:
hc_add_series(data, hcaes(x = data$Month, y = data$Total, color = data$Total), type = "line",dataLabels = list(
enabled = TRUE,
formatter = JS("function() {
return (this.y / 1000000).toFixed(2) + 'M'
}") )
) %>%
JS example: https://jsfiddle.net/BlackLabel/o49zcjLv
Let me know if it worked.
Edit: The whole working code with sample data:
library(highcharter)
data <- data.frame(
y = c(54324232,85325324,10424324,44234324,74324234, 44321413))
highchart() %>%
hc_add_series(data, type = "line", hcaes(y = y), dataLabels = list(
enabled = TRUE,
formatter = JS("function() {
return (this.y / 1000000).toFixed(2) + 'M'
}"
)))