2014-05-11 8 views
10

Próbuję dopasować kolor tekstu legendy do koloru tekstu wygenerowanego przez zmienną faktoryczną przy użyciu geom_text. Oto minimalne przykład roboczych:Dopasowanie koloru tekstu legendy w geom_text do symbolu

df <- data.frame(a=rnorm(10),b=1:10,c=letters[1:10],d=c("one","two")) 
p1 <-ggplot(data=df,aes(x=b,y=a)) 
p1 <- p1 + geom_text(aes(label = c, color=d, fontface="bold")) 
p1 <- p1 + scale_color_hue(name="colors should match",breaks=c("one", "two"), 
       labels=c("should be pink", "should be blue")) 
p1 

enter image description here

jestem pewien jego prosty fix. Pomocne mogłyby być wszelkie sugestie lub odniesienia do poprzednich postów. Nie znalazłem nic konkretnego.

Odpowiedz

11

Nawiązując do komentarza Jøran jest powyżej, można edytować bezpośrednio na grobs. To jest dość paskudny kawałek kodu, więc przepraszam [będzie o wiele bardziej elegancki sposób na wykonanie tego przy pomocy poleceń grid - i mam nadzieję, że ktoś napisze).

library(grid) 

gglabcol <- 
    function(plot1) 

     { 
     g <- ggplotGrob(plot1) 

     # legend grobs 
     g.b <- g[["grobs"]][[which(g$layout$name=="guide-box")]] 
     l <- g.b[["grobs"]][[1]][["grobs"]] 

     # get grobs for legend symbols (extract colour) 
     lg <- l[sapply(l, function(i) grepl("GRID.text", i))] 

     # get grobs for legend labels 
     lb <- l[sapply(l, function(i) grepl("guide.label", i))] 

     # get change colour of labels to colour of symbols 
     for(i in seq_along(lg)) { 

      lb[[i]]$gp$col <- lg[[i]]$gp$col 

      g.b[["grobs"]][[1]][["grobs"]][sapply(g.b[["grobs"]][[1]][["grobs"]], 
          function(i) grepl("guide.label", i))][[i]] <- lb[[i]] 
      } 

     # overwrite original legend 
     g[["grobs"]][[which(g$layout$name=="guide-box")]] <- g.b 

     grid.draw(g) 

     invisible(g) 
    } 

Działka

gglabcol(p1) 


enter image description here

+3

+1 za wykonanie ciężkiej pracy, chociaż PO powinien ocenić, czy naprawdę jest tego wart. – BrodieG

+0

BrodieG - jako OP zgadzam się z Tobą, ale starałem się odpowiedzieć na prośbę recenzentów w rękopisie, ponieważ istnieje więcej niż 2 poziomy czynników i kolor tekstu może wprowadzać w błąd. Może jest lepszy sposób na spisek. Zapoznam się z tym. –

3

Kolory na wykresie są takie same jak kolory w legendzie, ale legenda fontface pozostaje prosta nawet po ustawieniu font font symbol na pogrubienie (lub kursywę). Nie jestem pewien, czy jest to niedopatrzenie w projekcie ggplot2 lub zamierzonego zachowania. W przypadku niektórych kolorów pogrubiona czcionka wygląda bardziej nasycona niż zwykła czcionka, dzięki czemu wygląda na inny kolor.

W każdym razie tutaj jest kundel, który jest dużo łatwiejszy niż granie z grobami, ale to może ci dać to, czego chcesz. Użyj zwykłej font-font, ale rób to dwa lub trzy razy z rzędu (lub więcej), aby uzyskać overplotting. Spowoduje to, że zarówno symbole, jak i legenda będą wyglądać podobnie jak pogrubiona czcionka, ponieważ oba zostaną przesłonięte, a symbole legendy będą zawsze wyglądać tak samo, jak symbole działek.

Oto przykład:

library(ggplot2) 
library(gridExtra) 

# Original plot (with larger font size) 
p1 <- ggplot(data=df) + 
    geom_text(aes(x=b, y=a, label=c, color=d), fontface='bold', size=8) 
p1 <- p1 + scale_color_hue(name="colors should match",breaks=c("one", "two"), 
           labels=c("should be pink", "should be blue")) + 
      ggtitle("Original Plot with Bold Symbols and Plain Legend") 

# New version with overplotting. (You don't need to specify 'plain' fontface. 
# I've just included that to emphasize what the code is doing.) 
p1.overplot <- ggplot(data=df) + 
    geom_text(aes(x=b, y=a, label=c, color=d), fontface='plain', size=8) + 
    geom_text(aes(x=b, y=a, label=c, color=d), fontface='plain', size=8) + 
    geom_text(aes(x=b, y=a, label=c, color=d), fontface='plain', size=8) 
p1.overplot <- p1.overplot + 
    scale_color_hue(name="colors should match", 
        breaks=c("one", "two"), 
        labels=c("should be pink", "should be blue")) + 
    ggtitle("Both symbols and legend are overplotted 3 times") 

enter image description here

+0

Dzięki za tę fajną sztuczkę, która pasuje do kroju czcionki, ale - tak naprawdę próbowałem dopasować tekst legendy, "powinien być różowy" i "powinien być niebieski", do legendy i symbolu działki. np. Tekst "powinien być różowy" powinien mieć ten sam kolor, co litery "a", "c", "e", "g" i "i", natomiast tekst "powinien być niebieski" musi być taki sam kolor jako "b", "d", "f", "h" i "j" –

+0

Cóż, myślę, że następnym razem będę musiał uważniej przeczytać to pytanie! – eipi10

+0

@ eipi10, nie było łatwo zrozumieć pytanie, OP powinien napisać '' "ta czcionka tekstu powinna być różowa" ". Po przeczytaniu pierwszej części powyższego komentarza, myślałem, że chce, aby tekst "powinien być różowy", który zostanie wydrukowany na działce. Sądzę, że możliwości są nieskończone :-) Twoja kludka jest dla mnie bardzo przydatna! – PatrickT

4

Czasami łatwiej jest zmodyfikować Grob korzystając grid „s funkcje edycji - jeśli można znaleźć nazwy odpowiednich grobs . W takim przypadku można je znaleźć, a edycja jest prosta - zmień kolor etykiety z czarnego na czerwony lub niebieski.

library(ggplot2) 
library(grid) 

df <- data.frame(a=rnorm(10),b=1:10,c=letters[1:10],d=c("one","two")) 
p1 <-ggplot(data=df,aes(x=b,y=a)) 
p1 <- p1 + geom_text(aes(label = c, color=d, fontface="bold")) 
p1 <- p1 + scale_color_hue(name="colors should match",breaks=c("one", "two"), 
       labels=c("should be salmon", "should be sky blue")) 
p1 

# Get the ggplot grob 
g <- ggplotGrob(p1) 

# Check out the grobs 
grid.ls(grid.force(g)) 

Przejrzyj listę grobs. Groby, które chcemy edytować, znajdują się na samym dole listy, w zestawie "gr-guide", z nazwami zaczynającymi się od "label". Istnieją dwa grobs:

Etykieta 3-3.4-4-4-4
etykieta-4-3.5-4-5-4

# Get names of 'label' grobs. 
names.grobs <- grid.ls(grid.force(g))$name 
labels <- names.grobs[which(grepl("label", names.grobs))] 

# Get the colours 
# The colours are the same as the colours of the plotted points. 
# These are available in the ggplot build data. 
gt <- ggplot_build(p1) 
colours <- unique(gt$data[[1]][, "colour"]) 

# Edit the 'label' grobs - change their colours 
# Use the `editGrob` function 
for(i in seq_along(labels)) { 
    g <- editGrob(grid.force(g), gPath(labels[i]), grep = TRUE, 
     gp = gpar(col = colours[i])) 
} 

# Draw it 
grid.newpage() 
grid.draw(g) 

enter image description here

Co czy wymagano, aby klucze były punktami, a nie literami? Może to być przydatne, ponieważ "a" jest symbolem na wykresie i jest symbolem w kluczu legendy. To nie jest zwykła edycja, jak wyżej. Potrzebuję grobu punktowego, który zastąpi tekstowy grob.Rysuję groby w rzutniach, ale jeśli uda mi się znaleźć nazwy odpowiednich rzutni, zmiana powinna być prosta.

# Find the names of the relevant viewports 
current.vpTree() # Scroll out to the right to find he relevant 'key' viewports. 

wziernika [klucz 4-1-1.5-2-5-2] wziernika [klucz 3-1-1.4-2-4-2]

# Well, this is convenient. The names of the viewports are the same 
# as the names of the grobs (see above). 
# Easy enough to get the names from the 'names.grobs' list (see above). 
# Get the names of 'key' viewports(/grobs) 
keys <- names.grobs[which(grepl("key-[0-9]-1-1", names.grobs))] 

# Insert points grobs into the viewports: 
# Push to the viewport; 
# Insert the point grob; 
# Pop the viewport. 
for(i in seq_along(keys)) { 
    downViewport(keys[i]) 
    grid.points(x = .5, y = .5, pch = 16, gp = gpar(col = colours[i])) 
    popViewport() 
} 
popViewport(0) 

# I'm not going to worry about removing the text grobs. 
# The point grobs are large enough to hide them. 

plot = grid.grab() 
grid.newpage() 
grid.draw(plot) 

enter image description here

Aktualizacja

Uwzględniając @ „s user20650 radę zmienić lege nd key (patrz komentarz poniżej):

p1 <-ggplot(data=df,aes(x=b,y=a)) 
p1 <- p1 + geom_text(aes(label = c, color=d, fontface="bold")) 
p1 <- p1 + scale_color_hue(name="colors should match",breaks=c("one", "two"), 
       labels=c("should be salmon", "should be sky blue")) 

GeomText$draw_key <- function (data, params, size) { 
    pointsGrob(0.5, 0.5, pch = 16, 
    gp = gpar(col = alpha(data$colour, data$alpha), 
    fontsize = data$size * .pt)) } 

p1 

Następnie postępuj jak poprzednio, aby zmienić kolor tekstu legendy.

+1

@ user20650 Dziękuję bardzo za to. To jest bardzo użyteczne. –

+1

tak, jest to fajna nowa funkcja - szkoda, że ​​etykiety nie są tak łatwe – user20650