Yoink Line Extractor Walk-through

This is a walk through of the widgets yoink provides to facilitate pulling line data from a rasterized image. Sometimes the canned extraction routines will not be sufficiently flexible to deal with your data. The hope is that this walk-though is broken into enough pieces and sufficiently explicit for you to steal the pieces you need for your application.

For the benefit of folks readng this on the web, the walk-though will display each figure at each stage in the extraction. It is worth noting that Yoink requires interactive figures and is incompatible with embedded IPython figures (though the webAgg backend may fix this).


In [1]:
%pylab
import pylab as plt
import numpy as np

from yoink.widgets import ShutterCrop, DeformableLine


Using matplotlib backend: MacOSX
Populating the interactive namespace from numpy and matplotlib

Create Example Data

To simulate real life usage, plot a line, safe the figure, then read the file back in as an image.


In [2]:
plt.figure(1)
plt.clf()
X = np.linspace(0, 7, 100)
Y = np.sinc(X)
plt.plot(X, Y)
plt.title('original data')
plt.show()
plt.savefig('sinc.png')
img = plt.imread('sinc.png')

In [3]:
plt.gcf()


Out[3]:

Crop the Image

Crop the picture to edges of the axes. Crop out the border and axis tick labels.


In [4]:
plt.figure(2)
plt.clf()
plt.imshow(img)
cropper = ShutterCrop(plt.gca())
plt.title('Cropping')


Out[4]:
<matplotlib.text.Text at 0x109612ed0>

In [5]:
plt.gcf()


Out[5]:

The cropper gives you the extents (in pixel coordinate) of the edges of your embedded figure. Make a new image with only these pixels.


In [6]:
ext = cropper.get_extents()
j0, jx = sorted(ext[:2])
i0, ix = sorted(ext[2:])
img_crop = img[i0:ix+1, j0:jx+1]

Manually Pick Points on the Line

Use the DeformableLine to manually click points you want. The points are draggable, so don't worry if you miss. You can remove points by right-clicking on them.


In [7]:
plt.figure(3)
plt.clf()
plt.imshow(img_crop)
xl = plt.xlim()
yl = plt.ylim()
line = DeformableLine(gca())
plt.xlim(*xl)
plt.ylim(*yl)
plt.title('Pick Points (pixel coordinates)')


Out[7]:
<matplotlib.text.Text at 0x10813fe50>

In [8]:
plt.gcf()


Out[8]:

Rescale Points

Now that you've selected your data, you need to convert it from pixel coordinates to the scale in the original figure. Here we interpolate between axis extremes.

Note the indexing. img_crop has shape (ny, nx, nc) ny is the number of vertical pixels, nx is the number of horizontal pixels. nc is the number of color channels. Also notice that PNG's use the top left as the origin. So we had to flip the ymin/ymax order.

Finally, we plot the original data X, Y along with the picked data x, y to show that they overlay.


In [9]:
plt.figure(4)
plt.clf()
plt.title('rescale points to actual data scale')
xmin, xmax = 0, 7
ymin, ymax = -0.4, 1.2
ny, nx, nc = img_crop.shape
x = np.interp(line.xs, [0, nx], [xmin, xmax])
y = np.interp(line.ys, [0, ny], [ymax, ymin])
plt.plot(x, y, 'bo-', label='Picked')
plt.plot(X, Y, 'r', label='Original')
plt.legend(loc='upper right')


Out[9]:
<matplotlib.legend.Legend at 0x10ed0a9d0>

In [10]:
plt.gcf()


Out[10]:

In [ ]: