├── Brammer11_Fig7.png ├── .gitignore ├── LICENSE.md ├── README.md └── FigureData.py /Brammer11_Fig7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbrammer/FigureData/HEAD/Brammer11_Fig7.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | __pycache__ 21 | 22 | # Installer logs 23 | pip-log.txt 24 | 25 | # Unit test / coverage reports 26 | .coverage 27 | .tox 28 | nosetests.xml 29 | 30 | # Translations 31 | *.mo 32 | 33 | # Mr Developer 34 | .mr.developer.cfg 35 | .project 36 | .pydevproject 37 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Gabe Brammer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FigureData.py: 2 | ========== 3 | 4 | This program allows one to extract quantitative numbers from published 5 | figures that were not accompanied by tables with the data themselves. 6 | 7 | _Usage:_ 8 | ```python 9 | >>> import FigureData 10 | >>> FigureData.go(figure_file='Brammer11_Fig7.png', output_file='myfigure.data') 11 | ``` 12 | 13 | The primary input `figure_file` is an image file of the figure (PNG, GIF, JPG). 14 | The script prompts for the user to mark points on the figure defining the plot regions. 15 | 16 | The steps are as follows: 17 | 18 | 1. Click two points on the x axis where you know the values from, e.g., the 19 | axis labels. After clicking the points in the plot window, type the _x_ 20 | values of those coordinates on the command line and hit . 21 | 22 | 2. Same as 1) for two points on the _y_ axis. 23 | 24 | 3. Prompt to click on the lower-left and upper-right corners of the plot 25 | window 26 | 27 | 4. After 3) you can then click as many points as you want on the figure. 28 | To finish, click in the small border outside of the plot window to 29 | save the data to a file specified by the `output_file` keyword. 30 | 31 | The third column of the output file is a flag for marked data points 32 | that fall outside of the defined plot window. 33 | -------------------------------------------------------------------------------- /FigureData.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | FigureData.py: Extract quantitative data from figures 4 | 5 | This program allows one to extract quantitative numbers from published 6 | figures that were not accompanied by tables with the data themselves. 7 | 8 | Usage: 9 | 10 | >>> import FigureData 11 | >>> FigureData.go(figure_file='Brammer11_Fig7.png', output_file='myfigure.data') 12 | 13 | The primary input is an image file of the figure (PNG, GIF, JPG). The 14 | script prompts for the user to mark points on the figure defining the plot regions. The steps are as follows: 15 | 16 | 1) Click two points on the x axis where you know the values from, e.g., the 17 | axis labels. After clicking the points in the plot window, type the -x- 18 | values of those coordinates on the command line and hit . 19 | 20 | 2) Same as 1) for two points on the -y- axis. 21 | 22 | 3) Prompt to click on the lower-left and upper-right corners of the plot 23 | window 24 | 25 | 4) After 3) you can then click as many points as you want on the figure. 26 | To finish, click in the small border outside of the plot window to 27 | save the data to a file specified by the `output` keyword. 28 | 29 | The third column of the output file is a flag for marked data points 30 | that fall outside of the defined plot window. 31 | 32 | G.Brammer - Jan. 22, 2014 33 | """ 34 | import matplotlib.pyplot as plt 35 | import numpy as np 36 | #import Image 37 | 38 | class Globals(): 39 | """ 40 | Container for global variables accessible to the event handler 41 | """ 42 | def __init__(self): 43 | ### Data read from clicks in the plot window 44 | self.xdata = [] 45 | self.ydata = [] 46 | 47 | ### Plot range in axis coordinates 48 | self.xrange = None 49 | self.yrange = None 50 | 51 | ### Pixel coordinates of axes marks 52 | self.xpix = None 53 | self.ypix = None 54 | 55 | ### lower-left and upper-right coords of plot axes 56 | self.ll = None 57 | self.ur = None 58 | 59 | self.ax = None 60 | self.output_file = '' 61 | 62 | G = Globals() 63 | 64 | def onclick(event): 65 | """ 66 | Event handler for clicks in the matplotlib plot window 67 | """ 68 | if event.xdata is None: 69 | ### Click was outside the plot region 70 | #print 'Outside (%d, %d)' %(event.x, event.y) 71 | 72 | ### Write the output file 73 | fp = open(G.output_file, 'w') 74 | for i in range(len(G.xdata)-6): 75 | xi, yi = G.xdata[i+6], G.ydata[i+6] 76 | xval, yval = translate_xy(xi, yi) 77 | inplot = ((xi >= G.ll[0]) & (xi <= G.ur[0]) & 78 | (yi >= G.ll[1]) & (yi <= G.ur[1])) 79 | 80 | fp.write('%f %f %d\n' %(xval, yval, inplot*1)) 81 | 82 | fp.close() 83 | print(('Saved to %s.' %(G.output_file))) 84 | 85 | else: 86 | #print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%(event.button, event.x, event.y, event.xdata, event.ydata) 87 | G.xdata.append(event.xdata) 88 | G.ydata.append(event.ydata) 89 | # 90 | if len(G.xdata) < 7: 91 | print('< mark >') 92 | 93 | if len(G.xdata) > 6: 94 | xval, yval = translate_xy(G.xdata[-1], G.ydata[-1]) 95 | print('Mark [%f,%f]' %(xval, yval)) 96 | G.ax.scatter(G.xdata[-1], G.ydata[-1], marker='o', color='white', s=40, alpha=0.7) 97 | G.ax.scatter(G.xdata[-1], G.ydata[-1], marker='o', color='red', s=20, alpha=0.7) 98 | plt.draw() 99 | 100 | def translate_xy(x, y): 101 | """ 102 | Translate the event (x,y) coordinates to plot coordinates 103 | """ 104 | xval = (x-G.xpix[0])*np.diff(G.xrange)/np.diff(G.xpix)+G.xrange[0] 105 | yval = (y-G.ypix[0])*np.diff(G.yrange)/np.diff(G.ypix)+G.yrange[0] 106 | 107 | return xval, yval 108 | 109 | def go(figure_file='Brammer11_Fig7.png', output_file='plot.data'): 110 | """ 111 | Run the full script 112 | """ 113 | 114 | ### G is global container instantiated at import 115 | G.xdata = [] 116 | G.ydata = [] 117 | G.output_file = output_file 118 | 119 | ### Display the plot 120 | #im = Image.open(figure_file) 121 | im = plt.imread(figure_file) 122 | im = im[::-1,:,:] 123 | fig = plt.figure(figsize=(8,8.*im.shape[0]/im.shape[1])) 124 | fig.subplots_adjust(left=0.02, bottom=0.02, right=1-0.02, top=1-0.02) 125 | 126 | ax = fig.add_subplot(111) 127 | G.ax = ax 128 | 129 | ax.imshow(im, aspect='auto', origin='lower') 130 | ax.set_xticks([0,im.shape[1]]); ax.set_yticks([0,im.shape[0]]) 131 | ax.set_xlim([0,im.shape[1]]); ax.set_ylim([0,im.shape[0]]) 132 | ax.set_xticklabels([]); ax.set_yticklabels([]) 133 | 134 | plt.draw() 135 | 136 | ### Add "click" listener to the plot 137 | cid = fig.canvas.mpl_connect('button_press_event', onclick) 138 | 139 | ### Define -x- axis 140 | xticks = '' 141 | xticks = input('\n == Click two positions along the -x- axis and enter the tick coordinates here (e.g., 0,1): ') 142 | G.xrange = list(np.cast[float](xticks.split(','))) 143 | 144 | ### Define -y- axis 145 | yticks = input('\n == Click two positions along the -y- axis and enter the tick coordinates here (e.g., 0,1): ') 146 | G.yrange = list(np.cast[float](yticks.split(','))) 147 | 148 | ### Define the full plot window 149 | full = input('\n == Now mark the ll and ur corners of the plot axes. when done. ') 150 | 151 | G.xpix = G.xdata[0:2] 152 | G.ypix = G.ydata[2:4] 153 | G.ll = [G.xdata[4], G.ydata[4]] 154 | G.ur = [G.xdata[5], G.ydata[5]] 155 | xmin, ymin = translate_xy(G.ll[0], G.ll[1]) 156 | xmax, ymax = translate_xy(G.ur[0], G.ur[1]) 157 | print('\n Plot window: x=[%f,%f], y=[%f,%f] \n' %(xmin, xmax, ymin, ymax)) 158 | 159 | print("""\n == Now mark as many data points as you like. 160 | == Click outside the plot window to save the `output_file`. 161 | """) 162 | done = input('\n== when done.\n') 163 | 164 | --------------------------------------------------------------------------------