-
Notifications
You must be signed in to change notification settings - Fork 0
/
AL_legend.pro
573 lines (545 loc) · 27.4 KB
/
AL_legend.pro
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
;+
; NAME:
; AL_LEGEND
; PURPOSE:
; Create an annotation legend for a plot.
; EXPLANATION:
;
; This procedure makes a legend for a plot. The legend can contain
; a mixture of symbols, linestyles, Hershey characters (vectorfont),
; and filled polygons (usersym). A test procedure, al_legendtest.pro,
; shows legend's capabilities. Placement of the legend is controlled
; with keywords like /right, /top, and /center or by using a position
; keyword for exact placement (position=[x,y]) or via mouse (/position).
;
; The procedure CGLEGEND in the Coyote library provides a similar
; capability. https://www.idlcoyote.com/idldoc/cg/cglegend.html
; CALLING SEQUENCE:
; AL_LEGEND [,items][,keyword options]
; EXAMPLES:
; The call:
; al_legend,['Plus sign','Asterisk','Period'],psym=[1,2,3]
; produces:
; -----------------
; | |
; | + Plus sign |
; | * Asterisk |
; | . Period |
; | |
; -----------------
; Each symbol is drawn with a cgPlots command, so they look OK.
; Other examples are given in optional output keywords.
;
; lines = indgen(6) ; for line styles
; items = 'linestyle '+strtrim(lines,2) ; annotations
; al_legend,items,linestyle=lines ; vertical legend---upper left
; items = ['Plus sign','Asterisk','Period']
; sym = [1,2,3]
; al_legend,items,psym=sym ; ditto except using symbols
; al_legend,items,psym=sym,/horizontal ; horizontal format
; al_legend,items,psym=sym,box=0 ; sans border
; al_legend,items,psym=sym,delimiter='=' ; embed '=' betw psym & text
; al_legend,items,psym=sym,margin=2 ; 2-character margin
; al_legend,items,psym=sym,position=[x,y] ; upper left in data coords
; al_legend,items,psym=sym,pos=[x,y],/norm ; upper left in normal coords
; al_legend,items,psym=sym,pos=[x,y],/device ; upper left in device coords
; al_legend,items,psym=sym,/position ; interactive position
; al_legend,items,psym=sym,/right ; at upper right
; al_legend,items,psym=sym,/bottom ; at lower left
; al_legenditems,psym=sym,/center ; approximately near center
; al_legend,items,psym=sym,number=2 ; plot two symbols, not one
; Plot 3 filled colored squares
; al_legend,items,/fill,psym=[8,8,8],colors=['red','green','blue']
;
; Another example of the use of AL_LEGEND can be found at
; http://www.idlcoyote.com/cg_tips/al_legend.php
; INPUTS:
; items = text for the items in the legend, a string array.
; For example, items = ['diamond','asterisk','square'].
; You can omit items if you don't want any text labels. The
; text can include many LaTeX symbols (e.g. $\leq$) for a less
; than equals symbol) as described in cgsymbol.pro.
; OPTIONAL INPUT KEYWORDS:
;
; linestyle = array of linestyle numbers If linestyle[i] < 0, then omit
; ith symbol or line to allow a multi-line entry. If
; linestyle = -99 then text will be left-justified.
; psym = array of plot symbol numbers or names. If psym[i] is negative,
; then a line connects pts for ith item. If psym[i] = 8, then the
; procedure USERSYM is called with vertices defined in the
; keyword usersym. If psym[i] = 88, then use the previously
; defined user symbol. If 11 <= psym[i] <= 46 then David
; Fanning's function CGSYMCAT() will be used for additional
; symbols. Note that PSYM=10 (histogram plot mode) is not
; allowed since it cannot be used with the cgPlots command.
; vectorfont = vector-drawn characters for the sym/line column, e.g.,
; ['!9B!3','!9C!3','!9D!3'] produces an open square, a checkmark,
; and a partial derivative, which might have accompanying items
; ['BOX','CHECK','PARTIAL DERIVATIVE'].
; There is no check that !p.font is set properly, e.g., -1 for
; X and 0 for PostScript. This can produce an error, e.g., use
; !20 with PostScript and !p.font=0, but allows use of Hershey
; *AND* PostScript fonts together.
; N. B.: Choose any of linestyle, psym, and/or vectorfont. If none is
; present, only the text is output. If more than one
; is present, all need the same number of elements, and normal
; plot behaviour occurs.
; By default, if psym is positive, you get one point so there is
; no connecting line. If vectorfont[i] = '',
; then cgPlots is called to make a symbol or a line, but if
; vectorfont[i] is a non-null string, then cgText is called.
; /help = flag to print header
; /horizontal = flag to make the legend horizontal
; /vertical = flag to make the legend vertical (D=vertical)
; background_color - color name or number to fill the legend box.
; Automatically sets /clear. (D = -1)
; box = flag to include/omit box around the legend (D=include)
; outline_color = color of box outline (D = !P.color)
; bthick = thickness of the legend box (D = !P.thick)
; charsize = just like !p.charsize for plot labels
; charthick = just like !p.charthick for plot labels
; clear = flag to clear the box area before drawing the legend
; colors = array of colors names or numbers for plot symbols/lines
; See cgCOLOR for list of color names. Default is 'Opposite'
; If you are using index colors (0-255), then supply color as a byte,
; integer or string, but not as a long, which will be interpreted as
; a decomposed color. See http://www.idlcoyote.com/cg_tips/legcolor.php
; delimiter = embedded character(s) between symbol and text (D=none)
; font = scalar font graphics keyword (-1,0 or 1) for text
; linsize = Scale factor for line length (0-1), default = 1
; Set to 0 to give a dot, 0.5 give half default line length
; margin = margin around text measured in characters and lines
; number = number of plot symbols to plot or length of line (D=1)
; spacing = line spacing (D=bit more than character height)
; position = data coordinates of the /top (D) /left (D) of the legend
; pspacing = psym spacing (D=3 characters) (when number of symbols is
; greater than 1)
; textcolors = array of color names or numbers for text. See cgCOLOR
; for a list of color names. Default is 'Opposite' of background
; thick = array of line thickness numbers (D = !P.thick), if used, then
; linestyle must also be specified
; normal = use normal coordinates for position, not data
; device = use device coordinates for position, not data
; /window - if set then send legend to a resizeable graphics window
; usersym = 2-D array of vertices, cf. usersym in IDL manual.
; (/USERSYM =square, default is to use existing USERSYM definition)
; /fill = flag to fill the usersym
; /left_legend = flag to place legend snug against left side of plot
; window (D)
; /right_legend = flag to place legend snug against right side of plot
; window. If /right,pos=[x,y], then x is position of RHS and
; text runs right-to-left.
; /top_legend = flag to place legend snug against top of plot window (D)
; /bottom = flag to place legend snug against bottom of plot window
; /top,pos=[x,y] and /bottom,pos=[x,y] produce same positions.
;
; If LINESTYLE, PSYM, VECTORFONT, SYMSIZE, THICK, COLORS, or
; TEXTCOLORS are supplied as scalars, then the scalar value is set for
; every line or symbol in the legend.
; Outputs:
; legend to current plot device
; OPTIONAL OUTPUT KEYWORDS:
; corners = 4-element array, like !p.position, of the normalized
; coords for the box (even if box=0): [llx,lly,urx,ury].
; Useful for multi-column or multi-line legends, for example,
; to make a 2-column legend, you might do the following:
; c1_items = ['diamond','asterisk','square']
; c1_psym = [4,2,6]
; c2_items = ['solid','dashed','dotted']
; c2_line = [0,2,1]
; al_legend,c1_items,psym=c1_psym,corners=c1,box=0
; al_legend,c2_items,line=c2_line,corners=c2,box=0,pos=[c1[2],c1[3]]
; c = [c1[0]<c2[0],c1[1]<c2[1],c1[2]>c2[2],c1[3]>c2[3]]
; cgplots,[c[0],c[0],c[2],c[2],c[0]],[c[1],c[3],c[3],c[1],c[1]],/norm
;
; Useful also to place the legend. Here's an automatic way to place
; the legend in the lower right corner. The difficulty is that the
; legend's width is unknown until it is plotted. In this example,
; the legend is plotted twice: the first time in the upper left, the
; second time in the lower right.
;
; al_legend,['1','22','333','4444'],linestyle=indgen(4),corners=corners
; ; BOGUS LEGEND---FIRST TIME TO REPORT CORNERS
; xydims = [corners[2]-corners[0],corners[3]-corners[1]]
; ; SAVE WIDTH AND HEIGHT
; chdim=[!d.x_ch_size/float(!d.x_size),!d.y_ch_size/float(!d.y_size)]
; ; DIMENSIONS OF ONE CHARACTER IN NORMALIZED COORDS
; pos = [!x.window[1]-chdim[0]-xydims[0] $
; ,!y.window[0]+chdim[1]+xydims[1]]
; ; CALCULATE POSITION FOR LOWER RIGHT
; cgplot,findgen(10) ; SIMPLE PLOT; YOU DO WHATEVER YOU WANT HERE.
; al_legend,['1','22','333','4444'],linestyle=indgen(4),pos=pos
; ; REDO THE LEGEND IN LOWER RIGHT CORNER
; You can modify the pos calculation to place the legend where you
; want. For example to place it in the upper right:
; pos = [!x.window[1]-chdim[0]-xydims[0],!y.window[1]-xydims[1]]
; Common blocks:
; none
; Procedure:
; If keyword help is set, call doc_library to print header.
; See notes in the code. Much of the code deals with placement of the
; legend. The main problem with placement is not being
; able to sense the length of a string before it is output. Some crude
; approximations are used for centering.
; Restrictions:
; Here are some things that aren't implemented.
; - An orientation keyword would allow lines at angles in the legend.
; - An array of usersyms would be nice---simple change.
; - An order option to interchange symbols and text might be nice.
; - Somebody might like double boxes, e.g., with box = 2.
; - Another feature might be a continuous bar with ticks and text.
; - There are no guards to avoid writing outside the plot area.
; - There is no provision for multi-line text, e.g., '1st line!c2nd line'
; Sensing !c would be easy, but !c isn't implemented for PostScript.
; A better way might be to simply output the 2nd line as another item
; but without any accompanying symbol or linestyle. A flag to omit
; the symbol and linestyle is linestyle[i] = -1.
; - There is no ability to make a title line containing any of titles
; for the legend, for the symbols, or for the text.
; Notes:
; This procedure was originally named LEGEND, but a distinct LEGEND()
; function was introduced into IDL V8.0. Therefore, the
; original LEGEND procedure was renamed to AL_LEGEND to avoid conflict.
;
; Modification history:
; write, 24-25 Aug 92, F K Knight (knight@ll.mit.edu)
; allow omission of items or omission of both psym and linestyle, add
; corners keyword to facilitate multi-column legends, improve place-
; ment of symbols and text, add guards for unequal size, 26 Aug 92, FKK
; add linestyle(i)=-1 to suppress a single symbol/line, 27 Aug 92, FKK
; add keyword vectorfont to allow characters in the sym/line column,
; 28 Aug 92, FKK
; add /top, /bottom, /left, /right keywords for automatic placement at
; the four corners of the plot window. The /right keyword forces
; right-to-left printing of menu. 18 Jun 93, FKK
; change default position to data coords and add normal, data, and
; device keywords, 17 Jan 94, FKK
; add /center keyword for positioning, but it is not precise because
; text string lengths cannot be known in advance, 17 Jan 94, FKK
; add interactive positioning with /position keyword, 17 Jan 94, FKK
; allow a legend with just text, no plotting symbols. This helps in
; simply describing a plot or writing assumptions done, 4 Feb 94, FKK
; added thick, symsize, and clear keyword Feb 96, W. Landsman HSTX
; David Seed, HR Wallingford, d.seed@hrwallingford.co.uk
; allow scalar specification of keywords, Mar 96, W. Landsman HSTX
; added charthick keyword, June 96, W. Landsman HSTX
; Made keyword names left,right,top,bottom,center longer,
; Aug 16, 2000, Kim Tolbert
; Added ability to have regular text lines in addition to plot legend
; lines in legend. If linestyle is -99 that item is left-justified.
; Previously, only option for no sym/line was linestyle=-1, but then text
; was lined up after sym/line column. 10 Oct 2000, Kim Tolbert
; Make default value of thick = !P.thick W. Landsman Jan. 2001
; Don't overwrite existing USERSYM definition W. Landsman Mar. 2002
; Added outline_color BT 24 MAY 2004
; Pass font keyword to cgText commands. M. Fitzgerald, Sep. 2005
; Default spacing, pspacing should be relative to charsize. M. Perrin, July 2007
; Don't modify position keyword A. Kimball/ W. Landsman Jul 2007
; Small update to Jul 2007 for /NORMAL coords. W. Landsman Aug 2007
; Use SYMCAT() plotting symbols for 11<=PSYM<=46 W. Landsman Nov 2009
; Make a sharper box edge T. Robishaw/W.Landsman July 2010
; Added BTHICK keyword W. Landsman October 2010
; Added BACKGROUND_COLOR keyword W. Landsman February 2011
; Incorporate Coyote graphics W. Landsman February 2011
; Added LINSIZE keyword W.L./V.Gonzalez May 2011
; Fixed a small problem with Convert_Coord when the Window keyword is set.
; David Fanning, May 2011.
; Fixed problem when /clear and /Window are set J. Bailin/WL May 2011
; CGQUERY was called instead of CGCONTROL W.L. June 2011
; Fixed typo preventing BTHICK keyword from working W.L. Dec 2011
; Remove call to SYMCAT() W.L. Dec 2011
; Changed the way the WINDOW keyword adds commands to cgWindow, and
; now default to BACKGROUND for background color. 1 Feb 2012 David Fanning
; Allow 1 element SYMSIZE for vector input, WL Apr 2012.
; Allow to specify symbols by cgSYMCAT() name WL Aug 2012
; Fixed bug when linsize, /right called simultaneously, Dec 2012, K.Stewart
; Added a check for embedded symbols in the items string array. March 2013. David Fanning
;
;-
pro al_legend, items, BOTTOM_LEGEND=bottom, BOX = box, CENTER_LEGEND=center, $
CHARTHICK=charthick, CHARSIZE = charsize, CLEAR = clear, COLORS = colorsi, $
CORNERS = corners, DATA=data, DELIMITER=delimiter, DEVICE=device, $
FILL=fill, HELP = help, HORIZONTAL=horizontal,LEFT_LEGEND=left, $
LINESTYLE=linestylei, MARGIN=margin, NORMAL=normal, NUMBER=number, $
POSITION=position,PSPACING=pspacing, PSYM=psymi, RIGHT_LEGEND=right, $
SPACING=spacing, SYMSIZE=symsizei, TEXTCOLORS=textcolorsi, THICK=thicki, $
TOP_LEGEND=top, USERSYM=usersym, VECTORFONT=vectorfonti, $
VERTICAL=vertical,OUTLINE_COLOR = outline_color, FONT = font, $
BTHICK=bthick, background_color = bgcolor, WINDOW=window,LINSIZE = linsize
;
; =====>> HELP
;
compile_opt idl2
;On_error,2
if keyword_set(help) then begin & doc_library,'al_legend' & return & endif
; Should this commnad be added to a resizeable graphics window?
IF (Keyword_Set(window)) && ((!D.Flags AND 256) NE 0) THEN BEGIN
cgWindow, 'al_legend', items, BOTTOM_LEGEND=bottom, BOX = box, CENTER_LEGEND=center, $
CHARTHICK=charthick, CHARSIZE = charsize, CLEAR = clear, COLORS = colorsi, $
CORNERS = corners, DATA=data, DELIMITER=delimiter, DEVICE=device, $
FILL=fill, HELP = help, HORIZONTAL=horizontal,LEFT_LEGEND=left, $
LINESTYLE=linestylei, MARGIN=margin, NORMAL=normal, NUMBER=number, $
POSITION=position,PSPACING=pspacing, PSYM=psymi, RIGHT_LEGEND=right, $
SPACING=spacing, SYMSIZE=symsizei, TEXTCOLORS=textcolorsi, THICK=thicki, $
TOP_LEGEND=top, USERSYM=usersym, VECTORFONT=vectorfonti, $
VERTICAL=vertical,OUTLINE_COLOR = outline_color, FONT = font, $
BTHICK=thick, background_color = bgcolor, LINSIZE = linsize, ADDCMD=1
RETURN
ENDIF
;
;
; =====>> SET DEFAULTS FOR SYMBOLS, LINESTYLES, AND ITEMS.
;
ni = n_elements(items)
np = n_elements(psymi)
nl = n_elements(linestylei)
nth = n_elements(thicki)
nsym = n_elements(symsizei)
nv = n_elements(vectorfonti)
nlpv = max([np,nl,nv])
n = max([ni,np,nl,nv]) ; NUMBER OF ENTRIES
strn = strtrim(n,2) ; FOR ERROR MESSAGES
if n eq 0 then message,'No inputs! For help, type al_legend,/help.'
if ni eq 0 then begin
items = replicate('',n) ; DEFAULT BLANK ARRAY
endif else begin
if size(items,/TNAME) NE 'STRING' then message, $
'First parameter must be a string array. For help, type al_legend,/help.'
if ni ne n then message,'Must have number of items equal to '+strn
endelse
items = cgCheckForSymbols(items) ; Check for embedded symbols in the items array.
symline = (np ne 0) || (nl ne 0) ; FLAG TO PLOT SYM/LINE
if (np ne 0) && (np ne n) && (np NE 1) then message, $
'Must have 0, 1 or '+strn+' elements in PSYM array.'
if (nl ne 0) && (nl ne n) && (nl NE 1) then message, $
'Must have 0, 1 or '+strn+' elements in LINESTYLE array.'
if (nth ne 0) && (nth ne n) && (nth NE 1) then message, $
'Must have 0, 1 or '+strn+' elements in THICK array.'
case nl of
0: linestyle = intarr(n) ;Default = solid
1: linestyle = intarr(n) + linestylei
else: linestyle = linestylei
endcase
case nsym of
0: symsize = replicate(!p.symsize,n) ;Default = !P.SYMSIZE
1: symsize = intarr(n) + symsizei
else: symsize = symsizei
endcase
case nth of
0: thick = replicate(!p.thick,n) ;Default = !P.THICK
1: thick = intarr(n) + thicki
else: thick = thicki
endcase
if size(psymi,/TNAME) EQ 'STRING' then begin
psym = intarr(n)
for i=0,N_elements(psymi)-1 do psym[i] = cgsymcat(psymi[i])
endif else begin
case np of ;Get symbols
0: psym = intarr(n) ;Default = solid
1: psym = intarr(n) + psymi
else: psym = psymi
endcase
endelse
case nv of
0: vectorfont = replicate('',n)
1: vectorfont = replicate(vectorfonti,n)
else: vectorfont = vectorfonti
endcase
;
; =====>> CHOOSE VERTICAL OR HORIZONTAL ORIENTATION.
;
if n_elements(horizontal) eq 0 then $ ; D=VERTICAL
setdefaultvalue, vertical, 1 else $
setdefaultvalue, vertical, ~horizontal
;
; =====>> SET DEFAULTS FOR OTHER OPTIONS.
;
setdefaultvalue, box, 1
if N_elements(bgcolor) NE 0 then clear = 1
setdefaultvalue, bgcolor, 'BACKGROUND'
setdefaultvalue, clear, 0
setdefaultvalue, linsize, 1.
setdefaultvalue, margin, 0.5
setdefaultvalue, delimiter, ''
setdefaultvalue, charsize, !p.charsize
setdefaultvalue, charthick, !p.charthick
if charsize eq 0 then charsize = 1
setdefaultvalue, number, 1
; Default color is opposite the background color
case N_elements(colorsi) of
0: colors = replicate('opposite',n)
1: colors = replicate(colorsi,n)
else: colors = colorsi
endcase
case N_elements(textcolorsi) of
0: textcolors = replicate('opposite',n)
1: textcolors = replicate(textcolorsi,n)
else: textcolors = textcolorsi
endcase
fill = keyword_set(fill)
if n_elements(usersym) eq 1 then usersym = 2*[[0,0],[0,1],[1,1],[1,0],[0,0]]-1
;
; =====>> INITIALIZE SPACING
;
setdefaultvalue, spacing, 1.2*charsize
setdefaultvalue, pspacing , 3*charsize
xspacing = !d.x_ch_size/float(!d.x_size) * (spacing > charsize)
yspacing = !d.y_ch_size/float(!d.y_size) * (spacing > charsize)
ltor = 1 ; flag for left-to-right
if n_elements(left) eq 1 then ltor = left eq 1
if n_elements(right) eq 1 then ltor = right ne 1
ttob = 1 ; flag for top-to-bottom
if n_elements(top) eq 1 then ttob = top eq 1
if n_elements(bottom) eq 1 then ttob = bottom ne 1
xalign = ltor ne 1 ; x alignment: 1 or 0
yalign = -0.5*ttob + 1 ; y alignment: 0.5 or 1
xsign = 2*ltor - 1 ; xspacing direction: 1 or -1
ysign = 2*ttob - 1 ; yspacing direction: 1 or -1
if ~ttob then yspacing = -yspacing
if ~ltor then xspacing = -xspacing
;
; =====>> INITIALIZE POSITIONS: FIRST CALCULATE X OFFSET FOR TEXT
;
xt = 0
if nlpv gt 0 then begin ; SKIP IF TEXT ITEMS ONLY.
if vertical then begin ; CALC OFFSET FOR TEXT START
for i = 0,n-1 do begin
if (psym[i] eq 0) and (vectorfont[i] eq '') then num = (number + 1) > 3 else num = number
if psym[i] lt 0 then num = number > 2 ; TO SHOW CONNECTING LINE
if psym[i] eq 0 then expand = linsize else expand = 2
thisxt = (expand*pspacing*(num-1)*xspacing)
if ltor then xt = thisxt > xt else xt = thisxt < xt
endfor
endif ; NOW xt IS AN X OFFSET TO ALIGN ALL TEXT ENTRIES.
endif
;
; =====>> INITIALIZE POSITIONS: SECOND LOCATE BORDER
;
if !x.window[0] eq !x.window[1] then begin
cgplot,/nodata,xstyle=4,ystyle=4,[0],/noerase
endif
; next line takes care of weirdness with small windows
pos = [min(!x.window),min(!y.window),max(!x.window),max(!y.window)]
case n_elements(position) of
0: begin
if ltor then px = pos[0] else px = pos[2]
if ttob then py = pos[3] else py = pos[1]
if keyword_set(center) then begin
if ~keyword_set(right) && ~keyword_set(left) then $
px = (pos[0] + pos[2])/2. - xt
if ~keyword_set(top) && ~keyword_set(bottom) then $
py = (pos[1] + pos[3])/2. + n*yspacing
endif
nposition = [px,py] + [xspacing,-yspacing]
end
1: begin ; interactive
message,/inform,'Place mouse at upper left corner and click any mouse button.'
cursor,x,y,/normal
nposition = [x,y]
end
2: begin ; convert upper left corner to normal coordinates
; if keyword window is set, get the current graphics window.
if keyword_set(window) then begin
wid = cgQuery(/current)
WSet, wid
endif
if keyword_set(data) then $
nposition = convert_coord(position,/to_norm) $
else if keyword_set(device) then $
nposition = convert_coord(position,/to_norm,/device) $
else if ~keyword_set(normal) then $
nposition = convert_coord(position,/to_norm) else nposition= position
end
else: message,'Position keyword can have 0, 1, or 2 elements only. Try al_legend,/help.'
endcase
yoff = 0.25*yspacing*ysign ; VERT. OFFSET FOR SYM/LINE.
x0 = nposition[0] + (margin)*xspacing ; INITIAL X & Y POSITIONS
y0 = nposition[1] - margin*yspacing + yalign*yspacing ; WELL, THIS WORKS!
;
; =====>> OUTPUT TEXT FOR LEGEND, ITEM BY ITEM.
; =====>> FOR EACH ITEM, PLACE SYM/LINE, THEN DELIMITER,
; =====>> THEN TEXT---UPDATING X & Y POSITIONS EACH TIME.
; =====>> THERE ARE A NUMBER OF EXCEPTIONS DONE WITH IF STATEMENTS.
;
for iclr = 0,clear do begin
y = y0 ; STARTING X & Y POSITIONS
x = x0
if ltor then xend = 0 else xend = 1 ; SAVED WIDTH FOR DRAWING BOX
if ttob then ii = [0,n-1,1] else ii = [n-1,0,-1]
for i = ii[0],ii[1],ii[2] do begin
if vertical then x = x0 else y = y0 ; RESET EITHER X OR Y
x = x + xspacing ; UPDATE X & Y POSITIONS
y = y - yspacing
if nlpv eq 0 then goto,TEXT_ONLY ; FLAG FOR TEXT ONLY
num = number
if (psym[i] eq 0) && (vectorfont[i] eq '') then num = (number + 1) > 3
if psym[i] lt 0 then num = number > 2 ; TO SHOW CONNECTING LINE
if psym[i] eq 0 then expand = 1 else expand = 2
xp = x + expand*pspacing*indgen(num)*xspacing
if (psym[i] gt 0) && (num eq 1) && vertical then xp = x + xt/2.
yp = y + intarr(num)
if vectorfont[i] eq '' then yp += yoff
if psym[i] eq 0 then begin
if ltor eq 1 then xp = [min(xp),max(xp) -(max(xp)-min(xp))*(1.-linsize)]
if ltor ne 1 then xp = [min(xp) +(max(xp)-min(xp))*(1.-linsize),max(xp)]
yp = [min(yp),max(yp)] ; DITTO
endif
if (psym[i] eq 8) && (N_elements(usersym) GT 1) then $
usersym,usersym,fill=fill,color=colors[i]
;; extra by djseed .. psym=88 means use the already defined usersymbol
if psym[i] eq 88 then p_sym =8 else $
if psym[i] EQ 10 then $
message,'PSYM=10 (histogram mode) not allowed to al_legend.pro' $
else p_sym= psym[i]
if vectorfont[i] ne '' then begin
; if (num eq 1) && vertical then xp = x + xt/2 ; IF 1, CENTERED.
cgText,xp,yp,vectorfont[i],width=width,color=colors[i], $
size=charsize,align=xalign,charthick = charthick,/norm,font=font
xt = xt > width
xp = xp + width/2.
endif else begin
if symline and (linestyle[i] ge 0) then cgPlots,xp,yp,color=colors[i] $
,/normal,linestyle=linestyle[i],psym=p_sym,symsize=symsize[i], $
thick=thick[i]
endelse
if vertical then x += xt else if ltor then x = max(xp) else x = min(xp)
if symline then x += xspacing
TEXT_ONLY:
if vertical && (vectorfont[i] eq '') && symline && (linestyle[i] eq -99) then x=x0 + xspacing
cgText,x,y,delimiter,width=width,/norm,color=textcolors[i], $
size=charsize,align=xalign,charthick = charthick,font=font
x += width*xsign
if width ne 0 then x += 0.5*xspacing
cgText,x,y,items[i],width=width,/norm,color=textcolors[i],size=charsize, $
align=xalign,charthick=charthick,font=font
x += width*xsign
if ~vertical && (i lt (n-1)) then x += 2*xspacing; ADD INTER-ITEM SPACE
xfinal = (x + xspacing*margin)
if ltor then xend = xfinal > xend else xend = xfinal < xend ; UPDATE END X
endfor
if (iclr lt clear ) then begin
; =====>> CLEAR AREA
x = nposition[0]
y = nposition[1]
if vertical then bottom = n else bottom = 1
ywidth = - (2*margin+bottom-0.5)*yspacing
corners = [x,y+ywidth,xend,y]
cgColorfill,[x,xend,xend,x,x],y + [0,0,ywidth,ywidth,0],/norm, $
color=bgcolor
; cgPlots,[x,xend,xend,x,x],y + [0,0,ywidth,ywidth,0], $
; thick=2
endif else begin
;
; =====>> OUTPUT BORDER
;
x = nposition[0]
y = nposition[1]
if vertical then bottom = n else bottom = 1
ywidth = - (2*margin+bottom-0.5)*yspacing
corners = [x,y+ywidth,xend,y]
if box then cgPlots,[x,xend,xend,x,x,xend],y + [0,0,ywidth,ywidth,0,0],$
/norm, color = outline_color,thick=bthick
return
endelse
endfor
end