Contour plot equivalent to Wolfram Alpha's - r

I'm trying to create a contour plot for a very specific function. The contour plot I've obtained through ggplot2 is quite similar to Wolfram Alpha's plot, although I'm not getting the same "grid-like" (white stripes) behavior as in the latter source.
How could I get similar white stripes like those if I'm not sure what those values are? Should I increase the amount of points?
library(tidyverse)
v <- function(r, q){
value <- pmax(0, 3 * q - 1 + r - 3*r*q)^2 +
pmax(0, r - 3 * r * q)^2 +
pmax(0, -2 + 2*r + 2*q - 2*r*q)^2+
pmax(0, 2*q - 3*r*q)^2
return(value)
}
r <- q <- seq(0, 1, 0.001)
vertices <- expand_grid(r, q)
vertices %>% mutate(v = v(r, q)) %>%
ggplot(aes(x = r, y = q, z = v)) +
geom_contour_filled()

Related

Can you reverse scaling and centering in the axes of a ggplot2 plot?

I want to scale the predictor variable of a regression model but I then want to plot the original values on the x-axis for intelligibility using ggplot2. I have attempted to do this using scale_x_continuous().
library('tidyverse')
x <- rnorm(100, 10, 1.5)
Zx <- scale(x)
Zy <- .8*Zx + rnorm(100, 0, sqrt(1 - (.8^2)))
df <- tibble(Zx = Zx, y = Zy)
SD_scale <- attr(df$Zx, "scaled:scale")
center <- attr(df$Zx, "scaled:center")
unscale_trans <- function(x){
scales::trans_new(
"unscale",
function(x) center + x * SD_scale,
function(x) scale(x) )
}
df %>%
ggplot(aes(x=Zx,y=y)) + geom_point() +
geom_smooth(method = "lm") +
scale_x_continuous(trans="unscale")
This throws the following warnings:
1: In c(-1, 1) * (width * mul + add) :
Recycling array of length 1 in vector-array arithmetic is deprecated.
Use c() or as.vector() instead.
2: In c(-1, 1) * (width * mul + add) :
Recycling array of length 1 in vector-array arithmetic is deprecated.
Use c() or as.vector() instead.
And results in oddly scaled labels.
Scaled x predictor
Is there a means of satisfactorily 'unscaling' the axis?
Thank you in advance for your help,
John

See the plot close to the intersection

## Define the moment generating function of Weibull distribution
scale <- 1/2
shape <- 1
lambda <- 2
beta <- 0.1
## I have specified nmax=160 since I cant perform the sum until infinity
mgfw <- function(x){
nmax <- 160
scale <- scale
shape <- shape
suma <- 0
for(n in 0:nmax){
suma <- suma + ((x^n) * ((scale)^n)) * gamma(1 + (n/shape)) / factorial(n)
}
return(suma)
}
curve(mgfw, from=0.1, 0.25, ylim=c(1, 1.2))
mu <- (scale) * gamma(1 + (1 / shape))
fun2 <- function(x) 1 + x * (1 + beta) * mu
x <- seq(0, 10, length.out=100)
y <- fun2(x)
curve(fun2, from=0, 10, add=TRUE)
grid()
Solving the previous equations I got the next results:
library(rootSolve)
r <- uniroot.all(function(x) mgfw(x) - fun2(x), c(0.1, 0.185))
r
abline(v=r)
I got a plot like this
The intersection of both lines is given by the vertical line. But I would like to get a plot where the intersection can be clear in the plot. How to resize the plot? Or see in the area with different scale?

Plotting density lines of distributions in log-log scale (base 10) with R

I know about the parameter log="xy", but I don't know whether you can control the base of the logarithmic scale (my guess is that 10 may be the default (?)), and I'm not getting lucky on the specific issue below...
How can I reproduce the following plot (from this source) with R. In particular, I am having problems with the log base 10 x and y axes.
Leaving aside the power law red line, I was playing with
x = rlnorm(1e4,0,10)
h = hist(x, prob=T, plot=F)
plot(h$count, log="xy", type="l", lend=2)
without success.
Use the pdf of the lognormal in base10
[Generalising it to other log-bases is straightforward.]
We can then plot the pdf on a log10-log10 scale.
(gg)plotting
# lognormal base log10 pdf, w is in log10
lognorm_base10 <- function(w, mu, sigma) {
log10(exp(1)) / (sqrt(2*pi*sigma^2) * 10^w) * exp(- (w - mu)^2 / (2 * sigma^2));
}
# Generate data for mu = 0, sigma = 10
x <- seq(0, 10, length.out = 100);
y <- lognorm_base10(x, 0, 10);
# Plot
require(ggplot2);
gg <- ggplot(data.frame(x = x, y = y), aes(x, y));
gg <- gg + geom_line() + scale_y_log10();
gg <- gg + labs(x = "log10(x)", y = "log10(p)")
Plotting without ggplot
plot(x, log10(y), type = "l")

Plotting a 2D polar mesh with ggplot2

I have data that is computed on a 2D polar mesh:
# The mesh created is in two dimensions: r and theta.
# Mesh steps in theta are regular, while mesh steps in r are more refined
# close to the origin
nb.theta <- 50
theta.max <- 130
theta <- seq(0, theta.max, length.out = nb.theta)
nb.r <- 80
# r goes from r0 to rMax
q0 <- 1.1
z <- seq(1, nb.r)
rMax <- 30
r0 <- rMax / (q0 ^ nb.r - 1)
r <- r0 * (q0 ^ z - 1)
# Now let's add some data
mesh <- as.data.frame(expand.grid(r = r, theta = theta))
mesh$value <- mesh$r * mesh$theta / theta.max
Now, I want to plot the mesh in R (preferably with ggplot2). I tried:
ggplot(mesh, aes(r, theta, color = value)) + geom_point() + coord_polar(theta = "y")
But the result is far from satisfactory:
Ideally, I would like to have cells filled and not just points. I also would like the plot not to be a full circle: I only have data from 0 to 130 degrees.
Is this possible?
This should solve the circle issue:
ggplot(mesh, aes(r, theta, color = value)) +
geom_point() +
coord_polar(theta = "y") +
scale_y_continuous(limits=c(0,360))
We can use geom_tile rather than geom_point so that we fill the mesh. We need to calculate the width of each window. Here I've just set it to r/10 which is approximately correct. You will be able to calculate it exactly.
Adding ylim ensures that only part of the circle is filled.
mesh <- expand.grid(r = r, theta = theta)
mesh$value <- mesh$r * mesh$theta / theta.max
mesh$width <- mesh$r/10
ggplot(mesh, aes(r, theta, fill = value, width = width)) +
geom_tile() +
coord_polar(theta = "y") +
ylim(0, 360)
NB expand.grid returns a data.frame, so we don't need to convert it.

Plotting family of functions with qplot without duplicating data

Given family of functions f(x;q) (x is argument and q is parameter) I'd like to visulaize this function family on x taking from the interval [0,1] for 9 values of q (from 0.1 to 0.9). So far my solution is:
f = function(p,q=0.9) {1-(1-(p*q)^3)^1024}
x = seq(0.0,0.99,by=0.01)
q = seq(0.1,0.9,by=0.1)
qplot(rep(x,9), f(rep(x,9),rep(q,each=100)), colour=factor(rep(q,each=100)),
geom="line", size=I(0.9), xlab="x", ylab=expression("y=f(x)"))
I get quick and easy visual with qplot:
My concern is that this method is rather memory hungry as I need to duplicate x for each parameter and duplicate each parameter value for whole x range. What would be alternative way to produce same graph without these duplications?
At some point ggplot will need to have the data available to plot it and the way that package works prohibits simply doing what you want. I suppose you could set up a blank plot if you know the x and y axis limits, and then loop over the 9 values of q, generating the data for that q, and adding a geom_line layer to the existing plot object. However, you'll have to produce the colours for each layer yourself.
If this is representative of the size of problem you have, I wouldn't worry too much about the memory footprint. We're only talking about a two vectors of length 900
> object.size(rnorm(900))
7240 bytes
and the 100 values over the range of x appears sufficient to give a smooth plot.
for loop to add layers to ggplot
require("ggplot2")
## something to replicate ggplot's colour palette, sure there is something
## to do this already in **ggplot** now...
ggHueColours <- function(n, h = c(0, 360) + 15, l = 65, c = 100,
direction = 1, h.start = 0) {
turn <- function(x, h.start, direction) {
(x + h.start) %% 360 * direction
}
if ((diff(h) %% 360) < 1) {
h[2] <- h[2] - 360 / n
}
hcl(h = turn(seq(h[1], h[2], length = n), h.start = h.start,
direction = direction), c = c, l = l)
}
f = function(p,q=0.9) {1-(1-(p*q)^3)^1024}
x = seq(0.0,0.99,by=0.01)
q = seq(0.1,0.9,by=0.1)
cols <- ggHueColours(n = length(q))
for(i in seq_along(q)) {
df <- data.frame(y = f(x, q[i]), x = x)
if(i == 1) {
plt <- ggplot(df, aes(x = x, y = y)) + geom_line(colour = cols[i])
} else {
plt <- plt + geom_line(data = df, colour = cols[i])
}
}
plt
which gives:
I'll leave the rest to you - I'm not familiar enough with ggplot to draw a legend manually.

Resources