Skip to content

Commit

Permalink
Merge pull request #1490 from GenericMappingTools/better-nested-clip
Browse files Browse the repository at this point in the history
Expand the nested clip option so that we can also use the pscoast clipping capabilities.
  • Loading branch information
joa-quim authored Jul 21, 2024
2 parents e44dde3 + 03fd595 commit 4f6877f
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 53 deletions.
90 changes: 55 additions & 35 deletions src/common_options.jl
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,9 @@ function parse_J(d::Dict, cmd::String, default::String="", map::Bool=true, O::Bo
(IamInset[1] && !IamInset[2] && !contains(cmd, " -J")) && (cmd *= CTRL.pocket_J[1]::String) # Workaround GMT bug (#7005)
return cmd, ""
end
CTRL.proj_linear[1] = (length(opt_J) >= 4 && opt_J[4] != 'X' && opt_J[4] != 'x' && opt_J[4] != 'Q' && opt_J[4] != 'q') ? false : true
if (CTRL.proj_linear[1]) # Otherwise (CTRL.proj_linear[1] == false), trust it
CTRL.proj_linear[1] = (length(opt_J) >= 4 && opt_J[4] != 'X' && opt_J[4] != 'x' && opt_J[4] != 'Q' && opt_J[4] != 'q') ? false : true
end
(!map && opt_J != "") && return cmd * opt_J, opt_J

(O && opt_J == "") && (opt_J = " -J")
Expand Down Expand Up @@ -463,7 +465,9 @@ function parse_J(d::Dict, cmd::String, default::String="", map::Bool=true, O::Bo
end
end
end
CTRL.proj_linear[1] = (length(opt_J) >= 4 && opt_J[4] != 'X' && opt_J[4] != 'x' && opt_J[4] != 'Q' && opt_J[4] != 'q') ? false : true
if (CTRL.proj_linear[1]) # If CTRL.proj_linear[1] == false, trust it
CTRL.proj_linear[1] = (length(opt_J) >= 4 && opt_J[4] != 'X' && opt_J[4] != 'x' && opt_J[4] != 'Q' && opt_J[4] != 'q') ? false : true
end

(opt_J == " ") && (opt_J = "") # We use " " when wanting to prevent the default -J
fish_size_from_J(opt_J) # So far we only need this in plot(hexbin)
Expand Down Expand Up @@ -1002,6 +1006,8 @@ function parse_B(d::Dict, cmd::String, opt_B__::String="", del::Bool=true)::Tupl
(farg == "") && (farg = "auto") # Can't take the risk of letting go a "". GMT would (Ghrr) error
end
_tt, a_par = replace(str_with_blancs(farg), ' '=>'\x7f'), ""
_tt = replace(_tt, ">" => "\\076") # Avoid the shit of the shells taking precedence in parsing the > and < symbols
_tt = replace(_tt, "<" => "\\074")
else
_tt, a_par = fun(;arg...)
end
Expand Down Expand Up @@ -2119,34 +2125,32 @@ function finish_PS_nested(d::Dict, cmd::Vector{String})::Vector{String}
cmd2::Vector{String} = add_opt_module(d)
CTRL.proj_linear[1] = proj_linear_bak # Because add_opt_module may change it (coast does that)

if (!isempty(cmd2) && startswith(cmd2[1], "clip")) # Deal with the particular psclip case (Tricky)
if (isa(CTRL.pocket_call[1], Symbol) || isa(CTRL.pocket_call[1], String)) # Assume it's a clip=end
cmd::Vector{String}, CTRL.pocket_call[1] = [cmd; "psclip -C"], nothing
else
ind = findfirst(" -R", cmd[1]); opt_R::String = strtok(cmd[1][ind[1]:end])[1]
ind = findfirst(" -J", cmd[1]); opt_J::String = strtok(cmd[1][ind[1]:end])[1]
extra::String = strtok(cmd2[1])[2] * " " # When psclip recieved extra arguments
t::String, opt_B::String, opt_B1::String = "psclip " * extra * opt_R * " " * opt_J, "", ""
ind = findall(" -B", cmd[1])
if (!isempty(ind) && (findfirst("-N", extra) === nothing))
for k = 1:lastindex(ind)
opt_B *= " " * strtok(cmd[1][ind[k][1]:end])[1]
end
# Here we need to reset any -B parts that do NOT include the plotting area and which were clipped.
if (CTRL.pocket_B[1] == "" && CTRL.pocket_B[2] == "")
opt_B1 = opt_B * " -R -J"
else
(CTRL.pocket_B[1] != "") && (opt_B1 = replace(opt_B, CTRL.pocket_B[1] => "")) # grid
(CTRL.pocket_B[2] != "") && (opt_B1 = replace(opt_B1, CTRL.pocket_B[2] => "")) # Fill
(occursin("-Bp ", opt_B1)) && (opt_B1 = replace(opt_B1, "-Bp " => "")) # Delete stray -Bp
opt_B1 = replace(opt_B1, "-B " => "") # ""
(endswith(opt_B1, " -B")) && (opt_B1 = opt_B1[1:end-2])
(opt_B1 != "") && (opt_B1 *= " -R -J") # When not-empty it needs the -R -J
CTRL.pocket_B[1] = CTRL.pocket_B[2] = "" # Empty these guys
end
if (!isempty(cmd2) && startswith(cmd2[1], "clip")) # Deal with the particular psclip case (Tricky)
opt_R = scan_opt(cmd[1], "-R", true)
opt_J = scan_opt(cmd[1], "-J", true)
extra::String = strtok(cmd2[1])[2] * " " # When psclip recieved extra arguments
t::String = extra * opt_R * " " * opt_J
(!contains(cmd2[1], "pscoast")) && (t = "psclip " * t)
opt_B::String, opt_B1::String = "", ""
ind = findall(" -B", cmd[1])
if (!isempty(ind))
for k = 1:lastindex(ind)
opt_B *= " " * strtok(cmd[1][ind[k][1]:end])[1]
end
# Here we need to reset any -B parts that do NOT include the plotting area and which were clipped.
if (CTRL.pocket_B[1] == "" && CTRL.pocket_B[2] == "")
opt_B1 = opt_B * " -R -J"
else
(CTRL.pocket_B[1] != "") && (opt_B1 = replace(opt_B, CTRL.pocket_B[1] => "")) # grid
(CTRL.pocket_B[2] != "") && (opt_B1 = replace(opt_B1, CTRL.pocket_B[2] => "")) # Fill
(occursin("-Bp ", opt_B1)) && (opt_B1 = replace(opt_B1, "-Bp " => "")) # Delete stray -Bp
opt_B1 = replace(opt_B1, "-B " => "") # ""
(endswith(opt_B1, " -B")) && (opt_B1 = opt_B1[1:end-2])
(opt_B1 != "") && (opt_B1 *= " -R -J") # When not-empty it needs the -R -J
CTRL.pocket_B[1] = CTRL.pocket_B[2] = "" # Empty these guys
end
cmd = [t; cmd; "psclip -C" * opt_B1]
end
cmd = [t; cmd; "psclip -C" * opt_B1]
else
append!(cmd, cmd2)
end
Expand Down Expand Up @@ -2745,13 +2749,19 @@ function add_opt_module(d::Dict)::Vector{String}
r = colorbar!(; Vd=2, nt...)
!contains(r, " -B") && (r = replace(r, "psscale" => "psscale -Baf")) # Add -B if not present
elseif (symb == :clip) # Need lots of little shits to parse the clip options
(CTRL.pocket_call[1] === nothing) ? (CTRL.pocket_call[1] = val[1]) : (CTRL.pocket_call[2] = val[1])
k,v = keys(nt), values(nt)
nt = NamedTuple{Tuple(Symbol.(k[2:end]))}(v[2:end]) # Fck, what a craziness to remove 1 el from a nt
r = clip!(""; Vd=2, nt...)
if ((isa(nt, NamedTuple) && isa(nt[1], String)) || isa(nt[1], NamedTuple))
r = (isa(nt, NamedTuple)) ? coast!(""; Vd=2, E=nt) : coast!(""; Vd=2, nt...)
is_coast = true
else
(CTRL.pocket_call[1] === nothing) ? (CTRL.pocket_call[1] = val[1]) : (CTRL.pocket_call[2] = val[1])
k,v = keys(nt), values(nt)
nt = NamedTuple{Tuple(Symbol.(k[2:end]))}(v[2:end]) # Fck, what a craziness to remove 1 el from a nt
r = clip!(""; Vd=2, nt...)
is_coast = false
end
r = r[1:findfirst(" -K", r)[1]]; # Remove the "-K -O >> ..."
r = replace(r, " -R -J" => "")
r = "clip " * strtok(r)[2] # Make sure the prog name is 'clip' and not 'psclip'
r = (is_coast) ? "clip " * r : "clip " * strtok(r)[2] # coast case returns a "clip pscoast ..." string that caller can parse
else
!(symb in CTRL.callable) && error("Nested Fun call $symb not in the callable nested functions list")
_d = nt2dict(nt)
Expand All @@ -2775,8 +2785,18 @@ function add_opt_module(d::Dict)::Vector{String}
anc = (t == 't') ? "TC" : (t == 'b' ? "BC" : (t == 'l' ? "ML" : "MR"))
r = colorbar!(pos=(anchor=anc,), B="af", Vd=2)
elseif (symb == :clip)
(CTRL.pocket_call[1] === nothing) ? (CTRL.pocket_call[1] = val) : (CTRL.pocket_call[2] = val)
r = "clip"
if (isa(val, String)) # Accept also "land", "water" or "ocean" or DCW country codes(s) or a hard -E string
_str::String = val # Shoot the Any
if (_str == "land") r = "clip pscoast -Gc"
elseif (_str == "water" || _str == "ocean") r = "clip pscoast -Sc"
elseif (length(_str) == 2 || _str[1] == '=' || contains(_str, ','))
r = (_str[1] == '-') ? "clip pscoast " * _str : "clip pscoast -E" * _str * "+c" # Accept also clip="-E..."
else @error("Invalid string for clip option: $_str")
end
else
(CTRL.pocket_call[1] === nothing) ? (CTRL.pocket_call[1] = val) : (CTRL.pocket_call[2] = val)
r = "clip"
end
end
delete!(d, symb)

Expand Down
14 changes: 8 additions & 6 deletions src/gmtreadwrite.jl
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ function gmtread(_fname::String; kwargs...)
d = init_module(false, kwargs...)[1] # Also checks if the user wants ONLY the HELP mode
cmd::String, opt_R::String = parse_R(d, "")
cmd, opt_i = parse_i(d, cmd)
cmd = parse_common_opts(d, cmd, [:V_params :f :h])[1]
cmd, opt_h = parse_h(d, cmd)
cmd = parse_common_opts(d, cmd, [:V_params :f])[1]
cmd, opt_bi = parse_bi(d, cmd)
proggy = "read " # When reading an entire grid cube, this will change to 'grdinterpolate'

Expand Down Expand Up @@ -177,7 +178,6 @@ function gmtread(_fname::String; kwargs...)
end

if (opt_T != " -To") # All others but OGR
#(proggy == "read ") && (cmd *= opt_T)
if (proggy == "read ")
((val = find_in_dict(d, [:stride])[1]) !== nothing) && (cmd *= " -Em" * arg2str(val)::String; proggy = "gmtconvert ")
((val = find_in_dict(d, [:q :inrows :inrow])[1]) !== nothing) && (cmd *= " -q" * arg2str(val)::String; proggy = "gmtconvert ")
Expand Down Expand Up @@ -235,7 +235,7 @@ function gmtread(_fname::String; kwargs...)
end

# Try guess if ascii file has time columns and if yes leave trace of it in GMTdadaset metadata.
(opt_bi == "" && isa(o, GDtype)) && file_has_time!(fname, o, corder)
(opt_bi == "" && isa(o, GDtype)) && file_has_time!(fname, o, corder, opt_h)

if (isa(o, GMTgrid))
o.hasnans = any(!isfinite, o.z) ? 2 : 1
Expand Down Expand Up @@ -321,7 +321,7 @@ function helper_set_colnames!(o::GDtype, corder::Vector{Int}=Int[])
end

# ---------------------------------------------------------------------------------
function file_has_time!(fname::String, D::GDtype, corder::Vector{Int}=Int[])
function file_has_time!(fname::String, D::GDtype, corder::Vector{Int}=Int[], opt_h::String="")
# Try guess if 'fname' file has time columns and if yes leave trace of it in D's metadata.
# We do that by scanning the first valid line in file.
# 'corder' is a vector of ints filled with column orders specified by -i. If no -i that it is empty
Expand Down Expand Up @@ -353,8 +353,10 @@ function file_has_time!(fname::String, D::GDtype, corder::Vector{Int}=Int[])
fid = open(fname)
iter = eachline(fid)
try
n_hdr = (opt_h != "") ? parse(Int, opt_h[4:end]) : 0 # Number of declared header lines via -h option
for it in iter
(n_it > 30 || Tc != "") && break # Means that previous iteration found it.
(n_it < n_hdr) && (n_it += 1; continue)
(n_it > (30 + n_hdr) || Tc != "") && break # Means that previous iteration found it.
n_commas = count_chars(it)
use_commas = (n_cols > 1) && (n_commas >= n_cols-1) # To see if we split on spaces or on commas.
line1 = (use_commas) ? split(it, ',') : split(it)
Expand Down Expand Up @@ -404,7 +406,7 @@ function guess_T_from_ext(fname::String; write::Bool=false, text_only::Bool=fals
if (findfirst(isequal(ext), ["grd", "nc", "nc=gd"]) !== nothing) out = " -Tg";
elseif (findfirst(isequal(ext), ["dat", "txt", "csv"]) !== nothing) out = " -Td";
elseif (findfirst(isequal(ext), ["jpg", "jpeg", "png", "bmp", "webp"]) !== nothing) out = " -Ti";
elseif (findfirst(isequal(ext), ["arrow", "shp", _kml, "kmz", "json", "feather", "fgb", "geojson", "gmt", "gpkg", "gpx", "gml", "parquet"]) !== nothing) out = " -To";
elseif (findfirst(isequal(ext), ["arrow", "arrows", "shp", _kml, "kmz", "json", "feather", "fgb", "geojson", "gmt", "gpkg", "gpx", "gml", "ipc", "parquet", "sqlite"]) !== nothing) out = " -To";
elseif (ext == "jp2") ressurectGDAL(); out = (findfirst("Type=UInt", gdalinfo(fname)) !== nothing) ? " -Ti" : " -Tg"
elseif (ext == "cpt") out = " -Tc";
elseif (ext == "ps" || ext == "eps") out = " -Tp";
Expand Down
2 changes: 1 addition & 1 deletion src/grdimage.jl
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ function grdimage(cmd0::String="", arg1=nothing, arg2=nothing, arg3=nothing; fir
if (!occursin("-A", cmd)) # -A means that we are requesting the image directly
(haskey(d, :inset)) && (CTRL.pocket_call[4] = arg1) # If 'inset', it may be needed from next call
_cmd = finish_PS_nested(d, _cmd)
if ((ind = findfirst(startswith.(_cmd, "inset_"))) !== nothing) # inset commands must the last ones
if ((ind = findfirst(startswith.(_cmd, "inset_"))) !== nothing) # inset commands must be the last ones
ins = popat!(_cmd, ind) # Remove the 'inset' command
append!(_cmd, [ins]) # and add it at the end
end
Expand Down
1 change: 1 addition & 0 deletions src/psclip.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ clip(arg1; kwargs...) = clip_helper("", arg1; kwargs...)
clip!(cmd0::String; kwargs...) = clip_helper(cmd0, nothing; first=false, kwargs...)
clip!(arg1; kwargs...) = clip_helper("", arg1; first=false, kwargs...)
clip!(; kwargs...) = clip_helper("", nothing; first=false, kwargs...)
clip(; kwargs...) = clip_helper("", nothing; first=false, kwargs...) # For when user forgot to use clip! instead of clip

# ---------------------------------------------------------------------------------------------------
function clip_helper(cmd0::String, arg1; first=true, kwargs...)
Expand Down
18 changes: 9 additions & 9 deletions src/pscoast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,10 @@ function coast(cmd0::String=""; clip=nothing, first=true, kwargs...)
cmd = add_opt_fill(cmd, d, [:S :water :ocean], 'S')

if (clip !== nothing)
clip = string(clip)
if (clip == "land") cmd *= " -Gc"
elseif (clip == "water" || clip == "ocean") cmd *= " -Sc"
elseif (clip == "end") cmd *= " -Q"
_clip::String = string(clip)
if (_clip == "land") cmd *= " -Gc"
elseif (_clip == "water" || _clip == "ocean") cmd *= " -Sc"
elseif (_clip == "end") cmd = " -Q"; O = true # clip = end can never be a first command
else
@warn("The 'clip' argument can only be a string with 'land', 'water' or 'end'. Ignoring it.")
end
Expand All @@ -135,7 +135,7 @@ function coast(cmd0::String=""; clip=nothing, first=true, kwargs...)
!occursin(" -M",cmd) && !occursin(" -N",cmd) && !occursin(" -Q",cmd) && !occursin(" -S",cmd) && !occursin(" -W",cmd))
cmd *= " -W0.5p"
end
(!occursin("-D",cmd)) && (cmd *= " -Da") # Then pick automatic
(!occursin("-D",cmd) && !contains(cmd, " -Q")) && (cmd *= " -Da") # Then pick automatic
finish = !occursin(" -M",cmd) && !occursin("-E+l", cmd) && !occursin("-E+L", cmd) ? true : false # Otherwise the dump would be redirected to GMT_user.ps

# Just let D = coast(R=:PT, dump=true) work without any furthers shits (plain GMT doesn't let it)
Expand Down Expand Up @@ -201,8 +201,8 @@ function parse_E_coast(d::Dict, symbs::Vector{Symbol}, cmd::String)
!contains(t, "+") && (t *= "+p0.5") # If only code(s), append pen
cmd *= t
elseif (isa(val, NamedTuple) || isa(val, AbstractDict))
cmd = add_opt(d, cmd, "E", [:DCW :E], (country="", name="", continent="=",
pen=("+p", add_opt_pen), fill=("+g", add_opt_fill), file=("+f")))
cmd = add_opt(d, cmd, "E", [:DCW :E], (country="", name="", continent="=", pen=("+p", add_opt_pen),
fill=("+g", add_opt_fill), file=("+f"), inside=("_+c"), outside=("_+C"), adjust_r=("+r", arg2str), adjust_R=("+R", arg2str), adjust_e=("+e", arg2str), headers=("_+z")))
elseif (isa(val, Tuple))
cmd = parse_dcw(cmd, val)
end
Expand All @@ -223,8 +223,8 @@ function parse_dcw(cmd::String, val::Tuple)::String
for k = 1:numel(val)
if (isa(val[k], NamedTuple) || isa(val[k], Dict))
isa(val[k], AbstractDict) && (val[k] = Base.invokelatest(dict2nt, val[k]))
cmd *= add_opt(Dict(:DCW => val[k]), "", "E", [:DCW],
(country="", name="", continent="=", pen=("+p", add_opt_pen), fill=("+g", add_opt_fill), file=("+f")))
cmd *= add_opt(Dict(:DCW => val[k]), "", "E", [:DCW], (country="", name="", continent="=", pen=("+p", add_opt_pen),
fill=("+g", add_opt_fill), file=("+f"), inside=("_+c"), outside=("_+C"), adjust_r=("+r", arg2str), adjust_R=("+R", arg2str), adjust_e=("+e", arg2str), headers=("_+z")))
elseif (isa(val[k], Tuple))
cmd *= parse_dcw(val[k])
else
Expand Down
4 changes: 2 additions & 2 deletions src/show_pretty_datasets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ function _show(io::IO,
end

# See if we have attribs as vector of strings to be displayed as columns in the table.
function add_att_cols(D, names_str, types_str)
function add_att_cols(D, Dt, names_str, types_str)
isempty(D.attrib) && return Dt, names_str, types_str
ky = collect(keys(D.attrib))
for k = 1:numel(ky)
Expand Down Expand Up @@ -171,7 +171,7 @@ function _show(io::IO,
Dt = D.data
end

Dt, names_str, types_str = add_att_cols(D, names_str, types_str) # Check for string vector attributes
Dt, names_str, types_str = add_att_cols(D, Dt, names_str, types_str) # Check for string vector attributes

if ((Tc = get(D.attrib, "Timecol", "")) != "")
Tcn = parse.(Int, split(Tc, ","))
Expand Down

0 comments on commit 4f6877f

Please sign in to comment.