I import a csv of longitude and latitude coordinates and convert them to polygon shapefiles. I place a grid over the polygons and find the centroid of each grid square. I then extract the coordinates of the centroids and place it in a dataframe, but I need to be able to say which polygon a particular centroid is in.
#Create shapefile of polygons
polygon <- lapply(split(df, df$shape), function(x) { coords <-
as.matrix(cbind(x$longitude, x$latitude)); list(rbind(coords, coords[1,]))})
Coord_Ref <- st_crs(4326)
polygon <- st_sfc(st_multipolygon(x=polygon), crs = Coord_Ref)
polygon <- st_cast(polygon, "POLYGON")
#Create grid and centroids
PolygonBits <- st_make_grid(polygon, cellsize=0.0002)
PolygonBitCentroids <- st_centroid(st_make_grid(polygon, cellsize=0.0002))
#Extract coordinates and place them in dataframe
PolygonBitCentroids <- st_coordinates(PolygonBitCentroids)
PolygonBitCentroids <- as.data.frame(PolygonBitCentroids)
The first three rows of the PolygonBitCentroids dataframe looks as follows:
X Y
1 -0.0014 0.1990
2 -0.0012 0.1990
3 -0.0010 0.1990
But I need something like this:
X Y Shape
1 -0.0014 0.1990 Polygon 1
2 -0.0012 0.1990 Polygon 1
3 -0.0010 0.1990 Polygon 1
Reproducible data:
structure(list(shape = c("polygon 1", "polygon 1", "polygon 1",
"polygon 1", "polygon 2", "polygon 2", "polygon 2", "polygon 2",
"polygon 3", "polygon 3", "polygon 3", "polygon 3", "polygon 4",
"polygon 4", "polygon 4", "polygon 4"), longitude = c(0, 1, 1,
0, 1.5, 2, 2, 1.5, -2, -2, -1, -1, 0, 1, 1, 0), latitude = c(1,
1, 0, 0, 1, 1, 0, 0, -0.5, -2, -2, -0.5, 1.5, 1.5, 2, 2)), class =
"data.frame", row.names = c(NA,
-16L), spec = structure(list(cols = list(shape = structure(list(),
class = c("collector_character",
"collector")), longitude = structure(list(), class =
c("collector_double",
"collector")), latitude = structure(list(), class =
c("collector_double",
"collector"))), default = structure(list(), class =
c("collector_guess",
"collector")), skip = 1), class = "col_spec"))
The solution to this problem is to do point-in-polygon via st_join.
This is pretty straightforward with the tidyverse, and I'm sure you can use the following to translate to base R.
(I took the liberty to change your reproducible data slightly, since polygon 4 is not a valid polygon given that it only has 3 points):
First we create an sf from the xy dataframe
library(sf)
library(tidyverse)
polygons <- polygons %>%
st_as_sf(coords = c('longitude', 'latitude')) %>%
st_set_crs(4326)
When plotted, this looks like this
polygons <- polygons %>%
group_by(shape) %>%
summarise(do_union=FALSE) %>%
st_cast("POLYGON")
This correctly creates the polygons from the points.
a call to plot(polygons) produces the following plot:
(the do_union=FALSE argument is important because otherwise order is not preserved). Next we create a separate sf object for the grids:
grids <- polygons %>%
st_make_grid(cellsize = 0.2) %>%
st_centroid() %>%
st_sf()
Finally, we join the two sf objects using st_within`
grids %>% st_join(polygons, join = st_within)
What you get looks exactly as you asked for.
Simple feature collection with 92 features and 1 field
geometry type: POINT
dimension: XY
bbox: xmin: -1.9 ymin: -1.9 xmax: 1.9 ymax: 1.9
CRS: EPSG:4326
First 10 features:
shape geometry
1 <NA> POINT (-1.9 -1.9)
2 <NA> POINT (-1.1 -1.9)
3 <NA> POINT (-0.9 -1.9)
4 polygon 3 POINT (-1.9 -1.7)
5 <NA> POINT (-1.7 -1.7)
6 <NA> POINT (-1.3 -1.7)
7 polygon 3 POINT (-1.1 -1.7)
8 <NA> POINT (-0.9 -1.7)
9 polygon 3 POINT (-1.9 -1.5)
10 polygon 3 POINT (-1.7 -1.5)
If you plot the output, you'll get
Related
Given the following data:
library(tidyverse)
library(sf)
df <- structure(list(geometry = c("LINESTRING (-85.76 38.34, -85.72 38.38)",
"LINESTRING (-85.46 38.76, -85.42 38.76)",
"LINESTRING (-85.89 38.31, -85.89 38.31)"
), var1 = c(4, 5, 6
), var2 = c(1, 2, 3
)), row.names = c(NA, -3L), class = c("tbl_df", "tbl", "data.frame"
))
df
df_sf <- sf::st_as_sf( df, wkt = "geometry" )
# Simple feature collection with 3 features and 2 fields
# geometry type: LINESTRING
# dimension: XY
# bbox: xmin: -85.89 ymin: 38.31 xmax: -85.42 ymax: 38.76
# CRS: NA
# # A tibble: 3 x 3
# geometry var1 var2
# <LINESTRING> <dbl> <dbl>
# 1 (-85.76 38.34, -85.72 38.38) 4 1
# 2 (-85.46 38.76, -85.42 38.76) 5 2
# 3 (-85.89 38.31, -85.89 38.31) 6 3
We can use plot to plot the data including the LINESTRING that has two points at the same location (row = 3):
plot(st_geometry(df_sf), lwd = 10)
giving:
but when we plot it using ggplot the point is dropped:
ggplot() +
geom_sf(data = df_sf, lwd = 8)
Without manually extracting locations that only contain a point, is there a quick way to tell ggplot to plot these? I can see that these points are technically not a line as theres no distance between them but plot is able to pick them up. This question seems related but slightly different, my LINESTRINGs are already created.
thanks
This is one of those situations where the headdesk emoji might come in handy:
ggplot() +
geom_sf(data = df_sf, lwd = 8, lineend = "round")
From the package's vignette on aesthetic specs, the default lineend is "butt", which stops precisely at the end point of a line (so a line of 0 length won't have anything to show), while the "round" alternative extends beyond the end point:
TL;DR: The 0-length linestring wasn't dropped. We just couldn't see it.
I think that you can solve that problem if you modify the LINESTRING geometries whose length is equal to 0 and cast them as POINTS. For example:
# packages
library(ggplot2)
library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
# data
df <- structure(
list(
geometry = c(
"LINESTRING (-85.76 38.34, -85.72 38.38)",
"LINESTRING (-85.46 38.76, -85.42 38.76)",
"LINESTRING (-85.89 38.31, -85.89 38.31)"
),
var1 = c(4, 5, 6),
var2 = c(1, 2, 3)
),
row.names = c(NA, -3L),
class = c("tbl_df", "tbl", "data.frame")
)
df_sf <- st_as_sf( df, wkt = "geometry" )
# Rebuild the geometry column in such a way that the zero-length LINESTRINGS are
# actually POINTS:
new_df_sf_geometry <- st_geometry(df_sf)
idx <- which(st_length(new_df_sf_geometry) == 0)
for (i in idx) {
new_df_sf_geometry[i] <- unique(st_cast(new_df_sf_geometry[i], "POINT"))
}
# This is the result
new_df_sf_geometry
#> Geometry set for 3 features
#> geometry type: GEOMETRY
#> dimension: XY
#> bbox: xmin: -85.89 ymin: 38.31 xmax: -85.42 ymax: 38.76
#> CRS: NA
#> LINESTRING (-85.76 38.34, -85.72 38.38)
#> LINESTRING (-85.46 38.76, -85.42 38.76)
#> POINT (-85.89 38.31)
# Replace the geometry
st_geometry(df_sf) <- new_df_sf_geometry
# Plot
ggplot(df_sf) +
geom_sf(size = 3)
Created on 2020-05-25 by the reprex package (v0.3.0)
If you need, you can also adopt more sophisticated approaches than a for-loop such as purrr::map_if.
I am trying to plot gun violence occurrence coordinate points onto a shapefile map of New York. I applied a Google script to turn the original dataset street addresses into latitude and longitude coordinates. I exported it .csv into RStudio. Cleaned up the data a little more by removing unnecessary columns and NA values + changing the Lat. column to numeric.
I seem to have done everything right up until layering the points atop the shapefile map. When I run the following code, it returns the coordinate points separately from the map (see images attached). That is, they are not layered together so I can eventually use it to create a choropleth map. Also, the point image below doesn't seem to show all the latitude/longitude coordinates in the dataset. There are a total of 500 or so incidences with coordinate data provided spread out across the entire state of New York. I am not so confident in what is being shown, but that is probably a topic for another question.
library(data.table)
library(sp)
library(rgdal)
library(ggplot2)
df_2 <- Gun_Violence_Clean_3 %>%
select(-`Incident ID`, -Operations, -`City 2`, -Combine, -`Lat & Long`) %>%
na.omit()
df_2
df_2$Lat <- as.numeric(df_2$Lat)
coordinates(df_2) = c("Lat","Long")
crs.geo1 = CRS("+proj=longlat")
proj4string(df_2) = crs.geo1
plot(df_2, pch = 20, col = "steelblue")
New_York = readOGR(dsn = "./NYS Boundaries", layer = "new-york-state-city-and-town-
boundaries")
plot(New_York)
points(df_2, pch = 20, col = "orange")
Reproducible data:
structure(list(`Incident ID` = c(1664753, 1664770, 1664768, 1664751,
1664723, 1664721), `Incident Date` = c("23-Apr-20", "22-Apr-20",
"22-Apr-20", "22-Apr-20", "22-Apr-20", "22-Apr-20"), State = c("New
York",
"New York", "New York", "New York", "New York", "New York"),
`City Or County` = c("Buffalo", "Schenectady", "Schenectady",
"Albany", "Brooklyn", "Corona (Queens)"), Address = c("50 block of
Langmeyer Ave",
"1009 McClyman St", "1013 McClyman St", "200 block of Second Ave",
"255 Havemeyer St", "225-37 Murdock Ave"), `# Killed` = c(1,
0, 0, 0, 0, 0), `# Injured` = c(0, 0, 1, 1, 0, 1), Operations =
c("N/A",
"N/A", "N/A", "N/A", "N/A", "N/A"), `City 2` = c("Buffalo",
"Schenectady", "Schenectady", "Albany", "Brooklyn", "Corona (Queens)"
), Combine = c("50 block of Langmeyer Ave Buffalo", "1009 McClyman St
Schenectady",
"1013 McClyman St Schenectady", "200 block of Second Ave Albany",
"255 Havemeyer St Brooklyn", "225-37 Murdock Ave Corona (Queens)"
), `Lat & Long` = c("42.92484, -78.815534", "#ERROR!",
"42.80176729999999, -73.9331919",
"42.6390962, -73.77026289999999", "40.7079479, -73.95942509999999",
"40.703342, -73.731005"), Lat = c("42.92484000000", "#ERROR!",
"42.80176730000", "42.63909620000", "40.70794790000", "40.70334200000"
), Long = c(-78.815534, NA, -73.9331919, -73.7702629, -73.9594251,
-73.731005)), row.names = c(NA, -6L), class = c("tbl_df",
"tbl", "data.frame"))
Points
Map of New York
Dataset Screenshot
Where I got the shapefile of New York State
Thank you very much for your help.
Using this answer as a guide: out of bounds latitude and longitude values in converted shape file using ggplot
Here is a bare minimum solution:
library(rgdal)
library(sp)
df_2 <- structure(list(`Incident Date` = c("23-Apr-20", "22-Apr-20",
"22-Apr-20", "22-Apr-20", "22-Apr-20"), `City Or County` = c("Buffalo",
"Schenectady", "Albany", "Brooklyn", "Corona (Queens)"), `# Killed` = c(1,
0, 0, 0, 0), `# Injured` = c(0, 1, 1, 0, 1), Lat = c(42.92484,
42.8017673, 42.6390962, 40.7079479, 40.703342), Long = c(-78.815534,
-73.9331919, -73.7702629, -73.9594251, -73.731005)), row.names = c(NA,
-5L), na.action = structure(c(`2` = 2L), class = "omit"), class = c("tbl_df",
"tbl", "data.frame"))
#read shape file
New_York = readOGR(dsn = "./NYS Boundaries", layer = "Counties")
#Transform the shape file coordinates to Lat/Longitude
NY <-spTransform(New_York, CRS("+proj=longlat +ellps=WGS84 +datum=WGS84"))
plot(NY, xlab="long")
axis(1) #Check the coordinates
axis(2)
#plot the points
points(x=df_2$Long, y=df_2$Lat, pch = 20, col = "orange")
I would like to reproduce the last example from the marmap vignette: 'marmap-DataAnalysis' for a pacific region. The example shows the orthographic projection of the world centered at lon = 50. Here is the example:
library(marmap)
library(raster)
# Get data for the whole world. Careful: ca. 21 Mo!
world <- getNOAA.bathy(-180, 180, -90, 90, res = 15, keep = TRUE)
# Switch to raster
world.ras <- marmap::as.raster(world)
# Set the projection and project
my.proj <- "+proj=ortho +lat_0=0 +lon_0=50 +x_0=0 +y_0=0"
world.ras.proj <- projectRaster(world.ras,crs = my.proj)
# Switch back to a bathy object
world.proj <- as.bathy(world.ras.proj)
# Set colors for oceans and land masses
blues <- c("lightsteelblue4", "lightsteelblue3",
"lightsteelblue2", "lightsteelblue1")
greys <- c(grey(0.6), grey(0.93), grey(0.99))
# And plot!
plot(world.proj, image = TRUE, land = TRUE, lwd = 0.05,
bpal = list(c(0, max(world.proj, na.rm = T), greys),
c(min(world.proj, na.rm = T), 0, blues)),
axes = FALSE, xlab = "", ylab = "")
plot(world.proj, n = 1, lwd = 0.4, add = TRUE)
However, I would like to change the central to a pacific meridian, e.g. lon = 155.5. I tried this by changing the projection parameters to,
my.proj <- "+proj=ortho +lat_0=20 +lon_0=155.5 +x_0=0 +y_0=0"
but then,
world.ras.proj <- projectRaster(world.ras,crs = my.proj)
results in:
Error in if (nr != x#nrows | nc != x#ncols) { :
missing value where TRUE/FALSE needed
In addition: Warning messages:
1: In rgdal::rawTransform(projfrom, projto, nrow(xy), xy[, 1], xy[, :
259 projected point(s) not finite
2: In rgdal::rawTransform(projection(raster), crs, nrow(xy), xy[, 1], :
4 projected point(s) not finite
How can could I plot the 'bathymetric world' in a pacific region?
I have simplified your question (always good, and for me the data download did not work). In essence:
library(raster); library(rgdal)
prj1 <- "+proj=ortho +lat_0=0 +lon_0=0 +x_0=0 +y_0=0"
prj2 <- "+proj=ortho +lat_0=20 +lon_0=155.5 +x_0=0 +y_0=0"
r <- raster()
r <- init(r, 'col')
# works
x1 <- projectRaster(r, crs = prj1)
# fails
x2 <- projectRaster(r, crs = prj2)
This is a bug. I have fixed it in raster version 2.6-2 (under development, should be available next week or so)
This can be solved in marmap with the current/previous version of the raster package. You have to use the antimeridian=TRUE argument of the getNOAA.bathy() function and some trickery to allow the computations of the projection by the raster package.
The first trick is to download data with lon1 = lon2 = 0 since the antimeridian downloads 2 distinct datasets: from the antimeridian to lon1 and from lon2 to the antimeridian. Setting lon1 and lon2 equal to 0 downloads the whole world.
Then, you have to manually switch back to values of longitudes between -180 and 180 (and not 0 to 360 as produced by the animeridian argument of getNOAA.bathy()), hence the rownames(world2) <- ... line.
Finally, you have to apply the same -180 correction to specify the projection.
Here is the code:
library(marmap)
library(raster)
# Get data for the whole world. Careful: ca. 21 Mo!
world2 <- getNOAA.bathy(0, 0, -90, 90, res = 15, keep = TRUE, antimeridian=TRUE)
rownames(world2) <- as.numeric(rownames(world2))-180
# Switch to raster
world.ras <- marmap::as.raster(world2)
# Set the projection and project
my.proj <- "+proj=ortho +lat_0=20 +lon_0=155-180 +x_0=0 +y_0=0"
world.ras.proj <- projectRaster(world.ras,crs = my.proj)
# Switch back to a bathy object
world.proj <- as.bathy(world.ras.proj)
# Set colors for oceans and land masses
blues <- c("lightsteelblue4", "lightsteelblue3",
"lightsteelblue2", "lightsteelblue1")
greys <- c(grey(0.6), grey(0.93), grey(0.99))
# And plot!
plot(world.proj, image = TRUE, land = TRUE, lwd = 0.05,
bpal = list(c(0, max(world.proj, na.rm = T), greys),
c(min(world.proj, na.rm = T), 0, blues)),
axes = FALSE, xlab = "", ylab = "")
plot(world.proj, n = 1, lwd = 0.4, add = TRUE)
And here is the result:
The new version of raster (2.6-7) solves the problem of projecting across the date-line. However, due to rounding errors when downloading bathymetric data from NOAA servers, some missing cells may appear in plots. Here is an example with the code you posted in your original question:
And here is the summary() of the data:
summary(world)
# Bathymetric data of class 'bathy', with 1440 rows and 720 columns
# Latitudinal range: -89.88 to 89.88 (89.88 S to 89.88 N)
# Longitudinal range: -179.88 to 179.88 (179.88 W to 179.88 E)
# Cell size: 15 minute(s)
# Depth statistics:
# Min. 1st Qu. Median Mean 3rd Qu. Max.
# -10635 -4286 -2455 -1892 214 6798
#
# First 5 columns and rows of the bathymetric matrix:
# -89.875 -89.625 -89.375 -89.125 -88.875
# -179.875 2746 2836 2893 2959 3016
# -179.625 2746 2835 2892 2958 3015
# -179.375 2746 2835 2891 2957 3014
# -179.125 2746 2834 2890 2956 3013
# -178.875 2746 2834 2889 2955 3012
Hence, the solution using antimeridian=TRUE detailed above should be best.
I am struggling to get my first map to work. I have read every document I could find but I am not able to pull it all together to view my data on a map.
This is what I have done so far.
1. I created a very basic data table with 3 observations and 5 variables as a very simple starting point.
str(Datawithlatlongnotvector)
'data.frame': 3 obs. of 5 variables:
$ Client: Factor w/ 3 levels "Jan","Piet","Susan": 2 1 3
$ Sales : int 100 1000 15000
$ Lat : num 26.2 33.9 23.9
$ Lon : num 28 18.4 29.4
$ Area : Factor w/ 3 levels "Gauteng","Limpopo",..: 1 3 2
(the Area is the provinces of South Africa and also is as per the SHP file that I downloaded, see below)
I downloaded a map of South Africa and placed all 3 files (.dbf, shp and shx) files in the same directory - previous error but I found the answer from another user's question. http://www.mapmakerdata.co.uk.s3-website-eu-west-1.amazonaws.com/library/stacks/Africa/South%20Africa/index.htm and selected Simple base map.
I created a map as follows :
SAMap <- readOGR(dsn = ".", layer = "SOU-level_1")
and I can plot the map of the country showing the provinces with plot(SAMap)
I can also plot the data
plot(datawithlatlong)
I saw the instructions how to make a SpatialPointsData frame and I did that :
coordinates(Datawithlatlong) = ~Lat + Lon
I do not know how to pull it all together and do the following :
Show the data (100,1000 and 15000) on the map with different colours i.e. between 1 and 500 is one colour, between 501 and 10 000 is one colour and above 10 000 is one colour.
Maybe trying ggplot2 with some function like:
map = ggplot(df, aes(long, lat, fill = Sales_cat)) + scale_fill_brewer(type = "seq", palette = "Oranges", name = "Sales") + geom_polygon()
With scale_fill_brewer you can represent scales in terms of colours on the map. You should create a factor variable that represents categories according to the range of sales ("Sales_cat"). In any case, the shape file must be transformed into a data.frame.
Try this for 'SAMap' as the country shapefile and 'datawithlatlong' as your data convereted to SpatialPointDataFrame:
library(maptools)
library(classInt)
library(RColorBrewer)
# Prepare colour pallete
plotclr <- brewer.pal(3,"PuRd")
class<-classIntervals(datawithlatlong#data$sales, n=3, style="fixed", fixedBreaks=c(0, 500,1000,10000)) # you can adjust the intervals here
colcode <- findColours(class, plotclr)
# Plot country map
plot(SAMap,xlim=c(16, 38.0), ylim=c(-46,-23))# plot your polygon shapefile with appropriate xlim and ylim (extent)
# Plot dataframe convereted to SPDF (in your step 5)
plot(datawithlatlong, col=colcode, add=T,pch=19)
# Creating the legend
legend(16.2, -42, legend=names(attr(colcode, "table")), fill=attr(colcode, "palette"), cex=0.6, bty="n") # adjust the x and y for fixing appropriate location for the legend
I generated a bigger dataset because I think with only 3 points it hard to see how things are working.
library(rgdal)
library(tmap)
library(ggmap)
library(randomNames)
#I downloaded the shapefile with the administrative area polygons
map <- readOGR(dsn = ".", layer = "SOU")
#the coordinate system is not part of the loaded object hence I added this information
proj4string(map) <- CRS("+init=epsg:4326")
# Some sample data with random client names and random region
ADM2 <- sample(map#data$ADM2, replace = TRUE, 50)
name <- randomNames(50)
sales <- sample(0:5000, 50)
clientData <- data.frame(id = 1:50, name, region = as.character(ADM2), sales,
stringsAsFactors = FALSE)
#In order to add the geoinformation for each client I used the awesome
#function `ggmap::geocode` which takes a character string as input an
#provides the lon and lat for the region, city ...
geoinfo <- geocode(clientData$region, messaging = FALSE)
# Use this information to build a Point layer
clientData_point <- SpatialPointsDataFrame(geoinfo, data = clientData)
proj4string(clientData_point) <- CRS("+init=epsg:4326")
Now the part I hope that answers the question:
# Adding all sales which occured in one region
# If there are 3 clients in one region, the sales of the three are
# summed up and returned in a new layer
sales_map <- aggregate(x = clientData_point[ ,4], by = map, FUN = sum)
# Building a map using the `tmap` package`
tm_shape(sales_map) + tm_polygons(col = "sales")
Edit:
Here is a ggplot2 solution because it seems you want to stick with it.
First, for ggplot you have to transform your SpatialPolygonDataFrame to an ordinary data.frame. Fortunately, broom::tidy() will do the job automatically.
Second, your Lat values are missing a -. I added it.
Third, I renamed your objects for less typing.
point_layer<- structure(list(Client = structure(c(2L, 1L, 3L),
.Label = c("Jan", "Piet", "Susan"),
class = "factor"),
Sales = c(100, 1000, 15000 ),
Lat = c(-26.2041, -33.9249, -23.8962),
Lon = c(28.0473, 18.4241, 29.4486),
Area = structure(c(1L, 3L, 2L),
.Label = c("Gauteng", "Limpopo", "Western Cape"),
class = "factor"),
Sale_range = structure(c(1L, 2L, 4L),
.Label = c("(1,500]", "(500,2e+03]", "(2e+03,5e+03]", "(5e+03,5e+04]"),
class = "factor")),
.Names = c("Client", "Sales", "Lat", "Lon", "Area", "Sale_range"),
row.names = c(NA, -3L), class = "data.frame")
point_layer$Sale_range <- cut(point_layer$Sales, c(1,500.0,2000.0,5000.0,50000.0 ))
library(broom)
library(ggplot2)
ggplot_map <- tidy(map)
ggplot() + geom_polygon(ggplot_map, mapping = aes(x = long, y = lat, group = group),
fill = "grey65", color = "black") +
geom_point(point_layer, mapping = aes(x = Lon, y = Lat, col = Sale_range)) +
scale_colour_brewer(type = "seq", palette = "Oranges", direction = 1)
I'm trying to do a concentric pie chart. The internal pie represent three classes of subjects and each class has to be splitted in 3 sub-classes (of course the slices for the sub-classes have to be in line with the corresponding internal slice).
this is what I tried:
layout(matrix(c(1,1,1,1,2,1,1,1,1), nrow=3)); pie(x=c(14,22,15,3,15,33,0,6,45),labels="",col=c("#f21c39","#dba814","#7309de")); pie(x=c(51,51,51),labels=c("O","VG","V"),col=c("#c64719","#0600f5","#089c1f"))
This worked, but the internal pie is too small. I tried to play with the radius option, but then the external slices are not correspondent to the internal ones. how can I adjust them?
Use par(new=TRUE) to overplot the pies rather than layout() in this case
pie(x=c(14,22,15,3,15,33,0,6,45),labels="",
col=c("#f21c39","#dba814","#7309de"))
par(new=TRUE)
pie(x=c(51,51,51),labels=c("O","VG","V"),radius=.5,
col=c("#c64719","#0600f5","#089c1f"))
Three years later. this can be achieved using sunburstR package. http://timelyportfolio.github.io/sunburstR/example_baseball.html
Example:
DF <- data.frame(LOGRECNO = c(60, 61, 62, 63, 64, 65),
STATE = c(1, 1, 1, 1, 1, 1),
COUNTY = c(1, 1, 1, 1, 1, 1),
TRACT = c(21100, 21100, 21100, 21100, 21100, 21100),
BLOCK = c(1053, 1054, 1055, 1056, 1057, 1058))
DF$BLOCKID <-
paste(DF$LOGRECNO, DF$STATE, DF$COUNTY,
DF$TRACT, DF$BLOCK, sep = "-")
DF %>%
select(BLOCKID) %>%
group_by(BLOCKID) %>%
summarise(Tots=n())->dftest
sunburst(dftest)
I'm sure you are able to adapt this to suit your needs!
you could also use the ggsunburst package
# install ggsunburst
if (!require("ggplot2")) install.packages("ggplot2")
if (!require("rPython")) install.packages("rPython")
install.packages("http://genome.crg.es/~didac/ggsunburst/ggsunburst_0.0.9.tar.gz", repos=NULL, type="source")
library(ggsunburst)
df <- read.table(header=T, text = "
parent node size
O 1 14
O 2 22
O 3 15
V 1 3
V 2 15
V 3 33
VG 1 1
VG 2 6
VG 3 45")
write.table(df, file = 'df.txt', sep = ',', row.names = F)
sb <- sunburst_data('df.txt', type = "node_parent", sep = ",")
p <- sunburst(sb, node_labels = T, leaf_labels = F, rects.fill.aes = "name")
cols <- c("O" = "#c64719", "V" = "#0600f5", "VG" = "#089c1f", "1" = "#f21c39", "2" = "#dba814", "3" = "#7309de")
p + scale_fill_manual(values = cols)