#!/usr/bin/env python
# coding: utf-8
#
Tutorial for Box-X
#
# Tool-box for Efficient Build and Debug in Python. Especially for Scientific Computing and Computer Vision.
#
#
# ----
# We use [Binder](https://mybinder.org) to run this notebooks in an executable interactive online environment. That mean you can **run those cells rightnow** in your browser without download repository.
#
#
# This tutorial is divided into 2 parts by wether the tool is general:
# 1. [**General Python Tool**](#1.-General-Python-Tool). The tools could be used anywhere in Python
# 2. [**Scientific Computing and Computer Vision Tool**](#2.-Scientific-Computing-and-Computer-Vision-Tool). Those tools only be useful in Scientific Computing and Computer Vision field
#
#
# *P.S. This notebook compatible with Python 2/3*
#
#
#
# Table of Contents
#
#
# ## 1. General Python Tool
# ### ▶ `p` is a better way to do `print`
# ----
# #### 1. `p/x` will `print(x)` and return `x`
# In[1]:
from boxx import p
s = 'p/x will print(x) and return x'
p/s
# In[2]:
from boxx import p
from random import randint
s = 'ABCD'
print('the output of randint(0, 3) is :')
sample = s[p/randint(0, 3)]
sample
# As you see, `p/x` is easy to print value in expression while debugging.
#
# 💡 **Note:**
#
# `p/randint(0, 3)` print the value of `randint(0, 3)` and return the value itself, which won't influences the program.
#
# ---
# ↓ Use pow operator for highest evaluation order.
# In[ ]:
# try run this cell online
from boxx import p
from random import randint
tenx = 10 * p**randint(0,9)
tenx
# #### 2. `p()` to pretty print all variables in function or module with thier name
# In[3]:
from boxx import p
def f(arg=517):
l = [1, 2]
p()
f()
# `p()` will pretty print all variables in `locals()` and some infomation about the frame.
#
# BTW, `import boxx.p` has the same effect.
# #### 3. `with p:` will pretty print mulit variables under "with statement"
# Only interested variables are printed which is under "with statement"
# In[4]:
from boxx import p
from random import randint
def f():
other_vars = "No need to pay attention"
with p:
a = randint(1, 9)
l = [a, a*2]
others = "No need to pay attention"
f()
# ### ▶ `g` and `gg` could transport variable to Python interactive console
# ----
# #### 1. Use `g.name=x` or `g.name/x` to transport variable that in function or module to console.
# The meaning of `g`,`gg` are "to Global", "to Global and log"
# In[5]:
from boxx import g
def f():
listt = [1,2]
g.l = listt # `listt` is transported to console as `l`
f()
l
# `g.l = listt` create new var `l` In Python interactive console and transport `listt` assign to `l`.
#
# 💡 **Note:** if variable name exists in console before, the variable's value will be covered by new value.
#
# ---
# `gg` is same usage as `g`, but `gg` will print the transported variable.
# Use `g.name/x` to convenient transport value in expression.
# In[6]:
from boxx import g, gg
def f():
listt = [1,2]
gg.l = listt
return g.by_div/listt
listt = f()
# l, by_div are transported to console
(listt, l, by_div, l is listt, by_div is listt)
# 💡 **Note:**
# * In Python interactive console, variable `l`, `by_div` are created.
#
# * All of they are `listt` has the same `id`.
# #### 2. `g()` to transport all variables that in the function to Python interactive console
# `g()` in a function ,can transport all variables that in the function (or module) to console. It's a useful tool for debugging.
# In[7]:
from boxx import g
def f(arg=517):
l = [1, 2]
g()
f()
# transport all variables in function to console
arg, l
# 💡 **Note:**
#
# * `g()` only transport the `locals()` to console, the `globals()` will save to `boxx.p`
#
# * `gg()` is a print version of `g`, `gg()` will pretty print all variable with thier name and some infomation about the frame.
#
# * `import boxx.g` is convenient way to use `g()` instead of `from boxx import g;g()`(`import boxx.gg` is avaliable too)
# In[ ]:
# try run this cell online
def f(arg):
a = 2
import boxx.gg
inp = [5 ,1 , 7]
f(inp)
# gg will pretty print all variables in f
# and `a` and `arg` are transported to console
a, arg, arg is inp
# #### 3. `with g:` will transport mulit variables under "with statement"
# `with g` will transport the interested variables to Python interactive console under "with statement"(`with gg:` is avaliable too)
# In[8]:
from boxx import g
from random import randint
def f():
other_vars = "No need to pay attention"
with g: # only transport a, l
a = randint(1, 9)
l = [a, a*2]
others = "No need to pay attention"
f()
print('In console:',a , l, 'others' in locals())
# 💡 **Note:**
#
# 1 . `with p`, `with g`, `with gg` only act on assignment variables under "with statement".
#
# 2 . If variable's name exists in `locals()` before and `id(variable)` not change ,variable may not be detected
# Especially following cases:
# 1. var is int and < 256
# 2. `id(var)` not change
# ### ▶ Summary for debug tools
# ---
#
#
#
# boxx
debug tool matrix
#
#
#
# | How many vars \ Operation | print | transport | print & transport |
# | :---- | :---- | :---- | :---- |
# | Single variable | `p/x` | `g.name/x` | `gg.name/x`|
# |Multi variables | `with p:` | `with g:` | `with gg:` |
# |All `locals()`| `p()` | `g()` | `gg()` |
# |All `locals()`\_2 | `import boxx.p` | `import boxx.g` | `import boxx.gg` |
#
# 💡 **Note:**
# * **transport** mean "transport variable to Python interactive console"
# * **All `locals()`** mean operation will act on all variables in the function or module
# * **All `locals()`\_2 :** when `boxx` are not imported, `import boxx.{operation}` is a convenient way to execution operation
# ### ▶ `timeit` is convenient timing tool
# In[9]:
from boxx import timeit
from time import sleep
with timeit():
sleep(0.01) # simulation timing code
with timeit(name='sleep'):
sleep(0.1) # simulation timing code
# `timeit` will timing code block under "with statement" and print spend time in blue color.
# ### ▶ `mapmt` is Multi Threading version of `map`
# `mapmt` is the meaning of "MAP for Multi Threading", has almost same usage as `map`
# In[10]:
from boxx import mapmt, timeit
from time import sleep
def io_block(x): # simulation io block
sleep(0.1)
return x
xs = range(10)
with timeit('map'):
resoult_1 = list(map(io_block, xs))
with timeit('mapmt'):
resoult_2 = mapmt(io_block, xs, pool=10)
# pool=10 mean 10 threadings
resoult_1 == resoult_2
# ### ▶ `mapmp` is Multi Process version of `map`
# `mapmp` is the meaning of "MAP for Multi Process", has the same usage as `map` and `mapmt` but faster.
# In[11]:
from boxx import mapmp, timeit
def bad_fibonacci(x): # simulation Complex calculations
return x<=1 or x*bad_fibonacci(x-1)
xs = [800]*10000
if __name__ == '__main__':
with timeit('map'):
resoult_1 = list(map(bad_fibonacci, xs))
with timeit('mapmp'):
resoult_2 = mapmp(bad_fibonacci, xs)
resoult_1 == resoult_2
# the time printed below is run on a Intel i5 CPU on Ubuntu
# 💡 **Note:**
#
# `mapmp` and `mapmt` has same usage, they both support two parameters
#
# **pool** : int, default None
# > the number of Process or Threading, the default is the number of CPUs in the system
#
# **printfreq** : int or float, default None
# > the meaning of `print frequent`, auto print program progress in `mapmt` and `mapmp`
# > if `printfreq < 1` then `printfreq = len(iterables[0])*printfreq`
#
# * It's better to run multi process under `if __name__ == '__main__':`, [see multiprocessing programming guidelines](https://docs.python.org/3/library/multiprocessing.html#multiprocessing-programming)
#
# * `multiprocessing` may not work on Windows
#
# ---
#
# In multi process programs, display processing progress is troublesome.
# **printfreq** parameter in `mapmp` can handle this problem
# In[ ]:
# try run this cell
from boxx import mapmp
from operator import add
xs = list(range(100))
double_xs = mapmp(add, xs, xs, pool=2, printfreq=.2)
double_xs
# ### ▶ `x_` to quick build function without `lambda x:`
# In[12]:
from boxx import x_
f = x_**2
f(1), f(2), f(3)
# `x_` often used with map, reduce, filter
# In[ ]:
# try run this cell
xs = range(5)
powx = map(x_**x_, xs, xs)
list(powx)
# ### ▶ `mf` to quick add magic method to function
# `mf` is the meaning of "Magic Method", to wrap the function that often used while debugging.
# In[13]:
from boxx import mf
l = mf(list)
tuplee = (5, 1, 7)
print('- :', l-tuplee)
print('* :', l*tuplee)
print('**:', l**tuplee)
print('/ :', l/tuplee)
# 💡 **Note:**
#
# * when `-`, `*`, `**` as magic method: do `f(x)` and return `f(x)`
#
# * when `/` as magic metho: do `f(x)` but return `x`
#
# * **Functions that wraps by `mf` in `boxx`**: `stdout`, `log`, `logc`, `printt`, `pblue`, `pred`, `pdanger`, `perr`, `pinfo`, `typestr`, `getfathers`, `getfather`, `nextiter`, `mf`, `plot`, `show`, `showb`, `shows`, `loga`, `tree`, `treem`, `treea`, `dira`, `what`, `wtf`, `tprgb`, `torgb`, `normalizing`, `norma`, `npa`, `histEqualize`, `boolToIndex`
# ### ▶ `tree` to visualization complex struct in tree format
# In[14]:
from boxx import tree
complex_struct = dict(key=[0, 'str', ('in_tuple', None)], tree=tree)
tree(complex_struct)
# Like `tree` command in shell, `boxx.tree` could visualization any struct in tree format.
#
# Support types include `list`, `tuple`, `dict`, `numpy`, `torch.tensor`, `mxnet.ndarray`, `PIL.Image`.etc
# ### ▶ `dira(x)` to show `x`'s all attribute
# `dira(x)` is the meaning of "dir Attribute".
# In[15]:
from boxx import dira
dira(LookupError)
# `dira(x)` will pretty print `x`'s all attribute in tree format.
# And `dira(x)` will print `x`'s Father Classes too.
# ### ▶ `what` to know "What's this?"
# In[16]:
from boxx import what
from boxx import ylsys
what(ylsys)
# `what(x)` will show "what is `x`?" by pretty print it's **Document**, **Father Classes**, **Inner Struct** and **Attributes**. It is a supplement of `help(x)`
#
# 💡 **Note:**
#
# `boxx.what` is a useful tool when learn a new module or package.It reduce the time to check the API document.
#
# `wtf` is the short of `what`, use `wtf-x` for convenience.
# In[ ]:
# try run this cell
from collections import defaultdict
from boxx import wtf
ddict = defaultdict(lambda x:'boxx', Starman='Bowie')
wtf-ddict
# ### ▶ `logc` to pretty print expression by show every variable's value in expression
# `logc` is the meaning of "Log Code"
# In[17]:
from random import random
from boxx import logc
a = random()
b = random()
logc("mean = (a + b) / 2", exe=True) # exe=True mean exec(code)
# ### ▶ `heatmap` to show the time heat map of your code
# In[18]:
get_ipython().run_line_magic('matplotlib', 'inline')
from boxx import heatmap
heatmap('./yllab.py')
# `heatmap` also support python code string.
# In[19]:
get_ipython().run_line_magic('matplotlib', 'inline')
from boxx import heatmap
code = '''
def bad_fibonacci(x): # simulation Complex calculations
if x<=1 :
return 1
return x*bad_fibonacci(x-1)
bad_fibonacci(3)
'''
heatmap(code)
# ### ▶ `performance` could statistic function calls and visualize code performance
# In[ ]:
from boxx import performance
performance('./yllab.py')
# broswer will open a web page to visualization code perfomance if possible
# 💡 **Note:** if you are runing this Notebook on [Binder](https://mybinder.org/v2/gh/DIYer22/boxx/master?filepath=tutorial_for_boxx.ipynb), Browser won't open the web page. Please see demo here [performance demo.gif](https://raw.githubusercontent.com/DIYer22/boxx/master/other/gif/performance.gif)
#
# ---
#
# `performance` also support python code string.
# In[ ]:
code = '''
def bad_fibonacci(x): # simulation Complex calculations
if x<=1 :
return 1
return x*bad_fibonacci(x-1)
bad_fibonacci(5)
'''
performance(code)
# broswer will open a web page to visualization code perfomance if possible
# ### ▶ `dicto` is a convenient version of `dict`
# `dicto` is the meaning of "dict that like Object"
# In[20]:
from boxx import dicto
d = {'a':22}
dd = dicto(d)
print(dd.a)
dd.b = 517
dd
# 💡 **Note:** `dicto` is sub-class of `dict` that is easy to use, allows to get and set `dict` values as attributes.
#
# BTW, `boxx.cf` is a `dicto` instance that could save your global config, and it could be used at all your `.py` files by `from boxx import cf`
# ### ▶ `ll` is a convenient tool for `list`
# `ll` is the meaning of "List tooL"
# In[21]:
from boxx import ll
print(ll * 5) # instead of list(range(5))
print(ll/zip([0, 1])) # quick way to do `list(x)` when x iterable
ll # BTW, ll self is a list
# ### ▶ `sysi` include many infomation about operating environment
# In[22]:
from boxx import dira, sysi
dira(sysi, pattern='^[^_]')
# Use `sysi.cpun`, `sysi.user`, `sysi.host` to let code know wether the environment is local or remote.
# ## 2. Scientific Computing and Computer Vision Tool
#
# The tools introduced in [**General Python Tool**](#1.-General-Python-Tool) are also useful in Scientific Computing and Computer Vision(SC&CV) field.
#
# In this section we will introduce tools that only uesed in SC&CV field.
#
# BTW. Those tools support many array-like types include `numpy`, `torch.tensor`, `mxnet.ndarray`, `PIL.Image`.etc
# ### ▶ `loga` for visualization matrix and tensor
# `loga` is the meaning of "log array"
# In[23]:
get_ipython().run_line_magic('matplotlib', 'inline')
import numpy as np
array = np.random.normal(size=(5,3, 244, 244))
from boxx import loga
loga(array)
# 💡 **Note:**
#
# * `loga` analysis the `numpy.ndarray` by it's shape, max, min, mean, and distribute.
#
# * `loga` support other array-like types include list, `numpy`, `torch.tensor`, `mxnet.ndarray`, `PIL.Image`.etc
#
# * `loga` will tell you how many `nan`, `inf` in the array if array include `nan`, `inf`:
# In[24]:
array[...,:10] = np.inf
array[...,-10:] = -np.inf
array[...,:10,:] = np.nan
loga(array)
# ### ▶ `tree` to visualization complex struct for Scientific Computing
# In[25]:
# prepare images
import numpy as np
from skimage.io import imread
image_path = 'test/imgForTest/img.jpg'
ground_truth_path = 'test/imgForTest/gt_seg.png'
Lenna = imread('test/imgForTest/Lenna.jpg')
image = imread(image_path)
ground_truth = imread(ground_truth_path)
# complex struct
batch = dict(
path=(image_path, ground_truth_path),
img=image,
gt=ground_truth,
listt=[
np.append(image, ground_truth[..., None], -1),
np.array([Lenna, Lenna]),
],
)
from boxx import tree
print('visualization the struct:')
tree(batch)
# Like `tree` command in shell, `boxx.tree` could visualization complex struct (like `a batch of data`) in tree format.
# 💡 **Note:**
#
# * Support types include `list`, `tuple`, `dict`, `numpy`, `torch.tensor`, `mxnet.ndarray`, `PIL.Image`.etc
#
# * Support sample a batch from `torch.Dataset`, `torch.DataLoader`. then visualization the batch's struct.
# ### ▶ `show` is easy to do `imshow`, even images are in complex struct
# In[26]:
get_ipython().run_line_magic('matplotlib', 'inline')
from skimage.io import imread
Lenna = imread('test/imgForTest/Lenna.jpg')
from boxx import show
show(Lenna)
# ↓ `show` could find every image in complex struct and `plt.imshow` they.
# In[27]:
get_ipython().run_line_magic('matplotlib', 'inline')
# prepare images
import numpy as np
from skimage.io import imread
image_path = 'test/imgForTest/img.jpg'
ground_truth_path = 'test/imgForTest/gt_seg.png'
Lenna = imread('test/imgForTest/Lenna.jpg')
image = imread(image_path)
ground_truth = imread(ground_truth_path)
# complex struct
batch = dict(
path=(image_path, ground_truth_path),
img=image,
gt=ground_truth,
listt=[
np.append(image, ground_truth[..., None], -1),
np.array([Lenna, Lenna]),
],
)
from boxx import show, tree
print('the struct of batch:')
tree(batch)
print('show all images in batch:')
show(batch)
# 💡 **Note:**
#
# * Support image types include `numpy`, `torch.tensor`, `mxnet.ndarray`, `PIL.Image`.etc
#
# * And Support sample a batch from `torch.Dataset`, `torch.DataLoader`, then `plt.imshow` the batch.
# ### ▶ `npa` transform other array-like object to numpy in one way
# `npa` is the meaning of "numpy.array", use magic method to quick transform other numpy like object to numpy, suport `torch.tensor`, `mxnet.ndarray`, `PIL.Image`, `list`, `tuple` .etc
# In[28]:
from boxx import npa
print(npa-range(3))
import numpy as np
r = npa-range(3)
npa**[r, r]