Skip to content

Commit

Permalink
fix arbitrary bar symbols
Browse files Browse the repository at this point in the history
  • Loading branch information
yannikschaelte committed Aug 17, 2020
1 parent c8a7b3f commit 6babc50
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 15 deletions.
224 changes: 224 additions & 0 deletions example/Untitled.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# jabbar usage example"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"All we need to do is import the `jabbar` bar object."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import time\n",
"from jabbar import jabbar"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"jabbar can simply wrap around any iterable to make loops show a little progress bar:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"100% |████████████████████████| 666/666 \n"
]
}
],
"source": [
"for _ in jabbar(range(666)):\n",
" time.sleep(0.002)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The updating scheme can also be individually specified:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"100% |████████████████████████████████████████| 1000/1000 \n"
]
}
],
"source": [
"with jabbar(total=1000, width=40) as bar:\n",
" for _ in range(50):\n",
" time.sleep(0.001)\n",
" bar.inc(20)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The final count can be higher than the pre-defined maximum in case that is not completely known a-priori:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"100% |████████████████████████| 420/420 \n"
]
}
],
"source": [
"with jabbar(total=420) as bar:\n",
" for _ in range(420):\n",
" time.sleep(0.001)\n",
" bar.inc()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can also go fully manual without the context manager if needed. Just manually finish the bar afterwards:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"100% |████████████████████████| 753/753 \n"
]
}
],
"source": [
"bar = jabbar(total=753)\n",
"for _ in range(753):\n",
" time.sleep(0.001)\n",
" bar.inc()\n",
"# call finish afterwards\n",
"bar.finish()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can also individualize the used symbols:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"100% |========================| 404/404 \n",
"100% |yoyoyoyoyoyoyoyoyoyoyoyo| 404/404 \n"
]
}
],
"source": [
"for _ in jabbar(range(404), bar_symbols='='):\n",
" time.sleep(0.002)\n",
"for _ in jabbar(range(404), bar_symbols='yo'):\n",
" time.sleep(0.002)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Why not a bar of 🦄 or 🙄? Bam."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"100% |🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄| 42/42 \n"
]
}
],
"source": [
"for _ in jabbar(range(42), bar_symbols='🦄'):\n",
" time.sleep(0.05)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Just be aware that in particular unicorns are shy and may not show up sometimes."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Further configurations and details can be found in the API documentation."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.5"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
60 changes: 46 additions & 14 deletions jabbar/bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import sys
from collections.abc import Iterable, Sized
from typing import TextIO
from typing import TextIO, Tuple, Union
from unicodedata import east_asian_width as eaw

bar_symbols = ('', '▏', '▎', '▍', '▌', '▋', '▊', '▉', '█')
bar_prefix = ' |'
bar_suffix = '| '
BAR_SYMBOLS = ('', '▏', '▎', '▍', '▌', '▋', '▊', '▉', '█')
BAR_PREFIX = ' |'
BAR_SUFFIX = '| '


class JabBar:
Expand All @@ -20,7 +21,8 @@ def __init__(
width: int = 24,
file: TextIO = sys.stdout,
enable: bool = True,
keep: bool = True):
keep: bool = True,
bar_symbols: Union[Tuple[str], str] = BAR_SYMBOLS):
"""Initialize the bar.
:param iterable: An iterable to show the progress for while iterating
Expand All @@ -30,6 +32,7 @@ def __init__(
:param file: The target where to write the progress bar to
:param enable: Whether to actually show the progress bar
:param keep: Whether to keep or remove the bar afterwards
:param bar_symbols: Bar symbols to use, with increasing fill degree.
"""
self.iterable = iterable
self.total: int = total
Expand All @@ -38,6 +41,15 @@ def __init__(
self.file: TextIO = file
self.enable: bool = enable
self.keep: bool = keep

if isinstance(bar_symbols, str):
bar_symbols = (bar_symbols,)
bar_symbols = tuple(bar_symbols)
if '' not in bar_symbols:
# add empty element
bar_symbols = ('',) + bar_symbols
self.bar_symbols = bar_symbols

self.n_done: int = 0
self.len: int = 0

Expand Down Expand Up @@ -94,20 +106,27 @@ def get_line(self) -> str:

# number of full bar fields is the integer below
n_full = int(width_full)
bar_full = bar_symbols[-1] * n_full

# which of the bar symbols to select
phase = int((width_full - n_full) * len(bar_symbols))
bar_current = bar_symbols[phase]

n_empty = self.width - n_full - len(bar_current)
# number of full symbols
n_symbol_full = int(n_full / nchar(self.bar_symbols[-1]))
bar_full = self.bar_symbols[-1] * n_symbol_full

# which of the bar symbols to select for the current symbol
phase = int((width_full - n_full) * len(self.bar_symbols))
# number of current symbols
n_symbol_phase = 0
if len(self.bar_symbols[phase]):
n_symbol_phase = int(1 / nchar(self.bar_symbols[phase]))
bar_current = self.bar_symbols[phase] * n_symbol_phase

# number of empty symbols
n_empty = self.width - nchar(bar_full) - nchar(bar_current)
bar_empty = ' ' * n_empty

str_done = f"{self.n_done}/{self.total}"

line = ('\r' + str_r_done + bar_prefix +
line = ('\r' + str_r_done + BAR_PREFIX +
bar_full + bar_current + bar_empty +
bar_suffix + str_done +
BAR_SUFFIX + str_done +
" " + self.comment)

return line
Expand Down Expand Up @@ -139,5 +158,18 @@ def __iter__(self):
self.finish()


def nchar(symbol: str):
"""Calculate number of unit-width characters for a symbol.
This may not work on all systems and for all symbols.
Parameters
----------
symbol:
The symbol (single character or string).
"""
return len(symbol) + sum(1 for char in symbol if eaw(char) in ['F', 'W'])


# convenience alias
jabbar = JabBar
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

[metadata]
name = jabbar
version = 0.0.7
version = 0.0.8
description = Just Another Beautiful progress BAR
long_description = file: README.rst

Expand Down
6 changes: 6 additions & 0 deletions test/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,9 @@ def test_keep():
"""Test the keep functionality."""
for _ in jabbar(range(100), keep=False):
pass


def test_custom_symbols():
"""Test passing custom bar symbols."""
for _ in jabbar(range(100), bar_symbols='yo'):
pass

0 comments on commit 6babc50

Please sign in to comment.