Related
I want to design a worldmap to show from which country and which city the participants to my survey come from. I used the highcharter package.
First part is : colour the countries --> it worked well ! A scale is created from 0 to 1.
Second part is : adding the cities --> the points are created but the countries colored in blue disappeared ! The scale has changed and is now induced from cities.
I try to change the order of my code but nothing is working.
library(dplyr)
library(maps)
library(magrittr)
# I use the dataset called iso3166 from the {maps} package and rename it date
dat <- iso3166
head(dat)
# I rename the variable a3 by iso-a3
dat <- rename(dat, "iso-a3" = a3)
head(dat)
# I create a vector with the countries I want to colour
part1X_countries <- c("CHE", "FRA", "USA", "GBR", "CAN", "BRA")
dat$part1X <- ifelse(dat$`iso-a3` %in% part1X_countries, 1, 0)
head(dat)
# I add the name of cities with geographical coordinates
cities <- data.frame(
name = c("St Gallen", "Fort Lauderdale", "Paris", "Nottingham", "Winnipeg", "Chicago", "Leeds", "Montréal", "New Rochelle", "São Paulo", "Saint-Genis-Pouilly", "Canterbury"),
lat = c(47.42391, 26.122438, 48.866667, 52.950001, 49.8955, 41.881832, 53.801277, 45.5016889, 40.9232, -23.5489, 46.24356, 51.279999),
lon = c(9.37477, -80.137314, 2.333333, -1.150000, -97.1383, -87.623177, -1.548567, -73.567256, -73.7793, -46.6388, 6.02119, 1.080000))
# I create my worldmap with countries and cities
worldmap <- hcmap(
map = "custom/world-highres3", # high resolution world map
data = dat, # name of dataset
value = "part1X",
joinBy = "iso-a3",
showInLegend = FALSE, # hide legend
download_map_data = TRUE
) %>%
hc_add_series(
data = cities,
type = "mappoint",
name = "Cities"
) %>%
hc_title(text = "Representation of participants by country")```
You need to define a colorkey and add a color axis for the hcmap. The below code keeps the colors from the countries and has the name of the countries added on top as black map points.
worldmap <- hcmap(
map = "custom/world-highres3", # high resolution world map
data = dat, # name of dataset
value = "part1X",
joinBy = "iso-a3",
colorKey = "value",
showInLegend = F, # hide legend
download_map_data = TRUE) %>%
hc_colorAxis(min = min(dat$part1X),
max = max(dat$part1X)) %>%
hc_add_series(
data = cities,
type = "mappoint",
name = "Cities",
dataLabels = list(enabled = TRUE, format = '{point.name}'),
latField = "lat",
longField = "lon",
# color = "color"
valueField = "part1X"
) %>%
hc_title(text = "Representation of participants by country")
worldmap
I have this network graph that I made using the "igraph" library:
library(tidyverse)
library(igraph)
set.seed(123)
n=15
data = data.frame(tibble(d = paste(1:n)))
relations = data.frame(tibble(
from = sample(data$d),
to = lead(from, default=from[1]),
))
data$name = c("new york", "chicago", "los angeles", "orlando", "houston", "seattle", "washington", "baltimore", "atlanta", "las vegas", "oakland", "phoenix", "kansas", "miami", "newark" )
graph = graph_from_data_frame(relations, directed=T, vertices = data)
(edge_fac <- forcats::as_factor(get.edgelist(graph)[,1]))
n2 <- as.integer(factor(data$name,levels = levels(edge_fac)))
V(graph)$color <- ifelse(data$d == relations$from[1], "red", "orange")
V(graph)$label <- paste0(data$name,"\n\n\n",n2)
plot(graph, layout=layout.circle, edge.arrow.size = 0.2, main = "my_graph")
Is it somehow possible to convert the above graph into a "visnetwork" graph, so that it looks like this?
I know there is a function ( visIgraph() ) meant for converting "igraph" graps to "visnetwork" graphs: https://www.rdocumentation.org/packages/visNetwork/versions/2.1.0/topics/visNetwork-igraph
But I am not sure if I can transform the first "igraph" graph (with both "numeric" and "text" labels) into an interactive "visnetwork" graph.
I tried to do this with the following code :
visIgraph(graph)
But this creates an interactive graph without the "number" labels.
Is it possible to do this?
Thank you!
You have to do a bit of manipulation to make this work because this uses base R plotting.
Essentially, these are two different igraph objects lying on top of each other. This is the only way I could think of to have two different 'cex' sizes. It may require a bit of finesse, depending on where you go from here.
library(tidyverse)
library(igraph)
library(gridGraphics) # <--- I'm new!
library(grid) # <--- I'm new!
#----------- from question -----------
set.seed(123)
n=15
data = data.frame(tibble(d = paste(1:n)))
relations = data.frame(tibble(
from = sample(data$d),
to = lead(from, default=from[1]),
))
data$name = c("new york", "chicago", "los angeles", "orlando",
"houston", "seattle", "washington", "baltimore",
"atlanta", "las vegas", "oakland", "phoenix",
"kansas", "miami", "newark" )
graph = graph_from_data_frame(relations,
directed=T,
vertices = data)
(edge_fac <- forcats::as_factor(get.edgelist(graph)[,1]))
n2 <- as.integer(factor(data$name,levels = levels(edge_fac)))
V(graph)$color <- ifelse(data$d == relations$from[1],
"red", "orange")
This is where the changes begin.
#---------- prepare the first plot -----------
# make label text larger
V(graph)$label.cex = 1.5
# V(graph)$label <- paste0(data$name,"\n",n2)
V(graph)$label <- paste0(n2) # just the number instead
#---------- prepare to collect grob ----------
# collect base plot grob
grabber <- function(){
grid.echo()
grid.grab()
}
# create a copy for the top layer
graph2 <- graph
#-------------- plot and grab ----------------
# without arrow sizes
plot(graph, layout=layout.circle, main = "my_graph")
# grab the grob
g1 = grabber()
Now for the second graph; the top layer
#----------- create the top layer -------------
# with the copy, make the vertices transparent
V(graph2)$color <- "transparent"
# reset the font size
V(graph2)$label.cex = 1
# shift the labels below (while keeping the plot design the same)
V(graph2)$label <- paste0("\n\n\n\n", data$name)
# show me
plot(graph2, layout=layout.circle,
main = "my_graph",
edge.color = "transparent") # invisible arrows/ only 1 layer of arrows
# grab the grob
g2 = grabber()
Layer them!
#-------------- redraw the plots -------------
# make the plot background transparent on the top layer
g2[["children"]][["graphics-background"]][["gp"]][["fill"]] <- "transparent"
# draw it!
grid.draw(g1)
grid.draw(g2)
You might find it interesting that the graphs going into the grob look different than what comes out of them...grid essentially adjusts them. I thought that was kind of awesome.
What about creating the graph using visNetwork? You could then add both the number and name as a label inside the nodes.
library(tidyverse)
library(visNetwork)
set.seed(123)
n=15
data = data.frame(tibble(id = paste(1:n)))
relations = data.frame(tibble(
from = sample(data$id),
to = lead(from, default=from[1]),
))
data$name = c("new york", "chicago", "los angeles", "orlando", "houston", "seattle", "washington", "baltimore", "atlanta", "las vegas", "oakland", "phoenix", "kansas", "miami", "newark" )
data$shape ='circle'
data$label = paste0(data$id,'\n',data$name)
data$color = ifelse(data$id==1, 'red', 'orange')
visNetwork(data, relations, width = "100%") %>%
visEdges(arrows =list(to = list(enabled = TRUE))) %>%
visIgraphLayout(layout = "layout_in_circle")
I created the following two graphs using igraph:
t1terms <- c("fire",
"people",
"residents",
"victims",
"affected",
"please",
"can",
"london",
"support",
"survivors")
t1labels <- as.vector(t1terms)
g<-graph.full(n=10, directed = FALSE, loops = FALSE) %>%
set_vertex_attr("label", value = t1labels)
t2terms <- c("fire",
"victims",
"says",
"people",
"cladding",
"police",
"may",
"will",
"dead",
"theresa")
t2labels <- as.vector(t2terms)
g1<-graph.full(n=10, directed = FALSE, loops = FALSE) %>%
set_vertex_attr("label", value = t2labels)
I can't figure out how to merge the two graphs without duplicating common nodes. I really appreciate some help. I tried 'graph.union', but it didn't work.
Thank you,
Chamil
Use igraph's built-in conventions and make the vertex labels into each's name:
V(g)$name <- V(g)$label
V(g1)$name <- V(g1)$label
Grab the attributes and edge list of each graph and rbind() them together, creating a combination attribute data.frame and combination edge list data.frame while ensuring that you're only keeping unique() vertices:
attrs <- rbind(as_data_frame(g, "vertices"), as_data_frame(g1, "vertices")) %>% unique()
el <- rbind(as_data_frame(g), as_data_frame(g1))
Use attrs and el to make your new graph:
new_g <- graph_from_data_frame(el, directed = FALSE, vertices = attrs)
You can get the union by turning each graph into an edgelist, joining the edgelists and the making that into a graph.
EL = matrix(get.vertex.attribute(g, "label")[get.edgelist(g)], ncol=2)
EL1 = matrix(get.vertex.attribute(g1, "label")[get.edgelist(g1)], ncol=2)
ELU = rbind(EL, EL1)
ELU = ELU[!duplicated(ELU),]
GU = graph_from_edgelist(ELU, directed=FALSE)
## To check the result
par(mfrow=c(1,3))
plot(g)
plot(g1)
plot(GU)
I am generating a world map and hoping to highlight some specific countries. This is my attempt:
require(mapdata)
cc <- map('world', names = TRUE, plot = FALSE)
take <- unlist(sapply(c("uk", "usa", "switzerland","new zealand",
"israel","denmark","sweden","italy",'canada'),
grep, tolower(cc), value = TRUE))
map()
map('world', regions=take, fill=TRUE, col='red', add = TRUE)
nums <- c(12,11,1,2,1,1,1,1,1)
I have two questions.
1) Is it possible to include points on this map to correspond to the variable 'nums'. Each of the numbers in 'nums' refers to the number of measurements taken from a specific country, 12 is for the UK and so on... Is it possible to include a point on the map with the radius of that point corresponding to the number in 'nums'. I know this is possible with ggplot2 but am not sure how to do it with mapdata?
2) How can I make this map look nicer i.e. there seem to be a lot of empty countries here, is there an elegant way of only including the countries that are colored?
Hm something like this?
require(mapdata)
cc <- map('world', names = TRUE, plot = FALSE)
take <- unlist(sapply(countries <- c("uk", "usa", "switzerland","new zealand",
"israel","denmark","sweden","italy",'canada'),
grep, tolower(cc), value = TRUE))
nums <- c(12,11,1,2,1,1,1,1,1)
# gc <- ggmap::geocode(countries) # a googlemaps query gives this:
gc <- structure(list(lon =
c(-3.435973, -95.712891, 8.227512, 174.885971,
34.851612, 9.501785, 18.643501, 12.56738, -106.346771), lat = c(55.378051,
37.09024, 46.818188, -40.900557, 31.046051, 56.26392, 60.128161,
41.87194, 56.130366)),
.Names = c("lon", "lat"),
class = "data.frame",
row.names = c(NA, -9L))
map(xlim=c(-150, 40), ylim=c(25, 75)) # plot only a part of the world map
map('world', regions=take, fill=TRUE, col='red', add = TRUE, )
with(gc, points(lon, lat, cex=nums, pch=19, col=rgb(0, 1, 0, .8))) # add circles
I would like to use R to generate a very basic world map with a specific set of countries filled with a red colour to indicate that they are malaria endemic countries.
I have a list of these countries in a data frame but am struggling to overlay them on a world map.
I have tried using the wrld_simpl object and also the joinCountryData2Map method in the rworldmap package.
I would comment on this answer to prevent addition of a possibly redundant question but I do not have enough reputation at the moment, apologies for this.
https://stackoverflow.com/a/9102797/1470099
I am having difficulty understanding the arguments given to the plot() command - I wondered if there was just an easy way to tell R to plot all of the country NAMEs in my list on the wrld_simpl map instead of using grepl() etc. etc.
plot(wrld_simpl,
col = c(gray(.80), "red")[grepl("^U", wrld_simpl#data$NAME) + 1])
Using the rworldmap package, you could use the following:
library(rworldmap)
theCountries <- c("DEU", "COD", "BFA")
# These are the ISO3 names of the countries you'd like to plot in red
malDF <- data.frame(country = c("DEU", "COD", "BFA"),
malaria = c(1, 1, 1))
# malDF is a data.frame with the ISO3 country names plus a variable to
# merge to the map data
malMap <- joinCountryData2Map(malDF, joinCode = "ISO3",
nameJoinColumn = "country")
# This will join your malDF data.frame to the country map data
mapCountryData(malMap, nameColumnToPlot="malaria", catMethod = "categorical",
missingCountryCol = gray(.8))
# And this will plot it, with the trick that the color palette's first
# color is red
EDIT: Add other colors and include picture
## Create multiple color codes, with Burkina Faso in its own group
malDF <- data.frame(country = c("DEU", "COD", "BFA"),
malaria = c(1, 1, 2))
## Re-merge
malMap <- joinCountryData2Map(malDF, joinCode = "ISO3",
nameJoinColumn = "country")
## Specify the colourPalette argument
mapCountryData(malMap, nameColumnToPlot="malaria", catMethod = "categorical",
missingCountryCol = gray(.8), colourPalette = c("red", "blue"))
Try using googleVis package and use gvisGeoMap Functions
e.g.
G1 <- gvisGeoMap(Exports,locationvar='Country',numvar='Profit',options=list(dataMode='regions'))
plot(G1)
library(maptools)
data(wrld_simpl)
myCountries = wrld_simpl#data$NAME %in% c("Australia", "United Kingdom", "Germany", "United States", "Sweden", "Netherlands", "New Zealand")
plot(wrld_simpl, col = c(gray(.80), "red")[myCountries+1])