2013-05-07 13 views
17

Pracuję z naprawdę niesamowitą biblioteką ggplot2. Pomyślałem, jak ustawić współczynnik kształtu wykresu za pomocą coord_fixed. Teraz chciałbym zapisać wykres w pliku PDF o określonej szerokości (np. 10 cm) i obliczyć wymaganą wysokość. Nie wymyśliłem, jak to osiągnąć. Czy to możliwe?Zapisywanie działki o danym współczynniku kształtu

Odpowiedz

10

Możesz użyć funkcji siatki do obliczenia pełnego rozmiaru grobu ggplot, ale tam są (edit: co najmniej) dwóch Ostrzeżenia:

  • otworzy dodatkowe okno urządzenie, aby wykonać konwersji jednostek

  • fabuła rozmiar panelu będzie domyślnie 0, ponieważ jest przeznaczona do obliczenia w locie zgodnie z urządzeniem (rzutnia), w którym żyje, a nie odwrotnie.

Powiedział, że jest następująca funkcja próbuje otworzyć urządzenie, które pasuje dokładnie ggplot,

library(ggplot2) 
library(grid) 

sizeit <- function(p, panel.size = 2, default.ar=1){ 

    gb <- ggplot_build(p) 
    # first check if theme sets an aspect ratio 
    ar <- gb$plot$coordinates$ratio 

    # second possibility: aspect ratio is set by the coordinates, which results in 
    # the use of 'null' units for the gtable layout. let's find out 
    g <- ggplot_gtable(gb) 
    nullw <- sapply(g$widths, attr, "unit") 
    nullh <- sapply(g$heights, attr, "unit") 

    # ugly hack to extract the aspect ratio from these weird units 
    if(any(nullw == "null")) 
    ar <- unlist(g$widths[nullw == "null"])/unlist(g$heights[nullh == "null"]) 

    if(is.null(ar)) # if the aspect ratio wasn't specified by the plot 
     ar <- default.ar 

    # ensure that panel.size is always the larger dimension 
    if(ar <= 1) panel.size <- panel.size/ar 

    g$fullwidth <- convertWidth(sum(g$widths), "in", valueOnly=TRUE) + 
    panel.size 
    g$fullheight <- convertHeight(sum(g$heights), "in", valueOnly=TRUE) + 
    panel.size/ar 

    class(g) <- c("sizedgrob", class(g)) 
    g 
} 


print.sizedgrob <- function(x){ 
    # note: dev.new doesn't seem to respect those parameters 
    # when called from Rstudio; in this case it 
    # may be replaced by x11 or quartz or ... 
    dev.new(width=x$fullwidth, height=x$fullheight) 
    grid.draw(x) 
} 


p1 <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point() + coord_fixed() + 
    theme(plot.background = element_rect(colour = "red")) 

p2 <- p1 + aes(x = mpg, y = wt) 

# need for an explicit dummy device open, otherwise it's a bit off 
# for no apparent reason that I can understand 
dev.new() 

sizeit(p1, 0.1) 

enter image description here

sizeit(p2, 2) 

enter image description here

+0

dokładna odpowiedź na pytanie jest pozostawiona ćwiczeniu dla czytelnika (to hackowanie siatki staje się zbyt brzydkie, potrzebuję przerwy) – baptiste

+0

Dzięki za odpowiedź, baptysta. Wygląda na to, że nie ma pięknego rozwiązania. – marsl

+0

Zaakceptowałem twoją odpowiedź, ponieważ myślę, że nie ma lepszego rozwiązania. Dzięki wszystkim. – marsl

0

Jeśli używasz ggsave, możesz po prostu określić szerokość i wysokość urządzenia graficznego. Jeśli określasz współczynnik kształtu samego wykresu, dobrze jest mieć ten współczynnik proporcji (w przybliżeniu) w urządzeniu graficznym. Jednostką height i width Przy zapisywaniu pdf jest cale:

ggplot(...) # make a plot here 
ggsave("plot.pdf", width = 10) 

Teraz trzeba tylko przekształcać 10 cm w calach. Ponadto, height nie jest zmuszony do określonego współczynnika proporcji, jeśli go nie określisz. Jeśli chcesz proporcjach 16: 9, można łatwo obliczyć wysokość w oparciu o szerokość:

ggplot(...) # make plot 
width = 10 
height = (9/16) * width 
ggsave("plot.pdf", width = width, height = height) 

mogła owinąć to w zależności, jeśli naprawdę chcesz.


Edycja: Istotą jest zsynchronizowanie proporcje działki (poprzez coord_fixed()) i proporcji urządzenia graficznej. Na przykład

library(ggplot2) 
ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point() + coord_fixed() 
ggsave("plt.png", width = 7, height = 7) 

enter image description here prowadzi do dużo białej przestrzeni. Chociaż poniższy ggsave rozmowa, która ma znacznie lepsze dopasowanie się proporcjami, nie ma takiej ilości białej przestrzeni (przepraszam za dużego obrazu, nie może ustawić maksymalny rozmiar :)):

ggsave("plt.png", width = 2, height = 7) 

enter image description here

+1

Myślałem, że Paul, ale to rozmiar * urządzenia *, a nie fabuła. Po dodaniu tytułu, etykiet osi i legendy itp. Sam obszar kreślenia może nie być kwadratowy, a za pomocą 'coord_fixed()' sam obszar wykresu nie wypełnia dostępnego obszaru. Nie znam dobrej poprawki innej niż zmiana rozmiaru okna kreślenia, dopóki 'ggsave()' bez określenia szerokości nie dostarczy ci obrazu o szerokości 10 cm. –

+0

Dziękuję Ci za odpowiedź. Gavin, dokładnie tak, jak wskazałeś w swoim komentarzu. Myślę, że jest to problem, ponieważ trzeba ręcznie przyciąć każdy dział. Poczekajmy, aż ktoś wymyśli rozwiązanie. – marsl

2

Nie jestem pewien, ale czy jest coś takiego, czego szukasz?

ggplot(data.frame(x = seq(10), y = seq(10)), aes(x = x, y = y)) + 
    geom_point() + 
    coord_equal() + 
    theme(aspect.ratio = 1) 

To wygląda dobrze do mnie:

ggsave("test.pdf", width = 4, height = 4) 

Zbyt dużo białej przestrzeni, ale sama grafika ma proporcje 1:

ggsave("test2.pdf", width = 4) 

Wiadomość: Zapisywanie 4 x 6,93 w obrazie

+1

Dziękuję za odpowiedź Dennis. Niestety nie jest to właściwe, ponieważ 'ggsave' przyjmuje domyślnie rozmiar bieżącego okna kreślenia. – marsl

2

podstawie odpowiedzi Baptiste za I obnażył swój kod, aby przywrócić proporcje zgodnie z sugestią g eotheory. Było to dla mnie wygodniejsze, ponieważ chciałem mieć stałą szerokość lub wysokość, a także przekazywałem wszystko przez istniejącą funkcję opakowania, która również dodaje czcionki do mojego pdf.

A jeśli użyłeś faset, musisz wziąć je pod uwagę ręcznie. Podziel według wierszy i pomnóż przez kolumny. Nie jestem pewien, czy istnieje lepszy sposób .....

ggGetAr <- function(p, default.ar=-1){ 

    gb <- ggplot_build(p) 
    # first check if theme sets an aspect ratio 
    ar <- gb$plot$coordinates$ratio 

    # second possibility: aspect ratio is set by the coordinates, which results in 
    # the use of 'null' units for the gtable layout. let's find out 
    g <- ggplot_gtable(gb) 
    nullw <- sapply(g$widths, attr, "unit") 
    nullh <- sapply(g$heights, attr, "unit") 

    # ugly hack to extract the aspect ratio from these weird units 
    if(any(nullw == "null")) 
     ar <- unlist(g$widths[nullw == "null"])/unlist(g$heights[nullh == "null"]) 

    if(is.null(ar)) # if the aspect ratio wasn't specified by the plot 
     ar <- default.ar 

    ar[1] 
} 
0

bardziej uproszczone rozwiązaniem byłoby, aby zapisać wykres z marginesów domyślnych i przycinanie otrzymany png z ImageMagick.

require(ggplot2) 
require(dplyr) 

ggplot(iris, aes(Sepal.Length, Sepal.Width)) + geom_point() + coord_fixed(0.3) 
ggsave("untrimmed.png") 


system("convert untrimmed.png -trim -bordercolor white -border 20 reframed.png") 

Na pewno przycinanie będzie się różnić w zależności od używanego urządzenia wyjściowego. Na przykład. w przypadku pdf można użyć pdfcrop zgodnie z opisem here.

Powiązane problemy