; docformat = 'rst'
;+
; Plot (large number of) points as pixels (rectangles), with colour
; (white->black) representing density
;
; :Params:
; x : in, required
; x-coordinate of points
; y : in, required
; y-coordinate of points
; :Keywords:
; binsize1 : in, optional
; Size of bin in x-direction
; binsize2 : in, optional
; Size of bin in y-direction
; nbins1 : in, optional
; Number of bins in x-direction (ignored if xrange and binsize1
; set; default 50)
; nbins2 : in, optional
; Number of bins in y-direction (ignored if yrange and binsize2
; set; default 50)
; xrange : in, optional
; Range for plot (if not overplot) and range for histogram
; yrange : in, optional
; Range for plot (if not overplot) and range for histogram
; overplot : in, optional
; Set /overplot to overplot
; ct : in, optional
; Colour table: -1 = use current, -2 = fixed colour (color keyword),
; -3 (or not specified) = default (white -> black)
; If color keyword set, and ct != -2, generate colour table from color
; color : in, optional
; Colour to use instead of grayscale/black
; _REF_EXTRA : in, optional
; Extra keywords for plot
; :Examples:
; ajs_plot_radec, ra, dec, /nodata, xtitle='RA / degrees',
; ytitle='dec / degrees'
;
; ajs_pixel_plot, ra, sin(dec / !RADEG), nbins1=200, nbins2=200,
; /overplot, ct=40
;
; Sample output (click to enlarge):
;
; <a href="http://astronomy.sussex.ac.uk/~anthonys/images/sdss_radec.png"><img src="http://astronomy.sussex.ac.uk/~anthonys/images/sdss_radec.png" width="200"></a>
; :History:
; 18 Apr 2008 Written, Anthony Smith
;-
PRO ajs_pixel_plot, x, y, binsize1=binsize1, binsize2=binsize2, $
nbins1=nbins1, nbins2=nbins2, $
xrange=xrange, yrange=yrange, overplot=overplot, $
ct=ct, color=color, _REF_EXTRA=e
compile_opt idl2
;; No nbins? (Redundant if binsizes are set)
IF n_elements(nbins1) EQ 0 THEN $
nbins1 = 50
IF n_elements(nbins2) EQ 0 THEN $
nbins2 = 50
;; Overplot: get xrange & yrange from plot?
IF keyword_set(overplot) THEN BEGIN
IF n_elements(xrange) EQ 0 THEN $
xrange = !x.crange
IF n_elements(yrange) EQ 0 THEN $
yrange = !y.crange
ENDIF
;; No bin sizes?
IF n_elements(binsize1) EQ 0 THEN $
IF n_elements(xrange) EQ 0 THEN $
binsize1 = (max(x) - min(x)) / float(nbins1) $
ELSE $
binsize1 = (max(xrange) - min(xrange)) / float(nbins1)
IF n_elements(binsize2) EQ 0 THEN $
IF n_elements(yrange) EQ 0 THEN $
binsize2 = (max(y) - min(y)) / float(nbins2) $
ELSE $
binsize2 = (max(yrange) - min(yrange)) / float(nbins2)
;; Range for plot (if not set)
IF n_elements(xrange) EQ 0 THEN $
xrange = [min(x), $
(fix((max(x) - min(x)) / binsize1) + 1) * binsize1 + min(x)]
IF n_elements(yrange) EQ 0 THEN $
yrange = [min(y), $
(fix((max(y) - min(y)) / binsize2) + 1) * binsize2 + min(y)]
;; Make histogram
min = [min(xrange), min(yrange)]
max = [max(xrange), max(yrange)]
hist = hist_nd([1#x, 1#y], [binsize1, binsize2], $
min=min, max=max)
dims = size(hist, /dimensions)
;; Edges of the bins (left/bottom)
obin1 = dindgen(dims[0]) * binsize1 + min[0]
obin2 = dindgen(dims[1]) * binsize2 + min[1]
;; Convert obin1 and obin2 to array with same dimensions as hist
xbin = rebin(obin1, n_elements(obin1), n_elements(obin2))
ybin = rebin(transpose(obin2), n_elements(obin1), n_elements(obin2))
;; Axes
IF ~ keyword_set(overplot) THEN $
plot, [0], xrange=xrange, yrange=yrange, _STRICT_EXTRA=e, /nodata
;; Plot pixels
boxx = [0, 1, 1, 0, 0] * binsize1 * 1.05 ; No gaps between pixels
boxy = [0, 0, 1, 1, 0] * binsize2 * 1.05
nonzero = where(hist GT 0, n_nonzero)
IF n_nonzero GT 0 THEN BEGIN
;; Get current colour table (restore later)
tvlct, r_orig, g_orig, b_orig, /get
IF n_elements(ct) EQ 0 THEN $
ct = -3
IF n_elements(color) GT 0 AND ct NE -2 THEN BEGIN
;; Generate colour table
;; From white (0) to the input colour (255)
color_convert, r_orig, g_orig, b_orig, $
h_orig, l_orig, s_orig, /rgb_hls
hls = double([h_orig[color], l_orig[color], s_orig[color]])
h_curr = replicate(hls[0], 256)
l_curr = 1. - findgen(256) * (1. - hls[1]) / 255
s_curr = replicate(hls[2], 256)
tvlct, h_curr, l_curr, s_curr, /hls
colors = (hist[nonzero] * 255. / max(hist))
ENDIF ELSE IF ct EQ -2 THEN BEGIN
;; Fixed colour
IF n_elements(color) GT 0 THEN $
colors = replicate(color, n_nonzero) $
ELSE $
colors = replicate(0, n_nonzero)
ENDIF ELSE IF ct GE 0 THEN BEGIN
;; Load colour table
loadct, ct
colors = (hist[nonzero] * 255. / max(hist))
ENDIF ELSE IF ct EQ -3 THEN BEGIN
;; Default behaviour (white -> black)
loadct, 0
colors = 255 - (hist[nonzero] * 255. / max(hist))
ENDIF ELSE IF ct EQ -1 THEN BEGIN
;; Use current colour table
colors = (hist[nonzero] * 255. / max(hist))
ENDIF ELSE $
message, 'Don''t know which colours to use!'
;; Plot
FOR i = 0, n_nonzero - 1 DO BEGIN
polyfill, xbin[nonzero[i]] + boxx, ybin[nonzero[i]] + boxy, $
color=colors[i]
ENDFOR
;; Restore colour table
tvlct, r_orig, g_orig, b_orig
ENDIF
END