I’m trying to create a cross stitch pattern with python as shown in the attached image.
So far I simply have the pixilated image. I could import it in excel and manually add the grid and colors etc. But how can I ‘easily’ automate this in python? Can I use any of the normal figure plotting functions (pyplot), or should I look into tkinter?
I’m fairly ok making scripts in python for engineering purposes, but completely new to GUI-stuff.
Ideally my output would be a vectored pdf
from scipy import misc
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as plticker
arr = misc.imread('Fox_drawing_pixelized.png', mode= 'RGBA') # 640x480x3 array
fig = plt.figure()
imgplot = plt.imshow(arr) # RGBA
ax = plt.gca()
ax.grid(True)
ax.grid(b=True, which='major', color='b', linestyle='-')
plt.minorticks_on()
loc = plticker.MultipleLocator(base=1)
ax.xaxis.set_minor_locator(loc)
ax.yaxis.set_minor_locator(loc)
ax.grid(b=True, which='minor', color='k', linestyle='-',linewidth=.3)
fig.savefig("foo.pdf", bbox_inches='tight')
How do I set the gridlines at 0.5 rather than on the units (in the middle through each pixel)?
How do I plot text throught each pixel, I already have the image in an array with numbers how to plot this on top?
Advertisement
Answer
To shift the gridlines, you can simply change the ticks position:
ax.set_xticks(np.arange(-0.5, arr.shape[1], 5))
will put one major tick each 5 pixels starting from the border of the first pixel.
ax.set_xticks(np.arange(-0.5, arr.shape[1], 1), minor=True)
does the same thing but every pixel for minor ticks. And then do the same for y but witharr.shape[0]
.To add text, you can simply use
ax.text(x, y, 'text')
. I used a dictionary to match the colors (in hex format because rgb lists cannot be dictionary keys) to the texts. What you need to pay attention to is that (i, j) matrix indexes correspond to (y, x) coordinates.
Here is the full code:
from scipy import misc
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as plticker
from matplotlib.colors import to_hex
arr = misc.imread('image.png', mode= 'RGB') # array
# adapt figure size to the image size.
fig = plt.figure(figsize=(0.2*arr.shape[1], 0.2*arr.shape[0]))
imgplot = plt.imshow(arr) # RGB
ax = plt.gca()
ax.grid(True)
ax.grid(b=True, which='major', color='b', linestyle='-')
plt.minorticks_on()
ax.grid(b=True, which='minor', color='k', linestyle='-',linewidth=.3)
# put a major gridline every 5 pixels
ax.set_xticks(np.arange(-0.5, arr.shape[1], 5))
ax.set_yticks(np.arange(-0.5, arr.shape[0], 5))
# set ticks label
ax.set_xticklabels(np.arange(0, arr.shape[1], 5))
ax.set_yticklabels(np.arange(0, arr.shape[0], 5))
# put a minor gridline every pixel
ax.set_xticks(np.arange(-0.5, arr.shape[1], 1), minor=True)
ax.set_yticks(np.arange(-0.5, arr.shape[0], 1), minor=True)
fig.tight_layout(pad=0) # reduce space around image
# display text
colors_to_text = {'#000000': 'B', '#ffffff': 'W', '#f58a35': 'O', '#bcbbbb': 'G'}
for i in range(arr.shape[0]):
for j in range(arr.shape[1]):
# get the text corresponding to the pixel color
txt = colors_to_text.get(to_hex(arr[i,j]/255), '')
# display text (x, y are inverted compared to the i, j indexes of the matrix)
ax.text(j, i, txt, color='#888888', horizontalalignment='center',
verticalalignment='center', fontsize=7)
fig.savefig("foo.pdf", bbox_inches='tight')