From a157513ce4e6f84b574b579ae7c38220818e8382 Mon Sep 17 00:00:00 2001 From: Joaquim Date: Wed, 7 Jan 2026 00:47:42 +0000 Subject: [PATCH] Add spheres to plot3d --- src/marker_name.jl | 11 ++++++++++- src/psxy.jl | 6 +++--- src/utils.jl | 43 +++++++++++++++++++++++++++++++++++++++++++ test/test_avatars.jl | 7 +++++++ 4 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/marker_name.jl b/src/marker_name.jl index 6d3d49b8a..a85d7f0a9 100644 --- a/src/marker_name.jl +++ b/src/marker_name.jl @@ -14,6 +14,7 @@ function get_marker_name(d::Dict, arg1, symbs::Vector{Symbol}, is3D::Bool, del:: elseif (o == "j" || startswith(o, "rot")) opt = "j"; N = 3 elseif (o == "M" || startswith(o, "Mat")) opt = "M"; N = 3 elseif (o == "m" || startswith(o, "mat")) opt = "m"; N = 3 + elseif (o == "P" || startswith(o, "sph")) opt = "P"; N = 1 elseif (o == "R" || startswith(o, "Rec")) opt = "R"; N = 3 elseif (o == "r" || startswith(o, "rec")) opt = "r"; N = 2 elseif (o == "V" || startswith(o, "Vec")) opt = "V"; N = 2 @@ -23,6 +24,7 @@ function get_marker_name(d::Dict, arg1, symbs::Vector{Symbol}, is3D::Bool, del:: elseif (o == "W" || o == "Pie" || o == "Web" || o == "Wedge") opt = "W"; N = 2 end if (N > 0) marca, arg1, msg = helper_markers(opt, t[2], arg1, N, cst) end + (marca == "P") && (marca = "P$(t[2])") (msg != "") && error(msg) if (length(t) == 3 && isa(t[3], NamedTuple)) if (marca == "w" || marca == "W") # Ex (spiderweb): marker=(:pie, [...], (inner=1,)) @@ -41,6 +43,7 @@ function get_marker_name(d::Dict, arg1, symbs::Vector{Symbol}, is3D::Bool, del:: elseif (key == :K || key == :Custom) opt = "K" elseif (key == :k || key == :custom) opt = "k" elseif (key == :M || key == :Matang) opt = "M" + elseif (key == :P || key == :sphere) opt = "P" elseif (key == :m || key == :matang) opt = "m" elseif (key == :geovec) opt = "=" end @@ -54,6 +57,10 @@ function get_marker_name(d::Dict, arg1, symbs::Vector{Symbol}, is3D::Bool, del:: marca = opt * add_opt(t, (size=("", arg2str, 1), arrow=("", vector_attrib))) elseif (opt == "k" || opt == "K") marca = opt * add_opt(t, (custom="", size="/")) + elseif (opt == "P") + marca = opt * add_opt(t, (sphere=("", arg2str, 1), size=("", arg2str, 2), azim="+a", elev="+e", flat="_+f", nofill="_+n", no_fill="_+n")) + (marca == "P") && (marca = "P7p") # Default size 7p if none given + (marca[2] == '+') && (marca = "P7p" * marca[2:end]) # iden end else t1::String = string(t) @@ -63,7 +70,9 @@ function get_marker_name(d::Dict, arg1, symbs::Vector{Symbol}, is3D::Bool, del:: elseif (t1 == "a" || t1 == "*" || t1 == "star") marca = "a" elseif (t1 == "k" || t1 == "custom") marca = "k" elseif (t1 == "x" || t1 == "cross") marca = "x" - elseif (is3D && (t1 == "u" || t1 == "cube")) marca = "u" # Must come before next line + elseif (is3D) + (t1 == "P" || t1 == "sphere") && (marca = "P") + (t1 == "u" || t1 == "cube") && (marca = "u") # Must come before next line elseif (t1[1] == 'c') marca = "c" elseif (t1[1] == 'd') marca = "d" # diamond elseif (t1 == "g" || t1 == "octagon") marca = "g" diff --git a/src/psxy.jl b/src/psxy.jl index ee15caf99..79151e222 100644 --- a/src/psxy.jl +++ b/src/psxy.jl @@ -956,7 +956,7 @@ function parse_opt_S(d::Dict, arg1, is3D::Bool=false) opt_S = " -S" * marca # If data comes from a file, then no automatic symbol size is added op = lowercase(marca[1]) - def_size::String = (op == 'p') ? "2p" : "7p" # 'p' stands for symbol points, not units. Att 7p used in seismicity() + def_size::String = (marca[1] == 'P') ? "" : ((op == 'p') ? "2p" : "7p") # 'p' stands for symbol points, not units. Att 7p used in seismicity() (!more_cols && arg1 !== nothing && !isa(arg1, GMTcpt) && !occursin(op, "bekmrvw")) && (opt_S *= def_size) elseif (haskey(d, :hexbin)) inc::Float64 = parse(Float64, arg1.attrib["hexbin"]) @@ -1000,13 +1000,13 @@ function build_run_cmd(cmd, opt_B, opt_Gsymb, opt_ML, opt_S, opt_W, opt_Wmarker, elseif (opt_W == "" && (opt_S != "" || opt_Gsymb != "")) # We have a symbol request (opt_Wmarker != "" && opt_W == "") && (opt_Gsymb *= " -W" * opt_Wmarker) # reuse var name - (opt_ML != "") && (cmd *= opt_ML) # If we have a symbol outline pen + (opt_ML != "") && (cmd *= opt_ML) # If we have a symbol outline pen _cmd = [cmd * opt_S * opt_Gsymb * opt_UVXY] elseif (opt_W != "" && opt_S != "") # We have both line/polygon and a symbol (occursin(opt_Gsymb, cmd)) && (opt_Gsymb = "") c = lowercase(opt_S[4]) - if (c == 'v' || c == 'm' || c == 'w' || c == '=' || c == 'q') # Are there more cases where the pen applies to the symbol? + if (c == 'v' || c == 'm' || c == 'w' || c == '=' || c == 'q' || c == 'p') # Are there more cases where the pen applies to the symbol? _cmd = [cmd * opt_W * opt_S * opt_Gsymb * opt_UVXY] else (opt_Wmarker != "") && (opt_Wmarker = " -W" * opt_Wmarker) # Set Symbol edge color diff --git a/src/utils.jl b/src/utils.jl index 4da617560..2680aa5ba 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -247,6 +247,7 @@ end # -------------------------------------------------------------------------------------------------- # Incredibly Julia ignores the NaN nature and incredibly min(1,NaN) = NaN, so need to ... fck extrema_nan(A::AbstractArray{<:AbstractFloat}) = minimum_nan(A), maximum_nan(A) +extrema_nodataval(A::AbstractArray{<:Real}, val) = minimum_nodataval(A, val), maximum_nodataval(A, val) extrema_nan(A) = extrema(A) """ @@ -299,6 +300,20 @@ function maximum_nan(A::AbstractArray{<:AbstractFloat}) end maximum_nan(A) = maximum(A) +# Cases where a specific no-data value is used and therefore should be excluded from min/max calculations +function minimum_nodataval(A::AbstractArray{<:Real}, val) + (val == typemax(eltype(A))) && return minimum(A) # No need to check for no-data value + mi = typemax(eltype(A)) + @inbounds for k in eachindex(A) mi = ifelse((A[k] != val), min(mi, A[k]), mi) end + return mi +end +function maximum_nodataval(A::AbstractArray{<:Real}, val) + (val == typemin(eltype(A))) && return maximum(A) # No need to check for no-data value + ma = typemin(eltype(A)) + @inbounds for k in eachindex(A) ma = ifelse((A[k] != val), max(ma, A[k]), ma) end + return ma +end + function findmax_nan(x::AbstractVector{T}) where T # Since Julia doesn't ignore NaNs and prefer to return wrong results findmax is useless when data # has NaNs. We start by runing findmax() and only if max is NaN we fallback to a slower algorithm. @@ -1563,3 +1578,31 @@ end #include("tanakacontour.jl") #include("shufflelabel.jl") +function cut_icons(; nome="", size=350) + nomes = "basemap blockmean blockmode blockmedian clip coast colorbar contour dimfilter events filter1d fitcircle gmt2kml gmtbinstats gmtconnect gmtconvert gmtdefaults gmtinfo gmtlogo gmtmath gmtregress gmtselect gmtset gmtsplit gmtspatial gmtvector gmtwhich grd2cpt grd2kml grd2xyz grdblend grdclip grdcontour grdconver grdcut grdedit grdfft grdfill grdfilter grdgradient grdhisteq grdimage grdinfo grdinterpolate grdlandmask grdmask grdmath grdmix grdpaste grdproject grdsample grdtrack grdtrend grdvector grdview grdvolume greenspline histogram image inset kml2gmt legend mapproject mask movie nearneighbor plot plot3d project psconvert rose sample1d simplify solar spectrum1d sphinterpolate sphdistance sphtriangulate sph2grd splitxyz subplot surface ternary text trend1d trend2d triangulate wiggle xyz2grd" + + nomes = "band bar bar3 biplot boxplot bubblechart cornerplot ecdfplot feather fill_between lines marginalhist parallelplot scatter stem stairs triplot" + + nomes = "coupe earthtide flexure gmtflexure gmtisf gpsgridder gravfft gravmag3d gravprisms grdflexure grdgravmag3d grdpmodeler grdredpol grdrotater grdseamount grdspotter hotspotter polar img2grd magref meca mgd77convert mgd77track rotconverter rotsmoother sac talwani2d talwani3d velo windbarbs originater pmodeler polespotter segy2grd segy segyz backtracker" + + nomes = "ablines anaglyph append2fig arrows bezier coastlinesproj cart2pol cart2sph cpt4dcw contourf colorzones crop cubeplot lazread lazwrite decorated earthregions ecdfplot ecmwf ecmwf findpeaks gadm hband hlines imagesc maregrams meteosat mosaic okada orbits parkergrav parkermag pastplates pca pcolor piechart plotlinefit plotyy qqplot quiver radar scatter3 sealand seismicity slicecube stackgrids stereonet streamlines trisurf vband violin vlines weather wmsread whittaker geocoder inpolygon isoutlier linearfitxy mat2ds mat2grid mat2img leepacific lelandshade remotegrid theme whereami zonal_stats geodetic2enu gmtread gmtwrite graticules gridit hampel imshow ind2rgb inwhichpolygon rasterzones worldrectangular xyzw2cube date2doy doy2date getbyattrib info isnodata ode2ds regiongeog rescale worldrectcoast worldrectgrid gunique polygonlevels sph2cart uniqueind vecangles getprovider mapsize2region wmsinfo" + + nomes = "autocor blendimg! era5vars grid2tri grightjoin isclockwise isotime2unix kmeans lazinfo listecmwfvars yeardecimal" + #nomes = "gmt_core gmt_data gmt_grids gmt_jlext gmt_plot gmt_sup" + + nome !== "" && (nomes = nome) + pato = "C:/v/doc_t/GMTjl_doc/quarto_site/documentation/modules/assets/" + pato_in = pato * "e/" + + for name in split(nomes) + name_out = pato * name * "_logo.jpg" + name_in = pato_in * name * ".png" + I = gdalread(name_in) + Iw = binarize(I) + CC = bwconncomp(Iw) + Ic = gdaltranslate(I, R=CC.bbox[1].ds_bbox) + Ir = imresize(Ic, size) + gmtwrite(name_out, mat2img(Ir[:,:,1:3],Ir)) + println("Created: " * name_out) + end +end diff --git a/test/test_avatars.jl b/test/test_avatars.jl index 408a3335f..eeaa6948c 100644 --- a/test/test_avatars.jl +++ b/test/test_avatars.jl @@ -227,6 +227,13 @@ scatter3!(x -> sin(x), y -> cos(y), 0:pi/50:10pi, Vd=dbg2) scatter3!(x -> sin(x)*cos(10x), y -> sin(y)*sin(10y), z -> cos(z), 0:pi/100:pi, Vd=dbg2) + plot3([3 3 3], R="0/6/0/6/0/6", JZ=4, p="135/45", S="P2c", G=:blue, W="0.2p,red", Vd=dbg2) + plot3([3 3 3], R="0/6/0/6/0/6", JZ=4, p="135/45", marker=(:sphe, 2), G=:blue, W="0.2p,red", Vd=dbg2) + plot3([3 3 3], R="0/6/0/6/0/6", JZ=4, p="135/45", marker=:sphere, mc=:blue, mec="0.2p,red", ms=2, Vd=dbg2) + plot3([3 3 3], R="0/6/0/6/0/6", JZ=4, p="135/45", marker=(sphere=true, flat=true, azim=19), mc=:blue, mec="0.2p,red", Vd=dbg2) + plot3([3 3 3], R="0/6/0/6/0/6", JZ=4, p="135/45", marker=(sphere=3, flat=true, azim=19), mc=:blue, mec="0.2p,red", Vd=dbg2) + plot3([3 3 3], R="0/6/0/6/0/6", JZ=4, p="135/45", marker=(sphere=true, size=6, flat=true, azim=19), mc=:blue, mec="0.2p,red", Vd=dbg2) + println(" ARROWS") arrows([0 8.2 0 6], R="-2/4/0/9", arrow=(len=2,stop=1,shape=0.5,fill=:red), J=:X14, B=:a, pen="6p") arrows([0 8.2 0 6], R="-2/4/0/9", arrow=(len=2,start=:arrow,stop=:tail,shape=0.5), J=:X14, B=:a, pen="6p")