adding all possible connections between dots in r plot - r

I have data-frame DOTS with following columns: DOT, X, Y. There are 10 dots.
I want to display all possible connections: (a) between dots 1,2,3,4,5; (b) 5,6,7; and (c) between 7,8,9,10?
# what I tried so far
plot(DOTS$X, DOTS$Y, main= "DOTS", xlab= "X", ylab= "Y",
col= "blue", pch = 19, cex = 1, lty = "solid", lwd = 2)
text(DOTS$X, DOTS$Y, labels=DOTS$Dot, cex= 0.7, pos = 3)
lines(DOTS$X,DOTS$Y)
# the last line displays connection from 1 to 2 to 3 etc only
Thank you in advance for your suggestions.

I make a dataset first :
x <- runif(10, 0, 10)
y <- runif(10, 0, 10)
df <- data.frame(dot = LETTERS[1:10], x = x, y = y)
I think it's flexible to create a custom function and use combn() to generate all possible combinations of two dots. And then connect them with segments() respectively. In the custom function below, you can put any dots set and arguments e.g. col, lwd... etc.
plot(df$x, df$y)
text(df$x, df$y, labels = df$dot, pos = 3)
line.fun <- function(index, ...){
comb <- combn(index, 2)
start <- comb[1, ] # starting points
end <- comb[2, ] # end points
segments(df$x[start], df$y[start], df$x[end], df$y[end], ...)
}
line.fun(1:5, col = 2)
line.fun(5:7, col = 3)
line.fun(7:10, col = 4)

Related

Generalizing a 2D plot to 3D in R

I have a problem where I have data with (x,y) coordinates that I want to plot in the x-y plane. Furthermore, I have some box constraints such that -7 < x < 7 and -5 < y < 5 need to be drawn and checked. All points that fall outside of this box constraint I would like to color red. To do this I have the following code in R:
library(rgl)
x <- 7
y <- 5
data.x <- rnorm(10,0,5)
data.y <- rnorm(10,0,5)
plot(data.x, data.y, xlim = c(min(-x,data.x),max(x,data.x)),
ylim = c(min(-y,data.y),max(y,data.y)), pch = 19)
rect(-x, -y, x, y, col = "lightgrey")
idx <- abs(data.x) > x | abs(data.y) > y
points(data.x[idx], data.y[idx], col = "red", pch = 19)
points(data.x[!idx], data.y[!idx], col = "deepskyblue", pch = 19)
Now, where I am stuck, is on how to plot this type of data picture when I have a third group of data and a third constraint. I.e.,
### How to generalize when I have a third axis and constraint, i.e., a 3D cube
z <- 4
data.z <- rnorm(10, 0, 5)
So essentially I want to plot a box constraint as a cube in the x-y-z plane, and to color the points that fall outside the box constraint red again.
Also, I should say I understand there are functions for plottig 3d scatter plots in R, however, what I am struggling with is how to draw the 3D cube that defines the constraints.
The difficulty with a 3D plot such as this is being able to interpret the "depth" of the points in the image. An animated 3D image might be helpful here:
library(plot3D)
x <- 7
y <- 5
z <- 6
set.seed(123)
data.x <- rnorm(10, 0, 5)
data.y <- rnorm(10, 0, 5)
data.z <- rnorm(10, 0, 5)
in_out <- abs(data.x) > x | abs(data.y) > y | abs(data.z) > z
for(i in seq(0, 358, 2)) {
png(paste0("box", sprintf("%03d", i), ".png"))
box3D(-x, -y, -z, x, y, z, col = NA, border = "gray50", theta = i, phi = 15,
xlim = c(-10, 10), ylim = c(-10, 10), zlim = c(-10, 10),
axes = TRUE, ticktype = "detailed")
points3D(data.x, data.y, data.z, colvar = in_out, pch = 16, cex = 3,
add = TRUE, colkey = FALSE, col = c("lightblue", "red"))
dev.off()
}
library(magick)
list.files(pattern = 'box\\d+\\.png', full.names = TRUE) %>%
image_read() %>%
image_join() %>%
image_animate(fps=50) %>%
image_write("box.gif")
box.gif

How to arrange symbols randomly into grid

I have a Grid with n*m size and pch Symbols from 1-13 with 8 Colors(so 104 different combinations)
Grid empty:
And now I am trying to draw the symbols as pairs randomly onto my grid.
My thinking was I create a matrix with the same size as my grid and random integer numbers and a data frame with all combinations of pch and color and draw them on the grid.
My Goal:
row <- 4
col <- 13
n <- row * col
plot.new()
plot.window(xlim = c(1, col), ylim = c(1, row))
grid(nx = col, ny = row, col = "black")
box(lwd = 2)
axis(1, at=1:col,tick=FALSE,las = 1)
axis(2,at = 1:row,tick= FALSE,las = 2)
pch_v <- c(1:13)
col_v <- c(1:8)
board <- matrix(sample(1:n),nrow = row,ncol=col)
unique_combination <- expand.grid(pch_v,col_v)
Thats the point where I am stuck. If somebody got an idea I would appreciate it.
Shuffle the unique_combination, then plot:
row <- 4
col <- 13
pch_v <- c(1:col)
col_v <- c(1:row)
unique_combination <- expand.grid(pch_v,col_v)
# random sort
# set.seed(1) # if we want to reproduce
ucr <- unique_combination[ sample(nrow(unique_combination)), ]
d <- data.frame(x = 1:col, y = 1:row, pch = ucr$Var1, col = ucr$Var2)
with(d, plot(x, y, col = col, pch = pch, bty = "n"))
If we need to plot X points, subset before the data:
# subset x rows then plot
with(head(d, 6), plot(x, y, col = col, pch = pch, bty = "n"))

Border for thick lines in R plotting

The picture below explains what I'd like to achieve in R. The blue line is added with a simple call to lines. This line shows some values of parameter over time. The line is thick (lwd=3) so it can be seen at a low zoom, and also so that the individual data points fit inside of it. This means that it overlaps with itself when there is chatter over a small x interval. Can the line be made to have a border to better resolve areas with overlap?
Draw a thicker line first and then draw thinner line on top of it
set.seed(42)
x = 1:10
y = sample(1:10)
plot(x, y, type = "l", lwd = 5, col = "red")
lines(x, y, lwd = 3, col = "green")
An alternative.
Under the assumption that seeing borders in order and on top of the "fill" color is important, then borrowing from d.b's excellent, fast, and very-simple answer that intersections give no indication of which direction came first (left of the 3-pack, below).
Altered data, to show overlaps:
set.seed(42)
x <- sample(10)
y <- sample(10)
One solution is to draw each segment individually, controlling colors each time.
segments2 <- function(x, y, lwd = c(2, 1), ..., border = NA, fill = NA) {
stopifnot(length(x) == length(y))
len <- length(x)
ign <- Map(function(x0, y0, x1 = x0, y1 = y0) {
if (!is.na(border)) lines(c(x0, x1), c(y0, y1), lwd = lwd[1], col = border, ...)
if (!is.na(fill)) lines(c(x0, x1), c(y0, y1), lwd = lwd[2], col = fill, ...)
}, x[-len], y[-len], x[-1], y[-1])
invisible()
}
This produces the middle plot below, but notice that each vertex has border-intrusion. A third option, much more complex, can mitigate that with a lot of trickery.
segments3 <- function(x, y, lwd = c(2, 1), ..., border = NA, fill = NA, lend = 0) {
stopifnot(length(x) == length(y))
len <- length(x)
dx <- x[-len] + diff(x) / 2
mx <- rbind(
c(NA, x[1], dx[1]),
cbind(dx[-(len-1)], x[-c(1,len)], dx[-c(1)]))
mx <- rbind(
mx[-(len-1),],
c(x[len], dx[len-1], NA),
mx[len-1,])
dy <- y[-len] + diff(y) / 2
my <- rbind(
c(NA, y[1], dy[1]),
cbind(dy[-(len-1)], y[-c(1,len)], dy[-c(1)]))
my <- rbind(
my[-(len-1),],
c(y[len], dy[len-1], NA),
my[len-1,])
for (rn in seq_len(nrow(mx))) {
lend0 <- if (rn %in% c(1L, len-1)) lend else 1
lines(mx[rn,], my[rn,], lwd = lwd[1], col = border, ..., lend = lend0)
lines(mx[rn,], my[rn,], lwd = lwd[2], col = fill, ..., lend = lend0)
}
}
It is likely possible to simplify this, but its performance is not heinous, and it does produce a slightly clearer plot.
par(mfrow=c(1, 3))
# simpler method
plot(x, y, type = "l", lwd = 5, col = "red", main = "Simpler")
lines(x, y, lwd = 3, col = "green")
# slower method, full-size
plot(x, y, type = "n", main = "Slower")
segments2(x, y, lwd = c(5, 3), border="red", fill="green")
# slowest method, fairly complex
plot(x, y, type = "n", main = "Slowest")
segments3(x, y, lwd = c(5, 3), border="red", fill="green")
Some notes:
lwd is a length-2 vector used to control the widths of the two lines; perhaps it would be more intuitive to have lwd be the main line and border.lwd be the border's thickness?
... arguments are passed through to lines, except
lend, which is tightly-controlled in order to keep mid-segment line endings controller but allow the user to override the two ends
if either border or fill are NA, then they just won't be drawn, which would then make one question why using this function
depending on your perspective, dimensions, etc, it is possible that a segment mid-point hints at a little junction, which can be seen as a hint in the left-most segment around (1.8, 3.7) ... this can go away just be resizing, and is I believe just an artifact of raster graphics in general

R. How to avoid lines connecting dots in dotplot

I made a plot using plot() using RStudio.
x = X$pos
y = X$anc
z = data.frame(x,y)
#cut in segments
my_segments = c(52660, 106784, 151429, 192098, 233666,
273857, 307933, 343048, 373099, 408960,
441545, 472813, 497822, 518561, 537471,
556747, 571683, 591232, 599519, 616567,
625727, 633744)
my_cuts = cut(x,my_segments, labels = FALSE)
my_cuts[is.na(my_cuts)] = 0
This is the code:
#create subset of segments
z_alt = z
z_alt[my_cuts %% 2 == 0,] = NA
#plot green, then alternating segments in blue
plot(z, type="p", cex = 0.3,pch = 16,
col="black",
lwd=0.2,
frame.plot = F,
xaxt = 'n', # removes x labels,
ylim = c(0.3, 0.7),
las = 2,
xlim = c(0, 633744),
cex.lab=1.5, # size of axis labels
ann = FALSE, # remove axis titles
mgp = c(3, 0.7, 0))
lines(z_alt,col="red", lwd=0.2)
# adjust y axis label size
par(cex.axis= 1.2, tck=-0.03)
If you see, some black dots are separated, but other black dots have red connecting lines. Does anyone know how to remove these annoying lines?. I just want black and red dots. Many thanks
there is no need to call the points in a second function. you can try to directly set the color in the plot function using a color vector.
# create some data as you have not provided some
set.seed(123)
df <- data.frame(x=1:100,y=runif(100))
# some sgment breaks
my_segments <- c(0,10,20,50,60)
gr <- cut(df$x, my_segments,labels = FALSE, right = T)
gr[is.na(gr)] <- 0
# create color vector with 1 == black, and 2 == red
df$color <- ifelse(gr %% 2 == 0, 1, 2)
# and the plot
plot(df$x, df$y, col = df$color, pch = 16)
The problem here is that you are using lines to add your z_alt. As the name of the function suggests, you will be adding lines. Use points instead.
z <- runif(20,0,1)
z_alt <- runif(20,0.8,1.2)
plot(z, type="p", col="black", pch = 16, lwd=0.2, ylim = c(0,1.4))
points(z_alt, col = "red", pch = 16, lwd = 0.2)

Plot A Confusion Matrix with Color and Frequency in R

I want to plot a confusion matrix, but, I don't want to just use a heatmap, because I think they give poor numerical resolution. Instead, I want to also plot the frequency in the middle of the square. For instance, I like the output of this:
library(mlearning);
data("Glass", package = "mlbench")
Glass$Type <- as.factor(paste("Glass", Glass$Type))
summary(glassLvq <- mlLvq(Type ~ ., data = Glass));
(glassConf <- confusion(predict(glassLvq, Glass, type = "class"), Glass$Type))
plot(glassConf) # Image by default
However, 1.) I don't understand that the "01, 02, etc" means along each axis. How can we get rid of that?
2.) I would like 'Predicted' to be as the label of the 'y' dimension, and 'Actual' to be as the label for the 'x' dimension
3.) I would like to replace absolute counts by frequency / probability.
Alternatively, is there another package that will do this?
In essence, I want this in R:
http://www.mathworks.com/help/releases/R2013b/nnet/gs/gettingstarted_nprtool_07.gif
OR:
http://c431376.r76.cf2.rackcdn.com/8805/fnhum-05-00189-HTML/image_m/fnhum-05-00189-g009.jpg
The mlearning package seems quite inflexible with plotting confusion matrices.
Starting with your glassConf object, you probably want to do something like this:
prior(glassConf) <- 100
# The above rescales the confusion matrix such that columns sum to 100.
opar <- par(mar=c(5.1, 6.1, 2, 2))
x <- x.orig <- unclass(glassConf)
x <- log(x + 0.5) * 2.33
x[x < 0] <- NA
x[x > 10] <- 10
diag(x) <- -diag(x)
image(1:ncol(x), 1:ncol(x),
-(x[, nrow(x):1]), xlab='Actual', ylab='',
col=colorRampPalette(c(hsv(h = 0, s = 0.9, v = 0.9, alpha = 1),
hsv(h = 0, s = 0, v = 0.9, alpha = 1),
hsv(h = 2/6, s = 0.9, v = 0.9, alpha = 1)))(41),
xaxt='n', yaxt='n', zlim=c(-10, 10))
axis(1, at=1:ncol(x), labels=colnames(x), cex.axis=0.8)
axis(2, at=ncol(x):1, labels=colnames(x), las=1, cex.axis=0.8)
title(ylab='Predicted', line=4.5)
abline(h = 0:ncol(x) + 0.5, col = 'gray')
abline(v = 0:ncol(x) + 0.5, col = 'gray')
text(1:6, rep(6:1, each=6),
labels = sub('^0$', '', round(c(x.orig), 0)))
box(lwd=2)
par(opar) # reset par
The above code uses bits and pieces of the confusionImage function called by plot.confusion.
Here is a function for plotting confusion matrices I developed from jbaums excellent answer.
It is similar, but looks a bit nicer (IMO), and does not transpose the confusion matrix you feed it, which might be helpful.
### Function for plotting confusion matrices
confMatPlot = function(confMat, titleMy, shouldPlot = T) {
#' Function for plotting confusion matrice
#'
#' #param confMat: confusion matrix with counts, ie integers.
#' Fractions won't work
#' #param titleMy: String containing plot title
#' #return Nothing: It only plots
## Prepare data
x.orig = confMat; rm(confMat) # Lazy conversion to function internal variable name
n = nrow(x.orig) # conf mat is square by definition, so nrow(x) == ncol(x)
opar <- par(mar = c(5.1, 8, 3, 2))
x <- x.orig
x <- log(x + 0.5) # x<1 -> x<0 , x>=1 -> x>0
x[x < 0] <- NA
diag(x) <- -diag(x) # change sign to give diagonal different color
## Plot confusion matrix
image(1:n, 1:n, # grid of coloured boxes
# matrix giving color values for the boxes
# t() and [,ncol(x):1] since image puts [1,1] in bottom left by default
-t(x)[, n:1],
# ylab added later to avoid overlap with tick labels
xlab = 'Actual', ylab = '',
col = colorRampPalette(c("darkorange3", "white", "steelblue"),
bias = 1.65)(100),
xaxt = 'n', yaxt = 'n'
)
# Plot counts
text(rep(1:n, each = n), rep(n:1, times = n),
labels = sub('^0$', '', round(c(x.orig), 0)))
# Axis ticks but no lables
axis(1, at = 1:n, labels = rep("", n), cex.axis = 0.8)
axis(2, at = n:1, labels = rep("", n), cex.axis = 0.8)
# Tilted axis lables
text(cex = 0.8, x = (1:n), y = -0.1, colnames(x), xpd = T, srt = 30, adj = 1)
text(cex = 0.8, y = (n:1), x = +0.1, colnames(x), xpd = T, srt = 30, adj = 1)
title(main = titleMy)
title(ylab = 'Predicted', line = 6)
# Grid and box
abline(h = 0:n + 0.5, col = 'gray')
abline(v = 0:n + 0.5, col = 'gray')
box(lwd = 1, col = 'gray')
par(opar)
}
Example of output:

Resources