I am trying to run some code from the Meshes.jl test source code, and it fails. What am I missing?
using Meshes
points = P2[(0,0), (1,0), (0,1), (1,1), (0.5,0.5)]
#ERROR: UndefVarError: P2 not defined
#Stacktrace:
# [1] top-level scope
# # REPL[2]:1
The code is from here:
https://github.com/JuliaGeometry/Meshes.jl/blob/bcc08b0b53622f2578c61561fef91153c05c393b/test/mesh.jl#L176
If you look at the runtests.jl file (https://github.com/JuliaGeometry/Meshes.jl/blob/bcc08b0b53622f2578c61561fef91153c05c393b/test/runtests.jl#L118), P2 is defined as an alias for Point{2, Float64}.
T = Float64
P1, P2, P3 = Point{1,T}, Point{2,T}, Point{3,T}
If you run these two lines, your example code will work.
Alternatively, you can define your points as:
points = Point[(0,0), (1,0), (0,1), (1,1), (0.5,0.5)]
Related
using Plots
p_arr = Array{Plots.Plot{Plots.GRBackend}}(undef,10,10);
x=5;
y=10;
p_arr[1,1] = scatter!([x],[y],markersize=5,legend=false,markercolor = :green, showaxis =
false,size=(500,500));
p_arr[1,2] = scatter!([x],[y],markersize=5,legend=false,markercolor = :green, showaxis =
false,size=(500,500));
this is a very simple code of storing a point plot into an array. I just want to know how to change the x and y coordination for this point by the object it is stored in ?. in other words, I want to set x and y values by the object itself.
is there a better way to do this.
I am new to julia and I do not know where to search
While I'm not quite sure what you'll need for your end use case, storing an array of Plots.jl Plots.Plots has a lot of overhead and will not make it at all easy to modify the underlying points.
One approach that could be dramatically simpler would be to work directly with an array of Points instead. For example, let us first define:
struct Point{T}
x::T
y::T
end
then you have a type which can represent just an x-y point by itself. You can make an array of them:
p_arr = Array{Point{Int64}}(undef, 10, 10) # uninitialized, Int64
or to make this a little more interesting, an array of random points:
julia> p_arr = Point.(rand(10,10), rand(10,10))
10×10 Matrix{Point{Float64}}:
Point{Float64}(0.561232, 0.39038) … Point{Float64}(0.0564275, 0.851144)
⋮ ⋱
Point{Float64}(0.804435, 0.0717767) Point{Float64}(0.110489, 0.670536)
If you want to be able to plot these, then let's define some functions to let Plots.jl know how to plot our Point type:
using Plots
import Plots.scatter
scatter(p::Point, args...; kwargs...) = scatter([p.x], [p.y], args...; kwargs...)
scatter(p::AbstractArray{<:Point}, args...; kwargs...) = scatter(map(p->p.x, p), map(p->p.y, p), args...; kwargs...)
# You can do the same for `scatter!` if you want that version too
then you can write
scatter(p_arr, label="", framestyle=:box)
to obtain a plot that looks like:
(note that each column gets its own series in Plots.jl, hence the multiple colors; call vec on your matrix of Points first if you don't want that)
Now, say you want to move one of those points. Let's say the first one:
julia> p_arr[1,1] = Point(5.0, 10.0)
Point{Float64}(5.0, 10.0)
Then plotting again
scatter(p_arr, label="", framestyle=:box)
will yield
In Matlab, we would first use [x, y] = meshgrid to generate the grid, then use mesh(x, y, z) to plot the 3D plot. I want to use the same funtionality in Julia Plots.jl, which API should I use? And how can I achieve that?
Thanks a lot in advance!!!
use surface
using Plots
xs = range(-2, stop=2, length=100)\
ys = range(-pi, stop=pi, length=100)
f(x,y) = x*sin(y)
surface(xs, ys, f)
In modern Julia, v1.17, the approach is to create x and y ranges. Julia has changed over the years, and used to have linspace - it doesn't anymore.
There are three ways to create a range:
x = start:step:end
x = range(start,end,step=step)
x = range(start,end,length=npts)
You will also need Plots. If you precompile it, it takes less time to load.
]
pkg > add Plots
pkg > precompile
pkg > Ctrl-C
You need to select your backend for Plots. Choices are:
pyplot() to select PyPlot (also requires Python's MatPlotLib)
plotly() to select Plotly (displays in web browser)
gr() to select GR, the default
Finally, you need to use surface to draw the surface. The function surface can take either a function or a matrix of z values. The function takes two parameters, x and y. Either the function is supplied directly, or it is applied to the ranges:
z = f.(x',y);
One of the ranges is transposed with ', and output suppressed with ;
Surface also takes optional parameters:
fill = :fillname
legend = true | false
size = (width,height)
clims = (lowlimit,highlimit)
An example:
using Plots
plotly()
x=range(-5,5,length=101)
y=range(-5,5,length=101)
function f(x,y)
r = sqrt(x^2+y^2)
sinc(r)
end
z = f.(x',y);
surface(x,y,z,size=(1600,1000),fill=:greens,legend=false)
I am new to Julia.
While trying out examples online, I got to the plot below:
using Plots
# 10 data points in 4 series
xs = range(0, 2π, length = 10)
data = [sin.(xs) cos.(xs) 2sin.(xs) 2cos.(xs)]
# We put labels in a row vector: applies to each series
labels = ["Apples" "Oranges" "Hats" "Shoes"]
# Marker shapes in a column vector: applies to data points
markershapes = [:circle, :star5]
# Marker colors in a matrix: applies to series and data points
markercolors = [
:green :orange :black :purple
:red :yellow :brown :white
]
plot(
xs,
data,
label = labels,
shape = markershapes,
color = markercolors,
markersize = 10
)
The Problem I am facing is at the beginning. Even if I try below alone on REPL
julia> xs = range(0, 2π, length = 10)
I receive the error below:
ERROR: MethodError: no method matching range(::Int64, ::Float64; length=10)
Closest candidates are:
range(::Any; length, stop, step) at range.jl:76
Stacktrace:
[1] top-level scope at none:0
Did I forget to include some Package?
Which version of Julia are you using? It sounds like you are using a version that is older than the tutorial you are reading. I can verify that range(0, 2π, length = 10) yields 0.0:0.6981317007977318:6.283185307179586 on Julia 1.5 and Julia 1.6, even without specifying stop
I guess I should have made more research before posting. it's an error in the original post I guess.
I should have used:
julia> xs = range(0, stop=2π, length = 10)
0.0:0.6981317007977318:6.283185307179586
No more errors!!
It's weird, I am following official tutorial... :((
I want to compute the alpha-shape (or even only the concave hull) of a set of points using Julia. In other questions they have solved this problem in python by using Delaunay tesselation Boundary enclosing a given set of points .
This package in Julia can get a Delaunay tesselation https://github.com/JuliaGeometry/VoronoiDelaunay.jl (though I am not sure if it is updated for julia v0.7).
I am wondering if there is an implementation already for julia v0.7 that can get eh alpha-shape, or even just the concave hull of a set of points.
Alternatively, is there a way to efficiently call python (scipy.spatial.Delaunay) to do the job?
VoronoiDelaunay.jl works with Julia 1.0 and 1.1. It should also work with Julia 0.7.
VoronoiDelaunay.jl has some numerical restrictions, i.e. (1.0+eps(), 2.0-eps()), on coordinates so you may need to re-scale your data points.
To create a DelaunayTesselation with your own point type, make sure your type is a subtype of AbstractPoint2D, that is <: AbstractPoint2D, and defines getx, and gety methods.
The following example code, I believe, finds what you call the Concave Hull of a set of points using DelaunayTesselation and plots the result. It basically uses the same algorithm in this answer. You may easily edit the code to get the alpha shape.
I did not wrap some code snippets into a function. If you need high performance, please do so. I used === while checking for equality of points which actually checks if two points are the same object (i.e. address in memory). If you somehow end up in a code which breaks this part, you can extend == and use it instead of ===.
using Random, VoronoiDelaunay, Plots
import Base.==
struct MyEdge{T<:AbstractPoint2D}
_a::T
_b::T
end
==(e1::MyEdge{T}, e2::MyEdge{T}) where {T<:AbstractPoint2D} = ((e1._a === e2._a) && (e1._b === e2._b)) || ((e1._b === e2._a) && (e2._b === e1._a))
###==(p1::T, p2::T) where {T<:AbstractPoint2D} = (getx(p1) == getx(p2)) && (gety(p1) == gety(p2))
### Create a Delaunay tesselation from random points
tess = DelaunayTessellation2D(46)
for _ in 1:23
push!(tess, Point2D(rand()+1, rand()+1))
end
edges = MyEdge[]
function add_edge!(edges, edge)
i = findfirst(e -> e == edge, edges)
if isnothing(i) # not found
push!(edges, edge)
else # found so not outer, remove this edge
deleteat!(edges, i)
end
end
for trig in tess
a, b, c = geta(trig), getb(trig), getc(trig)
add_edge!(edges, MyEdge(b, c))
add_edge!(edges, MyEdge(a, b))
add_edge!(edges, MyEdge(a, c))
end
### PLOT
x, y = Float64[], Float64[] # outer edges
for edge in edges
push!(x, getx(edge._a))
push!(x, getx(edge._b))
push!(x, NaN)
push!(y, gety(edge._a))
push!(y, gety(edge._b))
push!(y, NaN)
end
xall, yall = getplotxy(delaunayedges(tess)) # all the edges
plot(xall, yall, color=:blue, fmt=:svg, size=(400,400))
plot!(x, y, color=:red, linewidth=3, opacity=0.5)
I am trying to solve the following problem in R :
I have a polygon object defined by a list l with two components x and y. The order defines the edges of the polygon.
For instance :
l=list(
x=c(-1.93400738955091,0.511747161547164,1.85047596846401,-1.4963460488281,-1.31613255558929,-0.0803828876660542,1.721752044722,-0.724002506376074,-2.08847609804132,2.13366860069641),
y=c(-1.02967154136169,1.53216851658359,-1.39564869249673,-1.21266011692921,1.6419616619241,-1.87141898897228,0.946605074767527,1.49557080147009,0.324443917837958,-0.517303529772633)
)
plot(l,type="b",pch=16)
points(l$x[c(10,1)],l$y[c(10,1)],type="b",pch=16)
Now what I am interested in is to keep only the outer boundary (but not the convex hull) of this polygon. The following picture highlights the point I'd like to keep
points(
x=c(-1.13927707377209,-1.31613255249992,-1.3598262571216,0.511747159281619,0.264900107013767,0.671727215417383,-0.724002505140328,-1.93400738893304,-1.4811931364624,-1.45298543105533,-2.08847609804132,-1.40787406113029,-1.3598262571216,0.278826441754518,1.85047596733123,1.48615105742673,1.48615105742673,2.13366860069641,1.38016944537233,1.38016944537233,1.17232981688283,1.17232981688283,1.72175204307433,0.671727215417383,-1.496346, -0.08038289, -0.2824999),
y=c(1.13914087952916,1.64196166071069,0.949843643913108,1.53216851597378,1.27360509238768,1.18229006681548,1.49557080106148,-1.02967154055378,-0.972634663817139,-0.525818314106921,0.324443915423533,0.188755761926866,0.949843643913108,-1.30971824545964,-1.3956486896768,-0.59886540309968,-0.59886540309968,-0.517303527559411,-0.367082245352325,-0.367082245352325,0.0874657083966551,0.0874657083966551,0.94660507315481,1.18229006681548,-1.21266,-1.871419,-1.281255),
pch=16,
col="red",
cex=0.75
)
I am really clueless about whether there are tools to easily do that. The closest I have found is the polysimplify function in the polyclip package, which identifies all the points I need, but also outputs some points I do not need (inner points where segments intersect).
I actually found a solution (below). The following function does what I want but I am unsure why it works (and whether it may fail).
Actually the function below correctly identifies the point I want but outputs them in the wrong order, so it is still useless to me...
polygon.clean<-function(poly){
require(polyclip)
poly.cleaned=polysimplify(poly)
x=unlist(sapply(poly.cleaned,function(x)x$x))
y=unlist(sapply(poly.cleaned,function(x)x$y))
x.src=x[!x%in%x[duplicated(x)]]
y.src=y[!y%in%y[duplicated(y)]]
poly.cleaned=poly.cleaned[sapply(poly.cleaned,function(poly.sub,x,y){
any(poly.sub$x%in%x&poly.sub$y%in%y)
},x=x.src,y=y.src)]
x=unlist(sapply(poly.cleaned,function(x){
res=x$x
if(length(res)==4){
res=vector()
}
res
}))
y=unlist(sapply(poly.cleaned,function(x){
res=x$y
if(length(res)==4){
res=vector()
}
res
}))
x=c(x,x.src)
y=c(y,y.src)
tester=duplicated(x)&duplicated(y)
x=x[!tester]
y=y[!tester]
list(x=x,y=y)
}
plot(l,type="b",pch=16)
points(l$x[c(10,1)],l$y[c(10,1)],type="b",pch=16)
points(polygon.clean(l),pch=16,cex=0.75,col="red")
Using rgeos routines, you first "node" your linestring to create all the intersections, then "polygonize" it, then "union" it to dissolve its insides.
First make a SpatialLines version of your data with duplicated first/last point:
library(sp)
library(rgeos)
coords = cbind(l$x, l$y); coords=rbind(coords,coords[1,])
s = SpatialLines(list(Lines(list(Line(coords)),ID=1)))
Then:
s_outer = gUnaryUnion(gPolygonize(gNode(s)))
Plot it thus:
plot(s,lwd=5)
plot(s_outer, lwd=2,border="red",add=TRUE)
If you want the coordinates of the surrounding polygon they are in the returned object and can be extracted with:
s_outer#polygons[[1]]#Polygons[[1]]#coords
# x y
# [1,] 0.27882644 -1.30971825
# [2,] -0.08038289 -1.87141899
# [3,] -0.28886517 -1.27867953
Assuming there's only one polygon, which might not be the case - suppose your line traces a figure-of-eight - then you'll get two polygons touching at a point. We don't know how free your jaggly line is to do things like that...