I am trying to create a tesselation of filled hexagons (polygons centered around a hexagonally-spaced lattice) in ggplot2. I have accomplished this using the 'plot' command but am struggling transitioning this to ggplot.
Here is the code for the set-up:
# Generate a lattice of points equally spaced in the centers of a hexagonal lattice
dist = 1 # distance between the centers of hexagons
nx = dist*15 # horizontal extent
ny = dist*15 # vertical extent
MakeHexLattice = function(nx, ny, dist, origin=c(0,0)) {
locations = cbind(location = 1:(nx*ny),
x = sort(c(rep(seq(from=0, by=dist, length.out=nx),each=ceiling(ny/2)),
rep(seq(from=dist/2, by=dist, length.out=nx),
each=floor(ny/2)))) + origin[1],
y = rep(c(seq(from=0, by = dist*sqrt(3), length.out=ceiling(ny/2)),
seq(from=dist*sqrt(3)/2, by=dist*sqrt(3),
length.out=floor(ny/2))) + origin[2], times=nx))
class(locations) = c(class(locations), "lattice")
attr(locations, "gridsize") = dist
return(locations)
}
Here is the code for creating the image using 'plot', which looks very nice:
landscape = MakeHexLattice(nx=nx,ny=ny,dist=dist,origin=c(0,0))
# Plot hexagonal lattice as points
plot(x=landscape[,2],y=landscape[,3], pch=19, col="black", cex=0.5, asp=1/1)
# Separate x and y coordinates
lx = landscape[,2] # x-coordinates
ly = landscape[,3] # y-coordinates
# Plot hexagonal lattice as filled hexagons
hex.x = cbind(lx + 0, lx + 0.5, lx + 0.5, lx + 0, lx - 0.5, lx - 0.5)
hex.y = cbind(ly - 1/(sqrt(3)), ly - 1/(2*sqrt(3)), ly + 1/(2*sqrt(3)), ly + 1/(sqrt(3)), ly + 1/(2*sqrt(3)), ly - 1/(2*sqrt(3)))
hex.vectors = cbind(hex.x, hex.y)
for(i in 1:(length(hex.vectors)/12)){
polygon(x=hex.vectors[i,1:6], y=hex.vectors[i,7:12], angle = 120, border=NULL, col="wheat",
lty = par("lty"), fillOddEven = FALSE)
}
Any tips on how to accomplish this same thing using ggplot2 (which I am transitioning to using)? I have tried using geom_polygon but can't seem to work out the for-loop. (Also, please don't tell me to use 'hexbin' -- not the goal that I am trying to accomplish!)
Thank for the help!
As with most things in ggplot, the plotting is actually extremely straightforward, most of the work is getting your data in the right shape so that it makes sense. A for loop is entirely unnecessary, geom_polygon() just needs a dataframe with the x and y coordinates, and a variable defining which group they belong to. With your data:
library(ggplot2)
library(reshape2)
#Get your coordinates in long format with an id
hexdat.x <- melt(cbind(id = 1:length(hex.x), as.data.frame(hex.x)), id.vars = "id", value.name = "x")
hexdat.y <- melt(cbind(id = 1:length(hex.y), as.data.frame(hex.y)), id.vars = "id", value.name = "y")
#Merge them into the same dataframe
hexdat <- merge(hexdat.x, hexdat.y)
head(hexdat)
# id variable x y
# 1 1 V1 0.0 -0.5773503
# 2 1 V2 0.5 -0.2886751
# 3 1 V3 0.5 0.2886751
# 4 1 V4 0.0 0.5773503
# 5 1 V5 -0.5 0.2886751
# 6 1 V6 -0.5 -0.2886751
Now to plot the hexagons, you just need to give ggplot the x and y coordinates, and specify the group each one belongs to:
ggplot(hexdat, aes(x, y)) +
geom_polygon(aes(group = id), fill = "wheat", colour = "black")
Related
I have a polygon that consists of 1,000 points. Is it possible to calculate the curvature at each point? The polygon originally contains only 13 points:
43748.72 40714.19
43743.99 40716.16
43741.36 40720.19
43740.95 40726.46
43742.67 40729.28
43745.52 40730.97
43748.72 40731.14
43752.86 40729.43
43756.77 40723.24
43757.19 40719.73
43755.27 40716.68
43752.23 40714.76
43748.72 40714.19
Then I use the smooth function in smoothr package for interpolation now that the polygon has 1,000 points and looks like:
And now I want to calculate curvature at each point. But since this is a closed object, how to actually perform the calculation?
EDIT
I finally found a cell with protrusions to test the robustness. The cell looks like:
And the corresponding K values are:
Indeed, this plot captures two protrusions but can the curvature value be that high? I read a paper and seems like their values are all within 1:
paper link: https://www.biorxiv.org/content/10.1101/623793v1.full
Your example is not fully reproducible on its own, though it can be made so with reference to your previous question:
library(sf)
library(smoothr)
library(ggplot2)
data <- structure(list(x = c(43740.95, 43741.36, 43742.67, 43743.99,
43745.52, 43748.72, 43748.72, 43748.72, 43752.23, 43752.86, 43755.27,
43756.77, 43757.19), y = c(40726.46, 40720.19, 40729.28, 40716.16,
40730.97, 40714.19, 40731.14, 40714.19, 40714.76, 40729.43, 40716.68,
40723.24, 40719.73)), class = "data.frame", row.names = c(NA, -13L))
smooth_poly <- data %>%
st_as_sf(coords=c("x", "y")) %>%
st_union() %>%
st_convex_hull() %>%
smooth(method='spline', n=1000)
smooth_df <- as.data.frame(sf::st_coordinates(smooth_poly))
ggplot(smooth_df, aes(X, Y)) +
geom_polygon(alpha = 0, colour = "black", size = 1) +
coord_equal()
Now we have all the X and Y co-ordinates of the smoothed polygon in a data frame called smooth_df. We can calculate the x and y components of the curvature vectors like this:
dx <- diff(c(smooth_df$X, smooth_df$X[1])) # Distance between x coords with wrap-around
dy <- diff(c(smooth_df$Y, smooth_df$Y[1])) # Distance between y coords with wrap-around
ds <- sqrt(dx^2 + dy^2) # Segment size between points
ddx <- dx/ds # Ratio of x distance to segment size
ddy <- dy/ds # Ratio of y distance to segment size
ds2 <- (ds + c(ds[-1], ds[1]))/2 # Mean segment length either side per point
smooth_df$Cx <- diff(c(ddx, ddx[1]))/ds2 # Change in ddx per unit length
smooth_df$Cy <- diff(c(ddy, ddy[1]))/ds2 # Change in ddy per unit length
These last two are the x and y components of the curvature vectors at each point on the periphery of the polygon. Since this polygon is smooth, the curvatures are small:
head(smooth_df)
#> X Y L1 L2 Cx Cy
#> 1 43748.72 40714.19 1 1 0.02288753 0.1419567
#> 2 43748.67 40714.20 1 1 0.02324771 0.1375075
#> 3 43748.61 40714.21 1 1 0.02356064 0.1332985
#> 4 43748.56 40714.22 1 1 0.02383216 0.1293156
#> 5 43748.51 40714.23 1 1 0.02406747 0.1255458
#> 6 43748.45 40714.24 1 1 0.02427127 0.1219768
Adding these vectors to a plot would just give the inside of the polygon some "fur", since there are so many of them and they are so small, so instead we can show that the directions are correct by plotting a subset of them, magnified by 10, with arrowheads. The arrows should start on the periphery and point directly in the direction of the concavity of the polygon at that point. We should also see longer arrows where the curves are tight, and shorter arrows where the polygon is flat.
smooth_df$Cx_plot <- 10 * smooth_df$Cx + smooth_df$X
smooth_df$Cy_plot <- 10 * smooth_df$Cy + smooth_df$Y
ggplot(smooth_df, aes(X, Y)) +
geom_polygon(alpha = 0, colour = "black", size = 1) +
geom_segment(data = smooth_df[seq(1, nrow(smooth_df), 50),],
mapping = aes(xend = Cx_plot, yend = Cy_plot),
arrow = arrow(length = unit(0.3, "cm"))) +
coord_equal()
If you want the curvature as a single dimensional number đťśż, you can do:
smooth_df$K <- (ddy * smooth_df$Cx - ddx * smooth_df$Cy)/
((ddx^2 + ddy^2)^(3/2))
Which then allows you to plot the curvature as a colour. This will also give negative values when the curve is concave outwards, though I have here just plotted the convex hull again. The red indicates areas with high curvature, the blue areas are flatter.
ggplot(smooth_df, aes(X, Y)) +
geom_point(aes(colour = K)) +
coord_equal() + scale_colour_gradient(low = "skyblue", high = "red")
Problem:
1.) I have a shapefile that looks like this:
Extreme values for coordinates are: xmin = 300,000, xmax = 620,000, ymin = 31,000 and ymax = 190,000.
2.) I have a dataset of approx. 2mio points (every point is inside the given polygon) - each one is in one of a 5 different categories.
Now, for every point inside the border (distance between points has to be 10, so that would give us 580,800,000 points) I want to determine color, depending on a category of the nearest point in a dataset.
In the end I would like to draw a ggplot, where the color of every point is dependent on its category (so I'll use 5 different colors).
What I have so far:
My ideas for solution are not optimized and it takes R forever to determine categories for every point inside the polygon.
1.) I created a new dataset with points in a shape of a rectangle with extreme values of coordinates, with 10 units between points. From a new dataset I selected points that have fallen inside the border of polygons (with a function pnt.in.poly from package SDMTools). Then I wanted to find nearest points (from dataset) of every point in a polygon and determined category, but I never manage to get a subset from 580,800,000 points (obviously).
2.) I tried to take 2mio points and color an area around them, dependent on their category, but that did not work right.
I know that it is not possible to plot so many points and see the difference between plot with 200,000,000 points and plot with 1,000,000 points, but I would like to have an accurate coloring when zooming (drawing) only one little spot in a polygon (size of 100 x 100 for example).
Question: Is there any better a way of coloring so many points in a polygon (with creating a new shapefile or grouping points)?
Thank you for your ideas!
It’s really helpful if you include some data with your question, even (especially) if it’s a toy data set. As you don’t, I’ve made a toy example. First, I define a simple shape data frame and a data frame of synthetic data that includes x, y, and grp (i.e., a categorical variable with 5 levels). I crop the latter to the former and plot the results,
# Dummy shape function
df_shape <- data.frame(x = c(0, 0.5, 1, 0.5, 0),
y = c(0, 0.2, 1, 0.8, 0))
# Load library
library(ggplot2)
library(sgeostat) # For in.polygon function
# Data frame of synthetic data: random [x, y] and category (grp)
df_synth <- data.frame(x = runif(500),
y = runif(500),
grp = factor(sample(1:5, 500, replace = TRUE)))
# Remove points outside polygon
df_synth <- df_synth[in.polygon(df_synth$x, df_synth$y, df_shape$x, df_shape$y), ]
# Plot shape and synthetic data
g <- ggplot(df_shape, aes(x = x, y = y)) + geom_path(colour = "#FF3300", size = 1.5)
g <- g + ggthemes::theme_clean()
g <- g + geom_point(data = df_synth, aes(x = x, y = y, colour = grp))
g
Next, I create a regular grid and crop that using the polygon.
# Create a grid
df_grid <- expand.grid(x = seq(0, 1, length.out = 50),
y = seq(0, 1, length.out = 50))
# Check if grid points are in polygon
df_grid <- df_grid[in.polygon(df_grid$x, df_grid$y, df_shape$x, df_shape$y), ]
# Plot shape and show points are inside
g <- ggplot(df_shape, aes(x = x, y = y)) + geom_path(colour = "#FF3300", size = 1.5)
g <- g + ggthemes::theme_clean()
g <- g + geom_point(data = df_grid, aes(x = x, y = y))
g
To classify each point on this grid by the nearest point in the synthetic data set, I use knn or k-nearest-neighbours with k = 1. That gives something like this.
# Classify grid points according to synthetic data set using k-nearest neighbour
df_grid$grp <- class::knn(df_synth[, 1:2], df_grid, df_synth[, 3])
# Show categorised points
g <- ggplot()
g <- g + ggthemes::theme_clean()
g <- g + geom_point(data = df_grid, aes(x = x, y = y, colour = grp))
g
So, that's how I'd address that part of your question about classifying points on a grid.
The other part of your question seems to be about resolution. If I understand correctly, you want the same resolution even if you're zoomed in. Also, you don't want to plot so many points when zoomed out, as you can't even see them. Here, I create a plotting function that lets you specify the resolution. First, I plot all the points in the shape with 50 points in each direction. Then, I plot a subregion (i.e., zoom), but keep the same number of points in each direction the same so that it looks pretty much the same as the previous plot in terms of numbers of dots.
res_plot <- function(xlim, xn, ylim, yn, df_data, df_sh){
# Create a grid
df_gr <- expand.grid(x = seq(xlim[1], xlim[2], length.out = xn),
y = seq(ylim[1], ylim[2], length.out = yn))
# Check if grid points are in polygon
df_gr <- df_gr[in.polygon(df_gr$x, df_gr$y, df_sh$x, df_sh$y), ]
# Classify grid points according to synthetic data set using k-nearest neighbour
df_gr$grp <- class::knn(df_data[, 1:2], df_gr, df_data[, 3])
g <- ggplot()
g <- g + ggthemes::theme_clean()
g <- g + geom_point(data = df_gr, aes(x = x, y = y, colour = grp))
g <- g + xlim(xlim) + ylim(ylim)
g
}
# Example plot
res_plot(c(0, 1), 50, c(0, 1), 50, df_synth, df_shape)
# Same resolution, but different limits
res_plot(c(0.25, 0.75), 50, c(0, 1), 50, df_synth, df_shape)
Created on 2019-05-31 by the reprex package (v0.3.0)
Hopefully, that addresses your question.
I am trying to have 2 "shadows" on the background of the below plot. These shadows should represent the density of the orange and blue points separately. Does it make sense?
Here is the ggplot to improve:
Here is the code and the data (matrix df) I used to create this plot:
PC1 PC2 aa
A_akallopisos 0.043272525 0.0151023307 2
A_akindynos -0.020707141 -0.0158198405 1
A_allardi -0.020277664 -0.0221016281 2
A_barberi -0.023165596 0.0389906701 2
A_bicinctus -0.025354572 -0.0059122384 2
A_chrysogaster 0.012608835 -0.0339330213 2
A_chrysopterus -0.022402365 -0.0092476009 1
A_clarkii -0.014474658 -0.0127024469 1
A_ephippium -0.016859412 0.0320034231 2
A_frenatus -0.024190876 0.0238499714 2
A_latezonatus -0.010718845 -0.0289904165 1
A_latifasciatus -0.005645811 -0.0183202248 2
A_mccullochi -0.031664307 -0.0096059126 2
A_melanopus -0.026915545 0.0308399009 2
A_nigripes 0.023420045 0.0293801537 2
A_ocellaris 0.052042539 0.0126144250 2
A_omanensis -0.020387101 0.0010944998 2
A_pacificus 0.042406273 -0.0260308092 2
A_percula 0.034591721 0.0071153133 2
A_perideraion 0.052830132 0.0064495142 2
A_polymnus 0.030902254 -0.0005091421 2
A_rubrocinctus -0.033318659 0.0474995722 2
A_sandaracinos 0.055839755 0.0093724082 2
A_sebae 0.021767793 -0.0218640814 2
A_tricinctus -0.016230301 -0.0018526482 1
P_biaculeatus -0.014466403 0.0024864574 2
ggplot(data=df,aes(x=PC1, y=PC2, color=factor(aa), label=rownames(df))) + ggtitle(paste('Site n° ',Sites_names[j],sep='')) +geom_smooth(se=F, method='lm')+ geom_point() + scale_color_manual(name='mutation', values = c("darkorange2","cornflowerblue"), labels = c("A","S")) + geom_text(hjust=0.5, vjust=-1 ,size=3) + xlim(-0.05,0.07)
Here are some possible approaches using stat_density2d() with geom="polygon" and mapping or setting alpha transparency for the density fill regions. If you are willing to experiment with some the parameters, I think you can get some very useful plots. Specifically, you may want to adjust the following:
n controls the smoothness of the density polygon.
h is the bandwidth of the density estimation.
bins controls the number of density levels.
df = read.table(header=TRUE, text=
" PC1 PC2 aa
A_akallopisos 0.043272525 0.0151023307 2
A_akindynos -0.020707141 -0.0158198405 1
A_allardi -0.020277664 -0.0221016281 2
A_barberi -0.023165596 0.0389906701 2
A_bicinctus -0.025354572 -0.0059122384 2
A_chrysogaster 0.012608835 -0.0339330213 2
A_chrysopterus -0.022402365 -0.0092476009 1
A_clarkii -0.014474658 -0.0127024469 1
A_ephippium -0.016859412 0.0320034231 2
A_frenatus -0.024190876 0.0238499714 2
A_latezonatus -0.010718845 -0.0289904165 1
A_latifasciatus -0.005645811 -0.0183202248 2
A_mccullochi -0.031664307 -0.0096059126 2
A_melanopus -0.026915545 0.0308399009 2
A_nigripes 0.023420045 0.0293801537 2
A_ocellaris 0.052042539 0.0126144250 2
A_omanensis -0.020387101 0.0010944998 2
A_pacificus 0.042406273 -0.0260308092 2
A_percula 0.034591721 0.0071153133 2
A_perideraion 0.052830132 0.0064495142 2
A_polymnus 0.030902254 -0.0005091421 2
A_rubrocinctus -0.033318659 0.0474995722 2
A_sandaracinos 0.055839755 0.0093724082 2
A_sebae 0.021767793 -0.0218640814 2
A_tricinctus -0.016230301 -0.0018526482 1
P_biaculeatus -0.014466403 0.0024864574 2")
library(ggplot2)
p1 = ggplot(data=df, aes(x=PC1, y=PC2, color=factor(aa), label=rownames(df))) +
ggtitle(paste('Site n° ',sep='')) +
stat_density2d(aes(fill=factor(aa), alpha = ..level..),
geom="polygon", color=NA, n=200, h=0.03, bins=4) +
geom_smooth(se=F, method='lm') +
geom_point() +
scale_color_manual(name='mutation',
values = c("darkorange2","cornflowerblue"),
labels = c("A","S")) +
scale_fill_manual( name='mutation',
values = c("darkorange2","cornflowerblue"),
labels = c("A","S")) +
geom_text(hjust=0.5, vjust=-1 ,size=3, color="black") +
scale_x_continuous(expand=c(0.3, 0)) + # Zooms out so that density polygons
scale_y_continuous(expand=c(0.3, 0)) + # don't reach edges of plot.
coord_cartesian(xlim=c(-0.05, 0.07),
ylim=c(-0.04, 0.05)) # Zooms back in for the final plot.
p2 = ggplot(data=df, aes(x=PC1, y=PC2, color=factor(aa), label=rownames(df))) +
ggtitle(paste('Site n° ',sep='')) +
stat_density2d(aes(fill=factor(aa)), alpha=0.2,
geom="polygon", color=NA, n=200, h=0.045, bins=2) +
geom_smooth(se=F, method='lm', size=1) +
geom_point(size=2) +
scale_color_manual(name='mutation',
values = c("darkorange2","cornflowerblue"),
labels = c("A","S")) +
scale_fill_manual( name='mutation',
values = c("darkorange2","cornflowerblue"),
labels = c("A","S")) +
geom_text(hjust=0.5, vjust=-1 ,size=3) +
scale_x_continuous(expand=c(0.3, 0)) + # Zooms out so that density polygons
scale_y_continuous(expand=c(0.3, 0)) + # don't reach edges of plot.
coord_cartesian(xlim=c(-0.05, 0.07),
ylim=c(-0.04, 0.05)) # Zooms back in for the final plot.
library(gridExtra)
ggsave("plots.png", plot=arrangeGrob(p1, p2, ncol=1), width=8, height=11, dpi=120)
Here's my suggestion. Using shadows or polygons is going to get pretty ugly when you overlay two colors and densities. Contour plot could be nicer to look at and is certainly easier to work with.
I've created some random data as a reproducible example and used a simple density function that uses the average distance of the nearest 5 points.
df <- data.frame(PC1 = runif(20),
PC2 = runif(20),
aa = rbinom(20,1,0.5))
point.density <- function(row){
points <- df[df$aa == row[[3]],]
x.dist <- (points$PC1 - row[[1]])^2
y.dist <- (points$PC2 - row[[2]])^2
x <- x.dist[order(x.dist)[1:5]]
y <- y.dist[order(y.dist)[1:5]]
1/mean(sqrt(x + y))
}
# you need to calculate the density for the whole grid.
res <- c(1:100)/100 # this is the resolution, so gives a 100x100 grid
plot.data0 <- data.frame(x.val = rep(res,each = length(res)),
y.val = rep(res, length(res)),
type = rep(0,length(res)^2))
plot.data1 <- data.frame(x.val = rep(res,each = length(res)),
y.val = rep(res, length(res)),
type = rep(1,length(res)^2))
plot.data <- rbind(plot.data0,plot.data1)
# we need a density value for each point type, so 2 grids
densities <- apply(plot.data,1,point.density)
plot.data <- cbind(plot.data, z.val = densities)
library(ggplot2)
# use stat_contour to draw the densities. Be careful to specify which dataset you're using
ggplot() + stat_contour(data = plot.data, aes(x=x.val, y=y.val, z=z.val, colour = factor(type)), bins = 20, alpha = 0.4) + geom_point(data = df, aes(x=PC1,y=PC2,colour = factor(aa)))
contour plot http://img34.imageshack.us/img34/6215/1yvb.png
rcontourggplot2
I would like to create a simple scatter plot in R or MATLAB involving two variables $x$ and $y$ which have errors associated with them, $\epsilon_x$ and $\epsilon_y$.
Instead of adding error-bars, however, I was hoping to create a "shaded box" around each $(x,y)$ pair where the height of the box ranges from ($y - \epsilon_y$) to ($y + \epsilon_y$) and the width of the box ranges from ($x - \epsilon_y$) to ($x + \epsilon_y$) .
Is this possible in R or MATLAB? If so, what package or code can I use to generate these plots. Ideally, I would like the package to also support asymmetric error bounds.
You could do it in matlab by creating the following function:
function errorBox(x,y,epsx,epsy)
%# make sure inputs are all column vectors
x = x(:); y = y(:); epsx = epsx(:); epsy = epsy(:);
%# define the corner points of the error boxes
errBoxX = [x-epsx, x-epsx, x+epsx, x+epsx];
errBoxY = [y-epsy, y+epsy, y+epsy, y-epsy];
%# plot the transparant errorboxes
fill(errBoxX',errBoxY','b','FaceAlpha',0.3,'EdgeAlpha',0)
end
x, y, epsx and epsy can all be vectors.
Example:
x = randn(1,5); y = randn(1,5);
epsx = rand(1,5)/5;
epsy = rand(1,5)/5;
plot(x,y,'rx')
hold on
errorBox(x,y,epsx,epsy)
Result:
It's probably easier using the ggplot2. First create some data:
set.seed(1)
dd = data.frame(x = 1:5, eps_x = rnorm(5, 0, 0.1), y = rnorm(5), eps_y = rnorm(5, 0, 0.1))
##Save space later
dd$xmin = dd$x - dd$eps_x
dd$xmax = dd$x + dd$eps_x
dd$ymin = dd$y - dd$eps_y
dd$ymax = dd$y + dd$eps_y
Then use the rectangle geom in ggplot2:
library(ggplot2)
ggplot(dd) +
geom_rect(aes( xmax = xmax, xmin=xmin, ymin=ymin, ymax = ymax))
gives the first plot. Of course, you don't need to use ggplot2, to get something similar in base graphics, try:
plot(0, 0, xlim=c(0.5, 5.5), ylim=c(-1, 1), type="n")
for(i in 1:nrow(dd)){
d = dd[i,]
polygon(c(d$xmin, d$xmax, d$xmax, d$xmin), c(d$ymin, d$ymin, d$ymax,d$ymax), col="grey80")
}
to get the second plot.
Here's how to do it using Matlab (with asymmetric intervals). Converting to symmetric ones should be trivial.
%# define some random data
x = rand(5,1)*10;y = rand(5,1)*10;
%# ex, ey have two columns for lower/upper bounds
ex = abs(randn(5,2))*0.3;ey=abs(randn(5,2));
%# create vertices, faces, for patches
vertx = bsxfun(#minus,y,ey(:,[1 2 2 1]))';
verty = bsxfun(#minus,y,ey(:,[1 1 2 2]))';
vertices = [vertx(:),verty(:)];
faces = bsxfun(#plus,[1 2 3 4],(0:4:(length(x)-1)*4)');
%# create patch
patch(struct('faces',faces,'vertices',vertices),'FaceColor',[0.5 0.5 0.5]);
%# add "centers" - note, the intervals are asymmetric
hold on, plot(x,y,'oy','MarkerFaceColor','r')
It's simple with the ggplot2 package in R.
# An example data frame
dat <- data.frame(x = 1:5, y = 5:1, ex = (1:5)/10, ey = (5:1)/10)
# Plot
library(ggplot2)
ggplot(dat) +
geom_rect(aes(xmin = x - ex, xmax = x + ex, ymin = y - ey, ymax = y + ey),
fill = "grey") +
geom_point(aes(x = x, y = y))
In the aes function inside geom_rect the size of the rectangle is defined by ex and ey around x and y.
Here's a MATLAB answer:
x = randn(1,5); y = 3-2*x + randn(1,5);
ex = (.1+rand(1,5))/5; ey = (.2+rand(1,5))/3;
plot(x,y,'ro')
patch([x-ex;x+ex;x+ex;x-ex],[y-ey;y-ey;y+ey;y+ey],[.9 .9 .9],'facealpha',.2,'linestyle','none')
Now I draw plot with ggplot2.
I want to draw circle in my plot.
So I searched it and found the solutions.
Draw a circle with ggplot2
However I can't use this solution, because my plot's x axis is Date format.
my_plot <- qplot(Day, value, data = target_data_melt, shape = variable, colour = variable, geom="line")
my_plot <- my_plot + scale_x_date(labels = date_format("%Y-%m"))
How can I draw a circle in my plot?
Is there any way to draw a circle in Date axis?
target_data_melt looks like this.
Day variable value
1 2010-10-01 231 0.007009346
2 2010-10-03 231 0.005204835
3 2010-10-05 231 0.006214004
You can adapt the code from the link you provided to format the x-coordinate as Date:
require("date")
circle <- function(center_Date = as.Date("2012-11-24"),
center_y = 0,
r.x = 100,
r.y = 100,
npoints = 100) {
cycle <- seq(0,2*pi,length.out = npoints)
xx <- center_Date + r.x * cos(cycle)
yy <- center_y + r.y * sin(cycle)
return(data.frame(x = xx, y = yy))
}
And a demonstration:
df <- circle()
plot <- ggplot(df, aes(x, y)) + geom_path()
plot(plot)
Example image (with an adjusted date and y-center) here.
You'll have to set the r.x and r.y properly to get a perfect circle (rather than an oval). What these should be depends on the scales you use in your plots.