Cannot 'convert' from Vector{struct} to UnionAll - julia

In my Julia code, I have created a mutable struct that I am going to call X. Then, I create a matrix as follows:
result = fill(X, (J, N))
with J and N being integers. Then, I call a function J times; each call creates an array of N objects of type X, and I have a simple assignment as follows:
for n = 1:N result[j, n] = X[n] end
However, Julia complains with the following error: "Load Error: MethodError: Cannot 'convert' an object of type X to an object of type UnionAll.
I am a newbie to Julia; thanks for your (detailed) help!

I think that there may be a very simple issue here that is misdirecting you toward the wrong presumed cause.
For instance, I built up an example based on what you said:
julia> struct Foo
a::Int32
b::Float64
end
julia> fill(Foo(3,1.2), (3,4))
3×4 Matrix{Foo}:
Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2)
Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2)
Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2)
julia> x = fill(Foo(3,1.2), (3,4))
3×4 Matrix{Foo}:
Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2)
Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2)
Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2)
julia> x[2,3] = Foo(1,π)
Foo(1, 3.141592653589793)
julia> x
3×4 Matrix{Foo}:
Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2)
Foo(3, 1.2) Foo(3, 1.2) Foo(1, 3.14159) Foo(3, 1.2)
Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2) Foo(3, 1.2)
julia>
This seems to work fine. The difference from your code is that I am calling the constructor for Foo which means that I used round brackets (parentheses). You used square brackets which indicates indexing, not object creation. Types (like X) are not normally indexed.

Related

Centering segments produced by the segment() function

Is there a way to specify a 'center' parameter using segments() without specifying individual x0/1 and y0/1 coordinates? Obviously align = 'center' does not work for this as the segments() function is base r code.
#Here is short excerpt from my code:
plot.new()
height1 = 0.9
height3 = 0.7
height5 = 0.5
height4 = 0.3
height2 = 0.1
segments(0, height1, species1_length/largestLength, height1,
lwd=3)
segments(0, height2, species2_length/largestLength, height2,
lwd=3)
segments(0, height3, species3_length/largestLength, height3,
lwd=3)
segments(0, height4, species4_length/largestLength, height4,
lwd=3)
segments(0, height5, species5_length/largestLength, height4,
lwd=3)
I ended up just doing it manually like so:
segments(0.143, height1, ((species1_length / largestLength) * 2) + 0.143,
height1, lwd = 3)
segments(0.16, height2, ((species2_length / largestLength) * 2) + 0.16,
height2, lwd = 3)
segments(0.258, height3, ((species3_length / largestLength) * 2) + 0.258,
height3, lwd = 3)
segments(0.083, height4, ((species4_length / largestLength) / 1.2) +
0.083,
height4, lwd = 3)
segments(0.155, height5, ((species5_length / largestLength) *
2) + 0.155,
height5, lwd = 3)
I just picked an amount to shift the x0 parameter (segments(x0,y0,x1,y1)) and corrected the x1 value by that amount. The length of the line is still the same but my initial value and the proportional shift stay equidistant
I would write a function to do this. For example, I think this should work:
centered_segments <- function(length, height, largest = max(length), ...) {
padding <- (largest - length)/2
segments( padding, height, padding + length, height, ... )
}
You would call it like this:
centered_segments( species_lengths, heights, lwd = 3 )
where species_lengths is a vector containing all of the lengths and heights contains all of the heights, or one at a time like
centered_segments( species1_length, height1, largest_length, lwd = 3 )
etc.

Is it possible to manage number format in guide_colorsteps?

I want to ask if it is possible to fix labels generated by the guide_colorsteps function in the same format with breaks used in the geom_contour_filled function used for plotting?
Here is my example:
ggplot(faithfuld, aes(y=eruptions, x=waiting, z=100*density)) +
geom_contour_filled(breaks = c(-Inf, -2.0, -1.5, -1.0, -0.05, -0.005, 0, 0.005, 0.05, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0, 7.0, 9.0, 11.0, Inf)) +
theme(plot.title = element_text(size = 10,hjust = 0.5)) +
scale_fill_manual(values = heat.colors(18),drop=FALSE) +
guides(fill = guide_colorsteps(barheight = unit(par("pin")[2], "in")))
which gives an output like this:
enter image description here
As you can see in the legend, there are added zeros to the numbers used in breaks (0 -> 0.000, 1.0 -> 1.000 etc.). I would like to have the numbers in the legend in the same format as I wrote them in the breaks.
Thanks a lot for any suggestions.

Algorithm to generate RYB color wheel?

I am attempting to generate a color wheel, but in RYB space. I have successfully implemented this in RGB. I start off with Red (255, 0, 0) and convert it to HSL, increment the hue value, then convert back to display on screen. The details are described here: https://serennu.com/colour/rgbtohsl.php
However, my attempts at doing so with RYB have not worked so far.
From what I have read, you get a value in RGB, such as Red (255, 0, 0). Then you ASSUME that it's RYB and use the code below to convert that "RYB" value to RGB. Then, what I have done is gotten that value, converted it to HSL, incremented the Hue, and then displayed it on the screen as before.
def _cubic(t, a, b):
weight = t * t * (3 - 2*t)
return a + weight * (b - a)
def ryb_to_rgb(r, y, b): # Assumption: r, y, b in [0, 1]
# red
x0, x1 = _cubic(b, 1.0, 0.163), _cubic(b, 1.0, 0.0)
x2, x3 = _cubic(b, 1.0, 0.5), _cubic(b, 1.0, 0.2)
y0, y1 = _cubic(y, x0, x1), _cubic(y, x2, x3)
red = _cubic(r, y0, y1)
# green
x0, x1 = _cubic(b, 1.0, 0.373), _cubic(b, 1.0, 0.66)
x2, x3 = _cubic(b, 0., 0.), _cubic(b, 0.5, 0.094)
y0, y1 = _cubic(y, x0, x1), _cubic(y, x2, x3)
green = _cubic(r, y0, y1)
# blue
x0, x1 = _cubic(b, 1.0, 0.6), _cubic(b, 0.0, 0.2)
x2, x3 = _cubic(b, 0.0, 0.5), _cubic(b, 0.0, 0.0)
y0, y1 = _cubic(y, x0, x1), _cubic(y, x2, x3)
blue = _cubic(r, y0, y1)
return (red, green, blue)
I expect to get the RYB color wheel as described here: Calculating the analogous color with python
I have followed the instructions on this post, and still am getting the wrong colors. I have tested this algorithm on a linear path (not a circle) to get http://prntscr.com/o3gcjr
This looks similar to the color wheel on that post I linked to above. However, when starting the wheel from a different color, I get this http://prntscr.com/o3gp76
And in my opinion, that doesn't seem correct.

How to find an intersection of curve and circle?

I have a curve, derived from empirical data, and I can obtain a reasonable model of it. I need to identify a point (x, y) where the curve intersects a circle of known center and radius. The following code illustrates the question.
x <- c(0.05, 0.20, 0.35, 0.50, 0.65, 0.80, 0.95,
1.10, 1.25, 1.40, 1.55, 1.70, 1.85, 2.00,
2.15, 2.30, 2.45, 2.60, 2.75, 2.90, 3.05)
y <- c(1.52, 1.44, 1.38, 1.31, 1.23, 1.15, 1.06,
0.96, 0.86, 0.76, 0.68, 0.61, 0.54, 0.47,
0.41, 0.36, 0.32, 0.29, 0.27, 0.26, 0.26)
fit <- loess(y ~ x, control = loess.control(surface = "direct"))
newx <- data.frame(x = seq(0, 3, 0.01))
fitline <- predict(fit, newdata = newx)
est <- data.frame(newx, fitline)
plot(x, y, type = "o",lwd = 2)
lines(est, col = "blue", lwd = 2)
library(plotrix)
draw.circle(x = 3, y = 0, radius = 2, nv = 1000, lty = 1, lwd = 1)
To obtain the point of intersection we can use the optim function in r to do so:
circle=function(x){
if(4<(x-3)^2) return(NA)# Ensure it is limited within the radius
sqrt(4-(x-3)^2)
}
fun=function(x)predict(fit,data.frame(x=x))
g=function(x)(circle(x)-fun(x))# We need to set this to zero. Ie solve this
sol1=optimise(function(x)abs(g(x)),c(1,5))$min
[1] 1.208466
Thus the two functions should evaluate to the same value at x=1.208466..
To make it even more precise, you can use the optim function:
sol2= optim(1,function(x)abs(g(x)),g,method="Brent",upper=5,lower=1)$par
[1] 1.208473
Now you can evaluate:
circle(sol1)
[1] 0.889047
fun(sol1)
1
0.8890654
circle(sol2)
[1] 0.889061
fun(sol2)
1
0.889061
From the above, you can tell that solution 2 is very close..
Plotting this point on the graph will be challenging since the draw.circle function draws circles in proportionality with the zxes.. Thus changing everytime depending on how big the plot region is.
If you were to write your own circle function:
circleplot=function(x,y,r){
theta=seq(0,2*pi,length.out = 150)
cbind(x+r*cos(theta),y+r*sin(theta))
}
Then you can do:
plot(x, y, type = "o",lwd = 2)
lines(est, col = "blue", lwd = 2)
lines(circleplot(3,0,2))
abline(v=sol2,col=2)
points(sol2,fun(sol2),col=2,pch=16)
It's straightforward to find the intersection using functions from the sf package.
Calculate the circle values (inspired by this answer and as done by #Onyambu)
circ <- function(xc = 0, yc = 0, r = 1, n = 100){
v <- seq(0, 2 * pi, len = n)
cbind(x = xc + r * cos(v),
y = yc + r * sin(v))
}
m <- circ(xc = 3, yc = 0, r = 2)
Convert the predicted values and the circle values to "simple features" (LINESTRING), and find their intersection (a POINT):
library(sf)
int <- st_intersection(st_linestring(as.matrix(est)),
st_linestring(m))
int
# POINT (1.2091 0.8886608)
Add the intersection to your plot:
plot(x, y, type = "o", lwd = 2)
lines(est, col = "blue", lwd = 2)
lines(m)
points(int[1], int[2], col = "red", pch = 19)

how to customize y-axis step size in R

I would like to plot a scatterplot with y-axis is customized to step size of 0.2, within range of 0 - 2.6, and x-axis can be auto-defined. I tried the below, but it doesnt work. May I know how should I set the param correctly?
# Read data
pt.n <- read.table("p0_n300m20r1c1_regression.txt", header=T)
# auto-scale
# plot(pt.n$maee~pt.n$idx, main="P2PSim Seq#1,300n,20%,1r,Corrective", ylab="MAEE", xlab="Seq #")
# customize
ylabel <- c(0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6)
y_range <- range(0, ylabel)
plot(pt.n$maee~pt.n$idx, main="P2PSim Seq#3,300n,20%,1r,Corrective", ylab="MAEE", xlab="Seq #", ylim=y_range, axes=FALSE, ann=FALSE)
axis(1, at=0:6, lab=c(0,50,100,150,200,250,300))
axis(2, las=1, at=0.2*0:y_range[1])
box()
If something is not working check each bit of the thing that isn't doing what you want to make sure you are supplying the correct data and haven't made a booboo. If we run the bits of your code that are associated with the axis
ylabel <- c(0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6)
y_range <- range(0, ylabel)
0.2*0:y_range[1]
You would immediately see the problem:
R> 0.2*0:y_range[1]
[1] 0
where you are basically telling R to draw a tick at 0. Even if you chose the correct element of y_range (the maximum is in the second element) you still wouldn't get the right answer:
R> 0.2*0:y_range[2]
[1] 0.0 0.2 0.4
R> 0:y_range[2]
[1] 0 1 2
and that is because of the way the : operator works. A call of x:y is essentially a call to seq(from = x, to = y, by = 1) and because 2.6+1 is greater than 2.6 (the to argument) R creates the sequence 0, 1, 2.
If you want to draw ticks and label at 0 - 2.6 incrementing by 0.2 then use:
ylabel <- seq(0, 2.6, by = 0.2)
axis(2, at = ylabel)
where ylabel now contains:
R> ylabel
[1] 0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 2.2 2.4 2.6
To illustrate:
dat <- data.frame(y = runif(20, min = 0, max = 3),
x = rnorm(20))
plot(y ~ x, data = dat, axes = FALSE)
ylabel <- seq(0, 2.6, by = 0.2)
axis(1)
axis(2, at = ylabel, las = 1)
box()
which produces

Resources