JuliaLang / Pkg.jl

Pkg - Package manager for the Julia programming language
https://pkgdocs.julialang.org
Other
625 stars 268 forks source link

smoothen progress bar #4038

Closed KristofferC closed 3 weeks ago

KristofferC commented 4 weeks ago

After suggestion by @tecosaur, also use the heavy right box drawing character. Can be tested with:

function test_progress(n, dt)
   io = stdout
   bar = Pkg.MiniProgressBars.MiniProgressBar(; indent=1, header = "Downloading packages", color = Base.info_color(),
                                    mode=:int, always_reprint=true)
   bar.max = n
   for i in 1:n
      bar.current = i
      Pkg.MiniProgressBars.show_progress(io, bar)
      sleep(dt)
   end
end

Doing something like test_progress(1000, 0.001) shows some difference vs the old behavior.

tecosaur commented 4 weeks ago

Nice! To engage in some blatant scope-creep, I've been thinking it would be nice for the bar to also show the packages currently being precompiled, with something like this:

image

Similarly, I think it could be fun to show the proportion that error/warn with a red/yellow bar, like so:

image

To actually help instead of keeping on repeating "this would be nice", I've put together what I think's actually a fairly nice function for displaying multi-segment progress bars.

"""
    multibar(io::IO, specs::Vector{<:Pair{Symbol, <:Real}}, width::Int=30)

Print a bar of certain `width` to `io`, split into segments according to `specs`.

Each element of `specs` is a pair `(color, weight)`, where `color` is
a named color recognised by `printstyled` and `weight` is a number.

Each segment is draw with a width proportional to its weight.

All segments with a non-zero weight are drawn.
"""
function multibar(io::IO, specs::Vector{<:Pair{Symbol, <:Real}}, width::Int=min(30, last(displaysize(io))))
    bars = (whole='━', lpart='╺', rpart='╸')
    specs = filter(s -> last(s) > 0, specs)
    isempty(specs) && return
    totalhalves = 2 * width - length(specs) + 1
    duowidth = totalhalves / sum(last, specs, init=0)
    halfwidths = [max(1, round(Int, weight * duowidth)) for (_, weight) in specs]
    widthdiff = sum(halfwidths) - totalhalves
    if widthdiff != 0
        rawproportions = map(last, specs) / sum(last, specs)
        stolenweights = ones(float(Int), length(halfwidths))
        while widthdiff != 0
            change = sign(widthdiff)
            i = argmax(rawproportions .* stolenweights)
            halfwidths[i] -= change
            stolenweights[i] = 1 - 1 / (1 + stolenweights[i])
            widthdiff -= change
        end
    end
    partial = false
    for ((color, _), halves) in zip(specs, halfwidths)
        partial && printstyled(io, bars.lpart; color)
        nbars = (halves - partial) ÷ 2
        partial = iszero(halves - partial - 2 * nbars)
        printstyled(io, bars.whole^nbars; color)
        !partial && printstyled(io, bars.rpart; color)
    end
end

What do you think?

KristofferC commented 4 weeks ago

I personally am not sure I like it so much because it becomes confusing when the progress bar double dips as progress and as a counter. To me it looks like the red part is anither progress overplayed the green one and is supposed to progress all the way to the right. Just my initial thoughts.

I'd rather have some numerical counters to show number of failed precompiles etc.

tecosaur commented 4 weeks ago

I find it difficult to see as double dipping. Ultimately a progress bar is just a visual representation of category sizes. Often there are two categories: "done" and "not done", and Pkg could keep with that but I think it could also expand without becoming confusing. Red xs and yellow warnings are already shown in the list of packages, so to me this proposal seems like a natural extension.

While segmented state bars may not be particularly common, I don't think they're rare either:

image

image

I feel like I've also seen these in a few task tracker apps/pages.

I actually see the current use of green checks put next to successfully precompiled packages as forming a natural association with the green section of the progress bar, and in that respect it's unintuitive that error/warn results also form part of the green progress bar.

KristofferC commented 4 weeks ago

While segmented state bars may not be particularly common, I don't think they're rare either:

But those aren't progress bars so then my double dip argument doesn't apply.

tecosaur commented 3 weeks ago

The line of thought I'm trying to articulate is that progress bars are just a special case of segmented state bars.

fredrikekre commented 3 weeks ago

I personally am not sure I like it so much because it becomes confusing when the progress bar double dips as progress and as a counter. To me it looks like the red part is anither progress overplayed the green one and is supposed to progress all the way to the right.

I agree. The extra grey bar for in progress ones would be fine though, since that will be eaten up by the green. On the other hand, it might not be obvious what it means so perhaps just the current thing is best.

tecosaur commented 3 weeks ago

Perhaps I'm overly optimistic, but I suspect that in practice it should be fairly intuitive to interpret since you don't just look at the progress bar by itself and have to guess what it means, you actually get the context of the precompile-log displayed underneath it.

Could it be would be worth whipping up a MWE and then asking some people who haven't seen this thread how much sense it makes/do they find it intuitive?

KristofferC commented 3 weeks ago

The line of thought I'm trying to articulate is that progress bars are just a special case of segmented state bars.

I disagree, the examples you showed are different in that they try to show how a whole (the code base, the hard drive, etc.) is divided into different categories. There is no progress toward completion and there isn't a continuous filling from left to right as time passes.

The extra grey bar for in progress ones would be fine though, since that will be eaten up by the green.

Okay, but do I really care to see in bar form how many packages are currently being precompiled out of a total? Like if I have two packages (out of two) that are currently precompiling the whole bar would be gray. It is giving the information "x% of packages out of the total number of packages I will precompile is currently precompiling" in a visual form. Even if it is intuitive it's a bit like "so what?"

tecosaur commented 3 weeks ago

I disagree, the examples you showed are different in that they try to show how a whole (the code base, the hard drive, etc.) is divided into different categories

...like the current progress bars, which split a number of packages up by state into "tried to precompile" and "haven't tried yet" :wink:

Okay, but do I really care to see in bar form how many packages are currently being precompiled out of a total?

It's just visual pizazz :shrug: I thought it could be nice, but it seems like I might be the odd one out.

KristofferC commented 3 weeks ago

...like the current progress bars, which split a number of packages up by state into "tried to precompile" and "haven't tried yet"

This is why I specifically emphasized the time and progress aspect, that we are watching something go from incomplete to complete. Anyway, I don't have much more to say about this.