Repository: JuliaPlots/Makie.jl (julia)

Issue:
ylims! is undocumented
`ylims!` is exported but undocumented. Documentation would be helpful.

Pull request:
# Description

Fixes #3240 
Fixes #2618 

Fixes `xlims!` and `ylims!` on an Axis that is initialized with `limits=(x1,x2,y1,y2)`. Also fixes the same bug with Axis3. Includes new tests to cover this situation.

Also adds docstrings for `xlims!`, `ylims!`, `zlims!` and `hidezdecorations!` and fixes a couple of other docstrings.

This also fixes `xlims!(ax)`. I think the intention was for this to reset the limits to be automatic, but it was throwing an error because the limits were the same (`nothing`).

## Type of change

Delete options that do not apply:

- [X] Bug fix (non-breaking change which fixes an issue)

## Checklist

- [ ] Added an entry in NEWS.md (for new features and breaking changes)
- [ ] Added or changed relevant sections in the documentation
- [X] Added unit tests
- [ ] Added reference image tests for new plotting functions, recipes, visual options, etc.

Patch:
diff --git a/src/makielayout/blocks/axis.jl b/src/makielayout/blocks/axis.jl
index 71e117ef2eb..f2bdd3d7266 100644
--- a/src/makielayout/blocks/axis.jl
+++ b/src/makielayout/blocks/axis.jl
@@ -1210,6 +1210,8 @@ function tight_xticklabel_spacing!(ax::Axis)
 end
 
 """
+    tight_ticklabel_spacing(ax::Axis)
+
 Sets the space allocated for the xticklabels and yticklabels of the `Axis` to the minimum that is needed.
 """
 function tight_ticklabel_spacing!(ax::Axis)
@@ -1235,7 +1237,7 @@ end
 function Makie.xlims!(ax::Axis, xlims)
     if length(xlims) != 2
         error("Invalid xlims length of $(length(xlims)), must be 2.")
-    elseif xlims[1] == xlims[2]
+    elseif xlims[1] == xlims[2] && xlims[1] !== nothing
         error("Can't set x limits to the same value $(xlims[1]).")
     elseif all(x -> x isa Real, xlims) && xlims[1] > xlims[2]
         xlims = reverse(xlims)
@@ -1243,8 +1245,9 @@ function Makie.xlims!(ax::Axis, xlims)
     else
         ax.xreversed[] = false
     end
+    mlims = convert_limit_attribute(ax.limits[])
 
-    ax.limits.val = (xlims, ax.limits[][2])
+    ax.limits.val = (xlims, mlims[2])
     reset_limits!(ax, yauto = false)
     nothing
 end
@@ -1252,7 +1255,7 @@ end
 function Makie.ylims!(ax::Axis, ylims)
     if length(ylims) != 2
         error("Invalid ylims length of $(length(ylims)), must be 2.")
-    elseif ylims[1] == ylims[2]
+    elseif ylims[1] == ylims[2] && ylims[1] !== nothing
         error("Can't set y limits to the same value $(ylims[1]).")
     elseif all(x -> x isa Real, ylims) && ylims[1] > ylims[2]
         ylims = reverse(ylims)
@@ -1260,22 +1263,95 @@ function Makie.ylims!(ax::Axis, ylims)
     else
         ax.yreversed[] = false
     end
+    mlims = convert_limit_attribute(ax.limits[])
 
-    ax.limits.val = (ax.limits[][1], ylims)
+    ax.limits.val = (mlims[1], ylims)
     reset_limits!(ax, xauto = false)
     nothing
 end
 
+"""
+    xlims!(ax, low, high)
+    xlims!(ax; low = nothing, high = nothing)
+    xlims!(ax, xlims)
+
+Set the x-axis limits of axis `ax` to `low` and `high` or a tuple
+`xlims = (low,high)`. If the limits are ordered high-low, the axis orientation
+will be reversed. If a limit is `nothing` it will be determined automatically
+from the plots in the axis.
+"""
 Makie.xlims!(ax, low, high) = Makie.xlims!(ax, (low, high))
+"""
+    ylims!(ax, low, high)
+    ylims!(ax; low = nothing, high = nothing)
+    ylims!(ax, ylims)
+
+Set the y-axis limits of axis `ax` to `low` and `high` or a tuple
+`ylims = (low,high)`. If the limits are ordered high-low, the axis orientation
+will be reversed. If a limit is `nothing` it will be determined automatically
+from the plots in the axis.
+"""
 Makie.ylims!(ax, low, high) = Makie.ylims!(ax, (low, high))
+"""
+    zlims!(ax, low, high)
+    zlims!(ax; low = nothing, high = nothing)
+    zlims!(ax, zlims)
+
+Set the z-axis limits of axis `ax` to `low` and `high` or a tuple
+`zlims = (low,high)`. If the limits are ordered high-low, the axis orientation
+will be reversed. If a limit is `nothing` it will be determined automatically
+from the plots in the axis.
+"""
 Makie.zlims!(ax, low, high) = Makie.zlims!(ax, (low, high))
 
+"""
+    xlims!(low, high)
+    xlims!(; low = nothing, high = nothing)
+
+Set the x-axis limits of the current axis to `low` and `high`. If the limits
+are ordered high-low, this reverses the axis orientation. A limit set to
+`nothing` will be determined automatically from the plots in the axis.
+"""
 Makie.xlims!(low::Optional{<:Real}, high::Optional{<:Real}) = Makie.xlims!(current_axis(), low, high)
+"""
+    ylims!(low, high)
+    ylims!(; low = nothing, high = nothing)
+
+Set the y-axis limits of the current axis to `low` and `high`. If the limits
+are ordered high-low, this reverses the axis orientation. A limit set to
+`nothing` will be determined automatically from the plots in the axis.
+"""
 Makie.ylims!(low::Optional{<:Real}, high::Optional{<:Real}) = Makie.ylims!(current_axis(), low, high)
+"""
+    zlims!(low, high)
+    zlims!(; low = nothing, high = nothing)
+
+Set the z-axis limits of the current axis to `low` and `high`. If the limits
+are ordered high-low, this reverses the axis orientation. A limit set to
+`nothing` will be determined automatically from the plots in the axis.
+"""
 Makie.zlims!(low::Optional{<:Real}, high::Optional{<:Real}) = Makie.zlims!(current_axis(), low, high)
 
+"""
+    xlims!(ax = current_axis())
+
+Reset the x-axis limits to be determined automatically from the plots in the
+axis.
+"""
 Makie.xlims!(ax = current_axis(); low = nothing, high = nothing) = Makie.xlims!(ax, low, high)
+"""
+    ylims!(ax = current_axis())
+
+Reset the y-axis limits to be determined automatically from the plots in the
+axis.
+"""
 Makie.ylims!(ax = current_axis(); low = nothing, high = nothing) = Makie.ylims!(ax, low, high)
+"""
+    zlims!(ax = current_axis())
+
+Reset the z-axis limits to be determined automatically from the plots in the
+axis.
+"""
 Makie.zlims!(ax = current_axis(); low = nothing, high = nothing) = Makie.zlims!(ax, low, high)
 
 """
diff --git a/src/makielayout/blocks/axis3d.jl b/src/makielayout/blocks/axis3d.jl
index b96f840efc8..525c009dd98 100644
--- a/src/makielayout/blocks/axis3d.jl
+++ b/src/makielayout/blocks/axis3d.jl
@@ -775,6 +775,12 @@ function hideydecorations!(ax::Axis3;
     ax
 end
 
+"""
+    hidezdecorations!(la::Axis; label = true, ticklabels = true, ticks = true, grid = true,
+        minorgrid = true, minorticks = true)
+
+Hide decorations of the z-axis: label, ticklabels, ticks and grid.
+"""
 function hidezdecorations!(ax::Axis3;
     label = true, ticklabels = true, ticks = true, grid = true)
 
@@ -877,7 +883,7 @@ end
 function Makie.xlims!(ax::Axis3, xlims::Tuple{Union{Real, Nothing}, Union{Real, Nothing}})
     if length(xlims) != 2
         error("Invalid xlims length of $(length(xlims)), must be 2.")
-    elseif xlims[1] == xlims[2]
+    elseif xlims[1] == xlims[2] && xlims[1] !== nothing
         error("Can't set x limits to the same value $(xlims[1]).")
     elseif all(x -> x isa Real, xlims) && xlims[1] > xlims[2]
         xlims = reverse(xlims)
@@ -885,8 +891,9 @@ function Makie.xlims!(ax::Axis3, xlims::Tuple{Union{Real, Nothing}, Union{Real,
     else
         ax.xreversed[] = false
     end
+    mlims = convert_limit_attribute(ax.limits[])
 
-    ax.limits.val = (xlims, ax.limits[][2], ax.limits[][3])
+    ax.limits.val = (xlims, mlims[2], mlims[3])
     reset_limits!(ax, yauto = false, zauto = false)
     nothing
 end
@@ -894,7 +901,7 @@ end
 function Makie.ylims!(ax::Axis3, ylims::Tuple{Union{Real, Nothing}, Union{Real, Nothing}})
     if length(ylims) != 2
         error("Invalid ylims length of $(length(ylims)), must be 2.")
-    elseif ylims[1] == ylims[2]
+    elseif ylims[1] == ylims[2] && ylims[1] !== nothing
         error("Can't set y limits to the same value $(ylims[1]).")
     elseif all(x -> x isa Real, ylims) && ylims[1] > ylims[2]
         ylims = reverse(ylims)
@@ -902,8 +909,9 @@ function Makie.ylims!(ax::Axis3, ylims::Tuple{Union{Real, Nothing}, Union{Real,
     else
         ax.yreversed[] = false
     end
+    mlims = convert_limit_attribute(ax.limits[])
 
-    ax.limits.val = (ax.limits[][1], ylims, ax.limits[][3])
+    ax.limits.val = (mlims[1], ylims, mlims[3])
     reset_limits!(ax, xauto = false, zauto = false)
     nothing
 end
@@ -911,25 +919,26 @@ end
 function Makie.zlims!(ax::Axis3, zlims)
     if length(zlims) != 2
         error("Invalid zlims length of $(length(zlims)), must be 2.")
-    elseif zlims[1] == zlims[2]
-        error("Can't set y limits to the same value $(zlims[1]).")
+    elseif zlims[1] == zlims[2] && zlims[1] !== nothing
+        error("Can't set z limits to the same value $(zlims[1]).")
     elseif all(x -> x isa Real, zlims) && zlims[1] > zlims[2]
         zlims = reverse(zlims)
         ax.zreversed[] = true
     else
         ax.zreversed[] = false
     end
+    mlims = convert_limit_attribute(ax.limits[])
 
-    ax.limits.val = (ax.limits[][1], ax.limits[][2], zlims)
+    ax.limits.val = (mlims[1], mlims[2], zlims)
     reset_limits!(ax, xauto = false, yauto = false)
     nothing
 end
 
 
 """
-    limits!(ax::Axis3, xlims, ylims)
+    limits!(ax::Axis3, xlims, ylims, zlims)
 
-Set the axis limits to `xlims` and `ylims`.
+Set the axis limits to `xlims`, `ylims`, and `zlims`.
 If limits are ordered high-low, this reverses the axis orientation.
 """
 function limits!(ax::Axis3, xlims, ylims, zlims)
@@ -941,7 +950,8 @@ end
 """
     limits!(ax::Axis3, x1, x2, y1, y2, z1, z2)
 
-Set the axis x-limits to `x1` and `x2` and the y-limits to `y1` and `y2`.
+Set the axis x-limits to `x1` and `x2`, the y-limits to `y1` and `y2`, and the
+z-limits to `z1` and `z2`.
 If limits are ordered high-low, this reverses the axis orientation.
 """
 function limits!(ax::Axis3, x1, x2, y1, y2, z1, z2)


Test patch:
diff --git a/test/makielayout.jl b/test/makielayout.jl
index 4366a1081ff..29f2335bf26 100644
--- a/test/makielayout.jl
+++ b/test/makielayout.jl
@@ -115,6 +115,47 @@ end
     @test ax.finallimits[] == BBox(-5, 11, 5, 7)
 end
 
+# issue 3240
+@testset "Axis limits 4-tuple" begin
+    fig = Figure()
+    ax = Axis(fig[1,1],limits=(0,600,0,15))
+    xlims!(ax,100,400)
+    @test ax.limits[] == ((100,400),(0,15))
+    xlims!()
+    @test ax.limits[] == ((nothing,nothing),(0,15))
+
+    ax = Axis(fig[1,1],limits=(0,600,0,15))
+    ylims!(ax,1,13)
+    @test ax.limits[] == ((0,600),(1,13))
+    ylims!()
+    @test ax.limits[] == ((0,600),(nothing,nothing))
+
+    ax = Axis(fig[1,1],limits=(0,600,0,15))
+    limits!(ax,350,700,2,14)
+    @test ax.limits[] == ((350,700),(2,14))
+end
+
+@testset "Axis3 limits 6-tuple" begin
+    fig = Figure()
+    ax = Axis3(fig[1,1],limits=(0,1,0,2,0,3))
+    xlims!(ax,1,2)
+    @test ax.limits[] == ((1,2),(0,2),(0,3))
+    xlims!()
+    @test ax.limits[] == ((nothing,nothing),(0,2),(0,3))
+
+    ax = Axis3(fig[1,1],limits=(0,1,0,2,0,3))
+    ylims!(ax,1,3)
+    @test ax.limits[] == ((0,1),(1,3),(0,3))
+    ylims!()
+    @test ax.limits[] == ((0,1),(nothing,nothing),(0,3))
+
+    ax = Axis3(fig[1,1],limits=(0,1,0,2,0,3))
+    zlims!(ax,1,5)
+    @test ax.limits[] == ((0,1),(0,2),(1,5))
+    zlims!()
+    @test ax.limits[] == ((0,1),(0,2),(nothing,nothing))
+end
+
 @testset "Colorbar plot object kwarg clash" begin
     for attr in (:colormap, :limits)
         f, ax, p = scatter(1:10, 1:10, color = 1:10, colorrange = (1, 10))