问题
I have the following data frame:
structure(list(X1 = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 4L, 4L,
4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L
), .Label = c("1", "2", "3", "4", "5", "6"), class = "factor"),
X2 = structure(c(1L, 6L, 8L, 10L, 12L, 13L, 3L, 4L, 1L, 6L,
7L, 9L, 10L, 12L, 13L, 3L, 4L, 5L, 10L, 12L, 13L, 4L, 1L,
6L, 12L, 13L, 3L, 1L, 6L, 7L, 8L, 10L, 11L, 12L, 13L, 2L,
3L, 11L, 12L, 13L), .Label = c("I1", "I10", "I11", "I12",
"I13", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9"), class = "factor")), .Names = c("X1",
"X2"), row.names = c(NA, -40L), class = "data.frame")
Where in X1 is the person number and in X2 the group to which the person belongs to. One person can be in different groups.
Now I want to draw a line from each person to each group he belongs to. With plot()
I solved it this way:
plot(0, xlim=c(0,1), ylim=c(0,1), type="n", axes=FALSE, xlab="", ylab="")
factor.to.int <- function(f) {
(as.integer(f) - 1) / (length(levels(f)) - 1)
}
segments(factor.to.int(data$X1), 0, factor.to.int(data$X2), 1, col=data$X1)
axis(1, at = seq(0, 1, by = 1 / (length(levels(data$X1)) - 1)), labels = levels(data$X1))
axis(3, at = seq(0, 1, by = 1 / (length(levels(data$X2)) - 1)), labels = levels(data$X2))
The result looks like this:
Now I wondering how I can do this with ggplot2?
Thanks for your help!
回答1:
A simple ggplot2
version of your graph is possible by using geom_segment()
and transforming the data much like you did for the base graphics version. I've also included an arguably more polished version, using some of the more advanced customization options in ggplot2.
# Using ggplot2 version 0.9.2.1
library(ggplot2)
dat$x1_norm = rangeTransform(as.integer(dat$X1))
dat$x2_norm = rangeTransform(as.integer(dat$X2))
dat$y1 = 0
dat$y2 = 1
# Simple version.
p1 = ggplot(dat, aes(x=x1_norm, xend=x2_norm, y=y1, yend=y2, colour=X1)) +
geom_segment(size=1.2) +
scale_colour_brewer(palette="Set1", name="Person")
ggsave(plot=p1, filename="plot_1.png", height=3.5, width=6)
# Fancy version.
# Create separate data.frames to manually specify axis ticks and axis text.
axis_1 = data.frame(x=rangeTransform(as.integer(unique(dat$X1))),
y=0, label=as.character(unique(dat$X1)))
axis_2 = data.frame(x=rangeTransform(as.integer(unique(dat$X2))),
y=1, label=as.character(unique(dat$X2)))
p2 = ggplot(data=dat) +
theme_bw() +
theme(axis.title=element_blank()) +
theme(axis.text=element_blank()) +
theme(axis.ticks=element_blank()) +
theme(panel.grid=element_blank()) +
geom_segment(aes(x=x1_norm, xend=x2_norm, y=y1, yend=y2, colour=X1),
size=1.2) +
geom_segment(x=0, xend=1, y=0, yend=0, size=0.7) +
geom_segment(x=0, xend=1, y=1, yend=1, size=0.7) +
scale_colour_brewer(palette="Set1", name="Person") +
scale_y_continuous(limits=c(-0.2, 1.2), expand=c(0, 0)) +
geom_segment(data=axis_1, aes(x=x, xend=x, y=y, yend=y-0.025), size=0.7) +
geom_segment(data=axis_2, aes(x=x, xend=x, y=y, yend=y+0.025), size=0.7) +
geom_text(data=axis_1, aes(label=label, x=x, y=y - 0.075)) +
geom_text(data=axis_2, aes(label=label, x=x, y=y + 0.075))
ggsave(plot=p2, filename="plot_2.png", height=3.5, width=6)
来源:https://stackoverflow.com/questions/13235972/bipartite-network-graph-with-ggplot2