Range step cannot be zero

I don’t know how to make a minimal reproducer of this but I can’t make it work either. Here’s the error I can share. Any ideas would be helpful. I’m trying to make a Band plot but all the high values are equal and all the low values are equal.

ERROR: LoadError: ArgumentError: range step cannot be zero
Stacktrace:
  [1] (::Colon)(start::Float32, step::Float32, stop::Float32)
    @ Base ./twiceprecision.jl:387
  [2] get_minor_tickvalues(i::IntervalsBetween, scale::Function, tickvalues::Vector{Float32}, vmin::Float32, vmax::Float32)
    @ Makie.MakieLayout ~/.julia/packages/Makie/c5WJV/src/makielayout/lineaxis.jl:606
  [3] (::Makie.MakieLayout.var"#177#208"{Observable{Vector{Float32}}, Observable{Any}, Attributes})(tickvalues::Vector{Float32}, minorticks::IntervalsBetween)
    @ Makie.MakieLayout ~/.julia/packages/Makie/c5WJV/src/makielayout/lineaxis.jl:251
  [4] (::Observables.OnUpdate{Makie.MakieLayout.var"#177#208"{Observable{Vector{Float32}}, Observable{Any}, Attributes}, Tuple{Observable{Vector{Float32}}, Observable{Any}}})(#unused#::Vector{Float64})
    @ Observables ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:298
  [5] setindex!(observable::Observable{Vector{Float32}}, val::Vector{Float64}; notify::Observables.var"#9#11")
    @ Observables ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:205
  [6] setindex!
    @ ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:201 [inlined]
  [7] (::Makie.MakieLayout.var"#173#204"{Observable{Vector{String}}, Observable{Vector{Point{2, Float32}}}, Observable{Vector{Float32}}, Observable{Tuple{Float32, Tuple{Float32, Float32}, Bool}}, Observable{Any}, Attributes})(tickvalues_labels_unfiltered::Tuple{Vector{Float64}, Vector{String}}, reversed::Bool)
    @ Makie.MakieLayout ~/.julia/packages/Makie/c5WJV/src/makielayout/lineaxis.jl:226
  [8] (::Observables.OnUpdate{Makie.MakieLayout.var"#173#204"{Observable{Vector{String}}, Observable{Vector{Point{2, Float32}}}, Observable{Vector{Float32}}, Observable{Tuple{Float32, Tuple{Float32, Float32}, Bool}}, Observable{Any}, Attributes}, Tuple{Observable{Tuple{Vector{Float64}, Vector{String}}}, Observable{Any}}})(#unused#::Tuple{Vector{Float64}, Vector{String}})
    @ Observables ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:298
  [9] setindex!(observable::Observable{Tuple{Vector{Float64}, Vector{String}}}, val::Tuple{Vector{Float64}, Vector{String}}; notify::Observables.var"#9#11")
    @ Observables ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:205
 [10] setindex!(observable::Observable{Tuple{Vector{Float64}, Vector{String}}}, val::Tuple{Vector{Float64}, Vector{String}})
    @ Observables ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:201
 [11] (::Observables.MapUpdater{Makie.MakieLayout.var"#172#203", Tuple{Vector{Float64}, Vector{String}}})(::Tuple{Float32, Tuple{Float32, Float32}, Bool}, ::Vararg{Any, N} where N)
    @ Observables ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:331
 [12] (::Observables.OnUpdate{Observables.MapUpdater{Makie.MakieLayout.var"#172#203", Tuple{Vector{Float64}, Vector{String}}}, Tuple{Observable{Tuple{Float32, Tuple{Float32, Float32}, Bool}}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}}})(#unused#::Tuple{Float32, Float32})
    @ Observables ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:298
 [13] setindex!(observable::Observable{Any}, val::Tuple{Float32, Float32}; notify::Observables.var"#9#11")
    @ Observables ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:205
 [14] setindex!
    @ ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:201 [inlined]
 [15] (::Observables.var"#3#4"{Any, Observable{Any}})(value::Tuple{Float32, Float32})
    @ Observables ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:46
 [16] #invokelatest#2
    @ ./essentials.jl:708 [inlined]
 [17] invokelatest
    @ ./essentials.jl:706 [inlined]
 [18] setindex!(observable::Observable{Tuple{Float32, Float32}}, val::Tuple{Float32, Float32}; notify::Observables.var"#9#11")
    @ Observables ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:207
 [19] setindex!
    @ ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:201 [inlined]
 [20] MapUpdater
    @ ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:331 [inlined]
 [21] (::Observables.OnUpdate{Observables.MapUpdater{typeof(Makie.MakieLayout.ylimits), Tuple{Float32, Float32}}, Tuple{Observable{GeometryBasics.HyperRectangle{2, Float32}}}})(#unused#::GeometryBasics.HyperRectangle{2, Float32})
    @ Observables ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:298
 [22] setindex!(observable::Observable{GeometryBasics.HyperRectangle{2, Float32}}, val::GeometryBasics.HyperRectangle{2, Float32}; notify::Observables.var"#9#11")
    @ Observables ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:205
 [23] setindex!
    @ ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:201 [inlined]
 [24] adjustlimits!(la::Axis)
    @ Makie.MakieLayout ~/.julia/packages/Makie/c5WJV/src/makielayout/layoutables/axis.jl:901
 [25] #262
    @ ~/.julia/packages/Makie/c5WJV/src/makielayout/layoutables/axis.jl:438 [inlined]
 [26] (::Observables.OnUpdate{Makie.MakieLayout.var"#262#294"{Axis}, Tuple{Observable{GeometryBasics.HyperRectangle{2, Int64}}, Observable{GeometryBasics.HyperRectangle{2, Float32}}}})(#unused#::GeometryBasics.HyperRectangle{2, Float32})
    @ Observables ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:298
 [27] setindex!(observable::Observable{GeometryBasics.HyperRectangle{2, Float32}}, val::GeometryBasics.HyperRectangle{2, Float32}; notify::Observables.var"#9#11")
    @ Observables ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:205
 [28] setindex!
    @ ~/.julia/packages/Observables/Yf3xU/src/Observables.jl:201 [inlined]
 [29] reset_limits!(ax::Axis; xauto::Bool, yauto::Bool, zauto::Bool)
    @ Makie.MakieLayout ~/.julia/packages/Makie/c5WJV/src/makielayout/layoutables/axis.jl:532
 [30] reset_limits!
    @ ~/.julia/packages/Makie/c5WJV/src/makielayout/layoutables/axis.jl:457 [inlined]
 [31] plot!(::Axis, ::Type{Lines{ArgType} where ArgType}, ::Attributes, ::Vector{Float64}, ::Vararg{Vector{Float64}, N} where N; kw_attributes::Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ Makie.MakieLayout ~/.julia/packages/Makie/c5WJV/src/makielayout/layoutables/axis.jl:649
 [32] plot!
    @ ~/.julia/packages/Makie/c5WJV/src/makielayout/layoutables/axis.jl:638 [inlined]
 [33] #plot!#311
    @ ~/.julia/packages/Makie/c5WJV/src/makielayout/layoutables/axis.jl:655 [inlined]
 [34] plot!(ae::AxisEntries)
    @ AlgebraOfGraphics ~/.julia/packages/AlgebraOfGraphics/3zSL9/src/entries.jl:117
 [35] foreach(f::typeof(plot!), itr::Matrix{AxisEntries})
    @ Base ./abstractarray.jl:2141
 [36] plot!(fig::Figure, s::AlgebraOfGraphics.Layer; axis::NamedTuple{(), Tuple{}}, palettes::NamedTuple{(), Tuple{}})
    @ AlgebraOfGraphics ~/.julia/packages/AlgebraOfGraphics/3zSL9/src/algebra/layers.jl:151
 [37] plot(s::AlgebraOfGraphics.Layer; axis::NamedTuple{(), Tuple{}}, figure::NamedTuple{(), Tuple{}}, palettes::NamedTuple{(), Tuple{}})
    @ AlgebraOfGraphics ~/.julia/packages/AlgebraOfGraphics/3zSL9/src/algebra/layers.jl:158
 [38] draw(s::AlgebraOfGraphics.Layer; axis::NamedTuple{(), Tuple{}}, figure::NamedTuple{(), Tuple{}}, palettes::NamedTuple{(), Tuple{}})
    @ AlgebraOfGraphics ~/.julia/packages/AlgebraOfGraphics/3zSL9/src/algebra/layers.jl:173
 [39] draw(s::AlgebraOfGraphics.Layer)

The code is something like this, except this doesn’t error.

data((x=[10., 20., 30., 40.], low=[1., 1., 1., 1.], high=[2., 2., 2., 2.], grp=['a','b', 'a', 'b'])) * 
mapping(:x, :low, :high, row=:grp) *
visual(Band) |> draw
1 Like

This is fixed in the upcoming version 1.7, where the step is allowed to be zero, if I remember correctly.

What would be the use case for step zero?

Having a “zero instance” or “empty instance” of a type is generally useful for handling the trivial case of an algorithm without special-casing it.

Instead of saying “if it’s empty, return; otherwise do such&such to each element” I can say “do such&such to each element”, and it will automatically handle the empty case.

But step zero does not advance!? So what should happen?

I haven’t tried it on 1.7, but

julia> collect(5:0:5)

could be an empty vector Int[].

I think it should be [5]. 5:1:5 is 5, isn’t it? So, if lower end is the same as the upper end of the range, there needs to be no advance. I think this is the only case where zero step makes sense?

Well, it also makes f(x) = x .* (1:3) == x .* [1,2,3] true for any finite x, including zero. Which means you can use lazy ranges in more places.

But the colon constructor, I guess 5:0:5 could have length 1, but what length does 5:0:6 have? Neither is defined in 1.7.

So it won’t solve OP’s plotting problem. It looks a bit like it’s trying to make evenly spaced ticks over no range. Can you tell it the limits of the y-axis manually, something like that?

1 Like

Good point.

This is usually caused by float32 conversion of values that are so close together that they have zero distance afterwards, and this messes with the limits calculation. The only option you have right now is to scale your data into a range that Float32 can represent better

3 Likes

Truncating the array to Float16 saves the world:

julia> a = [31.999999051331837, 31.99999905020038, 31.99999904907261, 31.999999047948524, 31.99999904682809, 31.99999904571132, 31.999999044598198, 31.999999043488696, 31.999999042382818, 31.999999041280553, 31.99999904018189]
11-element Vector{Float64}:
 31.999999051331837
 31.99999905020038
 31.99999904907261
 31.999999047948524
 31.99999904682809
 31.99999904571132
 31.999999044598198
 31.999999043488696
 31.999999042382818
 31.999999041280553
 31.99999904018189

julia> Makie.lines(a)
Error showing value of type Makie.FigureAxisPlot:
ERROR: ArgumentError: range step cannot be zero
...

julia> Makie.lines(Float32.(a))
Error showing value of type Makie.FigureAxisPlot:
ERROR: ArgumentError: range step cannot be zero
...

julia> Makie.lines(Float16.(a))
#! It works!

Related issue: Plotting fails only for specific range · Issue #931 · JuliaPlots/Makie.jl · GitHub