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:
Related
I'm currently making a choropleth map in plotly that tracks the population of ever US state from 1910 - 2020. The data is sorted into categorical variables with the percent change of every state in a decade. When I run my code the first year (1910) looks right, however when pressing "play" or moving the slider to any other year the colorscale resets to the default and the discrete scale and ticks are replaced with a continuous version. To be honest, I'm completely lost as to why only the first frame is correct, and when I return to the first frame after navigating to any of the other frames it changes to be like the other frames (colorscale wise).
Here is my code:
`
library(plotly)
library(dplyr)
library(readr)
library("RColorBrewer")
states <- read_csv("states.csv")
AllCountryPop <- read_csv("All50%d.csv",
col_types = cols(Year = col_number(),
Percent = col_number()))%>%
inner_join(states, by.x = State, by.x = state) %>%
select(Year, Code, Percent, Category) %>%
mutate(hover = paste(Code, "\n", 100*Percent, "%"))
AllCountryPop$Category = factor(AllCountryPop$Category)
AllCountryPop$Val = as.numeric(AllCountryPop$Category)
nfactor = length(levels(AllCountryPop$Category))
colr <- brewer.pal(n = nfactor,name = "Blues") #Color scale should be blue with five leves (for each category)
levels(AllCountryPop$Category) <- c("-30% - 0%" , "0% - 30%", "30% - 60%", "60% - 90%", "90% - 130%")
names(colr) = levels(AllCountryPop$Category)
colrS = function(n){
CUTS = seq(0,1,length.out=n+1)
rep(CUTS,ifelse(CUTS %in% 0:1,1,2))
}
graph_properties <- list(
scope = 'usa',
showland = TRUE,
landcolor = toRGB("white"),
color = toRGB("white")
)
font = list(
family = "DM Sans",
size = 15,
color = "black"
)
label = list(
bgcolor = "#EEEEEE",
bordercolor = "transparent",
font = font
)
colorScale <- data.frame(z=colrS(nfactor),
col=rep(colr,each=2),stringsAsFactors=FALSE)
p <- plot_geo(AllCountryPop,
locationmode = "USA-states",
frame = ~Year)%>%
add_trace(locations = ~ Code,
locationmode = "USA-states",
z = AllCountryPop$Val,
zmin = min(AllCountryPop$Val),
zmax = max(AllCountryPop$Val),
text = ~hover,
hoverinfo = 'text',
colorbar=list(tickvals=1:nfactor, ticktext=names(colr)),
colorscale= colorScale) %>%
layout(geo = graph_properties,
title = "Population Percent Change in the US\n1910 - 2020",
font = list(family = "DM Sans")) %>%
config(displayModeBar = FALSE) %>%
style(hoverlabel = label) %>%
colorbar(title = "Percent")
p
`
In case my CSV data may be of use:
The first two lines of "states.csv":
"State","Abbrev","Code" "Alabama","Ala.","AL"
The first two lines of "All50%d.csv":
State,Percent,Year,Category Alabama,0.051,2020,0% - 30%
P.S. First time asking a question here, please let me know if I need to change how I ask a question, provide info, etc,
I'm struggeling on a simple task. I have a database with 3 columns :
Year (numeric)
Age (numeric)
Pop (numeric)
Part60 : The % of individuals with age >= 60 (string like '% of poeple over 60 : 12%'). This value is the same for each rows of a year.
Dataset looks like :
I built a plotly bargraph with a frame based on the year. So I have a slider which allow me to show for each age the number of individuals and this is animated year by year.
I would like to add an anotation which shows the value of Part60 for the year of the frame... I know that it's possible with a ggplot sent to ggplotly function, however I want to do it from scratch with a plot_ly function as parameters are (for me) easier to control and follow the logic of my code.
This is my code :
gH <- plot_ly(data = dataH,
name = 'Hommes',
marker = list(color = ispfPalette[4]),
x = ~Pop,
y = ~Age,
frame = ~Annee)
gH <- gH %>% layout(yaxis = list(categoryorder="array",
categoryarray=dataH$Age))
gH <- gH %>% layout(yaxis = list(title = '',
zeroline = TRUE,
showline = TRUE,
showticklabels = TRUE,
showgrid = FALSE),
xaxis = list(title = '',
zeroline = TRUE,
showline = TRUE,
autorange = "reversed"),
shapes = hline(60))
gH <- gH %>% add_annotations(
x = 3000,
y = 62,
text = 'Part des 60 ans et + : 12 %',
showarrow = F,
color = ispfPalette[8]
Where text = 'Part des 60 ans et + : 12 %' should be replaced by something which allow me to get the value which belongs to the year of the slider.
Is someone may help me to do it ?
Thanks in advance for your great help.
Since I don't have your data, it's pretty difficult to give you the best answer. Although, here is a method in which you can add text that changes throughout the animation.
library(plotly)
library(tidyverse)
data(gapminder, package = "gapminder")
str(gapminder)
funModeling::df_status(gapminder)
# continent, lifeExp, year
gap <- gapminder %>% group_by(year, continent) %>%
summarise(Expectancy = mean(lifeExp))
# plot
p1 <- plot_ly(gap, x = ~Expectancy, y = ~continent,
frame = ~year, type = 'bar',
showlegend = F,
hovertemplate = paste0("Continent: %{y}<br>",
"<extra></extra>"),
texttemplate = "Life Expectancy: %{x:.2f}") %>%
layout(yaxis=list(title=""),
xaxis=list(title="Average Life Expectancy per Continent By Year"),
title=list(text=paste("Fancy Title")),
margin = list(t = 100))
p1
If you had text you wanted to animate that is not connected to each marker (bar, point, line), then you could do it this way.
# Something to add in the annotation text
gap2 <- gap %>% filter(continent == "Asia") %>%
droplevels() %>%
arrange(year)
# build to see frames
p2 <- plotly_build(p1)
# modify frames; need an annotation for each frame
# make sure the data is in order by year (order by frame)
lapply(1:nrow(gap2), # for each frame
function(i){
annotation = list(
data = gap2,
type = "text",
x = 77,
y = .5,
yref = "paper",
showarrow = F,
text = paste0("Asian Life Expectancy<br>",
sprintf("%.2f", gap2[i, ]$Expectancy)),
font = list(color = "#b21e29", size = 16))
p2$x$frames[[i]]$layout <<- list(annotations = list(annotation)) # change plot
})
p2
If anything is unclear, let me know.
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)
I was using Highchart to plot some time series and wanted to add some annotation to the plot to highlight some key points. I knew putting the cursor on the graph can pop up the context, however, some automatic graph generation is needed and hence annotating is the best approach.
And I did that, with the last line in the code below. However, the effect is not what I expected. The text was located at the bottom left corner, not located at the right horizontal position yet the vertical position is right. The time series are created using xts library, which means the horizontal axis is simply the date data structure, nothing fancy. xValue is specified as the 900th element of all the time points which have a total length of 1018, so the 900th time point must be in the second half of the graph.
Anyone knows how I can put the annotation at the right location? Many thanks.
hc <- highchart(type = "stock") %>%
hc_title(text = "Some time series") %>%
hc_add_series(x, color='green', name="x", showInLegend = TRUE) %>%
hc_add_series(y, color='red', name="y", showInLegend = TRUE) %>%
hc_add_series(z, color='blue', name="z", showInLegend = TRUE) %>%
hc_navigator(enabled=FALSE) %>%
hc_scrollbar(enabled=FALSE) %>%
hc_legend(enabled=TRUE, layout="horizontal") %>%
hc_annotations(list(enabledButtons=FALSE, xValue = index(x)[900], yValue = -5, title =list(text = "Hello world! How can I make this work!")))
hc
The data can be roughly generated using the following script:
dt <- seq(as.Date("2014/1/30"), as.Date("2018/2/6"), "days")
dt <- dt[!weekdays(dt) %in% c("Saturday", "Sunday")]
n <- length(dt)
x <- xts(rnorm(n), order.by=dt)
y <- xts(rnorm(n), order.by=dt)
z <- xts(rnorm(n), order.by=dt)
Let's star with the #kamil-kulig example, this will be a little out of R world but I want to give some justification if you don't mind.
If we see annotations options is not a object but a list of object(s), so in highcharter is implemented the hc_add_annotation function.
Now, you are using a old version of highcharter. Highcharter devlopment version is using v6 of highchartsJS which made some changes: before the annotations.js was a pluging now is included as a module with some changes in the names of arguments.
Example I: Simple
The example by Kamil Kulig is replicated doing:
highchart(type = "stock") %>%
hc_add_annotation(
labelOptions = list(
backgroundColor = 'rgba(255,255,255,0.5)',
verticalAlign = 'top',
y = 15
),
labels = list(
list(
point = list(
xAxis = 0,
yAxis = 0,
x = datetime_to_timestamp(as.Date("2017/01/02")),
y = 1.5
),
text = "Some annotation"
)
)
) %>%
hc_xAxis(
minRange = 1
) %>%
hc_add_series(
pointStart = start,
pointInterval = day,
data = c(3, 4, 1)
)
Example II: With your data
Be careful in the way you add the x position. Highcharter include a datetime_to_timestamp function to convert a date into a epoch/timestap which is required for highcharts.
library(xts)
dt <- seq(as.Date("2014/1/30"), as.Date("2018/2/6"), "days")
dt <- dt[!weekdays(dt) %in% c("Saturday", "Sunday")]
n <- length(dt)
x <- xts(rnorm(n), order.by=dt)
y <- xts(rnorm(n), order.by=dt)
z <- xts(rnorm(n), order.by=dt)
highchart(type = "stock") %>%
hc_title(text = "Some time series") %>%
hc_add_series(x, color='green', name="x", showInLegend = TRUE) %>%
hc_add_series(y, color='red', name="y", showInLegend = TRUE) %>%
hc_add_series(z, color='blue', name="z", showInLegend = TRUE) %>%
hc_navigator(enabled=FALSE) %>%
hc_scrollbar(enabled=FALSE) %>%
hc_legend(enabled=TRUE, layout="horizontal") %>%
hc_add_annotation(
labels = list(
list(
point = list(
xAxis = 0,
yAxis = 0,
x = datetime_to_timestamp(as.Date(index(x)[900])),
y = 1
),
text = "Hello world! How can I make this work!"
)
)
)
I'm trying to create a scatter plot in highcharts shiny R but I need to give a different color to points, individually. Consider for instance the following example:
library("MASS")
dscars <- round(mvrnorm(n = 20, mu = c(1, 1), Sigma = matrix(c(1,0,0,1),2)), 2)
highchart() %>%
hc_chart(type = "scatter", zoomType = "xy") %>%
hc_tooltip(
useHTML = TRUE,
pointFormat = paste0("<span style=\"color:{series.color};\">{series.options.icon}</span>",
"{series.name}: <b>[{point.x}, {point.y}]</b><br/>")
) %>%
hc_add_series(data = list.parse2(as.data.frame(dscars)),
marker = list(symbol = fa_icon_mark("car")),
icon = fa_icon("car"), name = "car")
My objective is to give to this 20 points, an unique color.
I tried to set the "fillColor" inside marker list as also as to define the color of the series, both with a vector of 20 colors but I had no success.
Can any one give me a hint?
Thank you
In highcharts (the highcharter) the point can be given as other parameter, same as x and y. So first
library("MASS")
dscars <- round(mvrnorm(n = 20, mu = c(1, 1), Sigma = matrix(c(1,0,0,1),2)), 2)
dscars <- as.data.frame(dscars)
names(dscars) <- c("x", "y") # it's better give a named list IMHO
dscars$color <- colorize(1:nrow(dscars))
colorizeis a function to create a color vector given other vector. In this case the input vector is a sequence (no repeated) so the output will be differents colors. But if you want yo can use your own colors.
highchart() %>%
hc_chart(type = "scatter", zoomType = "xy") %>%
hc_tooltip(
useHTML = TRUE,
pointFormat = paste0("<span style=\"color:{point.color};\">{series.options.icon}</span>",
"{series.name}: <b>[{point.x}, {point.y}]</b><br/>")
) %>%
hc_add_series(data = list_parse(dscars),
marker = list(symbol = fa_icon_mark("car")),
icon = fa_icon("car"), name = "car")
Note we used:
color:{point.color}; in the poinFormat, beacuse every point has its own color in the color accesor.
I used list_parse which parse the data frame in a named list instead of unnamed list so highcharts understand how to use the data. list_parse is the same list.parse3 for old version of highcharts.
Hope it helps.
Is this what you want?
rm(list = ls())
library(highcharter)
library(MASS)
dscars <- data.frame(round(mvrnorm(n = 20, mu = c(1, 1), Sigma = matrix(c(1,0,0,1),2)), 2))
highchart() %>%
hc_chart(type = "scatter", zoomType = "xy") %>%
hc_tooltip(
useHTML = TRUE,
pointFormat = paste0("<span style=\"color:{colorByPoint:true};\">{series.options.icon}</span>",
"{series.name}: <b>[{point.x}, {point.y}]</b><br/>")
) %>%
hc_add_series(data = list.parse2(as.data.frame(dscars)),colorByPoint = TRUE,
marker = list(symbol = fa_icon_mark("car")),
icon = fa_icon("car"), name = "car")