2012-08-02 12 views
20

Wie kann ich Drei-Wege-Farbverlauf (Heatmap) zu einem Triplot (Dreiecksdiagramm) füllen, so.Drei-Wege-Farbverlauf füllen r

plot(NA,NA,xlim=c(0,1),ylim=c(0,sqrt(3)/2),asp=1,bty="n",axes=F,xlab="",ylab="") 
segments(0,0,0.5,sqrt(3)/2) 
segments(0.5,sqrt(3)/2,1,0) 
segments(1,0,0,0) 

enter image description here

Farbe parallel laufen sollten triplot. Hier

Antwort

22

ist eine Möglichkeit, es zu tun - es ist ein bisschen wie ein Hack, Punkte für Stück der Steigung Stück zu zeichnen:

plot(NA,NA,xlim=c(0,1),ylim=c(0,1),asp=1,bty="n",axes=F,xlab="",ylab="") 
segments(0,0,0.5,sqrt(3)/2) 
segments(0.5,sqrt(3)/2,1,0) 
segments(1,0,0,0) 
# sm - how smooth the plot is. Higher values will plot very slowly 
sm <- 500 
for (y in 1:(sm*sqrt(3)/2)/sm){ 
    for (x in (y*sm/sqrt(3)):(sm-y*sm/sqrt(3))/sm){ 
     ## distance from base line: 
     d.red = y 
     ## distance from line y = sqrt(3) * x: 
     d.green = abs(sqrt(3) * x - y)/sqrt(3 + 1) 
     ## distance from line y = - sqrt(3) * x + sqrt(3): 
     d.blue = abs(- sqrt(3) * x - y + sqrt(3))/sqrt(3 + 1) 
     points(x, y, col=rgb(1-d.red,1 - d.green,1 - d.blue), pch=19) 
    } 
} 

Und die Ausgabe:

enter image description here

Did Sie möchten diese Gradienten zur Darstellung von Daten verwenden? Wenn ja, kann es möglich sein, d.red, d.green und d.blue zu ändern, um es zu tun - ich habe so etwas noch nicht getestet. Ich hoffe, das ist etwas hilfreich, aber eine richtige Lösung mit colorRamp zum Beispiel wird wahrscheinlich besser sein.

BEARBEITEN: Nach Baptistes Vorschlag, so würden Sie die Informationen in Vektoren speichern und alles auf einmal aufzeichnen. Es ist wesentlich schneller (vor allem mit sm Satz 500, zum Beispiel):

plot(NA,NA,xlim=c(0,1),ylim=c(0,1),asp=1,bty="n",axes=F,xlab="",ylab="") 
sm <- 500 
x <- do.call(c, sapply(1:(sm*sqrt(3)/2)/sm, 
         function(i) (i*sm/sqrt(3)):(sm-i*sm/sqrt(3))/sm)) 
y <- do.call(c, sapply(1:(sm*sqrt(3)/2)/sm, 
         function(i) rep(i, length((i*sm/sqrt(3)):(sm-i*sm/sqrt(3)))))) 
d.red = y 
d.green = abs(sqrt(3) * x - y)/sqrt(3 + 1) 
d.blue = abs(- sqrt(3) * x - y + sqrt(3))/sqrt(3 + 1) 
points(x, y, col=rgb(1-d.red,1 - d.green,1 - d.blue), pch=19) 
+0

Dank für die große Lösung ... ist es Art und Weise in mehr dunkler Farbe (rot, grün und blau) zu beginnen, so dass Gradienten Blick schärfer – jon

+1

ich ein paar verschiedene versucht haben, Dinge, um den Gradienten schärfer zu machen, aber ich konnte keinen Weg finden, der Bereiche des Graphen nicht sehr dunkel und langweilig macht. Geht es dir gut mit Rot, Grün und Blau in den Ecken? Wenn ja, versuchen Sie, die letzte Codezeile durch 'Punkte 'zu ersetzen (x, y, col = rgb (d.red, d.green, d.blau), pch = 19) '- die Farbverläufe für diese drei Farben erscheinen schärfer, da sie sich nicht so sehr mit den anderen Farben mischen. – Edward

+2

Warum plotten Sie jeden Punkt einzeln? Sie können einen Vektor von Farben speichern und alle Punkte auf einmal zeichnen. – baptiste

14

Hier ist eine Lösung mit einem gerasterten Hintergrundbild. Der sharpness Parameter der tricol Funktion steuert, wie schnell die Farben zu Schwarz werden. Wenn Sie es auf 1 setzen, erhalten Sie Edwards Farben und wenn Sie es auf 2 setzen, erhalten Sie die Farben darunter.

# Coordinates of the triangle 
tri <- rbind(sin(0:2*2/3*pi), cos(0:2*2/3*pi)) 

# Function for calculating the color of a set of points `pt` 
# in relation to the triangle 
tricol <- function(pt, sharpness=2){ 
    require(splancs) 
    RGB <- sapply(1:3, function(i){ 
     a <- sweep(pt, 2, tri[,i]) 
     b <- apply(tri[,-i], 1, mean) - tri[,i] 
     sharpness*((a %*% b)/sum(b^2))-sharpness+1 
    }) 
    RGB[-inpip(pt,t(tri)),] <- 1 # Color points outside the triangle white 
    do.call(rgb, unname(as.data.frame(pmin(pmax(RGB, 0), 1)))) 
} 

# Plot 
res <- 1000       # Resolution 
xi <- seq(-1, 1, length=res)  # Axis points 
yi <- seq(-.8, 1.2, length=res) 
x <- xi[1] + cumsum(diff(xi))  # Midpoints between axis points 
y <- yi[1] + cumsum(diff(yi)) 
xy <- matrix(1:(length(x)*length(y)), length(x)) 
image(xi, yi, xy, col=tricol(as.matrix(expand.grid(x,y))), useRaster=TRUE) 
lines(tri[1,c(1:3,1)], tri[2,c(1:3,1)], type="l") 

Was tricol() tut, ist jede Ecke stellen i mit einer Farbe (rot, grün, blau). Er definiert eine Matrix a von Vektoren von der Ecke zu den Punkten in pt und einem Vektor b von der Ecke zur Mitte der gegenüberliegenden Kante. Es projiziert dann a auf b und skaliert, um die relativen Abstände = Farbintensität zu erhalten (und wendet einen kleinen Hack mit sharpness an, um die Farben etwas anzupassen). Wenn es um Probleme wie diese einfache Algebra geht, kann Magie arbeiten.

Sie erhalten an den Rändern aufgrund von Aliasing ein kleines Rauschen, aber Sie könnten das möglicherweise etwas abschrauben oder etwas breitere Linien im Dreieck zeichnen. Gradient triangle

+0

Ich dachte über eine ähnliche Idee nach, aber mit drei Scheiben (R, G, B) von Radius der Seite des Dreiecks und einem Alpha-Kanal, der auf 0 verblasst. Ich glaube, R würde dann die Farbmischung automatisch machen. – baptiste

+0

Sortieren von. Es würde jedoch zeigen, welcher Kreis auf welchem ​​anderen gezeichnet wurde. Sagen wir, Rot ist oben, dann grün, dann blau. In der Mitte hätten Sie 50% Rot, aber nur 25% Grün (50% der verbleibenden 50%) und 12,5% Blau. Fast jedes Venn-Diagramm, das ich gesehen habe, leidet darunter, und sobald ich es gesehen habe, kann ich nicht aufhören es zu bemerken. [Nehmen Sie diese zum Beispiel] (http://stackoverflow.com/questions/8713994/venn-diagram-in-r-proportional-and-color-shading-possible-semi-transparency-sup). – Backlin

1

Hier ist eine Implementierung ich für das phonR Paket aufgearbeitet ... die fillTriangle Funktion nicht exportiert wird, so dass Sie den ::: Operator verwenden müssen, darauf zuzugreifen. Beispiel zeigt sowohl pch-basierte als auch rasterbasierte Ansätze.

# set up color scale 
colmap <- plotrix::color.scale(x=0:100, cs1=c(0, 180), cs2=100, cs3=c(25, 100), 
           alpha=1, color.spec='hcl') 
# specify triangle vertices and corner colors 
vertices <- matrix(c(1, 4, 2, 1, 3, 4, length(colmap), 1, 30), nrow=3, 
        dimnames=list(NULL, c("x", "y", "z"))) 
# edit next line to change density/resolution 
xseq <- yseq <- seq(0, 5, 0.01) 
grid <- expand.grid(x=xseq, y=yseq) 
grid$z <- NA 
grid.indices <- splancs::inpip(grid, vertices[,1:2], bound=FALSE) 
grid$z[grid.indices] <- with(grid[grid.indices,], 
          phonR:::fillTriangle(x, y, vertices)) 
# plot it 
par(mfrow=c(1,2)) 
# using pch 
with(grid, plot(x, y, col=colmap[round(z)], pch=16)) 
# overplot original triangle 
segments(vertices[,1], vertices[,2], vertices[c(2,3,1),1], 
     vertices[c(2,3,1),2]) 
points(vertices[,1:2], pch=21, bg=colmap[vertices[,3]], cex=2) 

# using raster 
image(xseq, yseq, matrix(grid$z, nrow=length(xseq)), col=colmap) 
# overplot original triangle 
segments(vertices[,1], vertices[,2], vertices[c(2,3,1),1], 
     vertices[c(2,3,1),2]) 
points(vertices[,1:2], pch=21, bg=colmap[vertices[,3]], cex=2) 

example graphs of gradient triangle filling