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

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

1 Like