R добавление таблицы данных к графику ggplot с использованием viewPorts: масштабирование Grob

Я пытаюсь добавить таблицу данных к графику, сделанному в ggplot (аналогично функциям Excel, но с возможностью изменения оси)

У меня было несколько попыток, и я продолжаю сталкиваться с проблемой масштабирования, поэтому попытка 1) была

library(grid)
library(gridExtra)
library(ggplot2)
xta=data.frame(f=rnorm(37,mean=400,sd=50))
xta$n=0
for(i in 1:37){xta$n[i]<-paste(sample(letters,4),collapse='')}
xta$c=0
for(i in 1:37){xta$c[i]<-sample((1:6),1)}
rect=data.frame(xmi=seq(0.5,36.5,1),xma=seq(1.5,37.5,1),ymi=0,yma=10)
xta=cbind(xta,rect)
a = ggplot(data=xta,aes(x=n,y=f,fill=c)) + geom_bar(stat='identity')
b = ggplot(data=xta,aes(x=n,y=5,label=round(f,1))) + geom_text(size=4) + geom_rect(aes(xmin=xmi,xmax=xma,ymin=ymi,ymax=yma),alpha=0,color='black')
z = theme(axis.text=element_blank(),panel.background=element_rect(fill='white'),axis.ticks=element_blank(),axis.title=element_blank())
b=b+z
la=grid.layout(nrow=2,ncol=1,heights=c(0.15,2),default.units=c('null','null'))
grid.show.layout(la)
grid.newpage()
pushViewport(viewport(layout=la))
print(a,vp=viewport(layout.pos.row=2,layout.pos.col=1))
print(b,vp=viewport(layout.pos.row=1,layout.pos.col=1))

который произвел

2 ggplots

вторая попытка 2) была

xta1=data.frame(t(round(xta$f,1)))
xtb=tableGrob(xta1,show.rownames=F,show.colnames=F,show.vlines=T,gpar.corefill=gpar(fill='white',col='black'),gp=gpar(fontsize=12),vp=viewport(layout.pos.row=1,layout.pos.col=1))
grid.newpage()
la=grid.layout(nrow=2,ncol=1,heights=c(0.15,2),default.units=c('null','null'))
grid.show.layout(la)
grid.newpage()
pushViewport(viewport(layout=la))
print(a,vp=viewport(layout.pos.row=2,layout.pos.col=1))
grid.draw(xtb)

который произвел

с использованием прямой таблицы grob и grid.draw

и, наконец, 3) был

grid.newpage()
print(a + annotation_custom(grob=xtb,xmin=0,xmax=37,ymin=450,ymax=460))

который произвел

использование annotate_custom

Из них вариант 2 был бы лучшим, если бы я мог масштабировать tableGrob до того же размера, что и график, но я понятия не имею, как это сделать. Любые указатели на то, как это сделать дальше? - Спасибо


person Tahnoon Pasha    schedule 05.04.2013    source источник


Ответы (3)


Вы можете попробовать новую версию tableGrob; результирующая ширина / высота gtable может быть установлена ​​​​на определенный размер (здесь равномерно распределенные единицы NPC)

library(ggplot2)
library(gridExtra)
library(grid)
tg <- tableGrob(head(iris), rows=NULL)
tg$widths <- unit(rep(1/ncol(tg),ncol(tg)),"npc")
tg$heights <- unit(rep(1/nrow(tg),nrow(tg)),"npc")

qplot(colnames(iris), geom="bar")+ theme_bw() +
  scale_x_discrete(expand=c(0,0)) +
  scale_y_continuous(lim=c(0,2), expand=c(0,0)) +
  annotation_custom(ymin=1, ymax=2, xmin=-Inf, xmax=Inf, tg)

введите описание изображения здесь

person baptiste    schedule 10.04.2013
comment
спасибо @baptiste, у меня еще не было возможности проверить это. Сделаю это на выходных, но это похоже на правильный ответ. Спасибо также за отличный пакет - person Tahnoon Pasha; 12.04.2013
comment
Быстрый вопрос, @baptiste, нужно ли каждый раз загружать source_gist? Когда вы ожидаете, что экспериментальный tableGrob войдет в основной код? - person Tahnoon Pasha; 14.04.2013
comment
Мой совет, если вы сочтете это полезным, - скопировать код и загрузить его локально самостоятельно (в пакете или в вашем .Rprofile). Я действительно не могу обещать какую-либо дату выпуска, так как я очень редко работаю над этим пакетом, и эта новая версия является экспериментальной. Если это работает для вас, должно быть легко адаптироваться с помощью пользовательских цветов и т. Д. - person baptiste; 14.04.2013

Вы можете использовать, например, таблицу, созданную ggplot, и объединить их, как в этом a-data-table/" rel="nofollow noreferrer">блог. Я сделал упрощенный и рабочий пример здесь:

Сначала создайте свой сюжет:

library(ggplot2)
library(reshape2)
library(grid)

 df <- structure(list(City = structure(c(2L,
     3L, 1L), .Label = c("Minneapolis", "Phoenix",
     "Raleigh"), class = "factor"), January = c(52.1,
     40.5, 12.2), February = c(55.1, 42.2, 16.5),
     March = c(59.7, 49.2, 28.3), April = c(67.7,
         59.5, 45.1), May = c(76.3, 67.4, 57.1),
     June = c(84.6, 74.4, 66.9), July = c(91.2,
         77.5, 71.9), August = c(89.1, 76.5,
         70.2), September = c(83.8, 70.6, 60),
     October = c(72.2, 60.2, 50), November = c(59.8,
         50, 32.4), December = c(52.5, 41.2,
         18.6)), .Names = c("City", "January",
     "February", "March", "April", "May", "June",
     "July", "August", "September", "October",
     "November", "December"), class = "data.frame",
     row.names = c(NA, -3L))

dfm <- melt(df, variable = "month")

 levels(dfm$month) <- month.abb
 p <- ggplot(dfm, aes(month, value, group = City,
     colour = City))
 p1 <- p + geom_line(size = 1) + theme(legend.position = "top") + xlab("")

Затем создайте таблицу данных в ggplot. Используйте ту же ось x, что и график:

none <- element_blank()
data_table <- ggplot(dfm, aes(x = month, y = factor(City),
     label = format(value, nsmall = 1), colour = City)) +
     geom_text(size = 3.5) +
  scale_y_discrete(labels = abbreviate)+ theme_bw()  +
     theme(panel.grid.major = none, legend.position = "none",
         panel.border = none, axis.text.x = none,
         axis.ticks = none) + theme(plot.margin = unit(c(-0.5,
     1, 0, 0.5), "lines")) + xlab(NULL) + ylab(NULL)

Объедините их с окном просмотра:

Layout <- grid.layout(nrow = 2, ncol = 1, heights = unit(c(2,
     0.25), c("null", "null")))
grid.show.layout(Layout)
vplayout <- function(...) {
     grid.newpage()
     pushViewport(viewport(layout = Layout))
 }

subplot <- function(x, y) viewport(layout.pos.row = x,
     layout.pos.col = y)

mmplot <- function(a, b) {
     vplayout()
     print(a, vp = subplot(1, 1))
     print(b, vp = subplot(2, 1))
 }

mmplot(p1, data_table)

Обратите внимание, что требуется еще некоторая настройка, например, положение легенды сюжета и аббревиатуры названий городов в таблице, но результат выглядит красиво: введите здесь описание изображения

Применительно к вашему примеру:

library(grid)
library(gridExtra)
library(ggplot2)
xta=data.frame(f=rnorm(37,mean=400,sd=50))
xta$n=0
for(i in 1:37){xta$n[i]<-paste(sample(letters,4),collapse='')}
xta$c=0
for(i in 1:37){xta$c[i]<-sample((1:6),1)}
rect=data.frame(xmi=seq(0.5,36.5,1),xma=seq(1.5,37.5,1),ymi=0,yma=10)
xta=cbind(xta,rect)
a = ggplot(data=xta,aes(x=n,y=f,fill=c)) + geom_bar(stat='identity')+ theme(legend.position = "top")+xlab("")

none <- element_blank()
z=ggplot(xta, aes(x = n, y = "fvalues",
     label = round(f,1)) )+
     geom_text(size = 3)+ theme_bw()  +
     theme(panel.grid.major = none, legend.position = "none",
         panel.border = none, axis.text.x = none,
         axis.ticks = none) + theme(plot.margin = unit(c(-0.5,
     1, 0, 0.5), "lines")) + xlab(NULL) + ylab(NULL)

Layout <- grid.layout(nrow = 2, ncol = 1, heights = unit(c(2,
     0.25), c("null", "null")))
grid.show.layout(Layout)
vplayout <- function(...) {
     grid.newpage()
     pushViewport(viewport(layout = Layout))
 }

subplot <- function(x, y) viewport(layout.pos.row = x,
     layout.pos.col = y)

mmplot <- function(a, b) {
     vplayout()
     print(a, vp = subplot(1, 1))
     print(b, vp = subplot(2, 1))
 }

mmplot(a, z)

введите здесь описание изображения

ИЗМЕНИТЬ:

похоже на решение Денниса, но с барплотом и с + coord_flip(). Вы можете удалить последний, если не хотите его переворачивать, но это повышает читабельность:

ggplot(xta, aes(x=n,y=f,fill=c)) +
   geom_bar() +
   labs(color = "c") +
   geom_text(aes(y = max(f)+30, label = round(f, 1)), size = 3, color = "black") + coord_flip()
person Jonas Tundo    schedule 05.04.2013
comment
Спасибо @ JT85, это полезно, и я видел этот блог. Моя первая попытка (без использования tableGrob) по сути является именно этим процессом, но с удаленными вызовами функций и прямоугольниками вокруг чисел. Я знаю, что могу заставить его работать, если я перемещу легенду, но я пытаюсь изменить размер гроба на графику, а не изменять графику, чтобы разрешить отображение данных. Хотя это почти то, что мне нужно. - person Tahnoon Pasha; 05.04.2013
comment
Я добавил еще одно решение к ответу. - person Jonas Tundo; 05.04.2013
comment
спасибо @JT85. Это определенно решение, но я хотел бы получить реальную таблицу данных, если это возможно. Если вы не возражаете, я не буду отмечать этот ответ как ответ, поскольку он по-прежнему выглядит как аннотация, а не как отдельная таблица для значений. У меня есть определенный взгляд и чувство, к которому я иду. - person Tahnoon Pasha; 06.04.2013

ИМХО, это не очень хорошая графика. Во-первых, я не понимаю, зачем вам нужно нулевое начало, когда значения варьируются от 300 до 500, что является замаскированным способом сказать, что мне не нравится метафора гистограммы. Вы также пытаетесь использовать штриховку для представления различий в значениях c, которых всего шесть. Вот то, что я считаю более простым подходом к проблеме. Учитывая ваши данные xta,

# Convert the categories to a factor
xta$N <- factor(xta$n, levels = xta$n)

# Simple approach:
ggplot(xta, aes(x = f, y = N, color = factor(c))) +
   geom_point() +
   labs(color = "c") +
   geom_text(aes(x = 575, label = round(f, 1)), size = 4, color = "black")

Мне не интересна такая графика. Что может добавить немного понимания, в зависимости от контекста проблемы, так это сортировка ответов в порядке возрастания и добавление эстетики размера, чтобы акцентировать различия между уровнями c. (Вы также можете использовать размер без цвета.) Наконец, поскольку мы помещаем уровни факторов на вертикальную ось, чтобы их метки были хорошо видны, мы также можем вставить значения f в виде текста, немного расширив горизонтальную ось.

ggplot(xta, aes(x = f, y = reorder(N, f), color = factor(c), size = c)) + 
   geom_point() +
   labs(color = "c") +
   geom_text(aes(x = 575, label = round(f, 1)), size = 4, color = "black")

В этом коде достаточно подсказок, чтобы вы могли пойти в другом направлении. Я оставлю это на ваше усмотрение.

person Dennis    schedule 05.04.2013
comment
спасибо за вклад @Dennis. Фактические данные отсортированы, и набор данных больше подходит для использования гистограммы. Я думал о точечном графике, но ожидаю, что моя аудитория просто запутается, потому что они не знакомы с графикой. Я ценю вклад, хотя. Я буду использовать точечный график для отдельного наглядного пособия в том же проекте. - person Tahnoon Pasha; 05.04.2013