Created
January 25, 2016 06:25
-
-
Save rougier/c0d31f5cbdaac27b876c to your computer and use it in GitHub Desktop.
A progress bar using unicode character for smoother display
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ----------------------------------------------------------------------------- | |
# Copyright (c) 2016, Nicolas P. Rougier | |
# Distributed under the (new) BSD License. | |
# ----------------------------------------------------------------------------- | |
import sys, math | |
def progress(value, length=40, title = " ", vmin=0.0, vmax=1.0): | |
""" | |
Text progress bar | |
Parameters | |
---------- | |
value : float | |
Current value to be displayed as progress | |
vmin : float | |
Minimum value | |
vmax : float | |
Maximum value | |
length: int | |
Bar length (in character) | |
title: string | |
Text to be prepend to the bar | |
""" | |
# Block progression is 1/8 | |
blocks = ["", "▏","▎","▍","▌","▋","▊","▉","█"] | |
vmin = vmin or 0.0 | |
vmax = vmax or 1.0 | |
lsep, rsep = "▏", "▕" | |
# Normalize value | |
value = min(max(value, vmin), vmax) | |
value = (value-vmin)/float(vmax-vmin) | |
v = value*length | |
x = math.floor(v) # integer part | |
y = v - x # fractional part | |
base = 0.125 # 0.125 = 1/8 | |
prec = 3 | |
i = int(round(base*math.floor(float(y)/base),prec)/base) | |
bar = "█"*x + blocks[i] | |
n = length-len(bar) | |
bar = lsep + bar + " "*n + rsep | |
sys.stdout.write("\r" + title + bar + " %.1f%%" % (value*100)) | |
sys.stdout.flush() | |
# ----------------------------------------------------------------------------- | |
if __name__ == '__main__': | |
import time | |
for i in range(1000): | |
progress(i, vmin=0, vmax=999) | |
time.sleep(0.0025) | |
sys.stdout.write("\n") |
This is awesome! I've made myself a port to Javascript (es6) with a little add (progresive option):
//@ts-check
const progress = ({
value,
length=40,
title = " ",
vmin=0.0,
vmax=1.0,
progressive = false
}) => {
// Block progression is 1/8
const blocks = ["", "▏","▎","▍","▌","▋","▊","▉","█"]
const lsep = "▏", rsep = "▕"
// Normalize value
const normalized_value = (Math.min(Math.max(value, vmin), vmax)-vmin)/Number(vmax-vmin)
const v = normalized_value * length
const x = Math.floor(v) // integer part
const y = v - x // fractional part
const i = Math.round(y*8)
const bar = Array(x).fill("█").join("") + blocks[i]
const remaining = Array(length - bar.length).fill(" ").join("")
return `${lsep}${bar}${!progressive ? remaining : ""}${rsep} ${(Math.round(normalized_value * 100 * 100) / 100)}%`
}
let prevStr = ""
for (let i = 0; i < 1000; i++) {
prevStr = Array(prevStr.length).fill('\b').join('') + progress({value: i, vmin: 0, vmax: 999})
process.stderr.write(prevStr)
}
prevStr = ""
for (let i = 0; i < 1000; i++) {
prevStr = Array(prevStr.length).fill('\b').join('') + progress({value: i, vmin: 0, vmax: 999, progressive: true})
process.stderr.write(prevStr)
}
I wonder if this chokes on Python 2.7.12 or if I copied script wrong? I get this error:
Traceback (most recent call last):
File "./progress_bar2", line 54, in <module>
progress(i, vmin=0, vmax=999)
File "./progress_bar2", line 41, in progress
bar = "█"*x + blocks[i]
TypeError: can't multiply sequence by non-int of type 'float'
I did add two lines to the top of the script though:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
Any thoughts?
int(x)
instead of x
maybe.
Here it is in Java, not really tested too much but seems to work okay.
import static java.lang.Math.*;
public class ProgressBar {
private static final String[] blocks = new String[]{"", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█"};
private static final double base = 0.125;
/**
* Renders a unicode block-based progress bar.
*
* @param value Current value to be displayed as progress.
* @param vmin Minimum value, usually 0.0.
* @param vmax Maximum value, usually 1.0.
* @param length Length of the progress bar, in characters.
* @return A rendered progress bar.
* @author <a href="https://gist.github.com/rougier/c0d31f5cbdaac27b876c">rougier</a>
*/
public static String generateProgressBar(double value, double vmin, double vmax, int length) {
// normalize value
value = min(max(value, vmin), vmax);
value = (value - vmin) / (vmax - vmin);
double v = value * length;
int x = (int) floor(v); // integer part
double y = v - x; // fractional part
// round(base*math.floor(float(y)/base),prec)/base
int i = (int) ((round((base * floor(y / base)) * 1000D) / base) / 1000D);
String bar = "█".repeat(x) + blocks[i];
int n = length - bar.length();
return bar + " ".repeat(n);
}
}
I just published a version is Bash:
https://www.pippim.com/programs/iothings.html#change-primary-tv-volume
Above link shows a .gif of progress bar in action. Below is the code:
VolumeBar () {
Bar="" # Progress Bar / Volume level
Len=25 # Length of Progress Bar / Volume level
Div=4 # Divisor into Volume for # of full blocks
Fill="▒" # Fill background up to $Len
Parts=8 # Divisor into Volume for # of part blocks
# UTF-8 left blocks: 1, 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8
Arr=("█" "▏" "▎" "▍" "▌" "▋" "▊" "█")
FullBlock=$((${1} / Div)) # Number of full blocks
PartBlock=$((${1} % Parts)) # Size of partial block (array index)
while [[ $FullBlock -gt 0 ]]; do
Bar="$Bar${Arr[0]}" # Add 1 full block into Progress Bar
(( FullBlock-- )) # Decrement full blocks counter
done
# If remainder zero no partial block, else append character from array
if [[ $PartBlock -gt 0 ]]; then
Bar="$Bar${Arr[$PartBlock]}"
fi
while [[ "${#Bar}" -lt "$Len" ]]; do
Bar="$Bar$Fill" # Pad Progress Bar with fill character
done
} # VolumeBar
Thanks,
- Rick
…On Mon, Dec 26, 2022 at 1:12 PM Hayden ***@***.***> wrote:
***@***.**** commented on this gist.
------------------------------
Here it is in Java, not really tested too much but seems to work okay.
import static java.lang.Math.*;
public class ProgessBar {
private static final String[] blocks = new String[]{"", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█"};
private static final double base = 0.125;
/** * Renders a unicode block-based progress bar. * * @param value Current value to be displayed as progress. * @param vmin Minimum value, usually 0.0. * @param vmax Maximum value, usually 1.0. * @param length Length of the progress bar, in characters. * @return A rendered progress bar. * @author <a href="https://gist.github.com/rougier/c0d31f5cbdaac27b876c">rougier</a> */
public static String generateProgressBar(double value, double vmin, double vmax, int length) {
// normalize value
value = min(max(value, vmin), vmax);
value = (value - vmin) / (vmax - vmin);
double v = value * length;
int x = (int) floor(v); // integer part
double y = v - x; // fractional part
// round(base*math.floor(float(y)/base),prec)/base
int i = (int) ((round((base * floor(y / base)) * 1000D) / base) / 1000D);
String bar = "█".repeat(x) + blocks[i];
int n = length - bar.length();
return bar + " ".repeat(n);
}
}
—
Reply to this email directly, view it on GitHub
<https://gist.github.com/c0d31f5cbdaac27b876c#gistcomment-4414015> or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AICIBH527ZEBZGJD6MLZWHTWPH34VBFKMF2HI4TJMJ2XIZLTSKBKK5TBNR2WLJDHNFZXJJDOMFWWLK3UNBZGKYLEL52HS4DFQKSXMYLMOVS2I5DSOVS2I3TBNVS3W5DIOJSWCZC7OBQXE5DJMNUXAYLOORPWCY3UNF3GS5DZVRZXKYTKMVRXIX3UPFYGLK2HNFZXIQ3PNVWWK3TUUZ2G64DJMNZZDAVEOR4XAZNEM5UXG5FFOZQWY5LFVAZTAMZZGY3TINFHORZGSZ3HMVZKMY3SMVQXIZI>
.
You are receiving this email because you commented on the thread.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>
.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Cool!
Instead of:
you can write a simpler expression:
i = int(round(y*8))