我有大量的小块地块需要放置在更大的地块画布中,并将小块地块排成一行并用线条连接起来。一个小例子如下所示:
A到L是独立的图。他们的位置是坐下来的。
绘制网格坐标:PlotgridX和plotgridY可以决定小图需要居中的时间
plotcord <- data.frame (
plotname = c("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"),
plotgridX = c( 1.5, 2, 5, 5.5, 1.75, 5.25, 8 , 1 , 2, 3.5, 6, 7.5),
plotgridY = c( 3, 3, 3, 3, 2 , 2, 2, 2 , 1, 1, 1, 1))
plotname plotgridX plotgridY
1 A 1.50 3
2 B 2.00 3
3 C 5.00 3
4 D 5.50 3
5 E 1.75 2
6 F 5.25 2
7 G 8.00 2
8 H 1.00 2
9 I 2.00 1
10 J 3.50 1
11 K 6.00 1
12 L 7.50 1
连接线由以下数据框决定:
connectd <- data.frame (id = c( "E", "F", "I", "J", "K", "L"),
parent1 = c("A", "C", "H", "E" ,"E", "F"),
parent2 = c("B", "D", "E", "F", "F", "G"))
connectd
id parent1 parent2
1 E A B
2 F C D
3 I H E
4 J E F
5 K E F
6 L F G
例如,这里图E应该连接到它的parent1“A”并且父2“B”图同时连接“A”,“B”应该连接以使其成为“T形”连接。对于其他ID也是如此。
虽然我有其他细节可以在每个子图中绘制,但作为概念验证,我想绘制一个带有名称为n1和n2的每个图的矩形,以形成如下图:
答案 0 :(得分:12)
编辑:
首先,我需要将连接数据从点标签转换为协调点(x,y)
## here the edit
dat.lines <- do.call(cbind,apply(connectd,2,
function(x){
id <- match(x,plotcord$plotname)
plotcord[id,c(2,3)]}))
colnames(dat.lines) <- paste(rep(c('x','y'),3),rep(1:3,each=2),sep='')
这就是我的dat.lines的样子:
x1 y1 x2 y2 x3 y3
1 1.750 2 1.50 3 2.00 3
2 5.250 2 5.00 3 5.50 3
3 1.375 1 1.00 2 1.75 2
4 3.500 1 1.75 2 5.25 2
5 6.000 1 1.75 2 5.25 2
6 7.500 1 5.25 2 8.00 2
然后,我使用格子xyplot
绘制点。晶格的使用非常适合这种情节。无需对数据进行处理(例如网格包)。然后我自定义面板添加矩形,段,......
library(latticeExtra))
xyplot(plotgridY~plotgridX,data= plotcord,
panel=function(x,y,...){
apply(dat.lines,1,function(x){
panel.segments(x0=x['x2'],y0=x['y2'],x1=x['x3'],y1=x['y3'])
boxh <- 0.5
x1=x['x1']
y1=x['y1']
y2 <- x['y2']
x2 <- (x['x2']+x['x3'])/2
ydelta <- (y2 - y1)/2
browser()
panel.segments(c(x1, x1, x2), c(y1, y1 + ydelta, y2 -
ydelta), c(x1, x2, x2), c(y1 + ydelta, y2 -
ydelta, y2))
})
panel.rect(x=x,y=y,width=unit(2,'cm'),
height=unit(2,'cm'),col='lightyellow')
panel.xyplot(x,y,...)
panel.text(x,y,adj=c(0,-3),
label=plotcord$plotname,cex=1.5)
## add some prove of concept detail
panel.rect(x=x,y=y,width=unit(0.5,'cm'),
height=unit(0.5,'cm'),col='lightblue',lty=2)
panel.text(x,y,adj=c(1,2),
label=paste(plotcord$plotname,1,sep=''),cex=1,col='blue')
panel.text(x,y,adj=c(-0.5,2),
label=paste(plotcord$plotname,2,sep=''),
cex=1,col='blue')
},ylim=extendrange(plotcord$plotgridY,f=0.5),xlab='',ylab='', axis = axis.grid,
main='Arrangement of large number of plots \n and connect with lines ')
答案 1 :(得分:11)
我正在写这个答案,部分是为了后代,部分是因为我一直想为其他一些试图在R中进行自定义可视化的人写一些这样的函数。
<强>背景强>
在R中,许多人正确地留下了基础绘图功能,并开始转向更灵活的包装包,&#39;格子&#39;和&#39; ggplot2&#39;。这些是通过在单个图上应用逻辑层来快速浏览数据的强大工具。然后包处理所有层并产生一个适当排列的绘图窗口。这些包很棒,我建议每个R用户至少学习其中一个。
但是,有一点需要注意的是,格子&#39;和&#39; ggplot2&#39;软件包比智能数据可视化更适合数据探索。在创建自定义数据可视化时,这些包为您做出了太多决定,因为它是包装器的用途:从您手中做出一些决定。自定义可视化?输入&#39; grid&#39;
基地&#39;网格&#39;包装是绘图灵活性的终极,部分原因在于它扩展了基础绘图功能的功能,而不是包装它们。使用&#39; grid&#39;功能,我们获得了使用各种不同单位创建视觉对象的能力,用于放置和尺寸调整,并且(这非常重要)我们获得了对我们的对象使用理由的能力。锚。 Paul Murrell的书,&#34; R Graphics,&#34;如果您想学习,这是一个很好的资源。它的副本放在我的桌子上。
如果您曾经使用过矢量图形绘制程序(如Illustrator或Inkscape),那么当我提到理由时,您可能已经知道我在谈论什么。这是通过引用其他项目的位置来对项目进行排序的功能。我更多地谈论这个,但我可以整天谈论它。让我们继续讨论这个过程。
流程
现在,我应该这样说,我花了大约两个小时来编写函数库,大约花了5分钟来编写演示代码。我将来将使用函数库作为培训工具,任何人都可以随意使用/修改它。
&#39;网格&#39;过程分为三个基本步骤:
在制作视口时,我们使用&#39; pushViewport&#39;推动“视口”#39;对象,像这样:
pushViewport(viewport(x=0, y=1, xscale=c(1, 10), yscale=c(0, 100), width=0.25, height=0.25, default.units="npc", just=c("left","bottom"), clip="off"))
基本视口有一个&#34; npc&#34;一组单位,其中x从0到1,从左到右,y从0到1,从下到上。这意味着原点位于左下角。上面的视口创建为左下角绘图的四分之一。当我们指定&#34; xscale&#34;然而,&#34; yscale&#34;但是,我们有能力引用单位&#34; native&#34;绘制对象时这意味着我们可以使用&#34; native&#34;用于绘制数据和使用的单位&#34; npc&#34;绘制轴和标签之类的单位。
绘制对象时,我们使用的功能包括&#39; grid.lines&#39;,&#39; grid.polygon&#39;,&#39; grid.points&#39;,&#39; grid。圈&#39;等等。我做过的每个可视化都使用了这些对象。通过手动指定这些对象来绘制数据时,您将获得大量的控制权。填充折线图是添加功能的最明显示例之一。填充区域只是一个多边形,其中多边形的点由数据指定,并添加了两个锚点。我用它来突出折线图的区域,或者更容易在同一个图表上读取多行。
您还可以获得创意,例如,创建不是矩形的条形图,或以更复杂的方式组合多个图形。我和其他一些人最近开了一个以科幻为主题的步行游戏,我们使用自定义图表(使用&#39;网格&#39;)来显示我们的最终表现。该图表结合了&#34;幸存者&#34;的天数。团队作为时间轴,每天显示玩家与敌人的步数作为条形图,并显示每天累积的玩家和敌人步数作为实线图。我很难用“格子”来创造一个类似的视觉效果。或者&#39; ggplot2&#39;包。
以下是其中一个图表(没有现实生活中的玩家名称)的示例,以便了解有多灵活的网格&#39;视觉效果可以是:
问题的概念证明
现在专门解决OP提出的问题。在这个问题中,OP意味着他/她将在每个区域内绘制图表。使用预先构建的绘图包时,这可能会变得棘手,因为大多数绘图功能都会覆盖您已设置的任何绘图规范。相反,使用像base&#39; grid&#39;这样的东西更可靠。用于指定绘图区域,然后在视口中绘制必要的数据对象。
为了避免工作太辛苦,我首先编写了一个自定义函数库,它设置了我的各种图表参数并为我绘制了每种类型的图表。我不喜欢调试代码,因此函数是我处理事物的方式。每次我得到一段正确的代码,我都会把它扔进一个函数供以后使用。
代码可能看起来有点复杂,但要记住三个网格&#39;步骤:推视口,绘制,弹出视口。这是每个功能正在做的事情。为了演示这项工作,我制作了四种不同的绘图功能:填充折线图,散点图,直方图和OP建议的方框图。每个函数都足够灵活,可以在每个图表中容纳多组数据值,设置alpha值以进行补偿,并允许我们查看相互叠加的值。
在这种情况下,你只需要你的功能就像你需要的那样灵活,所以我确实在线上设置了一个快捷方式,并从演示中的一些代码中抽取了它们,这些代码做了很多假设。不过,我仍然用逻辑驱动的代码绘制它,演示如何用简单的逻辑绘制更复杂的对象。
以下是演示代码的结果,使用一些内置的R数据集来获取简单的数据(EuStockMarkets,nottem,sunspots.month):
自定义函数库:
library(grid)
# Specify general chart options.
chart_Fill = "lemonchiffon"
chart_Col = "snow3"
space_Background = "white"
title_CEX = 0.8
axis_CEX = 0.6
chart_Width <- 3/3
chart_Height <- 2/5
# Function to initialize a plotting area.
init_Plot <- function(
.df,
.x_Loc,
.y_Loc,
.justify,
.width,
.height
){
# Initialize plotting area to fit data.
# We have to turn off clipping to make it
# easy to plot the labels around the plot.
pushViewport(viewport(xscale=c(min(.df[,1]), max(.df[,1])), yscale=c(min(0,min(.df[,-1])), max(.df[,-1])), x=.x_Loc, y=.y_Loc, width=.width, height=.height, just=.justify, clip="off", default.units="native"))
# Color behind text.
grid.rect(x=0, y=0, width=unit(axis_CEX, "lines"), height=1, default.units="npc", just=c("right", "bottom"), gp=gpar(fill=space_Background, col=space_Background))
grid.rect(x=0, y=1, width=1, height=unit(title_CEX, "lines"), default.units="npc", just=c("left", "bottom"), gp=gpar(fill=space_Background, col=space_Background))
# Color in the space.
grid.rect(gp=gpar(fill=chart_Fill, col=chart_Col))
}
# Function to finalize and label a plotting area.
finalize_Plot <- function(
.df,
.plot_Title
){
# Label plot using the internal reference
# system, instead of the parent window, so
# we always have perfect placement.
grid.text(.plot_Title, x=0.5, y=1.05, just=c("center","bottom"), rot=0, default.units="npc", gp=gpar(cex=title_CEX))
grid.text(paste(names(.df)[-1], collapse=" & "), x=-0.05, y=0.5, just=c("center","bottom"), rot=90, default.units="npc", gp=gpar(cex=axis_CEX))
grid.text(names(.df)[1], x=0.5, y=-0.05, just=c("center","top"), rot=0, default.units="npc", gp=gpar(cex=axis_CEX))
# Finalize plotting area.
popViewport()
}
# Function to plot a filled line chart of
# the data in a data frame. The first column
# of the data frame is assumed to be the
# plotting index, with each column being a
# set of y-data to plot. All data is assumed
# to be numeric.
plot_Line_Chart <- function(
.df,
.x_Loc,
.y_Loc,
.justify,
.width,
.height,
.colors,
.plot_Title
){
# Initialize plot.
init_Plot(.df, .x_Loc, .y_Loc, .justify, .width, .height)
# Calculate what value to use as the
# return for the polygons.
y_Axis_Min <- min(0, min(.df[,-1]))
# Plot each set of data as a polygon,
# so we can fill it in with color to
# make it easier to read.
for (i in 2:ncol(.df)){
grid.polygon(x=c(min(.df[,1]),.df[,1], max(.df[,1])), y=c(y_Axis_Min,.df[,i], y_Axis_Min), default.units="native", gp=gpar(fill=.colors[i-1], col=.colors[i-1], alpha=1/ncol(.df)))
}
# Draw plot axes.
grid.lines(x=0, y=c(0,1), default.units="npc")
grid.lines(x=c(0,1), y=0, default.units="npc")
# Finalize plot.
finalize_Plot(.df, .plot_Title)
}
# Function to plot a scatterplot of
# the data in a data frame. The
# assumptions are the same as 'plot_Line_Chart'.
plot_Scatterplot <- function(
.df,
.x_Loc,
.y_Loc,
.justify,
.width,
.height,
.colors,
.plot_Title
){
# Initialize plot.
init_Plot(.df, .x_Loc, .y_Loc, .justify, .width, .height)
# Plot each set of data as colored points.
for (i in 2:ncol(.df)){
grid.points(x=.df[,1], y=.df[,i], pch=19, size=unit(1, "native"), default.units="native", gp=gpar(col=.colors[i-1], alpha=1/ncol(.df)))
}
# Draw plot axes.
grid.lines(x=0, y=c(0,1), default.units="npc")
grid.lines(x=c(0,1), y=0, default.units="npc")
# Finalize plot.
finalize_Plot(.df, .plot_Title)
}
# Function to plot a histogram of
# all the columns in a data frame,
# except the first, which is assumed to
# be an index.
plot_Histogram <- function(
.df,
.x_Loc,
.y_Loc,
.justify,
.width,
.height,
.colors,
.plot_Title,
...
){
# Create a list containing the histogram
# data for each data column and calculate
# data ranges. Any extra parameters
# specified will pass to the 'hist' function.
hist_Data <- list()
hist_Count_Range <- c(0,NA)
hist_Breaks_Range <- c(NA,NA)
for (i in 2:ncol(.df)){
hist_Data[[i]] <- hist(.df[,i], plot=FALSE, ...)
hist_Count_Range[2] <- max(max(hist_Data[[i]]$counts), hist_Count_Range[2], na.rm=TRUE)
hist_Breaks_Range <- c(min(min(hist_Data[[i]]$breaks), hist_Breaks_Range[1], na.rm=TRUE), max(max(hist_Data[[i]]$breaks), hist_Breaks_Range[2], na.rm=TRUE))
}
# Initialize plotting area to fit data.
# We are doing this in a custom way to
# allow more flexibility than built into
# the 'init_Plot' function.
# We have to turn off clipping to make it
# easy to plot the labels around the plot.
pushViewport(viewport(xscale=hist_Breaks_Range, yscale=hist_Count_Range, x=.x_Loc, y=.y_Loc, width=.width, height=.height, just=.justify, clip="off", default.units="native"))
# Color behind text.
grid.rect(x=0, y=0, width=unit(axis_CEX, "lines"), height=1, default.units="npc", just=c("right", "bottom"), gp=gpar(fill=space_Background, col=space_Background))
grid.rect(x=0, y=1, width=1, height=unit(title_CEX, "lines"), default.units="npc", just=c("left", "bottom"), gp=gpar(fill=space_Background, col=space_Background))
# Color in the space.
grid.rect(gp=gpar(fill=chart_Fill, col=chart_Col))
# Draw x axis.
grid.lines(x=c(0,1), y=0, default.units="npc")
# Plot each set of data as a histogram.
for (i in 2:ncol(.df)){
grid.rect(x=hist_Data[[i]]$mids, y=0, width=diff(hist_Data[[i]]$mids[1:2]), height=hist_Data[[i]]$counts, default.units="native", just=c("center","bottom"), gp=gpar(fill=.colors[i-1], col=.colors[i-1], alpha=1/ncol(.df)))
}
# Label plot using the internal reference
# system, instead of the parent window, so
# we always have perfect placement.
grid.text(.plot_Title, x=0.5, y=1.05, just=c("center","bottom"), rot=0, default.units="npc", gp=gpar(cex=title_CEX))
grid.text(paste(names(.df)[-1], collapse=" & "), x=-0.05, y=0.5, just=c("center","bottom"), rot=90, default.units="npc", gp=gpar(cex=axis_CEX))
# Finalize plotting area.
popViewport()
}
draw_Sample_Box <- function(
.x_Loc,
.y_Loc,
.x_Scale,
.y_Scale,
.justify,
.width,
.height,
.colors,
.box_X,
.box_Y,
.plot_Title
){
pushViewport(viewport(xscale=.x_Scale, yscale=.y_Scale, x=.x_Loc, y=.y_Loc, width=chart_Width, height=chart_Height, just=.justify, clip="off", default.units="native"))
# Color behind text.
grid.rect(x=0, y=1, width=1, height=unit(title_CEX, "lines"), default.units="npc", just=c("left", "bottom"), gp=gpar(fill=space_Background, col=space_Background))
# Color in the space.
grid.rect(gp=gpar(fill=chart_Fill, col=chart_Col))
# Label plot.
grid.text(.plot_Title, x=0.5, y=1.05, just=c("center","bottom"), rot=0, default.units="npc", gp=gpar(cex=title_CEX))
# Draw box and label points.
grid.polygon(x=.box_X, y=.box_Y, default.units="native", gp=gpar(fill=.colors[1], col=.colors[2]))
grid.text(paste(.plot_Title, 1, sep=""), x=min(.box_X), y=min(.box_Y), default.units="native", just=c("right","top"), gp=gpar(cex=0.5))
grid.text(paste(.plot_Title, 2, sep=""), x=max(.box_X), y=min(.box_Y), default.units="native", just=c("left","top"), gp=gpar(cex=0.5))
# Finalize plot.
popViewport()
}
演示代码:
# Draw twelve independent charts as
# a demo and connect with lines similar
# to a heiritage chart.
grid.newpage()
# Initialize a viewport to make our locations
# easier to map.
pushViewport(viewport(x=0, y=0, width=1, height=1, just=c("left","bottom"), xscale=c(0,10), yscale=c(0,4)))
# Color background of overall plot.
grid.rect(gp=gpar(fill=space_Background, col=space_Background))
# Store plot locations for convenience.
plot_Loc <- data.frame(x=c(2,4,6,8,1,3,7,9,2,4,6,8), y=c(3,3,3,3,2,2,2,2,1,1,1,1))
# Draw connecting lines.
connections <- data.frame(a=c(1, 3, 5, 6, 7, 1, 3, 5, 7, 6), b=c(2, 4, 6, 7, 8, 2, 4, 6, 8, 7), c=c(NA, NA, NA, NA, NA, 6, 7, 9, 12, 10), d=c(NA, NA, NA, NA, NA, NA, NA, NA, NA, 11))
for (i in 1:nrow(connections)){
if (is.na(connections$c[i])){
grid.lines(x=plot_Loc$x[unlist(connections[i,1:2])], y=plot_Loc$y[unlist(connections[i,1:2])], default.units="native")
} else if (is.na(connections$d[i])) {
grid.lines(x=median(plot_Loc$x[unlist(connections[i,1:2])]), y=plot_Loc$y[unlist(connections[i,2:3])], default.units="native")
} else {
grid.lines(x=median(plot_Loc$x[unlist(connections[i,1:2])]), y=c(plot_Loc$y[connections[i,2]], median(plot_Loc$y[unlist(connections[i,2:3])])), default.units="native")
grid.lines(x=plot_Loc$x[unlist(connections[i,3:4])], y=median(plot_Loc$y[unlist(connections[i,2:3])]), default.units="native")
grid.lines(x=plot_Loc$x[connections[i,3]], y=c(median(plot_Loc$y[unlist(connections[i,2:3])]), plot_Loc$y[connections[i,3]]), default.units="native")
grid.lines(x=plot_Loc$x[connections[i,4]], y=c(median(plot_Loc$y[unlist(connections[i,2:3])]), plot_Loc$y[connections[i,4]]), default.units="native")
}
}
# Draw four independent line charts.
p <- 1
plot_Line_Chart(data.frame(time=1:1860, EuStockMarkets)[1:3], .x_Loc=plot_Loc$x[p], .y_Loc=plot_Loc$y[p], .just=c("center","center"), .width=chart_Width, .height=chart_Height, c("dodgerblue", "deeppink"), "EU Stocks")
p <- 2
plot_Line_Chart(data.frame(time=1:1860, EuStockMarkets)[c(1,4,5)], .x_Loc=plot_Loc$x[p], .y_Loc=plot_Loc$y[p], .just=c("center","center"), .width=chart_Width, .height=chart_Height, c("green", "purple"), "EU Stocks")
p <- 3
plot_Line_Chart(data.frame(time=1:(12*20), sunspots=sunspot.month[(171*12+1):(171*12+12*20)]), .x_Loc=plot_Loc$x[p], .y_Loc=plot_Loc$y[p], .just=c("center","center"), .width=chart_Width, .height=chart_Height, c("darkgoldenrod"), "Sunspots")
p <- 4
plot_Line_Chart(data.frame(time=1:(12*20), temp=nottem), .x_Loc=plot_Loc$x[p], .y_Loc=plot_Loc$y[p], .just=c("center","center"), .width=chart_Width, .height=chart_Height, c("red"), "Nottem")
# Draw four independent scatterplots.
p <- 5
plot_Scatterplot(data.frame(time=1:(1860 + 1 - 1000), DAX=rowMeans(embed(EuStockMarkets[,1], 1000)), FTSE=rowMeans(embed(EuStockMarkets[,4], 1000))), .x_Loc=plot_Loc$x[p], .y_Loc=plot_Loc$y[p], .just=c("center","center"), .width=chart_Width, .height=chart_Height, c("deeppink", "purple"), "Smooth")
p <- 6
plot_Scatterplot(data.frame(time=1:1860, EuStockMarkets)[c(1,2,5)], .x_Loc=plot_Loc$x[p], .y_Loc=plot_Loc$y[p], .just=c("center","center"), .width=chart_Width, .height=chart_Height, c("deeppink", "purple"), "EU Stocks")
p <- 9
plot_Scatterplot(data.frame(time=1:(1860 + 1 - 20), DAX=rowMeans(embed(EuStockMarkets[,1], 20)), FTSE=rowMeans(embed(EuStockMarkets[,4], 20))), .x_Loc=plot_Loc$x[p], .y_Loc=plot_Loc$y[p], .just=c("center","center"), .width=chart_Width, .height=chart_Height, c("deeppink", "purple"), "Smooth*20")
p <- 10
plot_Scatterplot(data.frame(time=1:(1860 + 1 - 100), DAX=rowMeans(embed(EuStockMarkets[,1], 100)), FTSE=rowMeans(embed(EuStockMarkets[,4], 100))), .x_Loc=plot_Loc$x[p], .y_Loc=plot_Loc$y[p], .just=c("center","center"), .width=chart_Width, .height=chart_Height, c("deeppink", "purple"), "Smooth*100")
# Draw two independent histograms.
p <- 7
plot_Histogram(data.frame(time=1:(12*20), sunspots=sunspot.month[(171*12+1):(171*12+12*20)]), .x_Loc=plot_Loc$x[p], .y_Loc=plot_Loc$y[p], .just=c("center","center"), .width=chart_Width, .height=chart_Height, c("darkgoldenrod"), "Sunspots", breaks=6)
p <- 8
plot_Histogram(data.frame(time=1:(12*20), temp=nottem), .x_Loc=plot_Loc$x[p], .y_Loc=plot_Loc$y[p], .just=c("center","center"), .width=chart_Width, .height=chart_Height, c("red"), "Nottem", breaks=6)
# Draw sample objects in two charts spaces.
p <- 11
draw_Sample_Box(.x_Loc=plot_Loc$x[p], .y_Loc=plot_Loc$y[p], .x_Scale=c(0,10), .y_Scale=c(-10,0), .justify=c("center","center"), .width=chart_Width, .height=chart_Height, .colors=c("dodgerblue","blue"), .box_X=c(4,6,6,4), .box_Y=c(-4,-4,-5,-5), .plot_Title="K")
p <- 12
draw_Sample_Box(.x_Loc=plot_Loc$x[p], .y_Loc=plot_Loc$y[p], .x_Scale=c(-1,1), .y_Scale=c(0,1), .justify=c("center","center"), .width=chart_Width, .height=chart_Height, .colors=c("dodgerblue","blue"), .box_X=c(-0.5,0,0,-0.5), .box_Y=c(0.8,0.8,0.7,0.7), .plot_Title="L")