Drawing circles in R - r

I'm using plotrix package to draw circles.
And I don't get what is wrong with my code... :-(
I have three points. The first point (1,1) should be the center of the circle. The following two points (1,4) and (4,1) have the same distance/radius to the center.
So the circle in the plot should go through these points, right?
And I don't know why the circle looks wrong. Is there an explanation?
p1 <- c(1,1)
p2 <- c(4,1)
p3 <- c(1,4)
r <- sqrt(sum((p1-p2)^2))
plot(x=c(p1[1], p2[1], p3[1]),
y=c(p1[2], p2[2], p3[2]),
ylim=c(-5,5), xlim=c(-5,5))
draw.circle(x=p1[1], y=p1[2], radius=(r))
abline(v=-5:5, col="#0000FF66")
abline(h=-5:5, col="#0000FF66")
Take a look at the produced output here

As #Baptiste says above, you can use plot(...,asp=1). This will only work if your x and y ranges happen to be the same, though (because it sets the physical aspect ratio of your plot to 1). Otherwise, you probably want to use the eqscplot function from the MASS package. A similar issue arises whenever you try to do careful plots of geometric objects, e.g. Drawing non-intersecting circles
This plot is produced by substituting MASS::eqscplot for plot in your code above:
Note that depending on the details of what R thinks about your monitor configuration etc., the circle may look a bit squashed (even though it goes through the points) when you plot in R's graphics window -- it did for me -- but should look OK in the graphical output.

Related

Difficulties with adding arrows to plot in R

I am attempting to project data onto a plot in R and see the correlation between the points. I have added a line to let the reader see the connection between these points. I am however stumped when it comes to inputting arrows to show the direction of the line. Rddproj was just an arbitrary name given to the data. Three sets of x and y coordinates are plotted x=c(-0.7159425, -0.8129311, -0.7392371); y=0.7743088, 0.7732762, 0.7490996) Here is the example below.
x<-rddproj[1:3,1]; y<-rddproj[1:3,2]
plot(x,y)
My concern is that the second group of coordinates is the greatest negative point on the x-axis. In drawing a line with arrows, the arrow will most likely point towards this point, when it should be forming a V with that point in the middle. Is it possible to plot an arrow to reflect the placement of points in a group and not just the most positive point to the most negative point or vice versa?
The arrows function ( a modified segments function) is used for this purpose (to the extent that I understand the question) in base R:
# fixed your assignment code.
plot(NA, xlim=range(x), ylim=range(y) )
arrows(head(x,-1),head(y,-1),tail(x,-1), tail(y,-1), angle=30)
An alternative reading of your question would have the glaringly obvious solution : plot(x,y) which I hope is not what you were asking since that should have been satisfactory.

Polygon/contour around subset of vertices on graph (more precise than mark.groups in igraph)

Problem definition
I need to produce a number of specific graphs, and on these graphs, highlight subsets of vertices (nodes) by drawing a contour/polygon/range around or over them (see image below).
A graph may have multiple of these contours/ranges, and they may overlap, iff one or more vertices belong to multiple subsets.
Given a graph of N vertices, any subset may be of size 1..N.
However, vertices not belonging to a subset must not be inside the contour (as that would be misleading, so that's priority no. 1). This is gist of my problem.
All these graphs happen to have the property that the ranges are continuous, as the data they represent covers only directly connected subsets of vertices.
All graphs will be undirected and connected (no unconnected vertices will ever be plotted).
Reproducible attempts
I am using R and the igraph package. I have already tried some solutions, but none of them work well enough.
First attempt, mark.groups in plot.igraph:
library(igraph)
g = make_graph("Frucht")
l = layout.reingold.tilford(g,1)
plot(g, layout=l, mark.groups = c(1,3,6,12,5), mark.shape=1)
# bad, vertex 11 should not be inside the contour
plot(g, layout=l, mark.groups = c(1,6,12,5,11), mark.shape=1)
# 3 should not be in; image below
# just choosing another layout here is not a generalizable solution
The plot.igraph calls igraph.polygon, which calls convex_hull (also igraph), which calls xspline. The results is, from what I understand, something called a convex hull (which otherwise looks very nice!), but for my purposes that is not precise enough, covering vertices that should not be covered.
Second attempt with contour. So I tried implementing my own version, based on the solution suggested here:
library(MASS)
xx <- runif(5, 0, 1);yy <- abs(xx)+rnorm(5,0,0.2)
plot(xx,yy, xlim=c( min(xx)-sd(xx),max(xx)+sd(xx)), ylim =c( min(yy)-sd(yy), max(yy)+sd(yy)))
dens2 <- kde2d(xx, yy, lims=c(min(xx)-sd(xx), max(xx)+sd(xx), min(yy)- sd(yy), max(yy)+sd(yy) ),h=c(bandwidth.nrd(xx)/1.5, bandwidth.nrd(xx)/ 1.5), n=50 )
contour(dens2, level=0.001, col="red", add=TRUE, drawlabels=F)
The contour plot looks in principle like something I could use, given enough tweaking of the bandwidth and level values (to make the contour snug enough so it doesn't cover any points outside the group). However, this solution has the drawback that when the level value is too small, the contour breaks (doesn't produce a continuous area) - so if I would go that way, controlling for continuity (and determining good bandwidth/level values on the fly) automatically should be implemented. Another problem is, I cannot quite see how could I plot the contour over the plots produced by igraph: the layout.* commands produce what looks like a coordinate matrix, but the coordinates do not match the axis coordinates on the plot:
# compare:
layout.reingold.tilford(g,1)
plot(g, layout=l, axes=T)
The question:
What would be a better way to achieve the plotting of such ranges on graphs (ideally igraphs) in R that would meet the criteria outlined above - ranges that include only the vertices that belong to their subset and exclude all else - while being continous ranges?
The solution I am looking for should be scalable to graphs of different sizes and layouts that I may need to create (so hand-tweaking each graph by hand using e.g. tkplot is not a good solution). I am aware that on some graphs with some vertex groups, meeting both the criteria will indeed be impossible in practise, but intuitively it should be possible to implement something that still works most of the time with smallish (10..20 vertices) and not-too-complex graphs (ideally it would be possible to detect and give a warning if a perfectly fitting range could not be plotted). Either an improvement of the mark.groups approach (not necessarily within the package, but using the hull-idea mentioned above), or something with contour or a similar suitable function, or suggesting something else entirely would be welcome, as long as it works (most of the time).
Update stemming from the discussion: a solution that only utilizes functions of core R or CRAN packages (not external software) is desirable, since I will eventually want to incorporate this functionality in a package.
Edit: specified the last paragraph as per the comments.
The comment area is not long enough to fit my answer there, so I'm putting this here, although I'd rather post it as a comment as it is not a full solution.
Quite a long throw, but the first thing that popped into my mind is support vector machines. The idea would be that you construct a support vector machine classifier that classifies your points into two groups (in or out) based on the coordinates of the vertices, using some non-linear kernel function (I would try the radial basis function). Then you plot the separating hyperplane of the trained support vector machine. One drawback is that the area that you obtain this way might be unbounded (i.e. go to infinity in some directions), so this idea definitely requires some further thinking, but at least that's one possible direction to go.

cluster: :clusplot axis in wrong direction

I'm trying to plot the cluster obtained from fuzzy c-means clustering.
The plot should look like this.
code for the plot
plot(data$Longitude, data$Latitude, main="Fuzzy C-Means",col=data$Revised, pch=16, cex=.6,
xlab="Longitude",ylab="Latitude")
library(maps)
map("state", add=T)
However, when I tried to use clusplot the plot is displaying in opposite direction(both top and bottom and left and right) as below.
I wanna know if there's a way to reverse the plot to show in the order as the above picture.
Also, for the very dense area, it's hard to find the ellipse label. I wanna know if there's a way to show the label inside the ellipse instead of outside.
code for 2nd pic
library(cluster)
clusplot(cbind(Geocode$Longitude, Geocode$Latitude), cluster, color=TRUE,shade=TRUE,
labels=4, lines=0,col.p=cluster,
xlab="Longitude",ylab="Latitude",cex=1)
clusplot is a function that performs a lot of magic for you. In particular it projects the data set - which happens in a way you don't like, unfortunately. (Also note the scales - it centered and scaled the data, too)
clusplot.default: Creates a bivariate plot visualizing a partition (clustering) of the data. All observation are represented by points in the plot, using principal components or multidimensional scaling.
As far as I can tell, clusplot doesn't have map support, but you will want such a map I guess...
While maybe you can use the s.x.2d parameter to specify the exact projection (and this way disable automatic scaling), it probably is still difficult to add the map. Maybe look at the source of clusplot instead, and take only the parts you want?

Shaded graph/network plot?

I am trying to plot quite large and dense networks (dput here). All I end up with is a bunch of overlapping dots, which does not really give me a sense of the structure or density of the network:
library(sna)
plot(data, mode = "fruchtermanreingold")
However, I have seen plots which utilizes fading to visualize the degree to which points overlap, e.g.:
How can I implement this "fading" in a plot of a graph?
Here's one way:
library(sna)
library(network)
source("modifieddatafromgist.R")
plot.network(data,
vertex.col="#FF000020",
vertex.border="#FF000020",
edge.col="#FFFFFF")
First, I added a data <- to the gist so it could be sourced.
Second, you need to ensure the proper library calls so the object classes are assigned correctly and the proper plot function will be used.
Third, you should use the extra parameters for the fruchtermanreingold layout (which is the default one for plot.network) to expand the area and increase the # of iterations.
Fourth, you should do a set.seed before the plot so folks can reproduce the output example.
Fifth, I deliberately removed cruft so you can see the point overlap, but you can change the alpha for both edges & vertices (and you should change the edge width, too) to get the result you want.
There's a ton of help in ?plot.network to assist you in configuring these options.

Plotting straight surface with lattice::wireframe()

Assume I want to plot the following dataframe:
df <- data.frame(expand.grid(1:10,1:10),rep(10,100))
colnames(df) <- c("x","y","z")
with the lattice wireframe() function:
wireframe(z~x*y,df,colorkey=TRUE,drape=TRUE)
How do I get it to plot the given coordinates? I would assume it has something to do with having to scale/adjust the z-axis as the automatic scaling within wireframe is probably confused by all z-coordinates being equal.
This is from the help page scales section: "The most common use for this argument is to set arrows=FALSE, which causes tick marks and labels to be used instead of arrows being drawn (the default)." So just add that as a list value to 'scales':
wireframe(z~x*y,df,colorkey=TRUE,drape=TRUE,
scales=list(arrows=FALSE), zlim=c(0,10.1))
The failure of wireframe to display anything when the plotted plane is at one of the extremes seems to be at least "unexpected behavior" if not a bug. I suspect you would not see this in real data. Your use of drape doesn't make much sense since the entire data-plane plane gets displayed at the white midpoint. (Again this is probably not a problem if you have something other than this pathological example.)
Just add a zlim argument.
wireframe(z~x*y,df,colorkey=TRUE,drape=TRUE, zlim=c(0,20))

Resources