I want to add another legend that tells me what ring of a circular heat map represents (from outer ring to inner ring).
I tried the following from another answer previously:
library(reshape)
library(ggplot2)
library(plyr)
nba <- read.csv("http://datasets.flowingdata.com/ppg2008.csv")
nba$Name <- with(nba, reorder(Name, PTS))
nba.m <- melt(nba)
nba.m <- ddply(nba.m, .(variable), transform, value = scale(value))
# Convert the factor levels (variables) to numeric + quanity to determine size of hole.
nba.m$var2 = as.numeric(nba.m$variable) + 15
# Labels and breaks need to be added with scale_y_discrete.
y_labels = levels(nba.m$variable)
y_breaks = seq_along(y_labels) + 15
nba.labs <- subset(nba.m, variable==levels(nba.m$variable) [nlevels(nba.m$variable)])
nba.labs <- nba.labs[order(nba.labs$Name),]
nba.labs$ang <- seq(from=(360/nrow(nba.labs))/1.5, to=(1.5* (360/nrow(nba.labs)))-360, length.out=nrow(nba.labs))+80
nba.labs$hjust <- 0
nba.labs$hjust[which(nba.labs$ang < -90)] <- 1
nba.labs$ang[which(nba.labs$ang < -90)] <- (180+nba.labs$ang)[which(nba.labs$ang < -90)]
p2 = ggplot(nba.m, aes(x=Name, y=var2, fill=value)) +
geom_tile(colour="white") +
geom_text(data=nba.labs, aes(x=Name, y=var2+1.5,
label=Name, angle=ang, hjust=hjust), size=3) +
scale_fill_gradient(low = "white", high = "steelblue") +
ylim(c(0, max(nba.m$var2) + 1.5)) +
scale_y_discrete(breaks=y_breaks, labels=y_labels) +
coord_polar(theta="x") +
theme(panel.background=element_blank(),
axis.title=element_blank(),
panel.grid=element_blank(),
axis.text.x=element_blank(),
axis.ticks=element_blank(),
axis.text.y=element_text(size=5))
print(p2)
However, instead of getting the legend, I'm having this error message instead:
Scale for 'y' is already present. Adding another scale for 'y', which
will replace the existing scale.
Any solutions?
Thanks in advance!
It's not entirely clear to me what you're looking for but this may be it.
You were originally using scale_y_discrete(breaks=y_breaks, labels=y_labels) to project to a continuous variable,var2, in aes(x=Name, y=var2, fill=value). By changing that to scale_y_continuous(breaks=y_breaks, labels=y_labels) you can get the categorical labels listed for nba.m$variable.
ggplot(nba.m, aes(x=Name, y=var2, fill=value)) +
geom_tile(colour="white") +
geom_text(data=nba.labs, aes(x=Name, y=var2+1.5,
label=Name, angle=ang, hjust=hjust), size=3) +
scale_fill_gradient(low = "white", high = "steelblue") +
ylim(c(0, max(nba.m$var2) + 1.5)) +
scale_y_continuous(breaks=y_breaks, labels=y_labels) +
coord_polar(theta="x") +
theme(panel.background=element_blank(),
axis.title=element_blank(),
panel.grid=element_blank(),
axis.text.x=element_blank(),
axis.ticks=element_blank(),
axis.text.y=element_text(size=5))
UPDATE
I'm not sure what you're trying to do here -those values are not blank in the center because there's data there, removing scale_y_continuous(breaks=y_breaks, labels=y_labels) limits the scale of the y-axis such that the date is no longer graphed. That's why you're not seeing the middle filled when that line of code is removed. At any rate, if that's what you're looking for, what you need to do is delete scale_y_continuous(breaks=y_breaks, labels=y_labels) and turn off the labels for the y-axis, then manually add those labels using grob. I'm sure there's a better way to accomplish what you need but this will get you started at least.
p<-ggplot(nba.m, aes(x=Name, y=var2, fill=value)) +
geom_tile(colour="white") +
geom_text(data=nba.labs, aes(x=Name, y=var2+1.5,
label=Name, angle=ang, hjust=hjust), size=2.5) +
scale_fill_gradient(low = "white", high = "steelblue") +
ylim(c(0, 50)) +
coord_polar(theta="x") +
theme(panel.background=element_blank(),
axis.title=element_blank(),
panel.grid=element_blank(),
axis.text.x=element_blank(),
axis.ticks=element_blank(),
axis.text.y=element_text(size=5))+ theme(axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank())
lab = textGrob((paste("G MIN PTS FGM FGA FGP FTM FTA FTP X3PM X3PA X3PP ORB DRB TRB AST STL BLK TO PF")),
x = unit(.1, "npc"), just = c("left"),
gp = gpar(fontsize = 7))
gp = ggplotGrob(p)
gp = gtable_add_rows(gp, unit(10, "grobheight", lab), -1)
gp = gtable_add_grob(gp, lab, t = -2, l = gp$layout[gp$layout$name == "panel",]$l)
grid.newpage()
grid.draw(gp)
Related
I would like to use ggplot() to produce a graph with truncated axis lines similar to what is seen in the lower left corner in the plot below (created with base R graphics).
I guess that I need to set the axis.line argument in my ggplot theme to something other than element_line(), but I have no idea to what. Here's the code I currently have
library("ggplot2")
library("ggrepel")
tab <- data.frame(
Average=rnorm(40, mean=12, sd=3),
SD =rnorm(40, mean=12, sd=3),
names = LETTERS[1:40],
class_num = sample(1:4, size=40, replace=TRUE)
)
ggplot(data=tab,
aes(x=Average, y=SD, label=rownames(tab))) +
stat_smooth(method="lm", size=1, se=FALSE, col="black") +
geom_point(aes(col=factor(class_num), shape=factor(class_num)), size=2) +
geom_text_repel(size=3) +
xlab(expression("Seasonal average" ~ widehat(ETI)[m])) +
ylab(expression("Seasonal SD of" ~ widehat(ETI)[m])) +
scale_x_continuous(breaks =seq(9.2, 11.8, length.out=5)) +
scale_shape_manual(values=c(15, 16, 17, 18)) +
scale_color_manual(values=c("#CC0000", "darkgreen", "#0000CC", "#000000")) +
theme_classic() +
theme(legend.position="none",
axis.ticks.length = unit(.25, "cm"),
axis.line = element_line())
This produces the following plot where the x-axis and y axis lines are connected in the lower left-hand corner.
How about this, it makes use of the coord_capped_cart() function from the lemon package. There's a nice discussion here.
library("ggplot2")
library("ggrepel")
library(lemon)
tab <- data.frame(
Average=rnorm(40, mean=12, sd=3),
SD =rnorm(40, mean=12, sd=3),
names = LETTERS[1:40],
class_num = sample(1:4, size=40, replace=TRUE)
)
ggplot(data=tab,
aes(x=Average, y=SD, label=rownames(tab))) +
stat_smooth(method="lm", size=1, se=FALSE, col="black") +
geom_point(aes(col=factor(class_num), shape=factor(class_num)), size=2) +
geom_text_repel(size=3) +
xlab(expression("Seasonal average" ~ widehat(ETI)[m])) +
ylab(expression("Seasonal SD of" ~ widehat(ETI)[m])) +
scale_x_continuous(breaks =seq(7, 17, length.out=5)) +
scale_y_continuous(breaks=seq(5,18, length.out=5)) +
scale_shape_manual(values=c(15, 16, 17, 18)) +
scale_color_manual(values=c("#CC0000", "darkgreen", "#0000CC", "#000000")) +
theme_classic() +
theme(legend.position="none",
axis.ticks.length = unit(.25, "cm"),
axis.line = element_line()) +
coord_capped_cart(bottom=capped_horizontal(),
left=capped_vertical(capped="both"))
I'm working in a Impulse-Response function plot (from a Vector AutoRegressive Model) with GGplot2 + grid.arrange. Below i give you my actual plot and the original one from the vars package. I really would like any hint to improve the final result
Would be nice, at least place both plots closer.
This is not a full question topic, but an improvement asking
here the full code
library(vars)
# Define lags
lag = VARselect(my_data, lag.max=12)
# Estimating var
my_var = VAR(my_data, min(lag$selection), type='both')
# Set the Impulse-Response data
impulse <- irf(my_var)
# Prepare plot data
number_ticks <- function(n) {function(limits) pretty(limits, n)}
lags <- c(1:11)
irf1<-data.frame(impulse$irf$PIB[,1],impulse$Lower$PIB[,1],
impulse$Upper$PIB[,1], lags)
irf2<-data.frame(impulse$irf$PIB[,2],impulse$Lower$PIB[,2],
impulse$Upper$PIB[,2])
# creating plots
PIB_PIB <- ggplot(data = irf1,aes(lags,impulse.irf.PIB...1.)) +
geom_line(aes(y = impulse.Upper.PIB...1.), colour = 'lightblue2') +
geom_line(aes(y = impulse.Lower.PIB...1.), colour = 'lightblue')+
geom_line(aes(y = impulse.irf.PIB...1.))+
geom_ribbon(aes(x=lags, ymax=impulse.Upper.PIB...1., ymin=impulse.Lower.PIB...1.), fill="lightblue", alpha=.1) +
xlab("") + ylab("PIB") + ggtitle("Orthogonal Impulse Response from PIB") +
theme(axis.title.x=element_blank(),
axis.text.x=element_blank(),
axis.ticks.x=element_blank()) +
geom_line(colour = 'black')
PIB_CON <- ggplot(data = irf2,aes(lags,impulse.irf.PIB...2.)) +
geom_line(aes(y = impulse.Upper.PIB...2.), colour = 'lightblue2') +
geom_line(aes(y = impulse.Lower.PIB...2.), colour = 'lightblue')+
geom_line(aes(y = impulse.irf.PIB...2.))+
geom_ribbon(aes(x=lags, ymax=impulse.Upper.PIB...2., ymin=impulse.Lower.PIB...2.), fill="lightblue", alpha=.1) +
scale_x_continuous(breaks=number_ticks(10)) +
xlab("") + ylab("CONSUMO") + ggtitle("") +
theme(axis.title.x=element_blank(),
axis.text.x=element_blank(),
axis.ticks.x=element_blank()) +
geom_line(colour = 'black')
# Generating plot
grid.arrange(PIB_PIB, PIB_CON, nrow=2)
Actual Output
Desired Style [when you call plot(irf(my_var))
Got something very close to desired model.
here the changed plots:
PIB_PIB <- ggplot(data = irf1,aes(lags,impulse.irf.PIB...1.)) +
geom_line(aes(y = impulse.Upper.PIB...1.), colour = 'lightblue2') +
geom_line(aes(y = impulse.Lower.PIB...1.), colour = 'lightblue')+
geom_line(aes(y = impulse.irf.PIB...1.))+
geom_ribbon(aes(x=lags, ymax=impulse.Upper.PIB...1., ymin=impulse.Lower.PIB...1.), fill="lightblue", alpha=.1) +
xlab("") + ylab("PIB") + ggtitle("Orthogonal Impulse Response from PIB") +
theme(axis.title.x=element_blank(),
axis.text.x=element_blank(),
axis.ticks.x=element_blank(),
plot.margin = unit(c(2,10,2,10), "mm"))+
scale_x_continuous(breaks=number_ticks(10)) +
geom_line(colour = 'black')
PIB_CON <- ggplot(data = irf2,aes(lags,impulse.irf.PIB...2.)) +
geom_line(aes(y = impulse.Upper.PIB...2.), colour = 'lightblue2') +
geom_line(aes(y = impulse.Lower.PIB...2.), colour = 'lightblue')+
geom_line(aes(y = impulse.irf.PIB...2.))+
geom_ribbon(aes(x=lags, ymax=impulse.Upper.PIB...2., ymin=impulse.Lower.PIB...2.), fill="lightblue", alpha=.1) +
xlab("") + ylab("CONSUMO") + ggtitle("") +
theme(axis.title.x=element_blank(),
# axis.text.x=element_blank(),
# axis.ticks.x=element_blank(),
plot.margin = unit(c(-10,10,4,10), "mm"))+
scale_x_continuous(breaks=number_ticks(10)) +
geom_line(colour = 'black')
grid.arrange(PIB_PIB, PIB_CON, nrow=2)
I'm trying to generate a multi-layered plot where the points in one layer gets displayed only in a fraction of the facets created using data from another layer. In the code below, the points in red are either x1 or x2 (just like the row labels of the facet).
library(ggplot2)
set.seed(1000)
#generate first df
df1 = data.frame(x=rep(rep(seq(2,8,2),4),4),
y=rep(rep(seq(2,8,2),each=4),4),
v1=rep(c("x1","x2"),each=32),
v2=rep(rep(c("t1","t2"),each=16),2),
v3=rbinom(64,1,0.5))
# generate second df
df2 = data.frame(x=runif(20)*10,
y=runif(20)*10,
v4=sample(c("x1","x2"),20,T))
# create theme
t1=theme(panel.grid.major = element_blank(), text = element_text(size=18),
panel.grid.minor = element_blank(), strip.background= element_blank(),
axis.title.x = element_blank(), axis.title.y = element_blank())
# plot
ggplot() +
geom_point(data=df1, aes(x=x, y=y, colour = factor(v3)), shape=15, size=5) +
scale_colour_manual(values = c(NA,"black")) + facet_grid(v1~v2) +
geom_point(data=df2, aes(x=x,y=y, shape=v4), colour="red", size=4) +
coord_equal(ratio=1) + xlim(0, 10) + ylim(0, 10) + t1
EDIT: The black squares are generated by manually setting the colour of df1$v3 = 1 to black and df1$v3 = 0 to NA. /EDIT
But what I actually want is to display only those points from df2 with df2$v4 = x1 in the first row of facets, and df2$v4 = x2 in the second row of facets (corresponding to the values of df1$v1 and the row labels of the facet).
I've done this by generating two separate graphs...
ggplot() +
geom_point(data=df1[df1$v1=="x1",], shape=15, size=5,
aes(x=x, y=y, colour = factor(v3)), ) +
scale_colour_manual(values = c(NA,"black")) + facet_grid(~v2) +
geom_point(data=df2[df2$v4=="x1",], aes(x=x,y=y), colour="red", size=4) +
coord_equal(ratio=1) + xlim(0, 10) + ylim(0, 10) + t1
ggplot() +
geom_point(data=df1[df1$v1=="x2",], shape=15, size=5,
aes(x=x, y=y, colour = factor(v3)), ) +
scale_colour_manual(values = c(NA,"black")) + facet_grid(~v2) +
geom_point(data=df2[df2$v4=="x2",], aes(x=x,y=y), colour="red", size=4) +
coord_equal(ratio=1) + xlim(0, 10) + ylim(0, 10) + t1
... but I'm curious if a single plot can be generated because with my actual data set I have several x's and it is time consuming to piece the graphs together.
does it help if we just rename df2$v4 or make a new column called df2$v1, for faceting purposes:
df2 <- dplyr::rename(df2, v1 = v4)
df2$v1 <- df2$v4
# either works
then ggplot will distribute the data points as you would like, with this:
ggplot() +
geom_point(data=df1, aes(x=x, y=y, colour = factor(v3)), shape=15, size=5) +
scale_colour_manual(values = c(NA,"black")) +
facet_grid(v1~v2) +
geom_point(data=df2, aes(x=x,y=y), colour="red", size=4) +
coord_equal(ratio=1) + xlim(0, 10) + ylim(0, 10) +
t1
not 100% sure I grasp your problem...
I have a simple problem but I can't figure out why it won't work -> I can't adjust the y scale range on my faceted bar plot:
# Data #
df<-as.data.frame(c("x","y","z","x","y","z","x","y","z","x","y","z"))
colnames(df)<-"x"
df$y<-c(10,15,20,5,25,45,10,10,20,40,20,5)
df$facet<-c(1,1,1,1,1,1,2,2,2,2,2,2)
df$group<-c("A","A","A","B","B","B","A","A","A","B","B","B")
# Plot #
ggplot(df, aes(x=x, y=y, fill=group)) +
facet_grid( ~ facet) +
scale_fill_manual(values=c("blue", "red")) +
geom_bar(position="dodge", stat="identity") +
theme(strip.text = element_text(face="bold", size=rel(1)),
strip.background = element_rect(fill="white", colour="white", size=1)) +
theme(panel.margin = unit(1, "lines")) +
scale_x_discrete(expand = c(0, 0)) +
theme(panel.grid.major.x = element_blank()) + theme(axis.ticks.x = element_blank()) +
theme(legend.background=element_blank()) +
scale_y_continuous("%", breaks=seq(0, 50, 10), minor_breaks=seq(0,50,5), expand = c(0, 0))
I would like the y-axis to go upto 50 but using scale_y_continuous strangely does not work, producing this result:
You need to add a limits argument in your scale_y_continuous :
scale_y_continuous("%", limits=c(0,50), breaks=seq(0, 50, 10), minor_breaks=seq(0,50,5), expand = c(0, 0))
Otherwise you just define the breaks position, not the axis values range.
I have some data:
dat <- data.frame(x=rnorm(100,100,100),y=rnorm(100,100,100))
I can plot it with a local trend line:
ggplot(dat, aes(x,y)) + stat_smooth()
But I want to overlay a density curve, on the same plot, showing the distribution of x. So just add the previous graph to this one (the y-axis is different, but I only care about relative differences in the density curve anyway):
ggplot(dat, aes(x)) + geom_density()
I know there's stat_binhex() and stat_sum() etc showing where the data falls. There are only a few y values, so what gets plotted by stat_binhex() etc is hard to read.
You can plot a combination of histograms and density curves at both sides of the scatterplot. In the example below I also included a confidence ellipse:
require(ggplot2)
require(gridExtra)
require(devtools)
source_url("https://raw.github.com/low-decarie/FAAV/master/r/stat-ellipse.R") # in order to create a 95% confidence ellipse
htop <- ggplot(data=dat, aes(x=x)) +
geom_histogram(aes(y=..density..), fill = "white", color = "black", binwidth = 2) +
stat_density(colour = "blue", geom="line", size = 1.5, position="identity", show_guide=FALSE) +
scale_x_continuous("x-var", limits = c(-200,400), breaks = c(-200,0,200,400)) +
scale_y_continuous("Density", breaks=c(0.0,0.01,0.02), labels=c(0.0,0.01,0.02)) +
theme_bw() + theme(axis.title.x = element_blank())
blank <- ggplot() + geom_point(aes(1,1), colour="white") +
theme(axis.ticks=element_blank(), panel.background=element_blank(), panel.grid=element_blank(),
axis.text.x=element_blank(), axis.text.y=element_blank(), axis.title.x=element_blank(), axis.title.y=element_blank())
scatter <- ggplot(data=dat, aes(x=x, y=y)) +
geom_point(size = 0.6) + stat_ellipse(level = 0.95, size = 1, color="green") +
scale_x_continuous("x-var", limits = c(-200,400), breaks = c(-200,0,200,400)) +
scale_y_continuous("y-var", limits = c(-200,400), breaks = c(-200,0,200,400)) +
theme_bw()
hright <- ggplot(data=dat, aes(x=y)) +
geom_histogram(aes(y=..density..), fill = "white", color = "black", binwidth = 1) +
stat_density(colour = "red", geom="line", size = 1, position="identity", show_guide=FALSE) +
scale_x_continuous("y-var", limits = c(-200,400), breaks = c(-200,0,200,400)) +
scale_y_continuous("Density", breaks=c(0.0,0.01,0.02), labels=c(0.0,0.01,0.02)) +
coord_flip() + theme_bw() + theme(axis.title.y = element_blank())
grid.arrange(htop, blank, scatter, hright, ncol=2, nrow=2, widths=c(4, 1), heights=c(1, 4))
the result: