I want to plot multiple lines(here simplified as two), but don't know how to draw in different colors on same plot. Here is the separated figures version.
using UnicodePlots, DataFrames
function job()
names, data = ["A", "B"], [
DataFrame("x"=>[1, 2, 3], "y"=>[3, 5, 7]),
DataFrame("x"=>[1, 2, 3], "y"=>[8, 2, 6]),
]
y_min, y_max = typemax(Int64), typemin(Int64)
y_min = min(minimum(data[1].y), minimum(data[2].y))
y_max = max(maximum(data[1].y), maximum(data[2].y))
ylim = (y_min, y_max)
for i = 1:length(names)
p = lineplot(data[i].x, data[i].y, name=names[i], ylim=ylim)
show(p)
println("")
#if i == 1
# p=lineplot(data[i].x, data[i].y, name=names[i], ylim=ylim)
#else # failed for p undefined when i == 2
# lineplot!(p, data[i].x, data[i].y, name=names[i], ylim=ylim)
#end
end
#show(p)
println("")
end
job()
It was almost correct. Here is the fixed version:
using UnicodePlots, DataFrames
function job()
names, data = ["A", "B"], [
DataFrame("x"=>[1, 2, 3], "y"=>[3, 5, 7]),
DataFrame("x"=>[1, 2, 3], "y"=>[8, 2, 6]),
]
y_min, y_max = typemax(Int64), typemin(Int64)
y_min = min(minimum(data[1].y), minimum(data[2].y))
y_max = max(maximum(data[1].y), maximum(data[2].y))
ylim = (y_min, y_max)
local p
for i = 1:length(names)
if i == 1
p=lineplot(data[i].x, data[i].y; name=names[i], ylim=ylim)
else
lineplot!(p, data[i].x, data[i].y; name=names[i])
end
end
show(p)
println("")
end
job()
Issues were:
When adding another line, cannot change axis.
Variables inside loops need to be defined outside to extend their scope.
Think that's it.
Related
Suppose I have a set of inequalities:
-2x + y <= -3
1.25x + y <= 2.5
y >= -3
And I can summarize the information as follows:
mat <- matrix(c(-2, 1, 1.25, 1, 0, 1), nrow = 3, byrow = TRUE)
dir <- c("<=", "<=", ">=")
rhs <- c(-3, 2.5, -3)
I wrote the following function to plot the inequalities:
plot(0, 0, xlim = c(-1, 5), ylim = c(-4, 1))
plot_ineq <- function(mat, dir, rhs, xlow, xhigh){
line <- list()
for(i in 1:nrow(mat)){
if(mat[i, 2] > 0){
line[[i]] <- sapply(seq(xlow, xhigh, 0.1), function(x) (rhs[i] - mat[i, 1] * x)/mat[i, 2])
}else if(mat[i, 2] < 0){
line[[i]] <- sapply(seq(xlow, xhigh, 0.1), function(x) (rhs[i] - mat[i, 1] * x)/mat[i, 2])
if(dir[i] == ">="){
dir[i] = "<="
}else dir[i] = ">="
}
lines(seq(xlow, xhigh, 0.1), line[[i]])
}
}
plot_ineq(mat = mat, dir = dir, rhs = rhs, xlow = -1, xhigh = 5)
I have two questions: (1) how can I have a blank plot without having the (0, 0) point there? and (2) how can I shade the corresponding region according to dir? Should I try ggplot2?
I'm simply looking to shade the area that is described by the set of inequalities above. Not where (0, 0) lies.
1) Change the last inequality to be the same direction as the others and then use plotPolytope in gMOIP.
library(gMOIP)
mat <- matrix(c(-2, 1, 1.25, 1, 0, -1), nrow = 3, byrow = TRUE)
rhs <- c(-3, 2.5, 3)
argsFaces <- list(argsGeom_polygon = list(fill = "blue"))
plotPolytope(mat, rhs, argsFaces = argsFaces)
giving (continued after image)
2) The above uses ggplot2 graphics but if you prefer classic graphics then using mat and rhs from above:
library(gMOIP)
cp <- cornerPoints(mat, rhs)
cp <- cp[chull(cp), ] # chull gives indices of convex hull in order
plot(cp, type = "n")
polygon(cp, col = "blue")
# not shown but to add lines run this too
for(i in 1:nrow(cp)) {
ix <- if (i < nrow(cp)) i + 0:1 else c(i, 1)
b <- diff(cp[ix, 2]) / (d <- diff(cp[ix, 1]))
if (abs(d) < 1e-5) abline(v = a <- cp[i, 1])
else abline(a = a <- cp[i, 2] - b * cp[i, 1], b = b)
}
giving (continued after image)
3) Note that there is an archived package named intpoint on CRAN and it could be used to draw the boundary of the feasible region and lines. It does have the limitation that it is hard coded to show X and Y axes between -1 and 5 although it might not be hard to generalize it. It is used like this (output not shown) where mat, rhs and cp are from above.
library(intpoint)
intpoint:::show2d(mat, rhs, c = numeric(2))
polygon(cp, col = "blue")
I have the following code (although without data, sadly):
detrend_plot <- cbind(l_p_lng,l_vol_lng,l_p_oil,l_rgdpe, ldiff_p_lng,ldiff_vol_lng,ldiff_p_oil,ldiff_rgdpe)
plot.ts(detrend_plot, main="",)
which gives the following plot:
What I want to do is to add custom titles, individual y-axis labels, and x-axis labels. I know that this is possible using GGPLOT, although my knowledge of it is sparse. Has anyone encountered a similar problem? I don't think this is possible using the regular plot.ts( ) function.
I don't think you can pass multiple titles and labels to plot.ts directly, but you can just loop over your columns with vectors of labels for each:
set.seed(1)
z <- ts(matrix(rt(200 * 8, df = 3), 200, 8), start = c(1961, 1), frequency = 12)
## vectors of x, y, and main labels
xl <- sprintf('x label %s', 1:8)
yl <- sprintf('y label %s', 1:8)
ml <- sprintf('main label %s', 1:8)
par(mfrow = c(4, 2), mar = c(5, 5, 1, 1), oma = c(0, 0, 1, 2))
lapply(1:8, function(ii) {
x <- z[, ii, drop = FALSE]
plot(x, xlab = xl[ii], ylab = yl[ii], main = ml[ii])
})
You can also pass vectors of arguments (eg, for x- or y-axis limits) using lists:
ylim <- list(c(-10, 10))
ylim <- rep(ylim, 8)
par(mfrow = c(4, 2), mar = c(5, 5, 1, 1), oma = c(0, 0, 1, 2))
lapply(1:8, function(ii) {
x <- z[, ii, drop = FALSE]
plot(x, xlab = xl[ii], ylab = yl[ii], main = ml[ii], col = ii, ylim = ylim[[ii]])
})
To get a figure closer to the default plot.ts look, you can just set top and bottom margins to 0 and adjust the axes (which is what plot.ts is doing under the hood). This method is a bit more verbose than plot.ts but will allow for more customization:
par(mfrow = c(4, 2), mar = c(0, 5, 0, 1), oma = c(5, 0, 3, 2))
lapply(1:8, function(ii) {
x <- z[, ii, drop = FALSE]
plot(x, xlab = xl[ii], ylab = yl[ii], col = ii, axes = FALSE)
axis(2, las = 1)
box()
if (ii %in% 7:8) {
axis(1)
title(xlab = 'Year', xpd = NA)
}
if (ii %in% 1:2)
title(main = c('Group 1', 'Group 2')[ii], xpd = NA, line = 1)
})
I have an R function called stock (below). I was wondering if it might be in any way possible that the result of each run of the function (which is a plot()) be plotted (i.e., added) on top of the plot from the previous run of the function? (the picture below the code may show this)
stock = function(m, s){
loop = length(s)
I = matrix(NA, loop, 2)
for(i in 1:loop){
I[i,] = quantile(rbeta(1e2, m, s[i]), c(.025, .975))
}
plot(rep(1:loop, 2), I[, 1:2], ty = "n", ylim = 0:1, xlim = c(1, loop))
segments(1:loop, I[, 1], 1:loop, I[, 2])
}
# Example of use:
stock(m = 2, s = c(1, 10, 15, 20, 25, 30))
stock(m = 50, s = c(1, 10, 15, 20, 25, 30)) #The result of this run be plotted on top of previous run above
Simplest would be to add an argument for the option. As segments() by default adds to the previous frame, all you have to do is to not do a new plot().
stock = function(m, s, add=FALSE) {
loop = length(s)
I = matrix(NA, loop, 2)
for(i in 1:loop) {
I[i,] = quantile(rbeta(1e2, m, s[i]), c(.025, .975))
}
if (!add) {
plot(rep(1:loop, 2), I[, 1:2], ty = "n", ylim = 0:1, xlim = c(1, loop))
}
segments(1:loop, I[, 1], 1:loop, I[, 2], xpd = NA)
}
# Example of use:
set.seed(1)
stock(m = 2, s = c(1, 10, 15, 20, 25, 30))
stock(m = 50, s = seq(1, 90, 10), add=TRUE)
I'm trying to loop over 2 curves in R but only one of the curves shows. More importantly, I call axis() command two times (for x and y axes) but I get the following error:
Error in axis(1, at = success/trials) : no locations are finite
'to' must be a finite number
Question
I'm wondering (a) why only my first curve is showing and (b) why I'm getting Inf/-Inf in my axis() calls?
Here is my R code:
success = c(10, 50) ; trials = 100
for(i in 1:length(success)){
success = success[i]
col = (1:length(success))[i]
c = curve( dbinom(success, trials, x), 0, 1, add = ifelse(i > 1, T, F), ty = "l", xlim = c(0, 1),
col = col, yaxt = "n")
text(success/trials, max(c$y), bquote(bolditalic(H[.(i)])), pos = 3, xpd = T )
axis(1, at = success/trials)
}
axis(2, at = seq(0, max(c$y), len = 7), labels = round(seq(0, max(c$y), len = 7), 2), las = 1 )
In your first pass through the loop you set success to success[1] and in the second pass through the loop you set success to success[2] but success was at that point length 1, so it becomes NA.
Similarly, the second plot doesn't show because col becomes NA for the same reason.
To fix this, use a different name for the list of successes and the variable in the loop. For example, use successes = c(10,50) and then use successes when setting success and col inside the loop. (Alternatively for col, just set col = i.)
Applying that to your code:
successes = c(10, 50) ; trials = 100
for(i in 1:length(successes)){
success = successes[i]
col = i
c = curve( dbinom(success, trials, x), 0, 1, add = ifelse(i > 1, T, F), ty = "l", xlim = c(0, 1),
col = col, yaxt = "n")
text(success/trials, max(c$y), bquote(bolditalic(H[.(i)])), pos = 3, xpd = T )
axis(1, at = success/trials)
}
axis(2, at = seq(0, max(c$y), len = 7), labels = round(seq(0, max(c$y), len = 7), 2), las = 1 )
I find this particular graph in ISLR (Figure 2.13) or ESL very well done. I can't guess how the authors would have made this in R. I know how to get the orange and blue points very easily. The main confusion is the background dots and the purple line.
Any ideas?
Here is some sample code to get the yellow and orange points with a grey grid. How do I get an arbitrary non-linear curve in purple and then color the grid according to the curve?
set.seed(pi)
points = replicate(100, runif(2))
pointsColored = ifelse(apply(points, 2, sum) <= 1, "orange", "blue")
# Confound some
pointsColored[sample.int(length(pointsColored), 10)] = "orange"
plot(x=points[1, ], y=points[2, ])
grid(nx=100, ny=100)
# Plot points over the grid.
points(x=points[1, ], y=points[2, ], col=pointsColored)
As I indicated in my comment, a solution was provided by #chl here on stats.stackexchange.com. Here it is, applied to your data set.
library(class)
set.seed(pi)
X <- t(replicate(1000, runif(2)))
g <- ifelse(apply(X, 1, sum) <= 1, 0, 1)
xnew <- cbind(rep(seq(0, 1, length.out=50), 50),
rep(seq(0, 1, length.out=50), each=50))
m <- knn(X, xnew, g, k=15, prob=TRUE)
prob <- attr(m, "prob")
prob <- ifelse(m=="1", prob, 1-prob)
prob15 <- matrix(prob, 50)
par(mar=rep(3, 4))
contour(unique(xnew[, 1]), unique(xnew[, 2]), prob15, levels=0.5,
labels="", xlab='', ylab='', axes=FALSE, lwd=2.5, asp=1)
title(xlab=expression(italic('X')[1]), ylab=expression(italic('X')[2]),
line=1, family='serif', cex.lab=1.5)
points(X, bg=ifelse(g==1, "#CA002070", "#0571B070"), pch=21)
gd <- expand.grid(x=unique(xnew[, 1]), y=unique(xnew[, 2]))
points(gd, pch=20, cex=0.4, col=ifelse(prob15 > 0.5, "#CA0020", "#0571B0"))
box()
(UPDATE: I changed the colour palette because the blue/yellow/purple thing was pretty hideous.)
This was my silly attempt at approximation. Clearly the issues raised by #StephenKolassa are valid and not handled by this approximation.
myCurve1 = function (x)
abs(x[[1]] * sin(x[[1]]) + x[[2]] * sin(x[[2]]))
myCurve2 = function (x)
abs(x[[1]] * cos(x[[1]]) + x[[2]] * cos(x[[2]]))
myCurve3 = function (x)
abs(x[[1]] * tan(x[[1]]) + x[[2]] * tan(x[[2]]))
tmp = function (myCurve, seed=99) {
set.seed(seed)
points = replicate(100, runif(2))
colors = ifelse(apply(points, 2, myCurve) > 0.5, "orange", "blue")
# Confound some
swapInts = sample.int(length(colors), 6)
for (i in swapInts) {
if (colors[[i]] == "orange") {
colors[[i]] = "blue"
} else {
colors[[i]] = "orange"
}
}
gridPoints = seq(0, 1, 0.005)
gridPoints = as.matrix(expand.grid(gridPoints, gridPoints))
gridColors = vector("character", nrow(gridPoints))
gridPch = vector("character", nrow(gridPoints))
for (i in 1:nrow(gridPoints)) {
val = myCurve(gridPoints[i, ])
if (val > 0.505) {
gridColors[[i]] = "orange"
gridPch[[i]] = "."
} else if (val < 0.495) {
gridColors[[i]] = "blue"
gridPch[[i]] = "."
} else {
gridColors[[i]] = "purple"
gridPch[[i]] = "*"
}
}
plot(x=gridPoints[ , 1], y=gridPoints[ , 2], col=gridColors, pch=gridPch)
points(x=points[1, ], y=points[2, ], col=colors, lwd=2)
}
par(mfrow=c(1, 3))
tmp(myCurve1)
tmp(myCurve2)
tmp(myCurve3)