Julia: ImplictPlots in a loop: setting colors - julia

How can I assign colors with implicit_plot?
using ImplicitPlots, Plots
v = [(x,y) -> (x+3)*(y^3-7)+18, (x,y) -> sin(y*exp(x)-1)]
p = plot()
for f in v
implicit_plot!(f; xlims = (-1, 3), ylims = (-1, 2), framestyle = :origin, lc = [:red, :blue])
end
p
I expected something along the lines of:
lc = [:red, :blue]
for (i, f) in enumerate (v)
implicit_plot!(f; xlims = (-1, 3), ylims = (-1, 2), lc = lc[i])
end
How can I pass a gradient of blue colors for the second function? (I can pass lc = :blues but that makes the first line blue as well.)
Bonus question: Can I pass a vector or tuple to implicit_plot? I guess it's not supported.

Are you sure it does not work? I tried
lc = [:red, :blue]
for (i, f) in enumerate(v)
implicit_plot!(f; xlims = (-1, 3), ylims = (-1, 2), lc = lc[i])
end
and I got
(You had an extra space in enumerate which maybe threw you off?)
Not sure about the tuple of functions.

Related

How to draw a regression formula in R? [duplicate]

What are the alternatives for drawing a simple curve for a function like
eq = function(x){x*x}
in R?
It sounds such an obvious question, but I could only find these related questions on stackoverflow, but they are all more specific
Plot line function in R
Plotting functions on top of datapoints in R
How can I plot a function in R with complex numbers?
How to plot a simple piecewise linear function?
Draw more than one function curves in the same plot
I hope I didn't write a duplicate question.
I did some searching on the web, and this are some ways that I found:
The easiest way is using curve without predefined function
curve(x^2, from=1, to=50, , xlab="x", ylab="y")
You can also use curve when you have a predfined function
eq = function(x){x*x}
curve(eq, from=1, to=50, xlab="x", ylab="y")
If you want to use ggplot,
library("ggplot2")
eq = function(x){x*x}
ggplot(data.frame(x=c(1, 50)), aes(x=x)) +
stat_function(fun=eq)
You mean like this?
> eq = function(x){x*x}
> plot(eq(1:1000), type='l')
(Or whatever range of values is relevant to your function)
plot has a plot.function method
plot(eq, 1, 1000)
Or
curve(eq, 1, 1000)
Here is a lattice version:
library(lattice)
eq<-function(x) {x*x}
X<-1:1000
xyplot(eq(X)~X,type="l")
Lattice solution with additional settings which I needed:
library(lattice)
distribution<-function(x) {2^(-x*2)}
X<-seq(0,10,0.00001)
xyplot(distribution(X)~X,type="l", col = rgb(red = 255, green = 90, blue = 0, maxColorValue = 255), cex.lab = 3.5, cex.axis = 3.5, lwd=2 )
If you need your range of values for x plotted in increments different from 1, e.g. 0.00001 you can use:
X<-seq(0,10,0.00001)
You can change the colour of your line by defining a rgb value:
col = rgb(red = 255, green = 90, blue = 0, maxColorValue = 255)
You can change the width of the plotted line by setting:
lwd = 2
You can change the size of the labels by scaling them:
cex.lab = 3.5, cex.axis = 3.5
As sjdh also mentioned, ggplot2 comes to the rescue. A more intuitive way without making a dummy data set is to use xlim:
library(ggplot2)
eq <- function(x){sin(x)}
base <- ggplot() + xlim(0, 30)
base + geom_function(fun=eq)
Additionally, for a smoother graph we can set the number of points over which the graph is interpolated using n:
base + geom_function(fun=eq, n=10000)
Function containing parameters
I had a function (emax()) involving 3 parameters (a, b & h) whose line I wanted to plot:
emax = function(x, a, b, h){
(a * x^h)/(b + x^h)
}
curve(emax, from = 1, to = 40, n=40 a = 1, b = 2, h = 3)
which errored with Error in emax(x) : argument "a" is missing, with no default error.
This is fixed by putting the named arguments within the function using this syntax:
curve(emax(x, a = 1, b = 2, h = 3), from = 1, to = 40, n = 40)
which is contrary to the documentation which writes curve(expr, from, to, n, ...) rather than curve(expr(x,...), from, to, n).

How to fill area between curves with Plots.jl?

Suppose I have a curve y, and two other curves u and l in the form of vectors. How to plot:
plot(y, lab="estimate")
plot!(y-l, lab="lower bound")
plot!(y+u, lab="upper bound")
That is, an asymmetric confidence interval? I know how to plot the symmetric case with the option ribbon as explained here.
The current answers are NOT correct. Here are two ways that are correct (as of v1.10.1 of Plots.jl):
Method 1: Using fillrange
plot(x, l, fillrange = u, fillalpha = 0.35, c = 1, label = "Confidence band")
Method 2: Using ribbon
plot(x, (l .+ u) ./ 2, ribbon = (l .- u) ./ 2, fillalpha = 0.35, c = 1, label = "Confidence band")
(Here, l and u denote the the "lower" and "upper" y values, respectively, and x denotes their common x values.) The key difference between these two methods is that fillrange shades the region between l and u, while the ribbon argument is a radius, i.e. half the width of the ribbon (or in other words, the vertical deviation from the midpoints).
Example using fillrange:
x = collect(range(0, 2, length= 100))
y1 = exp.(x)
y2 = exp.(1.3 .* x)
plot(x, y1, fillrange = y2, fillalpha = 0.35, c = 1, label = "Confidence band", legend = :topleft)
Let's scatter y1 and y2 on top of the plot, just to make sure we're filling in the right region.
plot!(x,y1, line = :scatter, msw = 0, ms = 2.5, label = "Lower bound")
plot!(x,y2, line = :scatter, msw = 0, ms = 2.5, label = "Upper bound")
Result:
Example using ribbon:
mid = (y1 .+ y2) ./ 2 #the midpoints (usually representing mean values)
w = (y2 .- y1) ./ 2 #the vertical deviation around the means
plot(x, mid, ribbon = w , fillalpha = 0.35, c = 1, lw = 2, legend = :topleft, label = "Mean")
plot!(x,y1, line = :scatter, msw = 0, ms = 2.5, label = "Lower bound")
plot!(x,y2, line = :scatter, msw = 0, ms = 2.5, label = "Upper bound")
(Here, x, y1, and y2 are the same as before.)
Result:
Notice that the labels for ribbon and fillrange are different in the legends: the former labels the midpoints/means, while the latter labels the shaded region itself.
Some additional comments:
The OP's answer of plot(y, ribbon=(l,u), lab="estimate") is not correct (at least for Plots v1.10.1.). I realize this thread is over 3 years old, so perhaps it worked in the earlier version of Plots.jl that the OP was using at the time)
Similar to one of the answers given,
plot(x, [mid mid], fillrange=[mid .- w, mid .+ w], fillalpha=0.35, c = [1 4], label = ["Band 1" "Band 2"], legend = :topleft, dpi = 80)
will work, but this actually creates TWO ribbons (and hence, two icons in the legend) which may or may not be what the OP was looking for. To illustrate the point:
It turns out that the option ribbon accepts both lower and upper bounds:
plot(y, ribbon=(l,u), lab="estimate")
Notice that by passing l and u in the ribbon option, the filled area will correspond to the region between y-l and y+u. In other words, l and u should be the "deviations" from the mean curve y.
Something like this? (seen here).
plot([y y], fillrange=[y.-l y.+u], fillalpha=0.3, c=:orange)
plot!(y)
The fillrange solution in #leonidas 's answer might bring an additional boundary line (at least in Plots v1.35). To remove such a line, a workaround is to specify linealpha = 0, that is,
plot(x, l, fillrange = u, fillalpha = 0.35, c = 1, label = "Confidence band", linealpha = 0)

How to fix the position of a text to follow an object plotted in R

I was wondering how I can fix a piece of text() to always appear above a bracket (or a points() etc.) in a dynamically changing plot? In other words, how should I determine the "x" and "y" for that piece of text to follow the bracket (or a points() etc.) around anywhere in the plot? (see my R code below)
Just as an example, suppose I have a bracket in the plot below whose position (xs and ys) is going to be always known regardless of how the plot will change. Here, how can I fix the position of the text() above this bracket (as currently seen in the plot) no matter where the bracket goes?
P.S. At first, I thought I can take the "y" of the bracket, and then make "y" of the text() to be: ("y" of bracket + .1* "y" of bracket). But given that the plot can dynamically change (i.e., the plot is connected to a function), + .1* "y" of bracket in any plot gives a different position for the text that doesn't guarantee the distance between he text and the bracket be always maintained.
Here is a piece of R code:
if(!require(library(pBrackets))){install.packages('pBrackets') }
library(pBrackets)
plot(1:10, ty = 'n')
brack <- brackets(x1 = 4, y1 = 6, x2 = 8, y2 = 6, h = 1, ticks = .5, curvature = .5,
type=1, col = "blue",
lwd = 2, xpd = T)
text(x = 6, y = 7.2, "Equivalent to ZERO", font = 2) ## How to determine "x" and "y"
# such that the "text" always
# appears above the bracket
# even if the plot changes. This helps making functions.
plot(1:10, ty = 'n')
x1 = 4
y1 = 6
x2 = 8
y2 = 6
h = 1 #Or some variation of h = sqrt( (x2-x1)^2 + (y2-y1)^2 )/4
brack <- brackets(x1 = x1, y1 = y1, x2 = x2, y2 = y2, h = h, ticks = .5, curvature = .5,
type=1, col = "blue",
lwd = 2, xpd = T)
text(x = (x1+x2)/2, y = (y1+h), "Equivalent to ZERO", font = 2, pos = 3)
#pos = 3 means the text will be on top of x and y

How to plot a function curve in R

What are the alternatives for drawing a simple curve for a function like
eq = function(x){x*x}
in R?
It sounds such an obvious question, but I could only find these related questions on stackoverflow, but they are all more specific
Plot line function in R
Plotting functions on top of datapoints in R
How can I plot a function in R with complex numbers?
How to plot a simple piecewise linear function?
Draw more than one function curves in the same plot
I hope I didn't write a duplicate question.
I did some searching on the web, and this are some ways that I found:
The easiest way is using curve without predefined function
curve(x^2, from=1, to=50, , xlab="x", ylab="y")
You can also use curve when you have a predfined function
eq = function(x){x*x}
curve(eq, from=1, to=50, xlab="x", ylab="y")
If you want to use ggplot,
library("ggplot2")
eq = function(x){x*x}
ggplot(data.frame(x=c(1, 50)), aes(x=x)) +
stat_function(fun=eq)
You mean like this?
> eq = function(x){x*x}
> plot(eq(1:1000), type='l')
(Or whatever range of values is relevant to your function)
plot has a plot.function method
plot(eq, 1, 1000)
Or
curve(eq, 1, 1000)
Here is a lattice version:
library(lattice)
eq<-function(x) {x*x}
X<-1:1000
xyplot(eq(X)~X,type="l")
Lattice solution with additional settings which I needed:
library(lattice)
distribution<-function(x) {2^(-x*2)}
X<-seq(0,10,0.00001)
xyplot(distribution(X)~X,type="l", col = rgb(red = 255, green = 90, blue = 0, maxColorValue = 255), cex.lab = 3.5, cex.axis = 3.5, lwd=2 )
If you need your range of values for x plotted in increments different from 1, e.g. 0.00001 you can use:
X<-seq(0,10,0.00001)
You can change the colour of your line by defining a rgb value:
col = rgb(red = 255, green = 90, blue = 0, maxColorValue = 255)
You can change the width of the plotted line by setting:
lwd = 2
You can change the size of the labels by scaling them:
cex.lab = 3.5, cex.axis = 3.5
As sjdh also mentioned, ggplot2 comes to the rescue. A more intuitive way without making a dummy data set is to use xlim:
library(ggplot2)
eq <- function(x){sin(x)}
base <- ggplot() + xlim(0, 30)
base + geom_function(fun=eq)
Additionally, for a smoother graph we can set the number of points over which the graph is interpolated using n:
base + geom_function(fun=eq, n=10000)
Function containing parameters
I had a function (emax()) involving 3 parameters (a, b & h) whose line I wanted to plot:
emax = function(x, a, b, h){
(a * x^h)/(b + x^h)
}
curve(emax, from = 1, to = 40, n=40 a = 1, b = 2, h = 3)
which errored with Error in emax(x) : argument "a" is missing, with no default error.
This is fixed by putting the named arguments within the function using this syntax:
curve(emax(x, a = 1, b = 2, h = 3), from = 1, to = 40, n = 40)
which is contrary to the documentation which writes curve(expr, from, to, n, ...) rather than curve(expr(x,...), from, to, n).

Modifying width of outline in a pie chart in R--what is the equivalent of lwd parameter for pie()?

I'm using base R plotting functions to produce a pie chart and I want to change the line thickness of the outlines of each pie segment. ?pie seems to indicate that I can add optional graphic parameters, but adding lwd= does not appear to work. Anyone have any clues as to how I might be able to do this. I'm not yet proficient in producing pie charts in ggplot, and would like to stick with base R plotting (if possible).
library(RColorBrewer)
x1 <- data.frame(V1 = c(200, 100)) ## generate data
row.names(x1) <- c("A", "B")
x1$pct <- round((x1$V1/sum(x1$V1))*100, 1)
lbls1 <- paste(row.names(x1), "-(",x1$pct, '%)', sep='') ## add some informative stuff
pie(x1$V1, labels=lbls1, col=tail(brewer.pal(3, 'PuBu'), n=2),
main=paste('My 3.1415'), cex=1.1, lwd= 3)
Notice lwd= does not increase line thickness like it would in other base plotting.
Anyone have any clues?
The call to polygon and lines within pie does not pass ... or lwd
...
polygon(c(P$x, 0), c(P$y, 0), density = density[i], angle = angle[i],
border = border[i], col = col[i], lty = lty[i])
P <- t2xy(mean(x[i + 0:1]))
lab <- as.character(labels[i])
if (!is.na(lab) && nzchar(lab)) {
lines(c(1, 1.05) * P$x, c(1, 1.05) * P$y)
....
You can get around this by setting par(lwd = 2) (or whatever) outside and prior to your call to pie
i.e.
# save original settings
opar <- par(no.readonly = TRUE)
par(lwd = 2)
pie(x1$V1, labels=lbls1, col=tail(brewer.pal(3, 'PuBu'), n=2),
main=paste('My 3.1415'), cex=1.1)
par(lwd = 3)
# reset to original
par(opar)
At the moment, the function inside pie that does the actual drawing is polygon and here is how it is called:
polygon(c(P$x, 0), c(P$y, 0), density = density[i], angle = angle[i],
border = border[i], col = col[i], lty = lty[i])
Notice there is no lwd argument and more critically no ... argument to accept arguments that might not have been hard coded.
Create a new pie2 function. First type pie, copy the code and make a few changes:
pie2 <-
function (x, labels = names(x), edges = 200, radius = 0.8, clockwise = FALSE,
init.angle = if (clockwise) 90 else 0, density = NULL, angle = 45,
col = NULL, border = NULL, lty = NULL, main = NULL, lwd=1,...)
{
................
polygon(c(P$x, 0), c(P$y, 0), density = density[i], angle = angle[i],
border = border[i], col = col[i], lty = lty[i], lwd=lwd )
.................
}
pie2(x1$V1, labels=lbls1, col=tail(brewer.pal(3, 'PuBu'), n=2),
main=paste('My 3.1415'), cex=1.1, lwd=5)

Resources