PLplot: pllegend.c Source File

PLplot 5.15.0

pllegend.c
Go to the documentation of this file.
1 // All routines that help to create a discrete legend (pllegend) or
2 // a continuous legend (plcolorbar).
3 //
4 // Copyright (C) 2010-2013 Hezekiah M. Carty
5 // Copyright (C) 2010-2014 Alan W. Irwin
6 //
7 // This file is part of PLplot.
8 //
9 // PLplot is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU Library General Public License as published
11 // by the Free Software Foundation; either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // PLplot is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU Library General Public License for more details.
18 //
19 // You should have received a copy of the GNU Library General Public License
20 // along with PLplot; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //
23
28 #include "plplotP.h"
29
30 //--------------------------------------------------------------------------
45
46 static void plgvpsp( PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax )
47 {
48 if ( plsc->level < 1 )
49 {
50 plabort( "plgvpsp: Please call plinit first" );
51 return;
52 }
53 if ( ( plsc->cursub <= 0 ) || ( plsc->cursub > ( plsc->nsubx * plsc->nsuby ) ) )
54 {
55 plabort( "plgvpsp: Please call pladv or plenv to go to a subpage" );
56 return;
57 }
58 *p_xmin = ( plsc->vpdxmi - plsc->spdxmi ) / ( plsc->spdxma - plsc->spdxmi );
59 *p_xmax = ( plsc->vpdxma - plsc->spdxmi ) / ( plsc->spdxma - plsc->spdxmi );
60 *p_ymin = ( plsc->vpdymi - plsc->spdymi ) / ( plsc->spdyma - plsc->spdymi );
61 *p_ymax = ( plsc->vpdyma - plsc->spdymi ) / ( plsc->spdyma - plsc->spdymi );
62 }
63
64 //--------------------------------------------------------------------------
86
87 static void legend_position( PLINT position, PLFLT legend_width, PLFLT legend_height,
88 PLFLT *x_legend_position, PLFLT *y_legend_position,
89 PLFLT *xsign, PLFLT *ysign )
90 {
91 // xorigin, yorigin, xlegend, and ylegend are all calculated for
92 // one of the 16 standard positions specified by position and are
93 // expressed in adopted coordinates. xorigin is the X value of
94 // the reference point of the adopted coordinates. yorigin is the
95 // Y value of the reference point of the adopted coordinates.
96 // xlegend is the X coordinate of the top-left of the legend box
97 // relative to the legend box reference point. ylegend is the y
98 // coordinate of the top-left of the legend box relative to the
99 // legend box reference point.
100
101 PLFLT xorigin = 0.0, yorigin = 0.0, xlegend = 0.0, ylegend = 0.0;
102 // By default the sign of the x and y offsets is positive.
103 *xsign = 1.;
104 *ysign = 1.;
105 if ( position & PL_POSITION_RIGHT )
106 {
107 xorigin = 1.;
108 if ( position & PL_POSITION_TOP )
109 {
110 yorigin = 1.;
111 if ( position & PL_POSITION_INSIDE )
112 {
113 xlegend = -legend_width;
114 ylegend = 0.;
115 *xsign = -1.;
116 *ysign = -1.;
117 }
118 else if ( position & PL_POSITION_OUTSIDE )
119 {
120 xlegend = 0.;
121 ylegend = legend_height;
122 }
123 else
124 {
125 plexit( "legend_position: internal logic error 1" );
126 }
127 }
128 else if ( !( position & PL_POSITION_TOP ) && !( position & PL_POSITION_BOTTOM ) )
129 {
130 yorigin = 0.5;
131 ylegend = 0.5 * legend_height;
132 if ( position & PL_POSITION_INSIDE )
133 {
134 xlegend = -legend_width;
135 *xsign = -1.;
136 }
137 else if ( position & PL_POSITION_OUTSIDE )
138 {
139 xlegend = 0.;
140 }
141 else
142 {
143 plexit( "legend_position: internal logic error 2" );
144 }
145 }
146 else if ( position & PL_POSITION_BOTTOM )
147 {
148 yorigin = 0.;
149 if ( position & PL_POSITION_INSIDE )
150 {
151 xlegend = -legend_width;
152 ylegend = legend_height;
153 *xsign = -1.;
154 }
155 else if ( position & PL_POSITION_OUTSIDE )
156 {
157 xlegend = 0.;
158 ylegend = 0.;
159 *ysign = -1.;
160 }
161 else
162 {
163 plexit( "legend_position: internal logic error 3" );
164 }
165 }
166 else
167 {
168 plexit( "legend_position: internal logic error 4" );
169 }
170 }
171 else if ( !( position & PL_POSITION_RIGHT ) && !( position & PL_POSITION_LEFT ) )
172 {
173 xorigin = 0.5;
174 xlegend = -0.5 * legend_width;
175 if ( position & PL_POSITION_TOP )
176 {
177 yorigin = 1.;
178 if ( position & PL_POSITION_INSIDE )
179 {
180 ylegend = 0.;
181 *ysign = -1.;
182 }
183 else if ( position & PL_POSITION_OUTSIDE )
184 {
185 ylegend = legend_height;
186 }
187 else
188 {
189 plexit( "legend_position: internal logic error 5" );
190 }
191 }
192 else if ( position & PL_POSITION_BOTTOM )
193 {
194 yorigin = 0.;
195 if ( position & PL_POSITION_INSIDE )
196 {
197 ylegend = legend_height;
198 }
199 else if ( position & PL_POSITION_OUTSIDE )
200 {
201 ylegend = 0.;
202 *ysign = -1.;
203 }
204 else
205 {
206 plexit( "legend_position: internal logic error 6" );
207 }
208 }
209 else
210 {
211 plexit( "legend_position: internal logic error 7" );
212 }
213 }
214 else if ( position & PL_POSITION_LEFT )
215 {
216 xorigin = 0.;
217 if ( position & PL_POSITION_TOP )
218 {
219 yorigin = 1.;
220 if ( position & PL_POSITION_INSIDE )
221 {
222 xlegend = 0.;
223 ylegend = 0.;
224 *ysign = -1.;
225 }
226 else if ( position & PL_POSITION_OUTSIDE )
227 {
228 xlegend = -legend_width;
229 ylegend = legend_height;
230 *xsign = -1.;
231 }
232 else
233 {
234 plexit( "legend_position: internal logic error 8" );
235 }
236 }
237 else if ( !( position & PL_POSITION_TOP ) && !( position & PL_POSITION_BOTTOM ) )
238 {
239 yorigin = 0.5;
240 ylegend = 0.5 * legend_height;
241 if ( position & PL_POSITION_INSIDE )
242 {
243 xlegend = 0.;
244 }
245 else if ( position & PL_POSITION_OUTSIDE )
246 {
247 xlegend = -legend_width;
248 *xsign = -1.;
249 }
250 else
251 {
252 plexit( "legend_position: internal logic error 9" );
253 }
254 }
255 else if ( position & PL_POSITION_BOTTOM )
256 {
257 yorigin = 0.;
258 if ( position & PL_POSITION_INSIDE )
259 {
260 ylegend = legend_height;
261 xlegend = 0.;
262 }
263 else if ( position & PL_POSITION_OUTSIDE )
264 {
265 xlegend = -legend_width;
266 ylegend = 0.;
267 *xsign = -1.;
268 *ysign = -1.;
269 }
270 else
271 {
272 plexit( "legend_position: internal logic error 10" );
273 }
274 }
275 else
276 {
277 plexit( "legend_position: internal logic error 11" );
278 }
279 }
280 else
281 {
282 plexit( "legend_position: internal logic error 12" );
283 }
284 *x_legend_position = xorigin + xlegend;
285 *y_legend_position = yorigin + ylegend;
286 }
287
288 //--------------------------------------------------------------------------
294
295 static void get_subpage_per_mm( PLFLT *x_subpage_per_mm, PLFLT *y_subpage_per_mm )
296 {
297 // Size of subpage in mm
298 PLFLT mxmin, mxmax, mymin, mymax;
299 plgspa( &mxmin, &mxmax, &mymin, &mymax );
300 *x_subpage_per_mm = 1. / ( mxmax - mxmin );
301 *y_subpage_per_mm = 1. / ( mymax - mymin );
302 }
303
304 //--------------------------------------------------------------------------
311
312 static PLFLT get_character_or_symbol_height( PLBOOL ifcharacter )
313 {
314 // Character height in mm
315 PLFLT default_mm, char_height_mm;
316 PLFLT x_subpage_per_mm, y_subpage_per_mm;
317
318 if ( ifcharacter )
319 {
320 plgchr( &default_mm, &char_height_mm );
321 }
322 else
323 {
324 default_mm = plsc->symdef;
325 char_height_mm = plsc->symht;
326 }
327 get_subpage_per_mm( &x_subpage_per_mm, &y_subpage_per_mm );
328 return ( char_height_mm * y_subpage_per_mm );
329 }
330
331 //--------------------------------------------------------------------------
343
344 #define adopted_to_subpage_x( nx ) ( ( xdmin_adopted ) + ( nx ) * ( ( xdmax_adopted ) - ( xdmin_adopted ) ) )
345
346 //--------------------------------------------------------------------------
358
359 #define subpage_to_adopted_x( nx ) ( ( nx - xdmin_adopted ) / ( ( xdmax_adopted ) - ( xdmin_adopted ) ) )
360
361 //--------------------------------------------------------------------------
373
374 #define adopted_to_subpage_y( ny ) ( ( ydmin_adopted ) + ( ny ) * ( ( ydmax_adopted ) - ( ydmin_adopted ) ) )
375
376 //--------------------------------------------------------------------------
388
389 #define subpage_to_adopted_y( ny ) ( ( ny - ydmin_adopted ) / ( ( ydmax_adopted ) - ( ydmin_adopted ) ) )
390
391 //--------------------------------------------------------------------------
529
530 void
531 c_pllegend( PLFLT *p_legend_width, PLFLT *p_legend_height,
532 PLINT opt, PLINT position, PLFLT x, PLFLT y, PLFLT plot_width,
533 PLINT bg_color, PLINT bb_color, PLINT bb_style,
534 PLINT nrow, PLINT ncolumn,
535 PLINT nlegend, PLINT_VECTOR opt_array,
536 PLFLT text_offset, PLFLT text_scale, PLFLT text_spacing,
537 PLFLT text_justification,
538 PLINT_VECTOR text_colors, PLCHAR_MATRIX text,
539 PLINT_VECTOR box_colors, PLINT_VECTOR box_patterns,
540 PLFLT_VECTOR box_scales, PLFLT_VECTOR box_line_widths,
541 PLINT_VECTOR line_colors, PLINT_VECTOR line_styles,
542 PLFLT_VECTOR line_widths,
543 PLINT_VECTOR symbol_colors, PLFLT_VECTOR symbol_scales,
544 PLINT_VECTOR symbol_numbers, PLCHAR_MATRIX symbols )
545
546 {
547 // Legend position
548 PLFLT plot_x, plot_x_end, plot_x_subpage, plot_x_end_subpage;
549 PLFLT plot_y, plot_y_subpage;
550 PLFLT text_x, text_y, text_x_subpage, text_y_subpage;
551 // Character height (normalized subpage coordinates)
552 PLFLT character_height, character_width, symbol_width = 0.0;
553 // x, y-position of the current legend entry
554 PLFLT ty, xshift, drow, dcolumn;
555 // Positions of the legend entries
556 PLFLT dxs, *xs = NULL, *ys = NULL, xl[2], yl[2], xbox[4], ybox[4];
557 PLINT i, j;
558 // Active attributes to be saved and restored afterward.
559 PLINT col0_save = plsc->icol0,
560 line_style_save = plsc->line_style,
561 pattern_save = plsc->patt;
562 PLFLT line_width_save = plsc->width;
563 PLFLT text_scale_save = plsc->chrht / plsc->chrdef;
564 // Saved external world coordinates of viewport.
565 PLFLT xwmin_save, xwmax_save, ywmin_save, ywmax_save;
566 // Saved external normalized coordinates of viewport.
567 // (These are actual values used only for the restore.)
568 PLFLT xdmin_save = 0.0, xdmax_save = 0.0, ydmin_save = 0.0, ydmax_save = 0.0;
569 // Limits of adopted coordinates used to calculate all coordinate
570 // transformations.
571 PLFLT xdmin_adopted = 0.0, xdmax_adopted = 0.0, ydmin_adopted = 0.0, ydmax_adopted = 0.0;
572
573 PLFLT x_subpage_per_mm, y_subpage_per_mm, text_width0 = 0., text_width;
574 PLFLT width_border, column_separation,
575 legend_width, legend_height, legend_width_ac, legend_height_ac;
576 PLFLT x_legend_position, y_legend_position, xsign, ysign;
577
578 PLINT some_symbols = 0;
579 PLINT max_symbol_numbers = 0;
580 PLINT irow = 0, icolumn = 0;
581 int some_boxes = 0, some_lines = 0;
582
583 // Default nrow, ncolumn.
584 nrow = MAX( nrow, 1 );
585 ncolumn = MAX( ncolumn, 1 );
586 if ( nrow * ncolumn < nlegend )
587 {
588 // Make smaller one large enough to accomodate nlegend.
589 if ( ncolumn < nrow )
590 ncolumn = ( nlegend % nrow ) ? ( nlegend / nrow ) + 1 : nlegend / nrow;
591 else
592 nrow = ( nlegend % ncolumn ) ? ( nlegend / ncolumn ) + 1 : nlegend / ncolumn;
593 }
594 // fprintf(stdout, "nrow, ncolumn = %d, %d\n", nrow, ncolumn);
595
596 // Default position flags and sanity checks for position flags.
597 if ( !( position & PL_POSITION_RIGHT ) && !( position & PL_POSITION_LEFT ) && !( position & PL_POSITION_TOP ) && !( position & PL_POSITION_BOTTOM ) )
598 {
599 position = position | PL_POSITION_RIGHT | PL_POSITION_TOP;
600 }
601 else if ( ( position & PL_POSITION_RIGHT ) && ( position & PL_POSITION_LEFT ) )
602 {
603 plabort( "pllegend: PL_POSITION_RIGHT and PL_POSITION_LEFT cannot be simultaneously set." );
604 return;
605 }
606
607 else if ( ( position & PL_POSITION_TOP ) && ( position & PL_POSITION_BOTTOM ) )
608 {
609 plabort( "pllegend: PL_POSITION_TOP and PL_POSITION_BOTTOM cannot be simultaneously set." );
610 return;
611 }
612
613 if ( !( position & PL_POSITION_INSIDE ) && !( position & PL_POSITION_OUTSIDE ) )
614 {
615 position = position | PL_POSITION_INSIDE;
616 }
617 else if ( ( position & PL_POSITION_INSIDE ) && ( position & PL_POSITION_OUTSIDE ) )
618 {
619 plabort( "pllegend: PL_POSITION_INSIDE and PL_POSITION_OUTSIDE cannot be simultaneously set." );
620 return;
621 }
622
623 if ( !( position & PL_POSITION_VIEWPORT ) && !( position & PL_POSITION_SUBPAGE ) )
624 {
625 position = position | PL_POSITION_VIEWPORT;
626 }
627 else if ( ( position & PL_POSITION_VIEWPORT ) && ( position & PL_POSITION_SUBPAGE ) )
628 {
629 plabort( "pllegend: PL_POSITION_VIEWPORT and PL_POSITION_SUBPAGE cannot be simultaneously set." );
630 return;
631 }
632
633 // xdmin_save, etc., are the actual external relative viewport
634 // coordinates within the current sub-page used only for
635 // restoration at the end.
636 plgvpsp( &xdmin_save, &xdmax_save, &ydmin_save, &ydmax_save );
637
638 // Choose adopted coordinates.
639 if ( position & PL_POSITION_SUBPAGE )
640 plvpor( 0., 1., 0., 1. );
641
642 // xdmin_adopted, etc., are the adopted limits of the coordinates
643 // within the current sub-page used for all coordinate
644 // transformations.
645 // If position & PL_POSITION_VIEWPORT is true, these limits
646 // are the external relative viewport limits.
647 // If position & PL_POSITION_SUBPAGE is true, these
648 // coordinates are the relative subpage coordinates.
649 plgvpsp( &xdmin_adopted, &xdmax_adopted, &ydmin_adopted, &ydmax_adopted );
650
651 // xwmin_save, etc., are the external world coordinates corresponding
652 // to the external viewport boundaries.
653 plgvpw( &xwmin_save, &xwmax_save, &ywmin_save, &ywmax_save );
654
655 // Internal viewport corresponds to sub-page so that all legends will
656 // be clipped at sub-page boundaries.
657 plvpor( 0., 1., 0., 1. );
658
659 // Internal world coordinates are the same as normalized internal
660 // viewport coordinates which are the same as normalized subpage coordinates.
661 plwind( 0., 1., 0., 1. );
662
663 for ( i = 0; i < nlegend; i++ )
664 {
665 if ( opt_array[i] & PL_LEGEND_COLOR_BOX )
666 some_boxes = 1;
667 if ( opt_array[i] & PL_LEGEND_LINE )
668 some_lines = 1;
669 if ( opt_array[i] & PL_LEGEND_SYMBOL )
670 {
671 if ( symbol_numbers != NULL )
672 max_symbol_numbers = MAX( max_symbol_numbers, symbol_numbers[i] );
673 some_symbols = 1;
674 }
675 }
676
677 // Sanity checks on NULL arrays:
678 if ( some_boxes && ( box_colors == NULL || box_patterns == NULL || box_scales == NULL || box_line_widths == NULL ) )
679 {
680 plabort( "pllegend: all box_* arrays must be defined when the PL_LEGEND_COLOR_BOX bit is set." );
681 return;
682 }
683
684 if ( some_lines && ( line_colors == NULL || line_styles == NULL || line_widths == NULL ) )
685 {
686 plabort( "pllegend: all line_* arrays must be defined when the PL_LEGEND_LINE bit is set." );
687 return;
688 }
689
690 if ( some_symbols && ( symbol_colors == NULL || symbol_scales == NULL || symbol_numbers == NULL ) )
691 {
692 plabort( "pllegend: all symbol_* arrays must be defined when the PL_LEGEND_SYMBOL bit is set." );
693 return;
694 }
695
696 // Get character height and width in normalized subpage coordinates.
697 character_height = get_character_or_symbol_height( TRUE );
698 character_width = character_height;
699
700 // Calculate maximum width of text area.
701 plschr( 0., text_scale );
702 for ( i = 0; i < nlegend; i++ )
703 {
704 // units are mm.
705 text_width0 = MAX( text_width0, plstrl( text[i] ) );
706 }
707 get_subpage_per_mm( &x_subpage_per_mm, &y_subpage_per_mm );
708
709 // units are normalized subpage coordinates.
710 text_width0 = x_subpage_per_mm * text_width0;
711
712 // Allow gap on end closest to legend plot.
713 text_width = text_width0 + text_offset * character_width;
714
715 // Allow small border area where only the background is plotted
716 // for left and right of legend. 0.4 seems to be a reasonable factor
717 // that gives a good-looking result.
718 width_border = 0.4 * character_width;
719 // Separate columns (if any) by 2.0 * character_width.
720 column_separation = 2.0 * character_width;
721
722 // Total width and height of legend area in normalized subpage coordinates.
723 legend_width = 2. * width_border + ( ncolumn - 1 ) * column_separation +
724 ncolumn * ( text_width +
725 adopted_to_subpage_x( plot_width ) - adopted_to_subpage_x( 0. ) );
726 legend_height = nrow * text_spacing * character_height;
727
728 // Total width and height of legend area in adopted coordinates.
729
730 legend_width_ac = subpage_to_adopted_x( legend_width ) - subpage_to_adopted_x( 0. );
731 legend_height_ac = subpage_to_adopted_y( legend_height ) - subpage_to_adopted_y( 0. );
732 *p_legend_width = legend_width_ac;
733 *p_legend_height = legend_height_ac;
734
735 // dcolumn is the spacing from one column to the next and
736 // drow is the spacing from one row to the next.
737 dcolumn = column_separation + text_width +
738 adopted_to_subpage_x( plot_width ) - adopted_to_subpage_x( 0. );
739 drow = text_spacing * character_height;
740
741 legend_position( position, legend_width_ac, legend_height_ac, &x_legend_position, &y_legend_position, &xsign, &ysign );
742 plot_x = x * xsign + x_legend_position;
743 plot_y = y * ysign + y_legend_position;
744 plot_x_end = plot_x + plot_width;
745 // Normalized subpage coordinates for legend plots
746 plot_x_subpage = adopted_to_subpage_x( plot_x );
747 plot_y_subpage = adopted_to_subpage_y( plot_y );
748 plot_x_end_subpage = adopted_to_subpage_x( plot_x_end );
749
750 // Get normalized subpage positions of the start of the legend text
751 text_x = plot_x_end;
752 text_y = plot_y;
753 text_x_subpage = adopted_to_subpage_x( text_x ) +
754 text_offset * character_width;
755 text_y_subpage = adopted_to_subpage_y( text_y );
756
757 if ( opt & PL_LEGEND_BACKGROUND )
758 {
759 PLFLT xbg[4] = {
760 plot_x_subpage,
761 plot_x_subpage,
762 plot_x_subpage + legend_width,
763 plot_x_subpage + legend_width,
764 };
765 PLFLT ybg[4] = {
766 plot_y_subpage,
767 plot_y_subpage - legend_height,
768 plot_y_subpage - legend_height,
769 plot_y_subpage,
770 };
771 plpsty( 0 );
772 plcol0( bg_color );
773 plfill( 4, xbg, ybg );
774 plcol0( col0_save );
775 }
776
777 if ( opt & PL_LEGEND_BOUNDING_BOX )
778 {
779 PLFLT xbb[5] = {
780 plot_x_subpage,
781 plot_x_subpage,
782 plot_x_subpage + legend_width,
783 plot_x_subpage + legend_width,
784 plot_x_subpage,
785 };
786 PLFLT ybb[5] = {
787 plot_y_subpage,
788 plot_y_subpage - legend_height,
789 plot_y_subpage - legend_height,
790 plot_y_subpage,
791 plot_y_subpage,
792 };
793 pllsty( bb_style );
794 plcol0( bb_color );
795 plline( 5, xbb, ybb );
796 plcol0( col0_save );
797 pllsty( line_style_save );
798 }
799
800 if ( opt & PL_LEGEND_TEXT_LEFT )
801 {
802 // text area on left, plot area on right.
803 text_x_subpage = plot_x_subpage;
804 plot_x_subpage += text_width;
805 plot_x_end_subpage += text_width;
806 }
807 // adjust border after background is drawn.
808 plot_x_subpage += width_border;
809 plot_x_end_subpage += width_border;
810 text_x_subpage += width_border;
811
812 if ( some_symbols )
813 {
814 max_symbol_numbers = MAX( 2, max_symbol_numbers );
815 if ( ( ( xs = (PLFLT *) malloc( (size_t) max_symbol_numbers * sizeof ( PLFLT ) ) ) == NULL ) ||
816 ( ( ys = (PLFLT *) malloc( (size_t) max_symbol_numbers * sizeof ( PLFLT ) ) ) == NULL ) )
817 {
818 plexit( "pllegend: Insufficient memory" );
819 }
820
821 // Get symbol width in normalized subpage coordinates if symbols are plotted to
822 // adjust ends of line of symbols.
823 // AWI, no idea why must use 0.5 factor to get ends of symbol lines
824 // to line up approximately correctly with plotted legend lines.
825 // Factor should be unity.
826 symbol_width = 0.5 * get_character_or_symbol_height( TRUE );
827 }
828
829 // Draw each legend entry
830 for ( i = 0; i < nlegend; i++ )
831 {
832 // y position of text, lines, symbols, and/or centre of cmap0 box.
833 ty = text_y_subpage - ( (double) irow + 0.5 ) * drow;
834 xshift = (double) icolumn * dcolumn;
835 // Label/name for the legend
836 plcol0( text_colors[i] );
837 plschr( 0., text_scale );
838 plptex( text_x_subpage + xshift + text_justification * text_width0, ty, 0.1, 0.0, text_justification, text[i] );
839
840 if ( !( opt_array[i] & PL_LEGEND_NONE ) )
841 {
842 if ( opt_array[i] & PL_LEGEND_COLOR_BOX )
843 {
844 plcol0( box_colors[i] );
845 plpsty( box_patterns[i] );
846 plwidth( box_line_widths[i] );
847 xbox[0] = plot_x_subpage + xshift;
848 xbox[1] = xbox[0];
849 xbox[2] = plot_x_end_subpage + xshift;
850 xbox[3] = xbox[2];
851 ybox[0] = ty + 0.5 * drow * box_scales[i];
852 ybox[1] = ty - 0.5 * drow * box_scales[i];
853 ybox[2] = ty - 0.5 * drow * box_scales[i];
854 ybox[3] = ty + 0.5 * drow * box_scales[i];
855 plfill( 4, xbox, ybox );
856 pllsty( line_style_save );
857 plwidth( line_width_save );
858 }
859 if ( opt_array[i] & PL_LEGEND_LINE )
860 {
861 plcol0( line_colors[i] );
862 pllsty( line_styles[i] );
863 plwidth( line_widths[i] );
864 xl[0] = plot_x_subpage + xshift;
865 xl[1] = plot_x_end_subpage + xshift;
866 yl[0] = ty;
867 yl[1] = ty;
868 plline( 2, xl, yl );
869 pllsty( line_style_save );
870 plwidth( line_width_save );
871 }
872
873 if ( opt_array[i] & PL_LEGEND_SYMBOL )
874 {
875 plcol0( symbol_colors[i] );
876 plschr( 0., symbol_scales[i] );
877 dxs = ( plot_x_end_subpage - plot_x_subpage - symbol_width ) / (double) ( MAX( symbol_numbers[i], 2 ) - 1 );
878 for ( j = 0; j < symbol_numbers[i]; j++ )
879 {
880 xs[j] = plot_x_subpage + xshift +
881 0.5 * symbol_width + dxs * (double) j;
882 ys[j] = ty;
883 }
884 plstring( symbol_numbers[i], xs, ys, symbols[i] );
885 }
886 }
887
888 // Set irow, icolumn for next i value.
889 if ( opt & PL_LEGEND_ROW_MAJOR )
890 {
891 icolumn++;
892 if ( icolumn >= ncolumn )
893 {
894 icolumn = 0;
895 irow++;
896 }
897 }
898 else
899 {
900 irow++;
901 if ( irow >= nrow )
902 {
903 irow = 0;
904 icolumn++;
905 }
906 }
907 }
908 if ( some_symbols )
909 {
910 free( xs );
911 free( ys );
912 }
913
914 // Restore
915 plcol0( col0_save );
916 plschr( 0., text_scale_save );
917 plpsty( pattern_save );
918 plvpor( xdmin_save, xdmax_save, ydmin_save, ydmax_save );
919 plwind( xwmin_save, xwmax_save, ywmin_save, ywmax_save );
920
921 return;
922 }
923
924 //--------------------------------------------------------------------------
931
932 static void
933 remove_characters( char *string, PLCHAR_VECTOR characters )
934 {
935 char *src, *dst;
936 PLCHAR_VECTOR ptr;
937 for ( src = dst = string; *src != '\0'; src++ )
938 {
939 ptr = characters;
940 while ( ( *ptr != '\0' ) && ( *src != *ptr ) )
941 ptr++;
942 if ( *src != *ptr )
943 {
944 *dst = *src;
945 dst++;
946 }
947 }
948 *dst = '\0';
949 }
950
951 //--------------------------------------------------------------------------
971
972 static void
973 draw_cap( PLBOOL if_edge, PLINT orientation, PLFLT xmin, PLFLT xmax,
974 PLFLT ymin, PLFLT ymax, PLFLT color )
975 {
976 // Save current drawing color.
977 PLINT col0_save = plsc->icol0;
978 PLFLT xhalf = 0.5 * ( xmin + xmax );
979 PLFLT yhalf = 0.5 * ( ymin + ymax );
980
981 // World coordinates for the triangle. Due to setup in the
982 // plcolorbar routine that calls this, these are also normalized
983 // subpage coordinates.
984 PLFLT xs[3];
985 PLFLT ys[3];
986
987 if ( orientation == PL_COLORBAR_ORIENT_RIGHT )
988 {
989 xs[0] = xmin;
990 ys[0] = ymin;
991 xs[1] = xmax;
992 ys[1] = yhalf;
993 xs[2] = xmin;
994 ys[2] = ymax;
995 }
996 else if ( orientation == PL_COLORBAR_ORIENT_TOP )
997 {
998 xs[0] = xmax;
999 ys[0] = ymin;
1000 xs[1] = xhalf;
1001 ys[1] = ymax;
1002 xs[2] = xmin;
1003 ys[2] = ymin;
1004 }
1005 else if ( orientation == PL_COLORBAR_ORIENT_LEFT )
1006 {
1007 xs[0] = xmax;
1008 ys[0] = ymax;
1009 xs[1] = xmin;
1010 ys[1] = yhalf;
1011 xs[2] = xmax;
1012 ys[2] = ymin;
1013 }
1014 else if ( orientation == PL_COLORBAR_ORIENT_BOTTOM )
1015 {
1016 xs[0] = xmin;
1017 ys[0] = ymax;
1018 xs[1] = xhalf;
1019 ys[1] = ymin;
1020 xs[2] = xmax;
1021 ys[2] = ymax;
1022 }
1023 else
1024 {
1025 plexit( "draw_cap: internal error. Incorrect orientation" );
1026 }
1027
1028 plcol1( color );
1029 plfill( 3, xs, ys );
1030 // Restore the drawing color
1031 plcol0( col0_save );
1032
1033 // Draw cap outline
1034 if ( if_edge )
1035 plline( 3, xs, ys );
1036 }
1037
1038 //--------------------------------------------------------------------------
1060
1061 static void
1062 draw_box( PLBOOL if_bb, PLINT opt, PLCHAR_VECTOR axis_opts, PLBOOL if_edge,
1063 PLFLT ticks, PLINT sub_ticks, PLINT n_values, PLFLT_VECTOR values )
1064 {
1065 // axis option strings.
1066 PLCHAR_VECTOR edge_string;
1067 size_t length_axis_opts = strlen( axis_opts );
1068 char *local_axis_opts;
1069
1070 // local_axis_opts is local version that can be modified from
1071 // const input version.
1072 if ( ( local_axis_opts = (char *) malloc( ( length_axis_opts + 1 ) * sizeof ( char ) ) ) == NULL )
1073 {
1074 plexit( "draw_box: Insufficient memory" );
1075 }
1076 strcpy( local_axis_opts, axis_opts );
1077
1078 plsc->if_boxbb = if_bb;
1079 // Draw numerical labels and tick marks if this is a shade color bar
1080 // TODO: A better way to handle this would be to update the
1081 // internals of plbox to support custom tick and label positions
1082 // along an axis.
1083
1084 if ( opt & PL_COLORBAR_SHADE && opt & PL_COLORBAR_SHADE_LABEL )
1085 {
1086 if ( opt & PL_COLORBAR_ORIENT_RIGHT || opt & PL_COLORBAR_ORIENT_LEFT )
1087 label_box_custom( local_axis_opts, n_values, values, "", 0, NULL );
1088 else
1089 label_box_custom( "", 0, NULL, local_axis_opts, n_values, values );
1090 if ( if_bb )
1091 {
1092 plsc->if_boxbb = FALSE;
1093 free( local_axis_opts );
1094 return;
1095 }
1096 // Exclude ticks for plbox call below since those tick marks and
1097 // associated labels have already been handled in a custom way above.
1098 remove_characters( local_axis_opts, "TtXx" );
1099 }
1100
1101 // Draw the outline for the entire color bar, tick marks, tick labels.
1102
1103 if ( if_edge )
1104 edge_string = "bc";
1105 else
1106 edge_string = "uw";
1107 if ( opt & PL_COLORBAR_ORIENT_TOP || opt & PL_COLORBAR_ORIENT_BOTTOM )
1108 {
1109 plbox( edge_string, 0.0, 0, local_axis_opts, ticks, sub_ticks );
1110 }
1111 else
1112 {
1113 plbox( local_axis_opts, ticks, sub_ticks, edge_string, 0.0, 0 );
1114 }
1115 plsc->if_boxbb = FALSE;
1116
1117 free( local_axis_opts );
1118 }
1119
1120 //--------------------------------------------------------------------------
1136
1137 static void
1138 draw_label( PLBOOL if_bb, PLINT opt, PLCHAR_VECTOR label )
1139 {
1140 // Justification of label text
1141 PLFLT just = 0.0;
1142
1143 // How far away from the axis should the label be drawn in units of
1144 // the character height?
1145 PLFLT label_offset = 1.2;
1146
1147 // For building plmtex option string.
1148 #define max_opts 25
1149 char opt_label[max_opts];
1150 char perp;
1151
1152 // To help sanity check number of specified labels.
1153 PLINT nlabel = 0;
1154
1155 // aspect ratio of physical area of subpage.
1156 //PLFLT aspspp = ( ( plsc->sppxma - plsc->sppxmi ) / plsc->xpmm ) /
1157 // ( ( plsc->sppyma - plsc->sppymi ) / plsc->ypmm );
1158
1159 // Character height in y and x normalized subpage coordinates.
1160 //PLFLT character_height_y = get_character_or_symbol_height( TRUE );
1161 // character height _in normalized subpage coordinates_ is smaller
1162 // in the x direction if the subpage aspect ratio is larger than one.
1163 //PLFLT character_height_x = character_height_y / aspspp;
1164
1165 // Ratio of normalized subpage coordinates to mm coordinates in
1166 // x and y.
1167 //PLFLT spxpmm = plsc->xpmm / ( plsc->sppxma - plsc->sppxmi );
1168 //PLFLT spypmm = plsc->ypmm / ( plsc->sppyma - plsc->sppymi );
1169 PLFLT label_length_mm = plstrl( label );
1170
1171 PLFLT parallel_height_mm = 0.0, perpendicular_height_mm = 0.0,
1172 default_mm, char_height_mm;
1173
1174 // Only honor first bit in list of
1175 // PL_COLORBAR_LABEL_(RIGHT|TOP|LEFT|BOTTOM).
1176 if ( opt & PL_COLORBAR_LABEL_RIGHT )
1177 {
1178 nlabel = 1;
1179 }
1180 if ( opt & PL_COLORBAR_LABEL_TOP )
1181 {
1182 if ( nlabel == 1 )
1183 opt = opt & ~PL_COLORBAR_LABEL_TOP;
1184 else
1185 nlabel = 1;
1186 }
1187 if ( opt & PL_COLORBAR_LABEL_LEFT )
1188 {
1189 if ( nlabel == 1 )
1190 opt = opt & ~PL_COLORBAR_LABEL_LEFT;
1191 else
1192 nlabel = 1;
1193 }
1194 if ( opt & PL_COLORBAR_LABEL_BOTTOM )
1195 {
1196 if ( nlabel == 1 )
1197 opt = opt & ~PL_COLORBAR_LABEL_BOTTOM;
1198 else
1199 nlabel = 1;
1200 }
1201 // If no label wanted, then return.
1202 if ( nlabel == 0 )
1203 return;
1204
1205 plgchr( &default_mm, &char_height_mm );
1206
1207 // Start preparing data to help plot the label or
1208 // calculate the corresponding bounding box changes.
1209
1210 if ( if_bb )
1211 {
1212 // Bounding-box limits are the viewport limits in mm before corrections
1213 // for decorations are applied.
1214 plsc->boxbb_xmin = plsc->vppxmi / plsc->xpmm;
1215 plsc->boxbb_xmax = plsc->vppxma / plsc->xpmm;
1216 plsc->boxbb_ymin = plsc->vppymi / plsc->ypmm;
1217 plsc->boxbb_ymax = plsc->vppyma / plsc->ypmm;
1218
1219 // For labels written parallel to axis, label_offset of zero
1220 // corresponds to character centred on edge so should add 0.5 to
1221 // height to obtain bounding box edge in direction away from
1222 // edge. However, experimentally found 0.8 gave a better
1223 // looking result.
1224 parallel_height_mm = ( label_offset + 0.8 ) * char_height_mm;
1225
1226 // For labels written perpendicular to axis, label_offset of
1227 // zero corresponds to a character whose edge just touches the
1228 // edge of the box so should add 0. to label_offset (corrected
1229 // by -0.5 below) to obtain bounding box edge in direction away
1230 // from edge, and that value apparently works.
1231 perpendicular_height_mm = ( label_offset - 0.5 + 0.0 ) * char_height_mm;
1232 }
1233 if ( opt & PL_COLORBAR_LABEL_LEFT )
1234 {
1235 if ( opt & PL_COLORBAR_ORIENT_TOP || opt & PL_COLORBAR_ORIENT_BOTTOM )
1236 {
1237 perp = '\0';
1238 just = 0.5;
1239 if ( if_bb )
1240 {
1241 plsc->boxbb_xmin = MIN( plsc->boxbb_xmin, plsc->vppxmi /
1242 plsc->xpmm - parallel_height_mm );
1243 plsc->boxbb_ymin = MIN( plsc->boxbb_ymin,
1244 0.5 * ( plsc->vppymi + plsc->vppyma ) /
1245 plsc->ypmm - 0.5 * label_length_mm );
1246 plsc->boxbb_ymax = MAX( plsc->boxbb_ymax,
1247 0.5 * ( plsc->vppymi + plsc->vppyma ) /
1248 plsc->ypmm + 0.5 * label_length_mm );
1249 }
1250 }
1251 else
1252 {
1253 perp = 'v';
1254 just = 1.0;
1255 label_offset -= 0.5;
1256 if ( if_bb )
1257 {
1258 plsc->boxbb_xmin = MIN( plsc->boxbb_xmin, plsc->vppxmi /
1259 plsc->xpmm - perpendicular_height_mm - label_length_mm );
1260 }
1261 }
1262 snprintf( opt_label, max_opts, "l%c", perp );
1263 }
1264 else if ( opt & PL_COLORBAR_LABEL_RIGHT )
1265 {
1266 if ( opt & PL_COLORBAR_ORIENT_TOP || opt & PL_COLORBAR_ORIENT_BOTTOM )
1267 {
1268 perp = '\0';
1269 just = 0.5;
1270 if ( if_bb )
1271 {
1272 plsc->boxbb_xmax = MAX( plsc->boxbb_xmax, plsc->vppxma /
1273 plsc->xpmm + parallel_height_mm );
1274 plsc->boxbb_ymin = MIN( plsc->boxbb_ymin,
1275 0.5 * ( plsc->vppymi + plsc->vppyma ) /
1276 plsc->ypmm - 0.5 * label_length_mm );
1277 plsc->boxbb_ymax = MAX( plsc->boxbb_ymax,
1278 0.5 * ( plsc->vppymi + plsc->vppyma ) /
1279 plsc->ypmm + 0.5 * label_length_mm );
1280 }
1281 }
1282 else
1283 {
1284 perp = 'v';
1285 just = 0.0;
1286 label_offset -= 0.5;
1287 if ( if_bb )
1288 {
1289 plsc->boxbb_xmax = MAX( plsc->boxbb_xmax, plsc->vppxma /
1290 plsc->xpmm + perpendicular_height_mm + label_length_mm );
1291 }
1292 }
1293 snprintf( opt_label, max_opts, "r%c", perp );
1294 }
1295 else if ( opt & PL_COLORBAR_LABEL_TOP )
1296 {
1297 perp = '\0';
1298 just = 0.5;
1299 snprintf( opt_label, max_opts, "t%c", perp );
1300 if ( if_bb )
1301 {
1302 plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, plsc->vppyma /
1303 plsc->ypmm + parallel_height_mm );
1304 plsc->boxbb_xmin = MIN( plsc->boxbb_xmin,
1305 0.5 * ( plsc->vppxmi + plsc->vppxma ) /
1306 plsc->xpmm - 0.5 * label_length_mm );
1307 plsc->boxbb_xmax = MAX( plsc->boxbb_xmax,
1308 0.5 * ( plsc->vppxmi + plsc->vppxma ) /
1309 plsc->xpmm + 0.5 * label_length_mm );
1310 }
1311 }
1312 else if ( opt & PL_COLORBAR_LABEL_BOTTOM )
1313 {
1314 perp = '\0';
1315 just = 0.5;
1316 snprintf( opt_label, max_opts, "b%c", perp );
1317 if ( if_bb )
1318 {
1319 plsc->boxbb_ymin = MIN( plsc->boxbb_ymin, plsc->vppymi /
1320 plsc->ypmm - parallel_height_mm );
1321 plsc->boxbb_xmin = MIN( plsc->boxbb_xmin,
1322 0.5 * ( plsc->vppxmi + plsc->vppxma ) /
1323 plsc->xpmm - 0.5 * label_length_mm );
1324 plsc->boxbb_xmax = MAX( plsc->boxbb_xmax,
1325 0.5 * ( plsc->vppxmi + plsc->vppxma ) /
1326 plsc->xpmm + 0.5 * label_length_mm );
1327 }
1328 }
1329 if ( !if_bb )
1330 plmtex( opt_label, label_offset, 0.5, just, label );
1331 }
1332
1333 //--------------------------------------------------------------------------
1344 // dx_subpage, dy_subpageDifferences between normalized subpage coordinates for the old
1345 // bounding box and the new one.
1346
1347 static void
1348 calculate_limits( PLINT position, PLFLT x, PLFLT y,
1349 PLFLT xdmin_adopted, PLFLT xdmax_adopted, PLFLT ydmin_adopted, PLFLT ydmax_adopted,
1350 PLFLT prior_bb_height,
1351 PLFLT *p_colorbar_width_bb, PLFLT *p_colorbar_height_bb,
1352 PLFLT *p_colorbar_width_ac, PLFLT *p_colorbar_height_ac,
1353 PLFLT *p_plot_x_subpage_bb, PLFLT *p_plot_y_subpage_bb,
1354 PLFLT *p_dx_subpage, PLFLT *p_dy_subpage
1355 )
1356 {
1357 PLFLT x_colorbar_position, y_colorbar_position, xsign, ysign;
1358 PLFLT plot_x, plot_y;
1359 // Ratio of normalized subpage coordinates to mm coordinates in
1360 // x and y.
1361 PLFLT spxpmm = plsc->xpmm / ( plsc->sppxma - plsc->sppxmi );
1362 PLFLT spypmm = plsc->ypmm / ( plsc->sppyma - plsc->sppymi );
1363
1364 // New bounding box width and height in normalized subpage coordinates.
1365 *p_colorbar_width_bb = ( plsc->boxbb_xmax - plsc->boxbb_xmin ) * spxpmm;
1366 *p_colorbar_height_bb = ( plsc->boxbb_ymax - plsc->boxbb_ymin ) * spypmm;
1367
1368 // Offsets (in sense of prior minus current) of upper left corner of prior bounding box
1369 // relative to current bounding box in normalized subpage coordinates. From
1370 // the above comments, the upper left corner of prior bounding box
1371 // has the coordinates (0., prior_bb_height).
1372 *p_dx_subpage = -plsc->boxbb_xmin * spxpmm;
1373 *p_dy_subpage = prior_bb_height - plsc->boxbb_ymax * spypmm;
1374
1375 // Total width and height of new bounding box in adopted
1376 // coordinates.
1377 *p_colorbar_width_ac = subpage_to_adopted_x( *p_colorbar_width_bb ) -
1378 subpage_to_adopted_x( 0. );
1379 *p_colorbar_height_ac = subpage_to_adopted_y( *p_colorbar_height_bb ) -
1380 subpage_to_adopted_y( 0. );
1381
1382 // Calculate parameters that help determine the position of the top
1383 // left of the legend in adopted coordinates. See pllegend
1384 // documentation for definition of adopted coordinates.
1385 legend_position( position, *p_colorbar_width_ac, *p_colorbar_height_ac, &x_colorbar_position, &y_colorbar_position, &xsign, &ysign );
1386 plot_x = x * xsign + x_colorbar_position;
1387 plot_y = y * ysign + y_colorbar_position;
1388 // Calculate normalized subpage coordinates of top left of new bounding box.
1389 *p_plot_x_subpage_bb = adopted_to_subpage_x( plot_x );
1390 *p_plot_y_subpage_bb = adopted_to_subpage_y( plot_y );
1391 }
1392
1393
1394 //--------------------------------------------------------------------------
1523
1524 void
1525 c_plcolorbar( PLFLT *p_colorbar_width, PLFLT *p_colorbar_height,
1526 PLINT opt, PLINT position, PLFLT x, PLFLT y,
1527 PLFLT x_length, PLFLT y_length,
1528 PLINT bg_color, PLINT bb_color, PLINT bb_style,
1529 PLFLT low_cap_color, PLFLT high_cap_color,
1530 PLINT cont_color, PLFLT cont_width,
1531 PLINT n_labels, PLINT_VECTOR label_opts, PLCHAR_MATRIX labels,
1532 PLINT n_axes, PLCHAR_MATRIX axis_opts,
1533 PLFLT_VECTOR ticks, PLINT_VECTOR sub_ticks,
1534 PLINT_VECTOR n_values, PLFLT_MATRIX values )
1535 {
1536 // Min and max values
1537 // Assumes that the values array is sorted from smallest to largest
1538 // OR from largest to smallest.
1539 // Unnecessarily initialize min_value, max_value, and max_abs
1540 // to quiet -O1 -Wuninitialized warnings that are false alarms.
1541 // (n_axes is guaranteed to be 1 or greater so that the loops that
1542 // define these values must be executed at least once.)
1543 PLFLT min_value = 0., max_value = 0., max_abs = 0.;
1544 // Length of cap in orientation direction in normalized subpage
1545 // coordinates and mm.
1546 PLFLT cap_extent, cap_extent_mm;
1547
1548 // The color bar cap is an equilateral triangle with cap_angle
1549 // the angle (in degrees) of the unequal angle pointing in the
1550 // direction of the orientation of the cap. In other words,
1551 // cap_angle completely controls the shape of the triangle, but
1552 // not its scale.
1553 PLFLT cap_angle = 45.;
1554 // Ratio of length of cap in orientation direction
1555 // to the width of the bar (and cap) in the direction
1556 // perpendicular to the orientation in physical coordinates
1557 // (i.e., independent of aspect ratio).
1558 PLFLT cap_ratio = 0.5 / tan( PI / 360. * cap_angle );
1559
1560 // aspect ratio of physical area of subpage.
1561 PLFLT aspspp = ( ( plsc->sppxma - plsc->sppxmi ) / plsc->xpmm ) /
1562 ( ( plsc->sppyma - plsc->sppymi ) / plsc->ypmm );
1563
1564 // Min and max colors
1565 PLFLT min_color, max_color;
1566
1567 // Saved external world coordinates of viewport.
1568 PLFLT xwmin_save, xwmax_save, ywmin_save, ywmax_save;
1569 // Saved external normalized coordinates of viewport.
1570 // (These are actual values used only for the restore.)
1571 PLFLT xdmin_save = 0.0, xdmax_save = 0.0, ydmin_save = 0.0, ydmax_save = 0.0;
1572
1573 // Limits of adopted coordinates used to calculate all coordinate
1574 // transformations.
1575 PLFLT xdmin_adopted = 0.0, xdmax_adopted = 0.0, ydmin_adopted = 0.0, ydmax_adopted = 0.0;
1576
1577 // Active attributes to be saved and restored afterward.
1578 PLINT col0_save = plsc->icol0,
1579 line_style_save = plsc->line_style;
1580
1581 // Normalized subpage coordinates of top left of the bounding box.
1582 PLFLT plot_x_subpage_bb, plot_y_subpage_bb;
1583
1584 // color bar width and height in normalized subpage coordinates.
1585 // No suffix refers to bonding box of undecorated color bar, d
1586 // suffix refers to bounding box of decorated color bar, and l
1587 // suffix refers to bounding box of labelled and decorated
1588 // color bar.
1589 PLFLT colorbar_width, colorbar_height,
1590 colorbar_width_d, colorbar_height_d,
1591 colorbar_width_l, colorbar_height_l;
1592
1593 // ac suffix refers to latest color bar_width (d or l suffix) converted to
1594 // adopted coordinates.
1595 // mm suffix refers to colorbar_width and colorbar_height (with no suffix)
1596 // converted from normalized subpage coordinates to mm.
1597 PLFLT colorbar_width_ac, colorbar_height_ac,
1598 colorbar_width_mm, colorbar_height_mm;
1599
1600 // Change in normalized subpage coordinates of the top left of
1601 // undecorated color bar. (The omd suffix refers to original
1602 // color bar minus decorated color bar, and the dml suffix refers to
1603 // decorated color bar minus labelled and decorated color bar.)
1604 PLFLT dx_subpage_omd, dy_subpage_omd, dx_subpage_dml, dy_subpage_dml;
1605 PLFLT dx_subpage_omd_accu = 0.0, dy_subpage_omd_accu = 0.0, dx_subpage_dml_accu = 0.0, dy_subpage_dml_accu = 0.0;
1606 // Normalized subpage coordinates of the top left of undecorated
1607 // color bar,
1608 PLFLT plot_x_subpage, plot_y_subpage;
1609
1610 // Position of the undecorated color bar in normalized subpage coordinates.
1611 PLFLT vx_min = 0.0, vx_max = 0.0, vy_min = 0.0, vy_max = 0.0;
1612
1613 // World coordinate limits describing undecorated color bar.
1614 PLFLT wx_min = 0.0, wx_max = 0.0, wy_min = 0.0, wy_max = 0.0;
1615
1616 // The data to plot
1617 PLFLT **color_data;
1618
1619 // Setting up the data for display
1620 PLINT i, j, ni = 0, nj = 0, n_steps;
1621 PLFLT step_size;
1622
1623 PLBOOL if_edge = 0;
1624 PLBOOL if_edge_b = 0, if_edge_c = 0, if_edge_u = 0, if_edge_w = 0;
1625
1626 // Ratio of normalized subpage coordinates to mm coordinates in
1627 // x and y.
1628 PLFLT spxpmm = plsc->xpmm / ( plsc->sppxma - plsc->sppxmi );
1629 PLFLT spypmm = plsc->ypmm / ( plsc->sppyma - plsc->sppymi );
1630
1631 // plvpor limits for label.
1632 PLFLT label_vpor_xmin, label_vpor_xmax, label_vpor_ymin, label_vpor_ymax;
1633
1634 // Default position flags and sanity checks for position flags.
1635 if ( !( position & PL_POSITION_RIGHT ) && !( position & PL_POSITION_LEFT ) && !( position & PL_POSITION_TOP ) && !( position & PL_POSITION_BOTTOM ) )
1636 {
1637 position = position | PL_POSITION_RIGHT;
1638 }
1639 else if ( ( position & PL_POSITION_RIGHT ) && ( position & PL_POSITION_LEFT ) )
1640 {
1641 plabort( "plcolorbar: PL_POSITION_RIGHT and PL_POSITION_LEFT cannot be simultaneously set." );
1642 return;
1643 }
1644
1645 else if ( ( position & PL_POSITION_TOP ) && ( position & PL_POSITION_BOTTOM ) )
1646 {
1647 plabort( "plcolorbar: PL_POSITION_TOP and PL_POSITION_BOTTOM cannot be simultaneously set." );
1648 return;
1649 }
1650
1651 if ( !( position & PL_POSITION_INSIDE ) && !( position & PL_POSITION_OUTSIDE ) )
1652 {
1653 position = position | PL_POSITION_OUTSIDE;
1654 }
1655 else if ( ( position & PL_POSITION_INSIDE ) && ( position & PL_POSITION_OUTSIDE ) )
1656 {
1657 plabort( "plcolorbar: PL_POSITION_INSIDE and PL_POSITION_OUTSIDE cannot be simultaneously set." );
1658 return;
1659 }
1660
1661 if ( !( position & PL_POSITION_VIEWPORT ) && !( position & PL_POSITION_SUBPAGE ) )
1662 {
1663 position = position | PL_POSITION_VIEWPORT;
1664 }
1665 else if ( ( position & PL_POSITION_VIEWPORT ) && ( position & PL_POSITION_SUBPAGE ) )
1666 {
1667 plabort( "plcolorbar: PL_POSITION_VIEWPORT and PL_POSITION_SUBPAGE cannot be simultaneously set." );
1668 return;
1669 }
1670
1671 // Sanity check for NULL label arrays.
1672 if ( n_labels > 0 && ( label_opts == NULL || labels == NULL ) )
1673 {
1674 plabort( "plcolorbar: label_opts and labels arrays must be defined when n_labels > 0." );
1675 return;
1676 }
1677
1678 if ( n_axes < 1 )
1679 {
1680 plabort( "plcolorbar: At least one axis must be specified" );
1681 return;
1682 }
1683
1684 // xdmin_save, etc., are the actual external relative viewport
1685 // coordinates within the current sub-page used only for
1686 // restoration at the end.
1687 plgvpsp( &xdmin_save, &xdmax_save, &ydmin_save, &ydmax_save );
1688
1689 // Choose adopted coordinates.
1690 if ( position & PL_POSITION_SUBPAGE )
1691 plvpor( 0., 1., 0., 1. );
1692
1693 // xdmin_adopted, etc., are the adopted limits of the coordinates
1694 // within the current sub-page used for all coordinate
1695 // transformations.
1696 // If position & PL_POSITION_VIEWPORT is true, these limits
1697 // are the external relative viewport limits.
1698 // If position & PL_POSITION_SUBPAGE is true, these
1699 // coordinates are the relative subpage coordinates.
1700 plgvpsp( &xdmin_adopted, &xdmax_adopted, &ydmin_adopted, &ydmax_adopted );
1701
1702 // xwmin_save, etc., are the external world coordinates corresponding
1703 // to the external viewport boundaries.
1704 plgvpw( &xwmin_save, &xwmax_save, &ywmin_save, &ywmax_save );
1705
1706 // Default orientation.
1707 if ( !( opt & PL_COLORBAR_ORIENT_RIGHT ||
1708 opt & PL_COLORBAR_ORIENT_TOP ||
1709 opt & PL_COLORBAR_ORIENT_LEFT ||
1710 opt & PL_COLORBAR_ORIENT_BOTTOM ) )
1711 {
1712 if ( position & PL_POSITION_LEFT || position & PL_POSITION_RIGHT )
1713 opt = opt | PL_COLORBAR_ORIENT_TOP;
1714 else
1715 opt = opt | PL_COLORBAR_ORIENT_RIGHT;
1716 }
1717
1718 for ( i = 0; i < n_axes; i++ )
1719 {
1720 if_edge_b = if_edge_b || plP_stsearch( axis_opts[i], 'b' );
1721 if_edge_c = if_edge_c || plP_stsearch( axis_opts[i], 'c' );
1722 if_edge_u = if_edge_u || plP_stsearch( axis_opts[i], 'u' );
1723 if_edge_w = if_edge_w || plP_stsearch( axis_opts[i], 'w' );
1724 }
1725 if_edge = if_edge_b && if_edge_c && !( if_edge_u || if_edge_w );
1726
1727 // Assumes that the colors array is sorted from smallest to largest.
1728 plgcmap1_range( &min_color, &max_color );
1729
1730 // Width and height of the undecorated color bar in normalized
1731 // subpage coordinates and mm.
1732 colorbar_width = adopted_to_subpage_x( x_length ) -
1733 adopted_to_subpage_x( 0. );
1734 colorbar_height = adopted_to_subpage_y( y_length ) -
1735 adopted_to_subpage_y( 0. );
1736 colorbar_width_d = colorbar_width;
1737 colorbar_height_d = colorbar_height;
1738 colorbar_width_mm = colorbar_width / spxpmm;
1739 colorbar_height_mm = colorbar_height / spypmm;
1740 // Extent of cap in normalized subpage coordinates in either X or Y
1741 // direction as appropriate in normalized subpage coordinates and mm.
1742 if ( opt & PL_COLORBAR_ORIENT_RIGHT || opt & PL_COLORBAR_ORIENT_LEFT )
1743 {
1744 cap_extent = cap_ratio * colorbar_height / aspspp;
1745 cap_extent_mm = cap_extent / spxpmm;
1746 }
1747 else
1748 {
1749 cap_extent = cap_ratio * colorbar_width * aspspp;
1750 cap_extent_mm = cap_extent / spypmm;
1751 }
1752
1753 for ( i = n_axes - 1; i >= 0; i-- )
1754 {
1755 min_value = values[i][0];
1756 max_value = values[i][ n_values[i] - 1 ];
1757 max_abs = MAX( fabs( min_value ), fabs( max_value ) );
1758
1759 // Specify the proper window ranges for color bar depending on
1760 // orientation.
1761 if ( opt & PL_COLORBAR_ORIENT_RIGHT )
1762 {
1763 wx_min = min_value;
1764 wx_max = max_value;
1765 wy_min = 0.0;
1766 wy_max = max_abs;
1767 }
1768 else if ( opt & PL_COLORBAR_ORIENT_TOP )
1769 {
1770 wx_min = 0.0;
1771 wx_max = max_abs;
1772 wy_min = min_value;
1773 wy_max = max_value;
1774 }
1775 else if ( opt & PL_COLORBAR_ORIENT_LEFT )
1776 {
1777 wx_min = max_value;
1778 wx_max = min_value;
1779 wy_min = 0.0;
1780 wy_max = max_abs;
1781 }
1782 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM )
1783 {
1784 wx_min = 0.0;
1785 wx_max = max_abs;
1786 wy_min = max_value;
1787 wy_max = min_value;
1788 }
1789 else
1790 {
1791 plabort( "plcolorbar: Invalid PL_COLORBAR_ORIENT_* bits" );
1792 }
1793
1794 // Viewport has correct size but has a shifted zero-point
1795 // convention required by bounding-box calculations in draw_box,
1796 // further bounding-box calculations in the cap_extent section
1797 // below, and also in the calculate_limits call below that.
1798 plvpor( 0., colorbar_width_d, 0., colorbar_height_d );
1799 plwind( wx_min, wx_max, wy_min, wy_max );
1800
1801 // Calculate the bounding box for decorated (i.e., including tick
1802 // marks + numerical tick labels) box.
1803 draw_box( TRUE, opt, axis_opts[i], if_edge,
1804 ticks[i], sub_ticks[i], n_values[i], values[i] );
1805
1806 if ( i == n_axes - 1 )
1807 {
1808 if ( opt & PL_COLORBAR_CAP_LOW )
1809 {
1810 if ( opt & PL_COLORBAR_ORIENT_RIGHT )
1811 plsc->boxbb_xmin = MIN( plsc->boxbb_xmin, -cap_extent_mm );
1812 if ( opt & PL_COLORBAR_ORIENT_TOP )
1813 plsc->boxbb_ymin = MIN( plsc->boxbb_ymin, -cap_extent_mm );
1814 if ( opt & PL_COLORBAR_ORIENT_LEFT )
1815 plsc->boxbb_xmax = MAX( plsc->boxbb_xmax, colorbar_width_mm + cap_extent_mm );
1816 if ( opt & PL_COLORBAR_ORIENT_BOTTOM )
1817 plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, colorbar_height_mm + cap_extent_mm );
1818 }
1819 if ( opt & PL_COLORBAR_CAP_HIGH )
1820 {
1821 if ( opt & PL_COLORBAR_ORIENT_RIGHT )
1822 plsc->boxbb_xmax = MAX( plsc->boxbb_xmax, colorbar_width_mm + cap_extent_mm );
1823 if ( opt & PL_COLORBAR_ORIENT_TOP )
1824 plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, colorbar_height_mm + cap_extent_mm );
1825 if ( opt & PL_COLORBAR_ORIENT_LEFT )
1826 plsc->boxbb_xmin = MIN( plsc->boxbb_xmin, -cap_extent_mm );
1827 if ( opt & PL_COLORBAR_ORIENT_BOTTOM )
1828 plsc->boxbb_ymin = MIN( plsc->boxbb_ymin, -cap_extent_mm );
1829 }
1830 }
1831
1832 // Calculate limits relevant to label position.
1833 calculate_limits( position, x, y,
1834 xdmin_adopted, xdmax_adopted, ydmin_adopted, ydmax_adopted,
1835 colorbar_height_d,
1836 &colorbar_width_d, &colorbar_height_d,
1837 &colorbar_width_ac, &colorbar_height_ac,
1838 &plot_x_subpage_bb, &plot_y_subpage_bb,
1839 &dx_subpage_omd, &dy_subpage_omd );
1840
1841 // Viewport has correct size but has a shifted zero point
1842 // convention required by bounding-box calculations in draw_label
1843 // and further calculations in calculate_limits.
1844 plvpor( 0., colorbar_width_d, 0., colorbar_height_d );
1845
1846 dx_subpage_omd_accu += dx_subpage_omd;
1847 dy_subpage_omd_accu += dy_subpage_omd;
1848 }
1849
1850 // Capture the current bounding box dimensions
1851 colorbar_width_l = colorbar_width_d;
1852 colorbar_height_l = colorbar_height_d;
1853
1854 for ( i = 0; i < n_labels; i++ )
1855 {
1856 // Viewport has correct size but has a shifted zero-point
1857 // convention required by bounding-box calculations in draw_box,
1858 // further bounding-box calculations in the cap_extent section
1859 // below, and also in the calculate_limits call below that.
1860 plvpor( 0., colorbar_width_l, 0., colorbar_height_l );
1861 plwind( wx_min, wx_max, wy_min, wy_max );
1862
1863 // Calculate the bounding box for combined label + decorated box.
1864 draw_label( TRUE, opt | label_opts[i], labels[i] );
1865
1866 // Calculate overall limits.
1867 calculate_limits( position, x, y,
1868 xdmin_adopted, xdmax_adopted, ydmin_adopted, ydmax_adopted,
1869 colorbar_height_l,
1870 &colorbar_width_l, &colorbar_height_l,
1871 &colorbar_width_ac, &colorbar_height_ac,
1872 &plot_x_subpage_bb, &plot_y_subpage_bb,
1873 &dx_subpage_dml, &dy_subpage_dml );
1874
1875 dx_subpage_dml_accu += dx_subpage_dml;
1876 dy_subpage_dml_accu += dy_subpage_dml;
1877 }
1878
1879 // Normalized subpage coordinates (top-left corner) for undecorated
1880 // color bar
1881 plot_x_subpage = plot_x_subpage_bb + dx_subpage_omd_accu + dx_subpage_dml_accu;
1882 plot_y_subpage = plot_y_subpage_bb + dy_subpage_omd_accu + dy_subpage_dml_accu;
1883
1884 // Coordinates of bounding box for decorated color bar (without overall label).
1885 label_vpor_xmin = plot_x_subpage_bb + dx_subpage_dml_accu;
1886 label_vpor_xmax = label_vpor_xmin + colorbar_width_d;
1887 label_vpor_ymax = plot_y_subpage_bb + dy_subpage_dml_accu;
1888 label_vpor_ymin = label_vpor_ymax - colorbar_height_d;
1889
1890 // Return bounding box width and height in adopted coordinates for
1891 // labelled and decorated color bar.
1892 *p_colorbar_width = colorbar_width_ac;
1893 *p_colorbar_height = colorbar_height_ac;
1894
1895 // Specify the proper viewport ranges for color bar depending on
1896 // orientation.
1897 if ( opt & PL_COLORBAR_ORIENT_RIGHT )
1898 {
1899 vx_min = plot_x_subpage;
1900 vx_max = plot_x_subpage + colorbar_width;
1901 vy_min = plot_y_subpage - colorbar_height;
1902 vy_max = plot_y_subpage;
1903 }
1904 else if ( opt & PL_COLORBAR_ORIENT_TOP )
1905 {
1906 vx_min = plot_x_subpage;
1907 vx_max = plot_x_subpage + colorbar_width;
1908 vy_min = plot_y_subpage - colorbar_height;
1909 vy_max = plot_y_subpage;
1910 }
1911 else if ( opt & PL_COLORBAR_ORIENT_LEFT )
1912 {
1913 vx_min = plot_x_subpage;
1914 vx_max = plot_x_subpage + colorbar_width;
1915 vy_min = plot_y_subpage - colorbar_height;
1916 vy_max = plot_y_subpage;
1917 }
1918 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM )
1919 {
1920 vx_min = plot_x_subpage;
1921 vx_max = plot_x_subpage + colorbar_width;
1922 vy_min = plot_y_subpage - colorbar_height;
1923 vy_max = plot_y_subpage;
1924 }
1925 else
1926 {
1927 plabort( "plcolorbar: Invalid PL_COLORBAR_ORIENT_* bits" );
1928 }
1929
1930 // Viewport and world coordinate ranges for bounding-box.
1931 plvpor( 0., 1., 0., 1. );
1932 plwind( 0., 1., 0., 1. );
1933
1934 if ( opt & PL_COLORBAR_BACKGROUND )
1935 {
1936 PLFLT xbg[4] = {
1937 plot_x_subpage_bb,
1938 plot_x_subpage_bb,
1939 plot_x_subpage_bb + colorbar_width_l,
1940 plot_x_subpage_bb + colorbar_width_l,
1941 };
1942 PLFLT ybg[4] = {
1943 plot_y_subpage_bb,
1944 plot_y_subpage_bb - colorbar_height_l,
1945 plot_y_subpage_bb - colorbar_height_l,
1946 plot_y_subpage_bb,
1947 };
1948 plpsty( 0 );
1949 plcol0( bg_color );
1950 plfill( 4, xbg, ybg );
1951 plcol0( col0_save );
1952 }
1953
1954 // Viewport and world coordinate ranges for color bar.
1955 plvpor( vx_min, vx_max, vy_min, vy_max );
1956 plwind( wx_min, wx_max, wy_min, wy_max );
1957
1958 // What kind of color bar are we making?
1959 if ( opt & PL_COLORBAR_IMAGE )
1960 {
1961 // Interpolate
1962 // TODO: Should this be decided with an extra opt option instead of by
1963 // counting n_values?
1964 if ( n_values[0] == 2 )
1965 {
1966 // Use the same number of steps as there are steps in
1967 // color palette 1.
1968 // TODO: Determine a better way to specify the steps here?
1969 n_steps = plsc->ncol1;
1970 step_size = ( max_value - min_value ) / (PLFLT) n_steps;
1971 if ( opt & PL_COLORBAR_ORIENT_RIGHT )
1972 {
1973 ni = n_steps;
1974 nj = 2;
1975 plAlloc2dGrid( &color_data, ni, nj );
1976 for ( i = 0; i < ni; i++ )
1977 {
1978 for ( j = 0; j < nj; j++ )
1979 {
1980 color_data[i][j] = min_value + (PLFLT) i * step_size;
1981 }
1982 }
1983 }
1984 else if ( opt & PL_COLORBAR_ORIENT_TOP )
1985 {
1986 ni = 2;
1987 nj = n_steps;
1988 plAlloc2dGrid( &color_data, ni, nj );
1989 for ( i = 0; i < ni; i++ )
1990 {
1991 for ( j = 0; j < nj; j++ )
1992 {
1993 color_data[i][j] = min_value + (PLFLT) j * step_size;
1994 }
1995 }
1996 }
1997 else if ( opt & PL_COLORBAR_ORIENT_LEFT )
1998 {
1999 ni = n_steps;
2000 nj = 2;
2001 plAlloc2dGrid( &color_data, ni, nj );
2002 for ( i = 0; i < ni; i++ )
2003 {
2004 for ( j = 0; j < nj; j++ )
2005 {
2006 color_data[i][j] = max_value - (PLFLT) i * step_size;
2007 }
2008 }
2009 }
2010 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM )
2011 {
2012 ni = 2;
2013 nj = n_steps;
2014 plAlloc2dGrid( &color_data, ni, nj );
2015 for ( i = 0; i < ni; i++ )
2016 {
2017 for ( j = 0; j < nj; j++ )
2018 {
2019 color_data[i][j] = max_value - (PLFLT) j * step_size;
2020 }
2021 }
2022 }
2023 else
2024 {
2025 plabort( "plcolorbar: Invalid orientation bits" );
2026 }
2027 }
2028 // No interpolation - use values array as-is
2029 else
2030 {
2031 n_steps = n_values[0];
2032 // Use the provided values in this case.
2033 if ( opt & PL_COLORBAR_ORIENT_RIGHT )
2034 {
2035 ni = n_steps;
2036 nj = 2;
2037 plAlloc2dGrid( &color_data, ni, nj );
2038 for ( i = 0; i < ni; i++ )
2039 {
2040 for ( j = 0; j < nj; j++ )
2041 {
2042 color_data[i][j] = values[0][i];
2043 }
2044 }
2045 }
2046 else if ( opt & PL_COLORBAR_ORIENT_TOP )
2047 {
2048 ni = 2;
2049 nj = n_steps;
2050 plAlloc2dGrid( &color_data, ni, nj );
2051 for ( i = 0; i < ni; i++ )
2052 {
2053 for ( j = 0; j < nj; j++ )
2054 {
2055 color_data[i][j] = values[0][j];
2056 }
2057 }
2058 }
2059 else if ( opt & PL_COLORBAR_ORIENT_LEFT )
2060 {
2061 ni = n_steps;
2062 nj = 2;
2063 plAlloc2dGrid( &color_data, ni, nj );
2064 for ( i = 0; i < ni; i++ )
2065 {
2066 for ( j = 0; j < nj; j++ )
2067 {
2068 color_data[i][j] = values[0][ni - 1 - i];
2069 }
2070 }
2071 }
2072 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM )
2073 {
2074 ni = 2;
2075 nj = n_steps;
2076 plAlloc2dGrid( &color_data, ni, nj );
2077 for ( i = 0; i < ni; i++ )
2078 {
2079 for ( j = 0; j < nj; j++ )
2080 {
2081 color_data[i][j] = values[0][nj - 1 - j];
2082 }
2083 }
2084 }
2085 else
2086 {
2087 plabort( "plcolorbar: Invalid side" );
2088 }
2089 }
2090 // Draw the color bar
2091 plimage( (PLFLT_MATRIX) color_data, ni, nj, wx_min, wx_max, wy_min, wy_max,
2092 min_value, max_value, wx_min, wx_max, wy_min, wy_max );
2093 plFree2dGrid( color_data, ni, nj );
2094 }
2095 else if ( opt & PL_COLORBAR_SHADE )
2096 {
2097 // Transform grid
2098 // The transform grid is used to make the size of the shaded segments
2099 // scale relative to other segments. For example, if segment A
2100 // makes up 10% of the scale and segment B makes up 20% of the scale
2101 // then segment B will be twice the length of segment A.
2102 PLcGrid grid;
2103 PLFLT grid_axis[2] = { 0.0, max_abs };
2104 n_steps = n_values[0];
2105 // Use the provided values.
2106 if ( opt & PL_COLORBAR_ORIENT_RIGHT )
2107 {
2108 grid.xg = (PLFLT *) values[0];
2109 grid.yg = grid_axis;
2110 grid.nx = n_steps;
2111 grid.ny = 2;
2112 ni = n_steps;
2113 nj = 2;
2114 plAlloc2dGrid( &color_data, ni, nj );
2115 for ( i = 0; i < ni; i++ )
2116 {
2117 for ( j = 0; j < nj; j++ )
2118 {
2119 color_data[i][j] = values[0][i];
2120 }
2121 }
2122 }
2123 else if ( opt & PL_COLORBAR_ORIENT_TOP )
2124 {
2125 grid.xg = grid_axis;
2126 grid.yg = (PLFLT *) values[0];
2127 grid.nx = 2;
2128 grid.ny = n_steps;
2129 ni = 2;
2130 nj = n_steps;
2131 plAlloc2dGrid( &color_data, ni, nj );
2132 for ( i = 0; i < ni; i++ )
2133 {
2134 for ( j = 0; j < nj; j++ )
2135 {
2136 color_data[i][j] = values[0][j];
2137 }
2138 }
2139 }
2140 else if ( opt & PL_COLORBAR_ORIENT_LEFT )
2141 {
2142 grid.xg = (PLFLT *) values[0];
2143 grid.yg = grid_axis;
2144 grid.nx = n_steps;
2145 grid.ny = 2;
2146 ni = n_steps;
2147 nj = 2;
2148 plAlloc2dGrid( &color_data, ni, nj );
2149 for ( i = 0; i < ni; i++ )
2150 {
2151 for ( j = 0; j < nj; j++ )
2152 {
2153 color_data[i][j] = values[0][ni - 1 - i];
2154 }
2155 }
2156 }
2157 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM )
2158 {
2159 grid.xg = grid_axis;
2160 grid.yg = (PLFLT *) values[0];
2161 grid.nx = 2;
2162 grid.ny = n_steps;
2163 ni = 2;
2164 nj = n_steps;
2165 plAlloc2dGrid( &color_data, ni, nj );
2166 for ( i = 0; i < ni; i++ )
2167 {
2168 for ( j = 0; j < nj; j++ )
2169 {
2170 color_data[i][j] = values[0][nj - 1 - j];
2171 }
2172 }
2173 }
2174 else
2175 {
2176 plabort( "plcolorbar: Invalid orientation" );
2177 }
2178
2179 // Draw the color bar
2180 plshades( (PLFLT_MATRIX) color_data, ni, nj, NULL, wx_min, wx_max, wy_min, wy_max,
2181 values[0], n_steps, 0, cont_color, cont_width, plfill, TRUE,
2182 pltr1, (void *) ( &grid ) );
2183 plFree2dGrid( color_data, ni, nj );
2184 }
2185 else if ( opt & PL_COLORBAR_GRADIENT )
2186 {
2187 PLFLT xs[4], ys[4];
2188 PLFLT angle = 0.0;
2189 xs[0] = wx_min;
2190 ys[0] = wy_min;
2191 xs[1] = wx_max;
2192 ys[1] = wy_min;
2193 xs[2] = wx_max;
2194 ys[2] = wy_max;
2195 xs[3] = wx_min;
2196 ys[3] = wy_max;
2197 // Make sure the gradient runs in the proper direction
2198 if ( opt & PL_COLORBAR_ORIENT_RIGHT )
2199 {
2200 angle = 0.0;
2201 }
2202 else if ( opt & PL_COLORBAR_ORIENT_TOP )
2203 {
2204 angle = 90.0;
2205 }
2206 else if ( opt & PL_COLORBAR_ORIENT_LEFT )
2207 {
2208 angle = 180.0;
2209 }
2210 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM )
2211 {
2212 angle = 270.0;
2213 }
2214 else
2215 {
2216 plabort( "plcolorbar: Invalid orientation" );
2217 }
2218 plgradient( 4, xs, ys, angle );
2219 }
2220 else
2221 {
2222 plabort( "plcolorbar: One of PL_COLORBAR_IMAGE, PL_COLORBAR_SHADE, or PL_COLORBAR_GRADIENT bits must be set in opt" );
2223 }
2224
2225 // Restore the previous drawing color to use for outlines and text
2226 plcol0( col0_save );
2227
2228 // Draw end-caps
2229
2230 // Viewport and world coordinate ranges for cap.
2231 plvpor( 0., 1., 0., 1. );
2232 plwind( 0., 1., 0., 1. );
2233
2234 if ( opt & PL_COLORBAR_CAP_LOW )
2235 {
2236 // Draw a filled triangle (cap/arrow) at the low end of the scale
2237 if ( opt & PL_COLORBAR_ORIENT_RIGHT )
2238 draw_cap( if_edge, PL_COLORBAR_ORIENT_LEFT,
2239 plot_x_subpage - cap_extent, plot_x_subpage,
2240 plot_y_subpage - colorbar_height, plot_y_subpage,
2241 low_cap_color );
2242 else if ( opt & PL_COLORBAR_ORIENT_TOP )
2243 draw_cap( if_edge, PL_COLORBAR_ORIENT_BOTTOM,
2244 plot_x_subpage, plot_x_subpage + colorbar_width,
2245 plot_y_subpage - colorbar_height - cap_extent, plot_y_subpage - colorbar_height,
2246 low_cap_color );
2247 else if ( opt & PL_COLORBAR_ORIENT_LEFT )
2248 draw_cap( if_edge, PL_COLORBAR_ORIENT_RIGHT,
2249 plot_x_subpage + colorbar_width, plot_x_subpage + colorbar_width + cap_extent,
2250 plot_y_subpage - colorbar_height, plot_y_subpage,
2251 low_cap_color );
2252 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM )
2253 draw_cap( if_edge, PL_COLORBAR_ORIENT_TOP,
2254 plot_x_subpage, plot_x_subpage + colorbar_width,
2255 plot_y_subpage, plot_y_subpage + cap_extent,
2256 low_cap_color );
2257 }
2258 if ( opt & PL_COLORBAR_CAP_HIGH )
2259 {
2260 // Draw a filled triangle (cap/arrow) at the high end of the scale
2261 if ( opt & PL_COLORBAR_ORIENT_RIGHT )
2262 draw_cap( if_edge, PL_COLORBAR_ORIENT_RIGHT,
2263 plot_x_subpage + colorbar_width, plot_x_subpage + colorbar_width + cap_extent,
2264 plot_y_subpage - colorbar_height, plot_y_subpage,
2265 high_cap_color );
2266 else if ( opt & PL_COLORBAR_ORIENT_TOP )
2267 draw_cap( if_edge, PL_COLORBAR_ORIENT_TOP,
2268 plot_x_subpage, plot_x_subpage + colorbar_width,
2269 plot_y_subpage, plot_y_subpage + cap_extent,
2270 high_cap_color );
2271 else if ( opt & PL_COLORBAR_ORIENT_LEFT )
2272 draw_cap( if_edge, PL_COLORBAR_ORIENT_LEFT,
2273 plot_x_subpage - cap_extent, plot_x_subpage,
2274 plot_y_subpage - colorbar_height, plot_y_subpage,
2275 high_cap_color );
2276 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM )
2277 draw_cap( if_edge, PL_COLORBAR_ORIENT_BOTTOM,
2278 plot_x_subpage, plot_x_subpage + colorbar_width,
2279 plot_y_subpage - colorbar_height - cap_extent, plot_y_subpage - colorbar_height,
2280 high_cap_color );
2281 }
2282
2283 for ( i = n_axes - 1; i >= 0; i-- )
2284 {
2285 min_value = values[i][0];
2286 max_value = values[i][ n_values[i] - 1 ];
2287 max_abs = MAX( fabs( min_value ), fabs( max_value ) );
2288
2289 // Specify the proper window ranges for color bar depending on
2290 // orientation.
2291 if ( opt & PL_COLORBAR_ORIENT_RIGHT )
2292 {
2293 wx_min = min_value;
2294 wx_max = max_value;
2295 wy_min = 0.0;
2296 wy_max = max_abs;
2297 }
2298 else if ( opt & PL_COLORBAR_ORIENT_TOP )
2299 {
2300 wx_min = 0.0;
2301 wx_max = max_abs;
2302 wy_min = min_value;
2303 wy_max = max_value;
2304 }
2305 else if ( opt & PL_COLORBAR_ORIENT_LEFT )
2306 {
2307 wx_min = max_value;
2308 wx_max = min_value;
2309 wy_min = 0.0;
2310 wy_max = max_abs;
2311 }
2312 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM )
2313 {
2314 wx_min = 0.0;
2315 wx_max = max_abs;
2316 wy_min = max_value;
2317 wy_max = min_value;
2318 }
2319 else
2320 {
2321 plabort( "plcolorbar: Invalid PL_COLORBAR_ORIENT_* bits" );
2322 }
2323
2324 // Viewport and world coordinate ranges for box.
2325 plvpor( vx_min, vx_max, vy_min, vy_max );
2326 plwind( wx_min, wx_max, wy_min, wy_max );
2327
2328 // draw decorated (i.e., including tick marks + numerical tick
2329 // labels) box.
2330 draw_box( FALSE, opt, axis_opts[i], if_edge,
2331 ticks[i], sub_ticks[i], n_values[i], values[i] );
2332 }
2333
2334 // Viewport and world coordinate ranges for bounding-box.
2335 plvpor( 0., 1., 0., 1. );
2336 plwind( 0., 1., 0., 1. );
2337
2338 if ( opt & PL_COLORBAR_BOUNDING_BOX )
2339 {
2340 PLFLT xbb[5] = {
2341 plot_x_subpage_bb,
2342 plot_x_subpage_bb,
2343 plot_x_subpage_bb + colorbar_width_l,
2344 plot_x_subpage_bb + colorbar_width_l,
2345 plot_x_subpage_bb,
2346 };
2347 PLFLT ybb[5] = {
2348 plot_y_subpage_bb,
2349 plot_y_subpage_bb - colorbar_height_l,
2350 plot_y_subpage_bb - colorbar_height_l,
2351 plot_y_subpage_bb,
2352 plot_y_subpage_bb,
2353 };
2354 pllsty( bb_style );
2355 plcol0( bb_color );
2356 plline( 5, xbb, ybb );
2357 plcol0( col0_save );
2358 pllsty( line_style_save );
2359 }
2360
2361 // Write label.
2362 // Viewport coordinate ranges for label.
2363 plvpor( label_vpor_xmin, label_vpor_xmax, label_vpor_ymin, label_vpor_ymax );
2364 for ( i = 0; i < n_labels; i++ )
2365 {
2366 draw_label( FALSE, opt | label_opts[i], labels[i] );
2367 }
2368
2369 // Restore previous plot characteristics.
2370 plcol0( col0_save );
2371 plvpor( xdmin_save, xdmax_save, ydmin_save, ydmax_save );
2372 plwind( xwmin_save, xwmax_save, ywmin_save, ywmax_save );
2373
2374 return;
2375 }
max_opts
#define max_opts
plplotP.h
plexit
void plexit(PLCHAR_VECTOR errormsg)
Definition: plctrl.c:1958
plvpor
#define plvpor
Definition: plplot.h:860
PL_LEGEND_LINE
#define PL_LEGEND_LINE
Definition: plplot.h:1290
PL_COLORBAR_LABEL_TOP
#define PL_COLORBAR_LABEL_TOP
Definition: plplot.h:1301
plschr
#define plschr
Definition: plplot.h:790
PLFLT_MATRIX
const PLFLT *const * PLFLT_MATRIX
Definition: plplot.h:253
pllsty
#define pllsty
Definition: plplot.h:763
plwind
#define plwind
Definition: plplot.h:864
plfill
#define plfill
Definition: plplot.h:717
PL_POSITION_BOTTOM
#define PL_POSITION_BOTTOM
Definition: plplot.h:1280
PL_LEGEND_BACKGROUND
#define PL_LEGEND_BACKGROUND
Definition: plplot.h:1293
PLCHAR_VECTOR
const char * PLCHAR_VECTOR
Definition: plplot.h:243
plimage
#define plimage
Definition: plplot.h:753
PL_COLORBAR_ORIENT_TOP
#define PL_COLORBAR_ORIENT_TOP
Definition: plplot.h:1311
plgvpsp
static void plgvpsp(PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax)
Definition: pllegend.c:46
PL_LEGEND_SYMBOL
#define PL_LEGEND_SYMBOL
Definition: plplot.h:1291
PL_COLORBAR_BACKGROUND
#define PL_COLORBAR_BACKGROUND
Definition: plplot.h:1314
MAX
#define MAX(a, b)
Definition: dsplint.c:28
PL_POSITION_LEFT
#define PL_POSITION_LEFT
Definition: plplot.h:1277
plP_stsearch
PLBOOL plP_stsearch(PLCHAR_VECTOR str, int chr)
Definition: plsym.c:1256
PLCHAR_MATRIX
const char *const * PLCHAR_MATRIX
Definition: plplot.h:252
get_character_or_symbol_height
static PLFLT get_character_or_symbol_height(PLBOOL ifcharacter)
Definition: pllegend.c:312
plabort
void plabort(PLCHAR_VECTOR errormsg)
Definition: plctrl.c:1894
PL_COLORBAR_SHADE
#define PL_COLORBAR_SHADE
Definition: plplot.h:1304
remove_characters
static void remove_characters(char *string, PLCHAR_VECTOR characters)
Definition: pllegend.c:933
get_subpage_per_mm
static void get_subpage_per_mm(PLFLT *x_subpage_per_mm, PLFLT *y_subpage_per_mm)
Definition: pllegend.c:295
plstrl
PLFLT plstrl(PLCHAR_VECTOR string)
Definition: plsym.c:976
PL_LEGEND_BOUNDING_BOX
#define PL_LEGEND_BOUNDING_BOX
Definition: plplot.h:1294
c_pllegend
void c_pllegend(PLFLT *p_legend_width, PLFLT *p_legend_height, PLINT opt, PLINT position, PLFLT x, PLFLT y, PLFLT plot_width, PLINT bg_color, PLINT bb_color, PLINT bb_style, PLINT nrow, PLINT ncolumn, PLINT nlegend, PLINT_VECTOR opt_array, PLFLT text_offset, PLFLT text_scale, PLFLT text_spacing, PLFLT text_justification, PLINT_VECTOR text_colors, PLCHAR_MATRIX text, PLINT_VECTOR box_colors, PLINT_VECTOR box_patterns, PLFLT_VECTOR box_scales, PLFLT_VECTOR box_line_widths, PLINT_VECTOR line_colors, PLINT_VECTOR line_styles, PLFLT_VECTOR line_widths, PLINT_VECTOR symbol_colors, PLFLT_VECTOR symbol_scales, PLINT_VECTOR symbol_numbers, PLCHAR_MATRIX symbols)
Definition: pllegend.c:531
PL_LEGEND_NONE
#define PL_LEGEND_NONE
Definition: plplot.h:1288
color
static int color
Definition: ps.c:78
PLINT
int PLINT
Definition: plplot.h:181
draw_label
static void draw_label(PLBOOL if_bb, PLINT opt, PLCHAR_VECTOR label)
Definition: pllegend.c:1138
plshades
#define plshades
Definition: plplot.h:824
MIN
#define MIN(a, b)
Definition: dsplint.c:29
PLBOOL
PLINT PLBOOL
Definition: plplot.h:204
PL_POSITION_OUTSIDE
#define PL_POSITION_OUTSIDE
Definition: plplot.h:1282
PL_POSITION_RIGHT
#define PL_POSITION_RIGHT
Definition: plplot.h:1278
PL_COLORBAR_LABEL_LEFT
#define PL_COLORBAR_LABEL_LEFT
Definition: plplot.h:1299
PL_LEGEND_ROW_MAJOR
#define PL_LEGEND_ROW_MAJOR
Definition: plplot.h:1295
PLcGrid::ny
PLINT ny
Definition: plplot.h:509
PL_COLORBAR_SHADE_LABEL
#define PL_COLORBAR_SHADE_LABEL
Definition: plplot.h:1309
PL_COLORBAR_ORIENT_BOTTOM
#define PL_COLORBAR_ORIENT_BOTTOM
Definition: plplot.h:1313
PL_POSITION_VIEWPORT
#define PL_POSITION_VIEWPORT
Definition: plplot.h:1283
calculate_limits
static void calculate_limits(PLINT position, PLFLT x, PLFLT y, PLFLT xdmin_adopted, PLFLT xdmax_adopted, PLFLT ydmin_adopted, PLFLT ydmax_adopted, PLFLT prior_bb_height, PLFLT *p_colorbar_width_bb, PLFLT *p_colorbar_height_bb, PLFLT *p_colorbar_width_ac, PLFLT *p_colorbar_height_ac, PLFLT *p_plot_x_subpage_bb, PLFLT *p_plot_y_subpage_bb, PLFLT *p_dx_subpage, PLFLT *p_dy_subpage)
Definition: pllegend.c:1348
subpage_to_adopted_x
#define subpage_to_adopted_x(nx)
Definition: pllegend.c:359
PLcGrid
Definition: plplot.h:506
PL_COLORBAR_GRADIENT
#define PL_COLORBAR_GRADIENT
Definition: plplot.h:1305
snprintf
#define snprintf
Definition: plplotP.h:235
plgchr
#define plgchr
Definition: plplot.h:722
plFree2dGrid
void plFree2dGrid(PLFLT **f, PLINT nx, PLINT PL_UNUSED(ny))
Definition: plmem.c:116
TRUE
#define TRUE
Definition: plplotP.h:176
adopted_to_subpage_y
#define adopted_to_subpage_y(ny)
Definition: pllegend.c:374
PL_POSITION_SUBPAGE
#define PL_POSITION_SUBPAGE
Definition: plplot.h:1284
PLcGrid::yg
PLFLT_NC_FE_POINTER yg
Definition: plplot.h:508
plstring
#define plstring
Definition: plplot.h:841
FALSE
#define FALSE
Definition: plplotP.h:177
legend_position
static void legend_position(PLINT position, PLFLT legend_width, PLFLT legend_height, PLFLT *x_legend_position, PLFLT *y_legend_position, PLFLT *xsign, PLFLT *ysign)
Definition: pllegend.c:87
plcol1
#define plcol1
Definition: plplot.h:703
PL_COLORBAR_ORIENT_LEFT
#define PL_COLORBAR_ORIENT_LEFT
Definition: plplot.h:1312
plbox
#define plbox
Definition: plplot.h:697
plwidth
#define plwidth
Definition: plplot.h:863
PLINT_VECTOR
const PLINT * PLINT_VECTOR
Definition: plplot.h:241
label_box_custom
void label_box_custom(PLCHAR_VECTOR xopt, PLINT n_xticks, PLFLT_VECTOR xticks, PLCHAR_VECTOR yopt, PLINT n_yticks, PLFLT_VECTOR yticks)
Definition: plbox.c:1925
PL_POSITION_INSIDE
#define PL_POSITION_INSIDE
Definition: plplot.h:1281
plgspa
#define plgspa
Definition: plplot.h:743
c_plcolorbar
void c_plcolorbar(PLFLT *p_colorbar_width, PLFLT *p_colorbar_height, PLINT opt, PLINT position, PLFLT x, PLFLT y, PLFLT x_length, PLFLT y_length, PLINT bg_color, PLINT bb_color, PLINT bb_style, PLFLT low_cap_color, PLFLT high_cap_color, PLINT cont_color, PLFLT cont_width, PLINT n_labels, PLINT_VECTOR label_opts, PLCHAR_MATRIX labels, PLINT n_axes, PLCHAR_MATRIX axis_opts, PLFLT_VECTOR ticks, PLINT_VECTOR sub_ticks, PLINT_VECTOR n_values, PLFLT_MATRIX values)
Definition: pllegend.c:1525
plpsty
#define plpsty
Definition: plplot.h:784
plgvpw
#define plgvpw
Definition: plplot.h:747
text
static int text
Definition: ps.c:77
PL_COLORBAR_CAP_HIGH
#define PL_COLORBAR_CAP_HIGH
Definition: plplot.h:1308
PL_COLORBAR_ORIENT_RIGHT
#define PL_COLORBAR_ORIENT_RIGHT
Definition: plplot.h:1310
PLFLT
float PLFLT
Definition: plplot.h:163
PL_LEGEND_TEXT_LEFT
#define PL_LEGEND_TEXT_LEFT
Definition: plplot.h:1292
draw_cap
static void draw_cap(PLBOOL if_edge, PLINT orientation, PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax, PLFLT color)
Definition: pllegend.c:973
plAlloc2dGrid
void plAlloc2dGrid(PLFLT ***f, PLINT nx, PLINT ny)
Definition: plmem.c:91
subpage_to_adopted_y
#define subpage_to_adopted_y(ny)
Definition: pllegend.c:389
PL_COLORBAR_CAP_LOW
#define PL_COLORBAR_CAP_LOW
Definition: plplot.h:1307
PI
#define PI
Definition: plplotP.h:290
adopted_to_subpage_x
#define adopted_to_subpage_x(nx)
Definition: pllegend.c:344
plgcmap1_range
#define plgcmap1_range
Definition: plplot.h:723
plcol0
#define plcol0
Definition: plplot.h:702
PLcGrid::xg
PLFLT_NC_FE_POINTER xg
Definition: plplot.h:508
draw_box
static void draw_box(PLBOOL if_bb, PLINT opt, PLCHAR_VECTOR axis_opts, PLBOOL if_edge, PLFLT ticks, PLINT sub_ticks, PLINT n_values, PLFLT_VECTOR values)
Definition: pllegend.c:1062
plptex
#define plptex
Definition: plplot.h:785
plline
#define plline
Definition: plplot.h:760
PL_LEGEND_COLOR_BOX
#define PL_LEGEND_COLOR_BOX
Definition: plplot.h:1289
PL_COLORBAR_LABEL_BOTTOM
#define PL_COLORBAR_LABEL_BOTTOM
Definition: plplot.h:1302
plgradient
#define plgradient
Definition: plplot.h:741
PL_POSITION_TOP
#define PL_POSITION_TOP
Definition: plplot.h:1279
PL_COLORBAR_BOUNDING_BOX
#define PL_COLORBAR_BOUNDING_BOX
Definition: plplot.h:1315
PLFLT_VECTOR
const PLFLT * PLFLT_VECTOR
Definition: plplot.h:244
PL_COLORBAR_IMAGE
#define PL_COLORBAR_IMAGE
Definition: plplot.h:1303
plmtex
#define plmtex
Definition: plplot.h:773
plplotc.pltr1
def pltr1
Definition: plplotc.py:105
PL_COLORBAR_LABEL_RIGHT
#define PL_COLORBAR_LABEL_RIGHT
Definition: plplot.h:1300
PLcGrid::nx
PLINT nx
Definition: plplot.h:509