Given a vector of fractions(on the domain [0:1]), I want to plot the vertex just partially filled.
I.e. if the fraction is 1/2 the corresponding vertex should be half-filled(half-sphere)
I.e. if the fraction is 1/4 the corresponding vertex is only in one quarter (quarter-sphere)
and so forth...
library('igraph')
N <- 10
g <- graph.full(N)
values <- runif(N,0,1) # vector of fractions
V(g)$shape <-'circle'
plot.igraph(g,...)
for example:
http://www.google.ch/imgres?q=three+quarter-filled+circle&um=1&hl=de&sa=N&biw=1024&bih=751&tbm=isch&tbnid=fCz7FZ6JG38DzM:&imgrefurl=http://www.clipartstation.com/clipart_indexer4/index/search%3Fkeywords%3DART&docid=UPphGFugM1pYGM&imgurl=http://www.clipartstation.com/clipart/resized/Math/Transformations/__100x100//three%252520quarters%252520blue%252520circle.gif&w=100&h=99&ei=ETsNUNDeHbCL4gTT5rjACg&zoom=1&iact=rc&dur=331&sig=101088608959992434501&page=1&tbnh=79&tbnw=80&start=0&ndsp=24&ved=1t:429,r:8,s:0,i:97&tx=49&ty=38
If you have the igraph package version 0.6, you should be able to use the pie vertex in plot(), in which case your code would be:
library(igraph)
N <- 10
g <- graph.full(N)
values <- runif(N,0,1) # vector of fractions
plot(g, vertex.shape="pie", vertex.pie=values, vertex.frame.color="white",
vertex.pie.color=list(heat.colors(5)))
If you don't have this working (which I didn't), you can find the code here, which you can run and then use pie as a vertex.
Related
Suppose I have two datasets: (1) a data frame: coordinates of localities, each with ID; and (2) a linguistic distance matrix which reflects the linguistic distance between these localities.
# My data are similar to this structure
# dataframe
id <- c("A","B","C","D","E")
x_coor <- c(0.5,1,1,1.5,2)
y_coor <- c(5.5,3,7,6.5,5)
my.data <- data.frame(id = id, x_coor = x_coor, y_coor = y_coor)
# linguistic distance matrix
A B C D
B 308.298557
C 592.555483 284.256926
D 141.421356 449.719913 733.976839
E 591.141269 282.842712 1.414214 732.562625
Now, I want to visualize the linguistic distance between every two sites onto a map by the thickness or color of the line connect the adjacent localities in R.
Just like this:
enter image description here
My idea is to generate the delaunay triangulation by deldir or tripack package in R.
# generate delaunay triangulation
library(deldir)
de=deldir(my.data$x_coor,my.data$y_coor)
plot.deldir(de,wlines="triang",col='blue',wpoints = "real",cex = 0.1)
text(my.data$x_coor,my.data$y_coor,my.data$id)
this is the plot:
enter image description here
My question is how to reflect the linguistic distance by the thickness or color of the edges of triangles? Is there any other better method?
Thank you very much!
What you want to do in respect of the line widths can be done "fairly
easily" by the deldir package. You simply call plot.deldir() with the
appropriate value of "lw" (line width).
At the bottom of this answer is a demonstration script "demo.txt" which shows how to do this in the case of your example. In particular this script shows
how to obtain the appropriate value of lw from the "linguistic distance
matrix". I had to make some adjustments in the way this matrix was
presented. I.e. I had to convert it into a proper matrix.
I have rescaled the distances to lie between 0 and 10 to obtain the
corresponding values of the line widths. You might wish to rescale in a different manner.
In respect of colours, there are two issues:
(1) It is not at all clear how you would like to map the "linguistic
distances" to colours.
(2) Unfortunately the code for plot.deldir() is written in a very
kludgy way, whence the "col" argument to segments() cannot be
appropriately passed on in the same manner that the "lw" argument can.
(I wrote the plot.deldir() code a long while ago, when I knew far less about
R programming than I know now! :-))
I will adjust this code and submit a new version of deldir to CRAN
fairly soon.
#
# Demo script
#
# Present the linguistic distances in a useable way.
vldm <- c(308.298557,592.555483,284.256926,141.421356,449.719913,
733.976839,591.141269,282.842712,1.414214,732.562625)
ldm <- matrix(nrow=5,ncol=5)
ldm[row(ldm) > col(ldm)] <- vldm
ldm[row(ldm) <= col(ldm)] <- 0
ldm <- (ldm + t(ldm))/2
rownames(ldm) <- LETTERS[1:5]
colnames(ldm) <- LETTERS[1:5]
# Set up the example data. It makes life much simpler if
# you denote the "x" and "y" coordinates by "x" and "y"!!!
id <- c("A","B","C","D","E")
x_coor <- c(0.5,1,1,1.5,2)
y_coor <- c(5.5,3,7,6.5,5)
# Eschew nomenclature like "my.data". Such nomenclature
# is Micro$oft-ese and is an abomination!!!
demoDat <- data.frame(id = id, x = x_coor, y = y_coor)
# Form the triangulation/tessellation.
library(deldir)
dxy <- deldir(demoDat)
# Plot the triangulation with line widths proportional
# to "linguistic distances". Note that plot.deldir() is
# a *method* for plot, so you do not have to (and shouldn't)
# type the ".deldir" in the plotting command.
plot(dxy,col=0) # This, and plotting with "add=TRUE" below, is
# a kludge to dodge around spurious warnings.
ind <- as.matrix(dxy$delsgs[,c("ind1","ind2")])
lwv <- ldm[ind]
lwv <- 10*lwv/max(lwv)
plot(dxy,wlines="triang",col='grey',wpoints="none",
lw=10*lwv/max(lwv),add=TRUE)
with(demoDat,text(x,y,id,col="red",cex=1.5))
# Erdos
par(mfrow=c(1,2))
g <- erdos.renyi.game(100, 1/100)
V(g)$size<-seq(0.05,5,0.05)
betweenness(g)
# Draw nodes and save positions
locs <- layout.fruchterman.reingold(g)
plot(g,
layout=locs,
vertex.label=NA,
main="Original",
vertex.color=degree(g))
g
vertex.color=degree(g)
did not work. Could anyone tell me how to color the vertices by "degree"?
Red (high value) to blue (low value) would be perfect.
Thanks!
A solution I found is to create a new color vector with the grey color R provides us with colors()[]. If you check colors()[] in your terminal, you can see the full list of colors that are readable by the plot.igraph() function.
You first charge your data (graph, etc.) :
edgelist <- read.csv(...)
graph <- make_graph_from_data(edgelist)
Then you create a vector of colors that corresponds to the length of your vertices list :
length(V(g)) # with a length of X vertices :
colors <- c(paste0(rep("grey",X),seq(X,1)))
Finally, you plot it with the attribute vertex.color :
plot(g,vertex.color=colors[degree(graph)])
However, one can only use this little trick for graph with less than 100 values in degree(graph)...
I would like to match points in 3-dimensional space.
Therefore, I am using the Hungarian Method described in this question: Finding the best matching pairwise points from 2 vectors
Here is my example using R:
# packages
library(rgl)
library(clue)
library(plyr)
library(fields)
set.seed(1)
a <- c(rep(2,7), 3,4,5,6,3,4,5,6,7,7,7,7,7,7) # x values
b <- c(rep(3,7),3,3,3,3, 3,3,3,3,3,3,3,3,3,3) # y values
c <- c(seq(1,7),1,1,1,1,7,7,7,7,1,2,3,4,5,6) # z values
# transform the points
set.seed(2)
a1 <- a + seq(1,length(a))
b1 <- b + 8
c1 <- c + 9
# plot the data
plot3d(a,b,c, col="red", pch=16,size=10)
plot3d(a1,b1,c1, lwd=10, col="blue", pch=16,size=10, add=TRUE)
# run the Hungarian Method
A <- cbind(a,b,c)
B <- cbind(a1,b1,c1)
distances <- rdist(A,B) # calculate Euclidean Distance between points
min.dist <- solve_LSAP(distances) # minimizing the sum of distance
min.dist.num <- as.numeric(min.dist)
# plot the minimized lines between point sets
for (ii in 1:dim(B)[1]){
D <- c(A[ii,1], B[min.dist.num[ii],1])
R <- c(A[ii,2], B[min.dist.num[ii],2])
W <- c(A[ii,3], B[min.dist.num[ii],3])
segments3d(D,R,W,col=2,lwd=1)
}
# calculate the share of points that is matched correctly
sum(1:dim(B)[1]==min.dist.num)/dim(B)[1]* 100
The problem here is that only 5% of the points are matched correctly (see last line of the code). In my view, the main trouble is that the algorithm does not take the structure of the object (a square) into account.
Question: Is there any method that performs better for this sample data?
In my original data, the dimensional structure of the points is way more complicated. I have a cloud of data and within this cloud there are multiple subfigures.
I am seeking primarily for a solution in R, but other implementations (e.g. MATLAB, Excel, Java) are also welcome.
I have an unconnected graph that I plot with fruchterman-reingold layout in igraph
require(igraph)
er_graph <- erdos.renyi.game(100, 5/20)+erdos.renyi.game(100, 5/20)
coords<-layout.fruchterman.reingold(er_graph)
plot(er_graph,layout=coords, vertex.label=NA)
Plot Example :
The result was two distant clusters.
I wish to decrease the white area in my plot.
Is there a way to scale the coordinate in order to decrease the space between the clusters?
There may be an easy way to do this in one of the layout functions, but you can also directly change the node coordinates after creating the layout. If you look at coords, you can see it's just a matrix of node coordinates. You can use the cluster labels to move the two node clusters closer together programmatically:
require(igraph)
require(dplyr)
er_graph <- erdos.renyi.game(100, 5/20)+erdos.renyi.game(100, 5/20)
# Make layout reproducible
set.seed(40)
coords <- layout.fruchterman.reingold(er_graph)
# Original graph
plot(er_graph,layout=coords, vertex.label=NA)
Move clusters closer together: First, we add the cluster labels to the coordinates and set a parameter f for what fraction of the distance between clusters we want eliminate. Then we subtract from each node f times the difference between the mean coordinates for that cluster and the mean coordinates over both clusters.
# Add cluster labels to coords
coords = data.frame(coords, clust=clusters(er_graph)$membership)
# Move closer by a fraction "f" of mean distance between clusters
f = 0.6
# Shift each node closer to the overall center of mass of the node
coords = coords %>%
mutate(X1 = ifelse(clust==1, X1 - f*(mean(X1[clust==1]) - mean(X1)), X1 - f*(mean(X1[clust==2]) - mean(X1))),
X2 = ifelse(clust==1, X2 - f*(mean(X2[clust==1]) - mean(X2)), X2 - f*(mean(X2[clust==2]) - mean(X2))))
# Convert coords back to original matrix form
coords = as.matrix(coords[,1:2])
# Re-plot graph
plot(er_graph,layout=coords, vertex.label=NA)
Was wondering if the following is possible:
Currently, I have a subset of nodes in a graph, (graph A), which belongs in another separate and larger graph (graph B).
I would like to preserve the layout from graph B pertaining to this subset of nodes when running a layout generation algorithm on graph A. Could be any of the layout algorithms.
layout.circle(graph, params)
layout.sphere(graph, params)
layout.fruchterman.reingold(graph, ..., dim=2, params)
layout.kamada.kawai(graph, ..., dim=2, params)
layout.spring(graph, ..., params)
layout.reingold.tilford(graph, ..., params)
layout.fruchterman.reingold.grid(graph, ..., params)
layout.lgl(graph, ..., params)
layout.graphopt(graph, ..., params=list())
layout.mds(graph, dist=NULL, dim=2, options=igraph.arpack.default)
layout.svd(graph, d=shortest.paths(graph), ...)
You can use the minx, maxx, miny and maxy arguments of layout.fruchterman.reingold() or layout.kamada.kawai() to fix some vertices completely. These arguments specify vertex-specific lower and/or upper limits for the coordinates.
For the vertices you want to fix, set them exactly to the value to fix, and for the other vertices set minx to some small negative values (-Inf might work, too), and set maxx to some large value, (again, maybe Inf works, too).
You might need to use the rescale=FALSE argument in plot.igraph() to avoid rescaling the complete layout, for both the first and second graph.
Edit:
From the manual:
'minx' If not 'NULL', then it must be a numeric vector that gives
lower boundaries for the 'x' coordinates of the vertices. The
length of the vector must match the number of vertices in the
graph.
'maxx' Similar to 'minx', but gives the upper boundaries.
For example:
g <- graph.star(10, center=1)
minx <- rep(-Inf, vcount(g))
maxx <- rep( Inf, vcount(g))
minx[1] <- 0
maxx[1] <- 0
lay <- layout.fruchterman.reingold(g, minx=minx, maxx=maxx, miny=minx, maxy=maxx)
plot(g, layout=lay)
fixes the first vertex into (0,0) (might be modified by rescaling, to avoid rescaling, use rescale=FALSE in plot() and set the plotting limits).
The layout in igraph is defined as a n (number of nodes) by 2 matrix where the first column indicates the x-coordinate (on a arbitrary scale) and the second column the y-coordinate. You can store the result of any of these functions to obtain this matrix, and then pass that to the layout argument when you plot another graph.
library("igraph")
# A 3-node network:
g <- graph.adjacency(matrix(1,3,3))
# Obtain a layout:
l <- layout.circle(g)
# A different 3-node network:
g2 <- graph.adjacency(matrix(0,3,3))
# Plot second network with layout based on first network:
plot(g2,layout=l)
Edit
If you have a subset of a graph you can simply index this matrix. E.g.:
# A 3-node network:
g <- graph.adjacency(matrix(1,3,3))
# Obtain a layout:
l <- layout.circle(g)
# A 2-node subset:
g2 <- graph.adjacency(matrix(1,2,2))
# Plot second network with layout based on first network:
plot(g2,layout=l[1:2,])