Skip to main content
← Back to Side Projects & Archives

Extracting data points from plots, images in IDL

Written:

(aka, "I've got this dang figure and can't get access to the original data (or at least not fast enough)... how do I extract the data points from the plot / image?")

So you would like to extract points from a figure and you have access to IDL? Well, you're lucky that I've written the code for it.

;+
; NAME:
;	extract_points
;
; PURPOSE:
;	To facilitate the extraction of data points from a JPEG figure.
;
; EXPLANATION:
;	extract_points is pretty simple.  It reads in a JPEG file,
;	re-sizes it, and then prompts the user to do a bunch of
;	clicking to define the axes and then select points to output.
;
; CALLING SEQUENCE:
;	 extract_points, file, out_arr $
;	   [, xsize=XSIZE, retain=RETAIN]
;
; INPUTS:
;	file - a simple string that holds the JPEG filename.
;
; OUTPUT:
;	out_arr - a n x 2 floating point array with n being the number
;	          of points the user clicked on.
;
; REVISION HISTORY:
;       Written by:  Joseph Lorenzo Hall, 18 Feb 2003.
;-

pro extract_points, file, out_arr, xsize=XSIZE, retain=RETAIN

read_jpeg, file, im			      ;READ IN JPEG

;RESIZE AND DISPLAY JPEG
if n_elements(xsize) ne 1 then $
   x_pix = 640 else x_pix=xsize			;SET WINDOW SIZE
im_sz = size(im)				;GET IMAGE DIMENSIONS
jpg_type = im_sz[0]

if jpg_type eq 2 then begin			;8-BIT, 16-BIT
im_sz = size(im,/dim)
aspect = float(im_sz[1]) / float(im_sz[0])	;ASPECT RATIO
new_im = congrid(im,x_pix,x_pix*aspect)		;RESIZE IMAGE
endif

if jpg_type eq 3 then begin			;24-BIT
im_sz = size(im,/dim)
aspect = float(im_sz[2]) / float(im_sz[1])	;ASPECT RATIO
new_im = $
    congrid(im,im_sz[0],x_pix,x_pix*aspect)	;RESIZE IMAGE
endif

window, retain=retain, xsize=x_pix, $	;OPEN A SIZED WINDOW
	ysize=x_pix*aspect 

CASE StrUpCase(!D.Name) OF		;FANNING SUGGESTS THIS
   'WIN': Device, Decomposed=1
   'MAC': Device, Decomposed=1
    'X' : Device, Decomposed=1
   ELSE:
ENDCASE

if jpg_type eq 3 then tv, new_im, true=1
if jpg_type eq 2 then tv, new_im

;PROMPT TO CLICK ON A TICK LABELS ON X-AXIS
print, ' '
print, ' Please click on the FIRST labeled tick mark on the X-AXIS'
cursor, x1_x, x1_y, /normal, /down
print, ' Please enter the label of this tick mark:'
read, x1_val
print, ' Please click on the LAST labeled tick mark on the X-AXIS'
cursor, x2_x, x2_y, /normal, /down
print, ' Please enter the label of this tick mark:'
read, x2_val

;THE FOLLOWING ALLOWS A TRANFORMATION FROM NORMAL TO DATA COORDINATES
x_pix_diff = x2_x - x1_x
x_val_diff = x2_val - x1_val
x_scale = x_val_diff / x_pix_diff
x_int   = x1_val - x1_x * x_scale

;PROMPT TO CLICK ON A TICK LABEL ON Y-AXIS
print, ' '
print, ' Please click on the FIRST labeled tick mark on the Y-AXIS'
cursor, y1_x, y1_y, /normal, /down
print, ' Please enter the label of this tick mark:'
read, y1_val
print, ' Please click on the LAST labeled tick mark on the Y-AXIS'
cursor, y2_x, y2_y, /normal, /down
print, ' Please enter the label of this tick mark:'
read, y2_val

y_pix_diff = y2_y - y1_y
y_val_diff = y2_val - y1_val
y_scale = y_val_diff / y_pix_diff
y_int   = y1_val - y1_y * y_scale

cfx = [x_int,x_scale]
cfy = [y_int,y_scale]

repeat begin
 print, ' '
 print, ' Begin pixel input. Click on a data point to add it to your array.'
 print, ' Click on middle or right button to exit.'

 flag = 0
 repeat begin
   cursor, x, y, /normal, /down
   if !mouse.button eq 1 then begin
    if flag ne 1 then begin
     flag = 1
     x_arr = x & y_arr = y
    endif else begin
     x_arr = [x_arr,x] & y_arr = [y_arr,y]
    endelse
   endif
 endrep until !mouse.button ge 2

 npts = n_elements(x_arr)
 as = sort(x_arr)
 x_arr = x_arr(as) & y_arr = y_arr(as)	
 out_arr = fltarr(npts,2)
 out_arr[*,0] = poly(x_arr,cfx)
 out_arr[*,1] = poly(y_arr,cfy)

 print, "Are you satisfied with your extraction (0=Sure am, 1=Nope)?"
 read, ans

endrep until (ans eq 0)
end