ggplot: how to remove unused factor levels from a facet? - ggplot2

The following code
d1 = data.frame(y=1:2,group=factor(c('A','B'), levels=c('A','B','C')), fac = 'f1')
d2 = data.frame(y=1:3,group=factor(c('A','B','C'), levels=c('A','B','C')), fac = 'f2')
d = rbind(d1,d2)
library(ggplot2)
ggplot( d, aes(x=group, y=y) ) + geom_point(size=3) + facet_grid( ~ fac)
Results in the following plot. How can I remove the unused factor level C from the facet 'f1'?

Setting scales = free in facet grid will do the trick:
facet_grid( ~ fac, scales = "free")

Related

Expand margins of ggplot

Apologies for the simplistic question, but I'm having trouble adjusting the size (width) of this plot to include all the data so that it doesn't look so squished. I've tried adjusting the margins and the width in png(), but nothing seems to work.
png("file_name.png", units = "in", width = 10, height = 5, res = 300)
ggplot(pred, aes(x = Longitude, y = Latitude)) +
geom_raster(aes(fill = Fitted)) +
facet_wrap(~ CYR) +
scale_fill_viridis(option = 'plasma',
na.value = 'transparent') +
coord_quickmap() +
theme(legend.position = 'top')
# theme(plot.margin=grid::unit(c(0,20,0,20), "mm"))
dev.off()
Do you need to use coord_quickmap() for some reason? Removing it 'fixes' the plot dimensions, e.g. using the palmerpenguins dataset:
library(ggplot2)
library(palmerpenguins)
p1 <- ggplot(penguins, aes(x = sex,
y = bill_length_mm,
fill = bill_depth_mm)) +
geom_raster() +
scale_fill_viridis_c(option = 'plasma',
na.value = 'transparent') +
facet_wrap(~interaction(island, species, year)) +
theme(legend.position = 'top') +
coord_quickmap()
p1
#> Warning: Raster pixels are placed at uneven horizontal intervals and will be shifted
#> ℹ Consider using `geom_tile()` instead.
#> Warning: Removed 2 rows containing missing values (`geom_raster()`).
p2 <- ggplot(penguins, aes(x = sex,
y = bill_length_mm,
fill = bill_depth_mm)) +
geom_raster() +
scale_fill_viridis_c(option = 'plasma',
na.value = 'transparent') +
facet_wrap(~interaction(island, species, year)) +
theme(legend.position = 'top') #+
# coord_quickmap()
p2
#> Warning: Raster pixels are placed at uneven horizontal intervals and will be shifted
#> ℹ Consider using `geom_tile()` instead.
#> Removed 2 rows containing missing values (`geom_raster()`).
Created on 2023-02-13 with reprex v2.0.2

Correlation of error terms in time-series model

I am reading this statistics book where they have mentioned that the attached top plot has no correlation between adjacent residuals. Whereas, the bottom most has correlation with p-0.9. Can anybody please provide some direction as to how to analyze this? Thank you very much for your time.
Correlated errors mean that the lag 1 correlation is p. That is, Cor(Yi, Yi-1) = p. This can be modelled using Yi = mu + p epsiloni-1 + epsiloni where epsiloni ~ N(0, 1) for all i. We can verify that the correlation between adjacent data points is p: Cov(Yi, Yi-1) = Cov(p epsiloni-1 + epsiloni, p epsiloni-2 + epsiloni-1) = Cov(p epsiloni-1, epsiloni-1) = p Var(epsiloni-1) = p. Code to demonstrate appears below:
set.seed(123)
epsilonX <- rnorm(100, 0, 1)
epsilonY <- rnorm(100, 0, 1)
epsilonZ <- rnorm(100, 0, 1)
X <- NULL
Y <- NULL
Z <- NULL
Y[1] <- epsilonY[1]
X[1] = epsilonX[1]
Z[1] = epsilonZ[1]
rhoX = 0
rhoY = 0.5
rhoZ = 0.9
for (i in 2:100) {
Y[i] <- rhoY * epsilonY[i-1] + epsilonY[i]
X[i] <- rhoX * epsilonX[i-1] + epsilonX[i]
Z[i] <- rhoZ * epsilonZ[i-1] + epsilonZ[i]
}
param = par(no.readonly = TRUE)
par(mfrow=c(3,1))
plot(X, type='o', xlab='', ylab='Residual', main=expression(rho*"=0.0"))
abline(0, 0, lty=2)
plot(Y, type='o', xlab='', ylab='Residual', main=expression(rho*"=0.5"))
abline(0, 0, lty=2)
plot(Z, type='o', xlab='', ylab='Residual', main=expression(rho*"=0.9"))
abline(0, 0, lty=2)
#par(param)
acf(X)
acf(Y)
acf(Z)
Note from the acf plots that the lag 1 correlation is insignificant for p = 0, higher for p = 0.5 data (~0.3), and still higher for p = 0.9 data (~0.5).

Error in FUN(X[[i]], ...) : object 'Year' not found when plotting ordination in ggplot

I am having an issue with the ggplot code line where R doesn't like the "group = Year".
Here is what my data looks like:
> head(data.scores.pa)
NMDS1 NMDS2 NMDS3 Site Year Elevation Fire history
1 -0.737547 0.73473457 0.7575643 BF 2004 1710 Burnt
......
> head(spp.scrs2)
species MDS1 MDS2 pval
1 Acrothamnus.montanus 0.8383 -0.02382347 1e-04
........
> head(vec.sp.df.pa)
MDS1 MDS2 species pvals
Elevation 0.834847 0.747474 Elevation 0.005
Here is the code I am using:
>xy <- ggplot(data.scores.pa, aes(x = NMDS1, y = NMDS2, group = Year)) +
geom_point(size = 3, aes(shape = Fire history, colour = Year))+
stat_ellipse(mapping = NULL, data = NULL, geom = "path", position = "identity", type = "t", level = 0.95, segments = 51, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) +
geom_segment(data=vec.sp.df.pa, aes(x=0,xend=MDS1,y=0,yend=MDS2),
arrow = arrow(length = unit(0.5,"cm")),colour="grey")+
geom_text_repel(data=vec.sp.df.pa,aes(x=MDS1,y=MDS2,label=species),size=2)+
geom_segment(data=spp.scrs2,aes(x=0,xend=MDS1,y=0,yend=MDS2),
arrow = arrow(length = unit(0.5, "cm")),colour="black")+
geom_text_repel(data=spp.scrs2, aes(x=MDS1,y=MDS2,label=species),size=2)+
annotate("text", x = -1.6, y = 1, label = paste0("3D stress: ", format(ord.pa$stress, digits = 4)), hjust = 0) +
theme_cowplot() + scale_color_brewer(palette = "BrBG", direction = 1) +
theme(panel.border = element_rect(colour = "black"))+
ggtitle("All Sites - distance data using Bray-Curtis")+
labs(x = "NMDS1", y = "NMDS2")
> Error in FUN(X[[i]], ...) : object 'Year' not found
However, when I remove the geom_segment and geom_text_repel code lines it fixes the problem and I am able to plot the graph...
Is anyone able to provide some insight into this issue?
Thank you!

How to include a legend to a ggplot2?

Given this data here:
p <- ggplot(mpg, aes(displ, cty)) + geom_point() + facet_grid(drv ~ cyl)
g <- ggplot_gtable(ggplot_build(p))
strip_both <- which(grepl('strip-', g$layout$name))
fills <- c("red","green","blue","yellow","red","green","blue","yellow")
k <- 1
for (i in strip_both) {
j <- which(grepl('rect', g$grobs[[i]]$grobs[[1]]$childrenOrder))
g$grobs[[i]]$grobs[[1]]$children[[j]]$gp$fill <- fills[k]
k <- k+1
}
grid.draw(g)
I want to add a legend for the colors of the facets:
as shown here
One option to achieve your desired result would be with an auxiliary geom_point layer which draws nothing but is only used to map a variable with your desired four categories on the fill aes. Doing so will automatically add a fill legend for which we could set your desired colors using scale_fill_manual. Additionally I switched the key_glyph for the point layer to draw_key_rectto mimic your desired style for the legend keys and added na.rm to silent the warning about removed NAs:
library(ggplot2)
library(grid)
p <- ggplot(mpg, aes(displ, cty)) + geom_point() + facet_grid(drv ~ cyl) +
geom_point(data = data.frame(x = NA_real_, y = NA_real_, fill = c("AB", "D", "FF", "v")),
aes(x = x, y = y, fill = fill), na.rm = TRUE, key_glyph = "rect") +
scale_fill_manual(values = c("AB" = "red", D = "yellow", FF = "blue", v = "green"), name = NULL) +
theme(legend.position = "bottom")
g <- ggplot_gtable(ggplot_build(p))
strip_both <- which(grepl('strip-', g$layout$name))
fills <- c("red","green","blue","yellow","red","green","blue","yellow")
k <- 1
for (i in strip_both) {
j <- which(grepl('rect', g$grobs[[i]]$grobs[[1]]$childrenOrder))
g$grobs[[i]]$grobs[[1]]$children[[j]]$gp$fill <- fills[k]
k <- k+1
}
grid.draw(g)

Shifting HSV pixel values in python using Numpy

I'm trying to convert (shift) the values of every pixel in an HSV image (taken from a frame of a video).
The idea is to invert yellow and red colours into blue colour (to avoid using three threshold later in the program, when I can use just one) by inverting the red and yellow values into blue values using following equation.
(Hue + 90) % 180 (in OpenCV 3 Hue is in range [0,180])
Here's what I came up with:
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV);
H = hsv[:,:,0]
mask= [H<75 and H>128]
print("orig",hsv[mask])
hsv[mask] = ((hsv[mask]+90) % 180)
Unfortunately It doesn't work as by this approach Im selecting the whole hue channel not its pixel values
There's two different possibilities here, and I'm not sure which you want, but they're both trivial to implement. You can invert (reverse may be a better word) the hue rainbow, which you can just do by using 180 - hue. Or you can shift the color by 180 degrees by using (hue + 90) % 180 like you mention.
Reversing the colors:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
rev_h = 180 - h
rev_hsv = cv2.merge([rev_h, s, v])
rev_img = cv2.cvtColor(rev_hsv, cv2.COLOR_HSV2BGR)
Shifting the colors:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
shift_h = (h + 90) % 180
shift_hsv = cv2.merge([shift_h, s, v])
shift_img = cv2.cvtColor(shift_hsv, cv2.COLOR_HSV2BGR)
Those are the idiomatic ways to do it in OpenCV.
Now you want to do the same thing as above but only for some masked subset of pixels that meet a condition. This is not too hard to do; if you want to shift some masked pixels:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
h_mask = (h < 75) | (h > 128)
h[h_mask] = (h[h_mask] + 90) % 180
shift_hsv = cv2.merge([h, s, v])
shift_img = cv2.cvtColor(shift_hsv, cv2.COLOR_HSV2BGR)
Hue channel is uint8 type, value range is [0, 179]. Therefore, when add with a large number or a negative number, Python returns a garbage number. Here is my solution base on #alkasm color shifting code:
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(img_hsv)
shift_h = random.randint(-50, 50)
h = ((h.astype('int16') + shift_h) % 180).astype('uint8')
shift_hsv = cv2.merge([h, s, v])
For random hue, saturation, and value shifting. Shift channel base on #bill-grates:
def shift_channel(c, amount):
if amount > 0:
lim = 255 - amount
c[c >= lim] = 255
c[c < lim] += amount
elif amount < 0:
amount = -amount
lim = amount
c[c <= lim] = 0
c[c > lim] -= amount
return c
rand_h, rand_s, rand_v = 50, 50, 50
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(img_hsv)
# Random shift hue
shift_h = random.randint(-rand_h, rand_h)
h = ((h.astype('int16') + shift_h) % 180).astype('uint8')
# Random shift saturation
shift_s = random.randint(-rand_s, rand_s)
s = shift_channel(s, shift_s)
# Random shift value
shift_v = random.randint(-rand_v, rand_v)
v = shift_channel(v, shift_v)
shift_hsv = cv2.merge([h, s, v])
print(shift_h, shift_s, shift_v)
img_rgb = cv2.cvtColor(shift_hsv, cv2.COLOR_HSV2RGB)