Println and ProgressMeter in the same loop

I am trying to combine println (or @info for logging) and a ProgressMeter progress bar in a loop like this:

using ProgressMeter
prog = Progress(10)
for i in 1:10
    println("value: ", i^2)
    sleep(0.1)
    next!(prog)
end

But the output is not as nice as it could be:

value: 1
Progress:  10%|████▏                                    |  ETA: 0:00:01value: 4
Progress:  20%|████████▎                                |  ETA: 0:00:01value: 9
Progress:  30%|████████████▎                            |  ETA: 0:00:01value: 16
Progress:  40%|████████████████▍                        |  ETA: 0:00:01value: 25
Progress:  50%|████████████████████▌                    |  ETA: 0:00:01value: 36
Progress:  60%|████████████████████████▋                |  ETA: 0:00:00value: 49
Progress:  70%|████████████████████████████▊            |  ETA: 0:00:00value: 64
Progress:  80%|████████████████████████████████▊        |  ETA: 0:00:00value: 81
Progress:  90%|████████████████████████████████████▉    |  ETA: 0:00:00value: 100
Progress: 100%|█████████████████████████████████████████| Time: 0:00:01

Is it possible to get the output to look as follows (with a single progress bar always at the bottom of the screen)?

value: 1
value: 4
value: 9
value: 16
Progress:  40%|████████████████▍                        |  ETA: 0:00:01

Why don’t you use ProgressMeter’s ability to add extra info, it’s made for this:

2 Likes

I considered this but the information is not printed on every iteration (it depends on some conditionals elsewhere in the loop and there is more than one message). Also, I would like the printed output to go to a log file and for the message to remain on screen instead of being replaced when the progress bar is updated.

The actual use case is more like this:

prog = Progress(10)
for i in 1:10
    if i == 5
        println("value: ", i^2, " this is a message")
    end
    sleep(0.1)
    next!(prog)
end

and this is the curent output:

Progress:  40%|████████████████▍                        |  ETA: 0:00:01value: 25 this is a message
Progress: 100%|█████████████████████████████████████████| Time: 0:00:01

but I would prefer this:

value: 25 this is a message
Progress:  40%|████████████████▍                        |  ETA: 0:00:01

A bit of carriage-return trickery and filling your terminal with spaces via rpad() is probably the easiest way of doing this yourself. Using displaysize() to get the width of your terminal is needed unless there is another way to query how wide the progress meter is. (I haven’t used ProgressMeter.jl myself.)

prog = Progress(10)
for i in 1:10
    if i == 5
        println(rpad("\rvalue: $(i^2) this is a message",
                displaysize(stdout)[2]))
    end
    sleep(0.1)
    next!(prog)
end

I guess if this output is a common desire, submitting a feature request issue to ProgressMeter.jl or even submitting a PR would be welcome.

1 Like

This works quite well except that the carriage return \r is written to the log file. Also I needed to make the progress bar slightly narrower because the logging prefix requires some space (I’m using the Memento package).

I wrapped the logging macro in a function to make it easier to use in multiple places:

rpadinfo(s) = @info rpad("\r"*s, displaysize(stdout)[2])