Skip to content

Commit e1948cd

Browse files
authored
Move some functions around and replace some calls to module names by gmt(...) (#1828)
* Split of mapsize2region() function * Split of some functions from the pshistogram.jl file * Move some functions around and replace some calls to module names by GMT.jl(...) * A split from psxy.jl
1 parent 94ea35a commit e1948cd

21 files changed

Lines changed: 444 additions & 423 deletions

src/GMT.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ include("grdview.jl")
282282
include("grdvolume.jl")
283283
include("greenspline.jl")
284284
include("gridit.jl")
285+
include("histo_funs.jl")
285286
include("img_funs.jl")
286287
include("imgtiles.jl")
287288
include("imshow.jl")
@@ -291,6 +292,7 @@ include("loxodromics.jl")
291292
include("makecpt.jl")
292293
include("mapproject.jl")
293294
include("maregrams.jl")
295+
include("marker_name.jl")
294296
include("movie.jl")
295297
include("nearneighbor.jl")
296298
include("pastplates.jl")
@@ -345,6 +347,7 @@ include("extras/anaglyph.jl")
345347
include("extras/hampel_outliers.jl")
346348
include("extras/isoutlier.jl")
347349
include("extras/lowess.jl")
350+
include("extras/mapsize2region.jl")
348351
include("extras/seismicity.jl")
349352
include("extras/okada.jl")
350353
include("extras/weather.jl")

src/beziers.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,17 @@ function bezier(D::GMTdataset; t=nothing, np::Int=0, pure=false, firstcurve=true
6262
is_geo = isgeog(D)
6363
if (is_geo)
6464
mat::Matrix{Float64} = (size(D.data, 2) == 2) ? [D.data fill(0, size(D.data, 1))] : D.data
65-
mat = mapproject(mat, E=true).data # Convert to ECEF
65+
#mat = mapproject(mat, E=true).data # Convert to ECEF
66+
mat = gmt("mapproject -E", mat).data # Convert to ECEF
6667
else
6768
mat = D.data
6869
end
6970
(pure == 1 && size(mat, 1) > 4) && (pure = false;
7071
@warn("pure option not allowed for more than 4 control points. Reverting to 'impure'"))
7172

7273
out::Matrix{Float64} = bezier(mat; t=t, np=np, pure=pure, firstcurve=firstcurve)
73-
is_geo && (out = mapproject(out, E=true, I=true).data) # Convert back to geographic
74+
#is_geo && (out = mapproject(out, E=true, I=true).data) # Convert back to geographic
75+
is_geo && (out = gmt("mapproject -E -I", out).data) # Convert back to geographic
7476
return mat2ds(out, D)::GMTdataset{Float64, 2}
7577
end
7678

src/common_options.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4627,7 +4627,8 @@ function regiongeog(GI::GItype)::Tuple
46274627
end
46284628
function regiongeog(fname::String)::Tuple
46294629
((prj = getproj(fname, wkt=true)) == "") && (@warn("Input grid/image has no projection info"); return ())
4630-
info = grdinfo(fname, C=true); # It should also report the
4630+
#info = grdinfo(fname, C=true); # It should also report the
4631+
info = gmt("grdinfo -C " * fname);
46314632
c = xy2lonlat([info.data[1] info.data[3]; info.data[2] info.data[4]]; s_srs=prj)
46324633
tuple(c...)
46334634
end
@@ -4961,7 +4962,8 @@ Check if `cmd0` is a remote grid or a OceanColor one and return the default CPT
49614962
"""
49624963
function check_remote_cpt(cmd0::String)
49634964
(cmd0 == "") && return ""
4964-
cpt_path = joinpath(dirname(pathof(GMT)), "..", "share", "cpt")
4965+
#cpt_path = joinpath(dirname(pathof(GMT)), "..", "share", "cpt")
4966+
cpt_path = joinpath(dirname(pathof(getfield(Main, nameof(@__MODULE__)))), "..", "share", "cpt")
49654967
if (occursin("SST.sst", cmd0)) return cpt_path * "/sst_oc.cpt"
49664968
elseif (occursin("CHL.chlor_a", cmd0)) return cpt_path * "/chlor_oc.cpt"
49674969
end

src/extras/anaglyph.jl

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,19 @@ end
111111
# ---------------------------------------------------------------------------------------------------
112112
function anaglyph_3d(G::GMTgrid; zsize=4, azim=190, dazim=2, cmap="gray")
113113

114+
# We do this more convoluted call to grdview to avoid calling it directly (unknown in future GMT_base module)
114115
p_left, p_right = "$(azim)/30/0", "$(azim - dazim)/30/0"
115-
pato = TMPDIR_USR[1] * "/" * "GMTjl_" * TMPDIR_USR[2] * TMPDIR_USR[3]
116-
grdview(G, J="Q20c", JZ="$zsize", B=:none, C=string(cmap), Q=:i, p=p_left, I=true, figname=pato * ".jpg")
117-
Il = gdalread(pato * ".jpg", "-b 1", layout="TCBa")
116+
pato = TMPDIR_USR[1] * "/" * "GMTjl_" * TMPDIR_USR[2] * TMPDIR_USR[3] * ".jpg"
117+
opt_R = @sprintf("%.15g/%.15g/%.15g/%.15g/%.15g/%.15g", G.range[1], G.range[2], G.range[3], G.range[4], G.range[5], G.range[6])
118+
#grdview(G, J="Q20c", JZ="$zsize", B=:none, C=string(cmap), Q=:i, p=p_left, I=true, figname=pato)
119+
cmd = ["grdview -R$opt_R -JQ20c -JZ$zsize -C$cmap -Qi -p$p_left -I+a-45+nt1"]
120+
prep_and_call_finish_PS_module(Dict{Symbol, Any}(:figname => pato), cmd, "", true, false, true, G)
121+
Il = gdalread(pato, "-b 1", layout="TCBa")
118122
nr_l, nc_l = size(Il,1), size(Il,2)
119-
grdview(G, J="Q20c", JZ="$zsize", B=:none, C=string(cmap), Q=:i, p=p_right, I=true, figname=pato * ".jpg")
120-
Ir = gdalread(pato * ".jpg", layout="TCBa")
123+
#grdview(G, J="Q20c", JZ="$zsize", B=:none, C=string(cmap), Q=:i, p=p_right, I=true, figname=pato)
124+
cmd = ["grdview -R$opt_R -JQ20c -JZ$zsize -C$cmap -Qi -p$p_right -I+a-45+nt1"]
125+
prep_and_call_finish_PS_module(Dict{Symbol, Any}(:figname => pato), cmd, "", true, false, true, G)
126+
Ir = gdalread(pato, layout="TCBa")
121127
nr_r, nc_r = size(Ir,1), size(Ir,2)
122128

123129
center_left = (nr_l ÷ 2 + 1, nc_l ÷ 2 + 1)

src/extras/isoutlier.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,9 @@ function isoutlier(D::GMTdataset{<:Real,2}; critic=3.0, method::Symbol=:median,
9797
(threshold === nothing && width <= 0) && error("Must provide the window length of via the `width` option or use the `threshold` option.")
9898
if (width > 0)
9999
method in [:median, :mean] || throw(ArgumentError("Unknown method: $method. Here use only one of :median or :mean"))
100-
(method == :mean) && (method = boxcar) # :boxcar is the name in GMT for 'mean'
101-
Dres = filter1d(D, filter=(type=method, width=width, highpass=true), E=true)
100+
_method = (method == :mean) ? :boxcar : method # :boxcar is the name in GMT for 'mean'
101+
#Dres = filter1d(D, filter=(type=_method, width=width, highpass=true), E=true, Vd=1)
102+
Dres = gmt("filter1d -E -F" * string(_method)[1] * "$(width)+h", D)
102103
isoutlier(view(Dres.data, :, 2), critic=critic, method=method, threshold=threshold)
103104
else
104105
isoutlier(view(D.data, :, 2), critic=critic, method=method, threshold=threshold)

src/extras/mapsize2region.jl

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
2+
# ---------------------------------------------------------------------------------------------------
3+
"""
4+
region_opt, proj_opt = mapsize2region(proj=?, scale=?, clon=?, clat=?, width=?, height=0, bnds="", plot=false)
5+
6+
Compute the region for a map of user specified projection, scale, width and height.
7+
8+
### Kwargs
9+
- `proj`: Projection. Either a string (e.g. "m" for Mercator, "lambert", "stere", etc.), or a tuple for
10+
projections that demand more parameters. Same syntax as `coast`, etc.
11+
- `scale`: Scale of the map in the form of "1:xxxx" (e.g. "1:1000000").
12+
- `clon`: Center longitude of the map in degrees.
13+
- `clat`: Center latitude of the map in degrees.
14+
- `width`: Width of the map in centimeters.
15+
- `height`: Height of the map in centimeters. If not specified, it defaults to `width`.
16+
- `bnds`: We need a default limits as first approximation to obtain the seeked region. That normally is the global
17+
[-180 180 -90 90]. But that might not work for certain cases as for example the Mercator projection Where no poles
18+
are allowed). Thoug the Mercator case is dealt in internally, there are other projections that don't allow global
19+
limits. In those cases, you will need to specify `bnds` using the same syntax as for the `region` option of all
20+
GMT functions.
21+
- `plot`: If true, we generate an example map representative of the requested region using `coast` function.
22+
Use this only to get an idea of the obtained region. No fine tunings are done here. Default is false.
23+
24+
### Returns
25+
A tuple with the region in the form of "xmin/xmax/ymin/ymax" and the projection string used.
26+
Use this ooutput as input on all odules that require a `region` and `projection`.
27+
28+
### Credits
29+
Stolen fom Tim Hume's idea posted in the GMT forum:
30+
https://forum.generic-mapping-tools.org/t/script-to-create-a-map-with-defined-width-and-height/5909/17?u=joaquim
31+
32+
### Example
33+
```julia
34+
opt_R, opt_J = mapsize2region(proj=(name=:tmerc, center=-177), scale="1:10000000", clon=-177, clat=-21, width=15, height=10)
35+
36+
# And now do a simple coastline map showing the region.
37+
# Note that the same could be achieved by setting the `plot=true` but this shows more explicitly
38+
# how to use the mapsize2region() output.
39+
coast(region=opt_R, proj=opt_J, shore=true, show=true)
40+
```
41+
"""
42+
function mapsize2region(; proj="", scale="", clon=NaN, clat=NaN, width=0, height=0, bnds="", plot=false)::Tuple{String, String}
43+
(height == 0) && (height = width) # If height is not specified, use width
44+
@assert proj != "" "Projection must be specified"
45+
@assert clon != NaN && clat != NaN "Center longitude and latitude must be specified"
46+
@assert width > 0 && height > 0 "Width and height must be positive"
47+
@assert contains(scale, ':') "Scale must be in the form of '1:xxxx'"
48+
(!isa(proj, StrSymb)) && (proj = parse_J(Dict(:J => proj, :scale => scale), "")[1][4:end]; scale="") # scale is now in J
49+
(bnds != "") && (bnds = parse_R(Dict(:R => bnds), "")[4:end]) # If bnds is not empty, parse it
50+
(!isa(scale, StrSymb)) && (scale = parse_Scale(Dict(:S => scale), "")) # If scale is not a StrSymb, parse it
51+
(bnds == "" && proj == "m" || startswith(proj, "merc") || startswith(proj, "Merc")) && (bnds="-180/180/-85/85") # Default bounds for Mercator
52+
opt_R, opt_J = mapsize2region(string(proj), scale, Float64(clon), Float64(clat), Float64(width), Float64(height), bnds)
53+
(plot != 0) && coast(R=opt_R, J=opt_J, shore=true, show=true, Vd=1)
54+
return opt_R, opt_J
55+
end
56+
function mapsize2region(proj::String, scale::String, clon::Float64, clat::Float64, width::Float64, height::Float64, bnds)::Tuple{String, String}
57+
t::Matrix{Float64} = mapproject([clon clat], J=proj*scale, R=bnds).data
58+
t2 = [t[1]-width/2 t[2]-height/2; t[1]+width/2 t[2]+height/2]
59+
t3 = mapproject(t2, J=proj*scale, R=bnds, I=true) # Convert back to lon lat
60+
@sprintf("%.8f/%.8f/%.8f/%.8f+r", t3[1,1], t3[1,2], t3[2,1], t3[2,2]), proj*scale
61+
end

src/gdal_tools.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ function gdaldem(indata, method::String, opts::Vector{String}=String[]; dest="/v
251251
append!(opts, ["-compute_edges", "-b", band])
252252
if ((val = find_in_dict(d, [:scale])[1]) === nothing)
253253
if (isa(indata, GMTgrid) && (occursin("longlat", indata.proj4) || occursin("latlong", indata.proj4)) ||
254-
grdinfo(indata, C="n").data[end] == 1)
254+
gmt("grdinfo -Cn", indata).data[end] == 1)
255255
append!(opts, ["-s", "111120"])
256256
end
257257
else

src/grdimage.jl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,6 @@ function common_insert_R!(d::Dict, O::Bool, cmd0, I_G; is3D=false)
217217
(opt_R != "") && (CTRL.pocket_R[1] = " -R" * opt_R)
218218
return nothing
219219
end
220-
function isimgsize(GI)::Bool
221-
width, height = getsize(GI)
222-
(GI.range[2] - GI.range[1]) == width && (GI.range[4] - GI.range[3]) == height
223-
end
224220

225221
# ---------------------------------------------------------------------------------------------------
226222
function common_shade(d::Dict, cmd::String, arg1, arg2, arg3, arg4, prog)

src/histo_funs.jl

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
function find_histo_limits(In, thresholds=nothing, width=20, hst_::Matrix{Float64}=Matrix{Float64}(undef,0,2))
2+
# Find the histogram limits of a UInt16 GMTimage that allow to better stretch the histogram
3+
# THRESHOLDS is an optional Tuple input containing the left and right histo thresholds, in percentage,
4+
# between which the histogram values will be retained. Defaults are (0.1, 0.4) percent. Note, this
5+
# assumes the histogram follows some sort of Gaussian distribution. It it's flat, shit occurs.
6+
# WIDTH is bin width used to obtain a rough histogram that is used to compute the limits.
7+
if (isa(In, Array{UInt16,3}) || isa(In, Array{UInt8,3}))
8+
L1 = find_histo_limits(view(In, :, :, 1), thresholds, width)
9+
L2 = find_histo_limits(view(In, :, :, 2), thresholds, width)
10+
L3 = find_histo_limits(view(In, :, :, 3), thresholds, width)
11+
return (L1[1], L1[2], L2[1], L2[2], L3[1], L3[2])
12+
end
13+
hst = (isempty(hst_)) ? loc_histo(In, "", string(width), "")[1] : hst_
14+
if (size(hst, 1) > 10)
15+
all(hst[2:5,2] .== 0) && (hst[1,2] = 0) # Here we always check for high counts in zero bin
16+
# Some processed bands leave garbage on the low DNs and that fouls our detecting algo. So check more
17+
((hst[1,2] != 0) && hst[1,2] > 100 * mean(hst[2:10,2])) && (hst[1,2] = 0) # Ad-hoc numbers
18+
# Next is for the case of VIIRS bands that have nodata = 65535 but when called from 'truecolor'
19+
# it only passes a band view (the array) and we have access to image's header here.
20+
(width == 20 && eltype(In) == UInt16 && size(hst,1) == 3277) && (hst[end, 2] = 0)
21+
end
22+
max_ = maximum(hst, dims=1)[2]
23+
(max_ == 0) && error("This histogram had nothing but countings ONLY in first bin. No point to proceed.")
24+
thresh_l::Float64 = 0.001; thresh_r::Float64 = 0.004
25+
if (isa(thresholds, Tuple) && length(thresholds) == 2)
26+
thresh_l, thresh_r = thresholds[:] ./ 100
27+
end
28+
thresh_l *= max_
29+
thresh_r *= max_
30+
kl = 1; kr = size(hst, 1)
31+
while (hst[kl,2] == 0 || hst[kl,2] < thresh_l) kl += 1 end
32+
while (hst[kr,2] == 0 || hst[kr,2] < thresh_r) kr -= 1 end
33+
#return Int(hst[kl,1]), Int(min(hst[kr,1] + width, hst[end,1]))
34+
return hst[kl,1], min(hst[kr,1] + width, hst[end,1])
35+
end
36+
37+
# ---------------------------------------------------------------------------------------------------
38+
function loc_histo(in, cmd::String="", opt_T::String="", opt_Z::String="")
39+
# Very simple function to compute histograms of images (integers)
40+
# We put the countings in a Mx2 arrray to trick GMT (pshistogram) to think it's recieving a weighted input.
41+
(!isa(in[1], UInt16) && !isa(in[1], UInt8)) && error("Only UInt8 or UInt16 image types allowed here")
42+
43+
inc::Float64 = (opt_T != "") ? parse(Float64, opt_T) : 1.0
44+
(inc <= 0) && error("Bin width must be a number > 0 and no min/max")
45+
46+
n_bins::Int = (isa(in[1], UInt8)) ? 256 : Int(ceil((maximum(in) + 1) / inc)) # For UInt8 use the full [0 255] range
47+
hst = zeros(n_bins, 2)
48+
pshst_wall!(in, hst, inc, n_bins)
49+
50+
cmd = (opt_Z == "") ? cmd * " -Z0" : cmd * opt_Z
51+
(!occursin("+w", cmd)) && (cmd *= "+w") # Pretending to be weighted is crutial for the trick
52+
53+
return hst, cmd * " -T0/$(n_bins * inc)/$inc"
54+
end
55+
56+
# ---------------------------------------------------------------------------------------------------
57+
function pshst_wall!(in, hst, inc, n_bins::Int)
58+
# Function barrier for type instability. With the body of this in the calling fun the 'inc' var
59+
# introduces a mysterious type instability and execution times multiply by 3.
60+
if (inc == 1)
61+
@inbounds Threads.@threads for k = 1:numel(in) hst[in[k] + 1, 2] += 1 end
62+
else
63+
@inbounds Threads.@threads for k = 1:numel(in) hst[Int(floor(in[k] / inc) + 1), 2] += 1 end
64+
end
65+
(isa(in, GItype) && in.nodata == typemax(eltype(in))) && (hst[end] = 0)
66+
@inbounds Threads.@threads for k = 1:n_bins hst[k,1] = inc * (k - 1) end
67+
return nothing
68+
end
69+
70+
# ---------------------------------------------------------------------------------------------------
71+
# This version computes the histogram for a UInt8 image band with a bin width of 1
72+
histogray(img::GMTimage{<:UInt8}; band=1) = histogray(view(img.image, :, :, band))
73+
function histogray(img::AbstractMatrix{UInt8})
74+
edges, counts = 0:255, fill(0, 256)
75+
Threads.@threads for v in img
76+
@inbounds counts[v+1] += 1
77+
end
78+
return counts, edges
79+
end
80+
81+
# ---------------------------------------------------------------------------------------------------
82+
function hst_floats(arg1, opt_T::String=""; min_max=(0.0, 0.0))
83+
# Compute the histogram of a grid or matrix
84+
# Made a separate function to let it be called from rescale() and thus avoid calling the main histogram()
85+
# that seems to be be too havy (at least according to JET)
86+
_min_max::Tuple{Float64,Float64} = (isa(arg1, GMTgrid)) ?
87+
(arg1.range[5], arg1.range[6]) : (min_max != (0.0, 0.0) ? min_max : Float64.(extrema_nan(arg1)))
88+
if (opt_T != "")
89+
inc = parse(Float64, opt_T) + eps() # + EPS to avoid the extra last bin at right with 1 count only
90+
n_bins = Int(ceil((_min_max[2] - _min_max[1]) / inc))
91+
else
92+
n_bins = Int(ceil(sqrt(length(arg1))))
93+
reg = isa(arg1, GMTgrid) ? (1 - arg1.registration) : 1 # When called from RemoteS arg1 is a view of a layer.
94+
inc = (_min_max[2] - _min_max[1]) / (n_bins - reg) + eps()
95+
end
96+
(!isa(inc, Real) || inc <= 0) && error("Bin width must be a > 0 number and no min/max")
97+
hst = zeros(n_bins, 2)
98+
have_nans = false
99+
if (eltype(arg1) <: AbstractFloat) # Float arrays can have NaNs
100+
have_nans = !(isa(arg1, GMTgrid) && arg1.hasnans == 1)
101+
have_nans && (have_nans = any(!isfinite, arg1))
102+
end
103+
104+
_inc = inc + 10eps() # To avoid cases when index computing fall of by 1
105+
if (have_nans) # If we have NaNs in the grid, we need to take a slower branch
106+
@inbounds for k = 1:numel(arg1)
107+
!isnan(arg1[k]) && (hst[Int(floor((arg1[k] - _min_max[1]) / _inc) + 1), 2] += 1)
108+
end
109+
else
110+
@inbounds for k = 1:numel(arg1) hst[Int(floor((arg1[k] - _min_max[1]) / _inc) + 1), 2] += 1 end
111+
end
112+
@inbounds for k = 1:n_bins hst[k,1] = _min_max[1] + inc * (k - 1) end
113+
return hst, inc, _min_max
114+
end
115+
116+
# ---------------------------------------------------------------------------------------------------
117+
function binmethod(d::Dict, cmd::String, X, is_datetime::Bool)
118+
# Compute bin width for a series of binning alghoritms or intervals when X (DateTime) comes in seconds
119+
val::String = ((val_ = find_in_dict(d, [:binmethod :BinMethod])[1]) !== nothing) ? lowercase(string(val_)) : ""
120+
min_max = (zero(eltype(X)), zero(eltype(X)))
121+
(!is_datetime) && (min_max = extrema(X)) # X should already be sorted but don't trust that
122+
if (val == "")
123+
if (!is_datetime)
124+
val = "sqrt"
125+
else
126+
min_max = extrema(X) # X should already be sorted but don't trust that
127+
rng = (min_max[2] - min_max[1])
128+
if (rng < 150) val = "second"
129+
elseif (rng / (60) < 150) val = "minute"
130+
elseif (rng / (3600) < 150) val = "hour"
131+
elseif (rng / (86400) < 150) val = "day"
132+
elseif (rng / (86400 * 7) < 150) val = "week"
133+
elseif (rng / (86400 * 31) < 150) val = "month"
134+
else val = "year"
135+
end
136+
end
137+
end
138+
139+
n_bins = 0.0; bin = 0
140+
if (val == "scott") n_bins = 3.5 .* std(X) .* length(X)^(-1/3)
141+
elseif (val == "fd") n_bins = 2 .* IQR(X) .* length(X)^(-1/3)
142+
elseif (val == "sturges") n_bins = ceil.(1 .+ log2.(length(X)))
143+
elseif (val == "sqrt") n_bins = ceil.(sqrt(length(X)))
144+
elseif (val == "year") bin = 86400 * 365.25
145+
elseif (val == "month") bin = 86400 * 31
146+
elseif (val == "week") bin = 86400 * 7
147+
elseif (val == "day") bin = 86400
148+
elseif (val == "hour") bin = 3600
149+
elseif (val == "minute") bin = 60
150+
elseif (val == "second") bin = 1
151+
elseif (!is_datetime) error("Unknown BinMethod $val")
152+
end
153+
if (bin == 0)
154+
bin = (min_max[2] - min_max[1]) / n_bins # Should be made a "pretty" number?
155+
end
156+
return @sprintf("%.12g", bin), min_max
157+
end

src/lepto_funs.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,11 +368,13 @@ function fillsinks(G::GMTgrid; conn=4, region=nothing, saco=false, insitu=false)
368368
d = (I .== I2')
369369
D = polygonize(d)
370370
if (saco == 1)
371-
Dtrk = grdtrack(G, D)
371+
Dtrk = gmt("grdtrack -G -n+a", D, G)
372372
means = isa(D, Vector) ? median.(Dtrk) : median(Dtrk)
373373
SACO[1] = Dict("saco" => Dtrk) # Save the grdtrack interpolated lines for eventual external use.
374374
else
375-
means = isa(D, Vector) ? median.(grdtrack(G, D, o=2)) : median(grdtrack(G, D, o=2)) # The mean of each interpolated contour
375+
#Dtrk = grdtrack(G, D, o=2)
376+
Dtrk = gmt("grdtrack -G -n+a -o2", D, G)
377+
means = isa(D, Vector) ? median.(Dtrk) : median(Dtrk) # The mean of each interpolated contour
376378
end
377379
_G = (insitu == 1) ? G : deepcopy(G)
378380

0 commit comments

Comments
 (0)