Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/choropleth.jl
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ function extract_ids_vals(D, attrib::String)
vals = deleteat!(vals, ind)
ids = deleteat!(ids, ind)
end
ids, parse.(Float64, vals)
ids, (tryparse(Float64, vals[1]) === nothing) ? collect(1.0:length(vals)) : parse.(Float64, vals)
end

# ------------------------------------------------------------------------------------------------------
Expand Down
14 changes: 14 additions & 0 deletions src/gdal_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,20 @@ function getregion(input; pad=0, xSize=0, ySize=0, gridreg::Bool=false, sds::Int
return x_min, x_max, y_min, y_max, x_inc, y_inc
end

# ---------------------------------------------------------------------------------------------------
"""
opr_R = getR(X, full::Bool=false)::String

Return a string with the -R option made up of the region of 'X'.

`X` is a GMTimage, GMTgrid or GMTdataset(s). The `full` flag adds the " -R" prefix.
"""
function getR(X, full::Bool=false)::String
x_min, x_max, y_min, y_max = getregion(X)
pre = full ? " -R" : ""
@sprintf("%s%f/%f/%f/%f", pre, x_min, x_max, y_min, y_max)
end

# ---------------------------------------------------------------------------------------------------
function coords_resque(dataset)
# We come here when GDAL stuburnly finds a netcdf file indign and ignores its coordinates
Expand Down
2 changes: 1 addition & 1 deletion src/gmtlogo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function logo(cmd0::String=""; first=true, kwargs...)
if (!occursin("-R", cmd)) cmd = @sprintf("-R0/%f/0/%f ", 2r, 2r) * cmd end
if (!occursin("-J", cmd)) cmd = " -Jx1 " * cmd end
if (do_GMTjulia) # Too soon to use the show, fmt, ...
do_show, fmt, savefig = get_show_fmt_savefig(d, true) # Default is to show
do_show, fmt, savefig = get_show_fmt_savefig(d, false) # Default is to !show
end
cmd = "psxy " * c * cmd
((_r = check_dbg_print_cmd(d, cmd)) !== nothing && startswith(_r, "psxy")) && return _r
Expand Down
40 changes: 6 additions & 34 deletions src/grdimage.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function grdimage(cmd0::String="", arg1=nothing, arg2=nothing, arg3=nothing; fir
(!haskey(d, :R) && any(startswith.(cmd0, ["@earth_", "@mars_", "@pluto_", "@moon_", "@venus_"]))) &&
(CTRL.limits[1:4] = CTRL.limits[7:10] = [-180, 180, -90, 90])

if (arg1 === nothing && haskey(d, :R) && guess_T_from_ext(cmd0) == " -Ti")
if (arg1 === nothing && (get(d, :R, nothing) !== nothing) && guess_T_from_ext(cmd0) == " -Ti")
_opt_R = d[:R]
t = (isa(_opt_R, Tuple) || isa(_opt_R, VMr)) ?
["$(_opt_R[1])", "$(_opt_R[2])", "$(_opt_R[3])", "$(_opt_R[4])"] : split(_opt_R, '/')
Expand All @@ -77,22 +77,6 @@ end
function _grdimage(cmd0::String, arg1, arg2, arg3, O::Bool, K::Bool, d::Dict)

arg4 = nothing # For the r,g,b + intensity case
#=
common_insert_R!(d, O, cmd0, arg1) # Set -R in 'd' out of grid/images (with coords) if limits was not used

# Remote files with no -R are all global. Set CTRL.limits so we can guess the projection.
(!haskey(d, :R) && any(startswith.(cmd0, ["@earth_", "@mars_", "@pluto_", "@moon_", "@venus_"]))) &&
(CTRL.limits[1:4] = CTRL.limits[7:10] = [-180, 180, -90, 90])

if (arg1 === nothing && haskey(d, :R) && guess_T_from_ext(cmd0) == " -Ti")
_opt_R = d[:R]
t = (isa(_opt_R, Tuple) || isa(_opt_R, VMr)) ?
["$(_opt_R[1])", "$(_opt_R[2])", "$(_opt_R[3])", "$(_opt_R[4])"] : split(_opt_R, '/')
opts = ["-projwin", t[1], t[4], t[2], t[3]] # -projwin <ulx> <uly> <lrx> <lry>
arg1 = cut_with_gdal(cmd0, opts)
cmd0 = ""
end
=#

# Prevent that J=guess is applied to a non-geog grid/image
(arg1 !== nothing && (symb = is_in_dict(d, [:proj :projection])) !== nothing && (d[symb] == "guess" || d[symb] == :guess) && !isgeog(arg1)) &&
Expand All @@ -102,8 +86,11 @@ function _grdimage(cmd0::String, arg1, arg2, arg3, O::Bool, K::Bool, d::Dict)
(is_in_dict(d, [:A :img_out :image_out]) !== nothing) && (d[:B] = "none") # When -A is used, -B is forbiden
cmd::String, opt_B::String, opt_J::String, opt_R::String = parse_BJR(d, "", "", O, " -JX" * split(DEF_FIG_SIZE, '/')[1] * "/0")
(startswith(opt_J, " -JX") && !contains(opt_J, "/")) && (cmd = replace(cmd, opt_J => opt_J * "/0")) # When sub-regions
(!has_opt_B && isa(arg1, GMTimage) && (isimgsize(arg1) || CTRL.limits[1:4] == zeros(4)) && opt_B == DEF_FIG_AXES_BAK) &&
(cmd = replace(cmd, opt_B => "")) # Dont plot axes for plain images if that was not required
sim = (!has_opt_B && isa(arg1, GMTimage) && (isimgsize(arg1) || CTRL.limits[1:4] == zeros(4)) && opt_B == DEF_FIG_AXES_BAK)
if (!sim && cmd0 !== "" && !has_opt_B)
sim = (lowercase(splitext(cmd0)[2]) in [".jpg", ".jpeg", ".png", ".bmp", ".webp"])
end
sim && (cmd = replace(cmd, opt_B => ""))

cmd, = parse_common_opts(d, cmd, [:UVXY :params :margin :c :f :n :p :t]; first=!O)
cmd = parse_these_opts(cmd, d, [[:A :img_out :image_out], [:D :img_in :image_in], [:E :dpi], [:G :bit_color],
Expand All @@ -122,21 +109,6 @@ function _grdimage(cmd0::String, arg1, arg2, arg3, O::Bool, K::Bool, d::Dict)
end
end

#=
if (isa(arg1, Matrix{<:Real}) || isa(arg1, Array{<:Real,3}))
if (isa(arg1, Matrix{UInt8}) || isa(arg1, Matrix{UInt16}) || isa(arg1, Array{UInt8,3}))
arg1 = mat2img(arg1; d...)
else
arg1 = mat2grid(arg1)
(isa(arg2, Matrix{<:Real})) && (arg2 = mat2grid(arg2))
(isa(arg3, Matrix{<:Real})) && (arg3 = mat2grid(arg3))
end
elseif (isa(arg1, GMTimage) && size(arg1, 3) <= 3 && eltype(arg1.image) <: UInt16)
arg1 = mat2img(arg1; d...)
(haskey(d, :stretch) || haskey(d, :histo_bounds)) && delete!(d, [:histo_bounds, :stretch])
end
=#

set_defcpt!(d, cmd0, arg1) # When dealing with a remote grid assign it a default CPT
(isa(arg1, GMTgrid) && arg1.cpt != "") && (d[:this_cpt] = arg1.cpt)
(haskey(d, :this_cpt) && isfile(d[:this_cpt])) && (CURRENT_CPT[] = gmtread(d[:this_cpt]))
Expand Down
94 changes: 94 additions & 0 deletions src/montage.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
export montage

# This file was initially created by Claude and still needs lots of cleanings.


# ------------------------------------------------------------------------------------------
"""
montage(images; kwargs...)

Display multiple images arranged in a grid using GMT's subplot.

### Arguments
- `images`: Vector of GMTimage/GMTgrid objects, filenames, or a 3D/4D array.

### Keywords
- `grid`: Tuple (nrows, ncols) specifying grid dimensions. Default: approximately square.
- `panels_size`: Size of each panel in cm, e.g. `5` or `(5, 4)`. Default: auto.
- `margin`: Margin between panels. Default: "0.1c"
- `title`: Overall figure title.
- `titles`: Vector of titles for each panel.
- `frame`: Frame setting for panels. Default: :none
- `indices`: Vector of indices selecting which images to display.
- `show`: Display the result. Default: true.
- `savefig`: Filename to save the montage.

### Example
```julia
# From files
montage(["img1.png", "img2.png", "img3.png", "img4.png"], grid=(2,2))

# From GMTimage array with titles
imgs = [gmtread("img\$i.png") for i in 1:6]
montage(imgs, grid=(2,3), titles=["A","B","C","D","E","F"], panels_size=5)

# From 3D array
montage(rand(UInt8, 64, 64, 9), grid=(3,3), margin="0.2c")
```
"""
function montage(images; grid=nothing, panels_size=nothing, margin="0.0c",
title=nothing, titles=nothing, frame=:none, indices=nothing,
show::Bool=true, noR::Bool=false, kw...)

(indices !== nothing) && (images = images[indices]) # Apply indices selection
((n = length(images)) == 0) && error("No images to display")
nrows, ncols = _montage_grid_size(n, grid) # Calculate grid dimensions

# Build subplot options
subplot_kw = Dict{Symbol, Any}(:grid => (nrows, ncols), :margin => margin, :frame => frame)

if panels_size !== nothing
subplot_kw[:panels_size] = panels_size
else # Auto size based on grid
ps = max(3, min(8, 18 / max(nrows, ncols)))
subplot_kw[:panels_size] = ps
end

title !== nothing && (subplot_kw[:title] = title)

# Merge additional kwargs
for (k, v) in kw
subplot_kw[k] = v
end
subplot_kw[:Vd] = 1

subplot(; subplot_kw...) # Create subplot

# Plot each image
k = 0
for row in 1:nrows
for col in 1:ncols
k += 1
panel_title = (titles !== nothing && k <= length(titles)) ? titles[k] : nothing
opt_R = isa(images[k], GItype) ? (noR ? "" : getR(images[k])) : ""
viz(images[k], panel=(row, col), title=panel_title, R=(opt_R !== "" ? opt_R : nothing), Vd=1, show=false)
#grdimage(images[k], panel=(row, col), title=panel_title, R=(opt_R !== "" ? opt_R : nothing), Vd=1, show=false)
end
end
subplot(show ? :show : :end) # End subplot

return nothing
end

# Calculate grid dimensions
function _montage_grid_size(n, size)
if size === nothing || all(x -> x === nothing || x == 0 || (isa(x, AbstractFloat) && isnan(x)), size)
ncols = ceil(Int, sqrt(n))
nrows = ceil(Int, n / ncols)
else
nrows, ncols = size
(nrows == 0 || (isa(nrows, AbstractFloat) && isnan(nrows))) && (nrows = ceil(Int, n / ncols))
(ncols == 0 || (isa(ncols, AbstractFloat) && isnan(ncols))) && (ncols = ceil(Int, n / nrows))
end
return Int(nrows), Int(ncols)
end
1 change: 1 addition & 0 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1769,3 +1769,4 @@ end

include("getdcw.jl")
include("choropleth.jl")
include("montage.jl")
Loading