In [67]:
%%javascript
IPython.OutputArea.prototype._should_scroll = function(lines) {
return false;
}

In [2]:
from numpy import *
import matplotlib.pyplot as plt
%matplotlib inline


## Drawing on top of an image¶

Use extent option in imshow:

In [8]:
a = 255*ones((400,500,3),dtype=uint8)
a[100:200,:,:] = [150,0,150]
plt.imshow(a,extent=[-2,2,-1.5,1.5])
plt.plot(0,0.5,'wo')
plt.plot([0,1],[0,1],'#FF8000');


Step by step:

In [13]:
nr = 10
nc = 16
L = 3
m = empty((nr,nc,3),dtype=int)

In [14]:
arange(nc)

Out[14]:
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15])
In [15]:
arange(nc)//L

Out[15]:
array([0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5])
In [16]:
mod(arange(nc)//L,2)

Out[16]:
array([0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1])
In [19]:
mod((1+arange(nc))//L,2)  # to offset

Out[19]:
array([0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1])
In [20]:
mod((1+arange(nc))//L,2)==1  # create bool array that we can use for indexing into m

Out[20]:
array([False, False,  True,  True,  True, False, False, False,  True,
True,  True, False, False, False,  True,  True], dtype=bool)

All together now:

In [9]:
nr = 10
nc = 16
L = 3
m = zeros((nr,nc,3),dtype=uint8)
for i in range(nr):
m[i,mod((-i+arange(nc))//L,2)==1,:] = 1
m[:,:,0]

Out[9]:
array([[0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1],
[1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0],
[1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0],
[0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1],
[0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1],
[1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0],
[1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0]], dtype=uint8)

A bit bigger:

In [10]:
nr = 500
nc = 500
L = 2
m = zeros((nr,nc,3),dtype=uint8)
for i in range(nr):
m[i,mod((-i+arange(nc))//L,2)==1,:] = 1
#m[:,:,0]


Now let's use the mask to draw a simple woven fabric:

In [12]:
v = zeros((nr,nc,3),dtype=uint8)  # vertical threads
v[:,100:120,:] = [255,128,0]  # add a vertical orange stripe
plt.imshow(v);

In [13]:
v = zeros((nr,nc,3),dtype=uint8)  # vertical threads
v[:,100:120,:] = [255,128,0]
v[:,150:170,:] = [255,128,0]
v[:,130:140,:] = [0  ,  0,200]
plt.imshow(v);


In [14]:
v = zeros((nr,nc,3),dtype=uint8)  # vertical threads
v[:,100:120,:] = [255,128,0]
v[:,150:170,:] = [255,128,0]
v[:,130:140,:] = [0  ,  0,200]
from scipy.misc import imsave
imsave('temp.png',m*v)
plt.figure(figsize=(10,10))
plt.imshow(m*v);


Now use colored horizontal threads too:

In [16]:
v = zeros((nr,nc,3),dtype=uint8)  # vertical threads
v[:,100:120,:] = [255,128,0]
v[:,150:170,:] = [255,128,0]
v[:,130:140,:] = [0  ,  0,200]
from scipy.misc import imsave
h = v.transpose(1,0,2)
a = m*v + (1-m)*h
imsave('temp.png',a)
plt.figure(figsize=(10,10))
plt.imshow(a)
plt.axis('off');


## Parse the color palette string¶

### Dictionaries¶

In [36]:
d = {'apple':'round crispy fruit', 'banana':'long yellow fruit'}

In [37]:
d

Out[37]:
{'apple': 'round crispy fruit', 'banana': 'long yellow fruit'}
In [38]:
d['banana']

Out[38]:
'long yellow fruit'
In [39]:
d['orange'] = 'round orange fruit'

In [40]:
d

Out[40]:
{'apple': 'round crispy fruit',
'banana': 'long yellow fruit',
'orange': 'round orange fruit'}
In [41]:
d['orange']

Out[41]:
'round orange fruit'
In [101]:
#p = 'B=2C4084BLUE;K=101010BLACK;G=005020MOD GREEN;W=E0E0E0WHITE;'
p = 'B=2C99FFLIGHT BLUE;K=101010BLACK;G=005020MOD GREEN;W=E0E0E0WHITE;'

In [102]:
colors = p.split(';')[:-1]
colors

Out[102]:
['B=2C99FFLIGHT BLUE', 'K=101010BLACK', 'G=005020MOD GREEN', 'W=E0E0E0WHITE']
In [103]:
[color[0] for color in colors]

Out[103]:
['B', 'K', 'G', 'W']
In [104]:
[zebra[0] for zebra in colors]  # item name can be anything you like!

Out[104]:
['B', 'K', 'G', 'W']

Above assumed every color shorthand was just one character. Evidently some have more than one.

We can accommodate this by splitting on the "=" sign, and taking the part before it:

In [105]:
keys = [color.split('=')[0] for color in colors]
keys

Out[105]:
['B', 'K', 'G', 'W']
In [106]:
values = [color.split('=')[1] for color in colors]
values

Out[106]:
['2C99FFLIGHT BLUE', '101010BLACK', '005020MOD GREEN', 'E0E0E0WHITE']

Let's throw away the descriptor after the 6 hex digits:

In [107]:
values = [color.split('=')[1][:6] for color in colors]
values

Out[107]:
['2C99FF', '101010', '005020', 'E0E0E0']
In [108]:
d = {k:v for k,v in zip(keys,values)}
d

Out[108]:
{'B': '2C99FF', 'G': '005020', 'K': '101010', 'W': 'E0E0E0'}
In [109]:
d['G']

Out[109]:
'005020'
In [110]:
dict(zip(keys,values))  # another way of creating a dict

Out[110]:
{'B': '2C99FF', 'G': '005020', 'K': '101010', 'W': 'E0E0E0'}

Converting hex numbers to ints:

In [111]:
int('FF',16)

Out[111]:
255
In [112]:
# need to convert hex triples to triples of ints
def hex2int(h):
return [int(h[i:i+2],16) for i in [0,2,4]]

In [113]:
hex2int('005020')

Out[113]:
[0, 80, 32]
In [114]:
s = '005020'
s[2:4]

Out[114]:
'50'

Now we can create a usable color lookup table:

In [115]:
d = {k:hex2int(v) for k,v in zip(keys,values)}
d

Out[115]:
{'B': [44, 153, 255],
'G': [0, 80, 32],
'K': [16, 16, 16],
'W': [224, 224, 224]}
In [116]:
d['B']

Out[116]:
[44, 153, 255]
In [117]:
d['foo']

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-117-96e03e4217d2> in <module>()
----> 1 d['foo']

KeyError: 'foo'

In [118]:
tc = 'B4K4B36K40G36W8G36K40B34K6'

In [119]:
import re  # "regular expressions"

In [120]:
re.findall('[A-Z]+',tc)

Out[120]:
['B', 'K', 'B', 'K', 'G', 'W', 'G', 'K', 'B', 'K']
In [121]:
re.findall('[0-9]+',tc)

Out[121]:
['4', '4', '36', '40', '36', '8', '36', '40', '34', '6']
In [122]:
stripes = re.findall('[A-Z]+',tc)
counts = [int(count) for count in re.findall('[0-9]+',tc)]

In [123]:
stripes

Out[123]:
['B', 'K', 'B', 'K', 'G', 'W', 'G', 'K', 'B', 'K']
In [124]:
counts

Out[124]:
[4, 4, 36, 40, 36, 8, 36, 40, 34, 6]
In [125]:
# to duplicate the colors in reverse order

In [126]:
stripes = re.findall('[A-Z]+',tc)
counts = [int(count) for count in re.findall('[0-9]+',tc)]

# append reversed copies
stripes += stripes[::-1]
counts += counts[::-1]
counts

Out[126]:
[4, 4, 36, 40, 36, 8, 36, 40, 34, 6, 6, 34, 40, 36, 8, 36, 40, 36, 4, 4]
In [127]:
stripes

Out[127]:
['B',
'K',
'B',
'K',
'G',
'W',
'G',
'K',
'B',
'K',
'K',
'B',
'K',
'G',
'W',
'G',
'K',
'B',
'K',
'B']
In [128]:
nr = sum(counts)
nc = nr
nr

Out[128]:
488

Useful to have the thread number of the start of each stripe. This can be obtained from the cumulative sum (cumsum) of the stripe widths:

In [129]:
cumsum(counts)

Out[129]:
array([  4,   8,  44,  84, 120, 128, 164, 204, 238, 244, 250, 284, 324,
360, 368, 404, 444, 480, 484, 488])
In [130]:
starts = [0]+list(cumsum(counts))

In [131]:
starts[:16]

Out[131]:
[0, 4, 8, 44, 84, 120, 128, 164, 204, 238, 244, 250, 284, 324, 360, 368]