Skip to content

Instantly share code, notes, and snippets.

@Joshua1989
Created June 14, 2018 22:55
Show Gist options
  • Select an option

  • Save Joshua1989/7c7bce4e317b099ef507eea4d02657d6 to your computer and use it in GitHub Desktop.

Select an option

Save Joshua1989/7c7bce4e317b099ef507eea4d02657d6 to your computer and use it in GitHub Desktop.
Solution of unexpected spacing on nested tqdm progressbars by adding a VBox container
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"metadata": {},
"cell_type": "markdown",
"source": "Solution of unexpected spacing on nested tqdm progressbars by adding a VBox container"
},
{
"metadata": {
"ExecuteTime": {
"start_time": "2018-06-14T22:50:00.609881Z",
"end_time": "2018-06-14T22:50:00.630930Z"
},
"code_folding": [
196,
206,
215,
229,
233
],
"trusted": true
},
"cell_type": "code",
"source": "\"\"\"\nIPython/Jupyter Notebook progressbar decorator for iterators.\nIncludes a default (x)range iterator printing to stderr.\nUsage:\n >>> from tqdm_notebook import tnrange[, tqdm_notebook]\n >>> for i in tnrange(10): #same as: for i in tqdm_notebook(xrange(10))\n ... ...\n\"\"\"\n# future division is important to divide integers and get as\n# a result precise floating numbers (instead of truncated int)\nfrom __future__ import division, absolute_import\n# import compatibility functions and utilities\nimport sys\nfrom tqdm._utils import _range\n# to inherit from the tqdm class\nfrom tqdm._tqdm import tqdm\n\nif True: # pragma: no cover\n # import IPython/Jupyter base widget and display utilities\n try: # IPython 4.x\n import ipywidgets\n IPY = 4\n except ImportError: # IPython 3.x / 2.x\n IPY = 32\n import warnings\n with warnings.catch_warnings():\n ipy_deprecation_msg = \"The `IPython.html` package\" \\\n \" has been deprecated\"\n warnings.filterwarnings('error',\n message=\".*\" + ipy_deprecation_msg + \".*\")\n try:\n import IPython.html.widgets as ipywidgets\n except Warning as e:\n if ipy_deprecation_msg not in str(e):\n raise\n warnings.simplefilter('ignore')\n try:\n import IPython.html.widgets as ipywidgets # NOQA\n except ImportError:\n pass\n except ImportError:\n pass\n\n try: # IPython 4.x / 3.x\n if IPY == 32:\n from IPython.html.widgets import IntProgress, HBox, HTML\n IPY = 3\n else:\n from ipywidgets import IntProgress, HBox, HTML\n except ImportError:\n try: # IPython 2.x\n from IPython.html.widgets import IntProgressWidget as IntProgress\n from IPython.html.widgets import ContainerWidget as HBox\n from IPython.html.widgets import HTML\n IPY = 2\n except ImportError:\n IPY = 0\n\n try:\n from IPython.display import display # , clear_output\n except ImportError:\n pass\n\n # HTML encoding\n try: # Py3\n from html import escape\n except ImportError: # Py2\n from cgi import escape\n\n__author__ = {\"github.com/\": [\"lrq3000\", \"casperdcl\", \"alexanderkuk\"]}\n__all__ = ['tqdm_notebook_EX', 'tnrange_EX']\n \nclass tqdm_notebook_EX(tqdm):\n \"\"\"\n Experimental IPython/Jupyter Notebook widget using tqdm!\n \"\"\"\n\n def status_printer(self, _, total=None, desc=None, ncols=None):\n \"\"\"\n Manage the printing of an IPython/Jupyter Notebook progress bar widget.\n \"\"\"\n # Fallback to text bar if there's no total\n # DEPRECATED: replaced with an 'info' style bar\n # if not total:\n # return super(tqdm_notebook_EX, tqdm_notebook).status_printer(file)\n\n # fp = file\n\n # Prepare IPython progress bar\n if total:\n pbar = IntProgress(min=0, max=total)\n else: # No total? Show info style bar with no progress tqdm status\n pbar = IntProgress(min=0, max=1)\n pbar.value = 1\n pbar.bar_style = 'info'\n if desc:\n pbar.description = desc\n # Prepare status text\n ptext = HTML()\n # Only way to place text to the right of the bar is to use a container\n container = HBox(children=[pbar, ptext])\n if self.vbox:\n self.vbox.children = self.vbox.children + (container,)\n else:\n display(container)\n # Prepare layout\n if ncols is not None: # use default style of ipywidgets\n # ncols could be 100, \"100px\", \"100%\"\n ncols = str(ncols) # ipywidgets only accepts string\n if ncols[-1].isnumeric():\n # if last value is digit, assume the value is digit\n ncols += 'px'\n pbar.layout.flex = '2'\n container.layout.width = ncols\n container.layout.display = 'inline-flex'\n container.layout.flex_flow = 'row wrap'\n\n def print_status(s='', close=False, bar_style=None, desc=None):\n # Note: contrary to native tqdm, s='' does NOT clear bar\n # goal is to keep all infos if error happens so user knows\n # at which iteration the loop failed.\n\n # Clear previous output (really necessary?)\n # clear_output(wait=1)\n\n # Get current iteration value from format_meter string\n if total:\n # n = None\n if s:\n npos = s.find(r'/|/') # cause we use bar_format=r'{n}|...'\n # Check that n can be found in s (else n > total)\n if npos >= 0:\n n = int(s[:npos]) # get n from string\n s = s[npos + 3:] # remove from string\n\n # Update bar with current n value\n if n is not None:\n pbar.value = n\n\n # Print stats\n if s: # never clear the bar (signal: s='')\n s = s.replace('||', '') # remove inesthetical pipes\n s = escape(s) # html escape special characters (like '?')\n ptext.value = s\n\n # Change bar style\n if bar_style:\n # Hack-ish way to avoid the danger bar_style being overriden by\n # success because the bar gets closed after the error...\n if not (pbar.bar_style == 'danger' and bar_style == 'success'):\n pbar.bar_style = bar_style\n\n # Special signal to close the bar\n if close and pbar.bar_style != 'danger': # hide only if no error\n try:\n container.close()\n except AttributeError:\n container.visible = False\n if self.vbox:\n self.vbox.children = tuple(ch for ch in self.vbox.children if ch is not container)\n\n # Update description\n if desc:\n pbar.description = desc\n\n return print_status\n\n def __init__(self, *args, **kwargs):\n # Setup default output\n if kwargs.get('file', sys.stderr) is sys.stderr:\n kwargs['file'] = sys.stdout # avoid the red block in IPython\n\n # Remove the bar from the printed string, only print stats\n if not kwargs.get('bar_format', None):\n kwargs['bar_format'] = r'{n}/|/{l_bar}{r_bar}'\n\n # Initialize parent class + avoid printing by using gui=True\n kwargs['gui'] = True\n # Set VBox as the overall container, useful for nested bars in Jupyter\n self.vbox = kwargs.pop('vbox', None)\n super(tqdm_notebook_EX, self).__init__(*args, **kwargs)\n if self.disable or not kwargs['gui']:\n return\n\n # Delete first pbar generated from super() (wrong total and text)\n # DEPRECATED by using gui=True\n # self.sp('', close=True)\n\n # Get bar width\n self.ncols = '100%' if self.dynamic_ncols else kwargs.get(\"ncols\", None)\n\n # Replace with IPython progress bar display (with correct total)\n self.sp = self.status_printer(\n self.fp, self.total, self.desc, self.ncols)\n self.desc = None # trick to place description before the bar\n\n # Print initial bar state\n if not self.disable:\n self.sp(self.__repr__()) # same as self.refresh without clearing\n\n def __iter__(self, *args, **kwargs):\n try:\n for obj in super(tqdm_notebook_EX, self).__iter__(*args, **kwargs):\n # return super(tqdm...) will not catch exception\n yield obj\n # NB: except ... [ as ...] breaks IPython async KeyboardInterrupt\n except: # NOQA\n self.sp(bar_style='danger')\n raise\n\n def update(self, *args, **kwargs):\n try:\n super(tqdm_notebook_EX, self).update(*args, **kwargs)\n except Exception as exc:\n # cannot catch KeyboardInterrupt when using manual tqdm\n # as the interrupt will most likely happen on another statement\n self.sp(bar_style='danger')\n raise exc\n\n def close(self, *args, **kwargs):\n super(tqdm_notebook_EX, self).close(*args, **kwargs)\n # If it was not run in a notebook, sp is not assigned, check for it\n if hasattr(self, 'sp'):\n # Try to detect if there was an error or KeyboardInterrupt\n # in manual mode: if n < total, things probably got wrong\n if self.total and self.n < self.total:\n self.sp(bar_style='danger')\n else:\n if self.leave:\n self.sp(bar_style='success')\n else:\n self.sp(close=True)\n\n def moveto(self, *args, **kwargs):\n # void -> avoid extraneous `\\n` in IPython output cell\n return\n\n def set_description(self, desc=None, **_):\n \"\"\"\n Set/modify description of the progress bar.\n Parameters\n ----------\n desc : str, optional\n \"\"\"\n self.sp(desc=desc)\n\n\ndef tnrange_EX(*args, **kwargs):\n \"\"\"\n A shortcut for tqdm_notebook(xrange(*args), **kwargs).\n On Python3+ range is used instead of xrange.\n \"\"\"\n return tqdm_notebook_EX(_range(*args), **kwargs)\n",
"execution_count": 63,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Example code: before adding container"
},
{
"metadata": {
"ExecuteTime": {
"start_time": "2018-06-14T22:53:24.154431Z",
"end_time": "2018-06-14T22:53:29.603895Z"
},
"trusted": true
},
"cell_type": "code",
"source": "for i in tnrange_EX(10):\n print('i =', i)\n for j in tnrange_EX(5, leave=False):\n sleep(0.1)",
"execution_count": 72,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": "HBox(children=(IntProgress(value=0, max=10), HTML(value='')))",
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "ecb6146c1aaa49fb8f29d8c0ca517a20"
}
},
"metadata": {}
},
{
"output_type": "stream",
"text": "i = 0\n",
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"text/plain": "HBox(children=(IntProgress(value=0, max=5), HTML(value='')))",
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "1705c3349ed54712bfa14896511d6e5b"
}
},
"metadata": {}
},
{
"output_type": "stream",
"text": "i = 1\n",
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"text/plain": "HBox(children=(IntProgress(value=0, max=5), HTML(value='')))",
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "c9566b9ab41f495fa918321cf8e138af"
}
},
"metadata": {}
},
{
"output_type": "stream",
"text": "i = 2\n",
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"text/plain": "HBox(children=(IntProgress(value=0, max=5), HTML(value='')))",
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "01ca8d06f9f24d89a15c48d96497bda8"
}
},
"metadata": {}
},
{
"output_type": "stream",
"text": "i = 3\n",
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"text/plain": "HBox(children=(IntProgress(value=0, max=5), HTML(value='')))",
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "44fa0d2bf8aa4a768b89aabe17a43d14"
}
},
"metadata": {}
},
{
"output_type": "stream",
"text": "i = 4\n",
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"text/plain": "HBox(children=(IntProgress(value=0, max=5), HTML(value='')))",
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "7b525852e7574dd8b2246736a5836989"
}
},
"metadata": {}
},
{
"output_type": "stream",
"text": "i = 5\n",
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"text/plain": "HBox(children=(IntProgress(value=0, max=5), HTML(value='')))",
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "0baf8149e748459d9b80e429a94b47be"
}
},
"metadata": {}
},
{
"output_type": "stream",
"text": "i = 6\n",
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"text/plain": "HBox(children=(IntProgress(value=0, max=5), HTML(value='')))",
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "50cc722f98f44cc1b32cc73c04353618"
}
},
"metadata": {}
},
{
"output_type": "stream",
"text": "i = 7\n",
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"text/plain": "HBox(children=(IntProgress(value=0, max=5), HTML(value='')))",
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "a30ca9114bd24762bc3e9e1e4403aa2c"
}
},
"metadata": {}
},
{
"output_type": "stream",
"text": "i = 8\n",
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"text/plain": "HBox(children=(IntProgress(value=0, max=5), HTML(value='')))",
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "65b177cacffa436b8f0bc184a17b5e4b"
}
},
"metadata": {}
},
{
"output_type": "stream",
"text": "i = 9\n",
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"text/plain": "HBox(children=(IntProgress(value=0, max=5), HTML(value='')))",
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "28ae85cecb9d4ce394343322c5797b77"
}
},
"metadata": {}
},
{
"output_type": "stream",
"text": "\n",
"name": "stdout"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Example code: after adding container"
},
{
"metadata": {
"ExecuteTime": {
"start_time": "2018-06-14T22:53:40.191683Z",
"end_time": "2018-06-14T22:53:45.589001Z"
},
"trusted": true
},
"cell_type": "code",
"source": "vb = VBox()\ndisplay(vb)\nfor i in tnrange_EX(10, vbox=vb):\n print('i =', i)\n for j in tnrange_EX(5, leave=False, vbox=vb):\n sleep(0.1)",
"execution_count": 73,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": "VBox()",
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "46343c683d0342f69efcefc6e310ba14"
}
},
"metadata": {}
},
{
"output_type": "stream",
"text": "i = 0\ni = 1\ni = 2\ni = 3\ni = 4\ni = 5\ni = 6\ni = 7\ni = 8\ni = 9\n\n",
"name": "stdout"
}
]
}
],
"metadata": {
"hide_input": false,
"kernelspec": {
"name": "python3",
"display_name": "Python 3",
"language": "python"
},
"varInspector": {
"window_display": false,
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"library": "var_list.py",
"delete_cmd_prefix": "del ",
"delete_cmd_postfix": "",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"library": "var_list.r",
"delete_cmd_prefix": "rm(",
"delete_cmd_postfix": ") ",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
]
},
"gist": {
"id": "020e4c60efeda4b28ddf7966ea22f45f",
"data": {
"description": "Solution of unexpected spacing on nested tqdm progressbars by adding a VBox container",
"public": true
}
},
"_draft": {
"nbviewer_url": "https://gist.github.com/020e4c60efeda4b28ddf7966ea22f45f"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment