2 static char *RCSid() { return RCSid("$Id: plot2d.c,v 1.133.2.17 2009/07/21 18:16:11 sfeam Exp $"); }
5 /* GNUPLOT - plot2d.c */
8 * Copyright 1986 - 1993, 1998, 2004 Thomas Williams, Colin Kelley
10 * Permission to use, copy, and distribute this software and its
11 * documentation for any purpose with or without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and
13 * that both that copyright notice and this permission notice appear
14 * in supporting documentation.
16 * Permission to modify the software is granted, but not the right to
17 * distribute the complete modified source code. Modifications are to
18 * be distributed as patches to the released version. Permission to
19 * distribute binaries produced by compiling modified sources is granted,
21 * 1. distribute the corresponding source modifications from the
22 * released version in the form of a patch file along with the binaries,
23 * 2. add special version identification to distinguish your version
24 * in addition to the base release version number,
25 * 3. provide your name and address as the primary contact for the
26 * support of your modified version, and
27 * 4. retain our contact information in regard to use of the base
29 * Permission to distribute the released version of the source code along
30 * with corresponding source modifications in the form of a patch file is
31 * granted with same provisions 2 through 4 for binary distributions.
33 * This software is provided "as is" without express or implied warranty
34 * to the extent permitted by applicable law.
55 #ifdef BINARY_DATA_FILE
63 /* minimum size of points[] in curve_points */
64 #define MIN_CRV_POINTS 100
66 /* static prototypes */
68 static struct curve_points * cp_alloc __PROTO((int num));
69 static int get_data __PROTO((struct curve_points *));
70 static void store2d_point __PROTO((struct curve_points *, int i, double x, double y, double xlow, double xhigh, double ylow, double yhigh, double width));
71 static void print_table __PROTO((struct curve_points * first_plot, int plot_num));
72 static void eval_plots __PROTO((void));
73 static void parametric_fixup __PROTO((struct curve_points * start_plot, int *plot_num));
75 static void histogram_range_fiddling __PROTO((struct curve_points *plot));
78 /* internal and external variables */
80 /* the curves/surfaces of the plot */
81 struct curve_points *first_plot = NULL;
82 static struct udft_entry plot_func;
84 /* box width (automatic) */
85 double boxwidth = -1.0;
86 /* whether box width is absolute (default) or relative */
87 TBOOLEAN boxwidth_is_absolute = TRUE;
90 static double histogram_rightmost = 0.0; /* Highest x-coord of histogram so far */
91 static char *histogram_title = NULL; /* Subtitle for this histogram */
92 static struct coordinate GPHUGE *stackheight = NULL; /* Scratch space for y autoscale */
93 static int stack_count = 0; /* counter for stackheight */
96 /* function implementations */
98 /* HBB 20000508: moved cp_alloc() &friends to the main module using them, and
99 * made cp_alloc 'static'.
102 * cp_alloc() allocates a curve_points structure that can hold 'num'
103 * points. Initialize all fields to NULL.
105 static struct curve_points *
108 struct curve_points *cp;
109 struct lp_style_type default_lp_properties = DEFAULT_LP_STYLE_TYPE;
111 cp = (struct curve_points *) gp_alloc(sizeof(struct curve_points), "curve");
112 memset(cp,0,sizeof(struct curve_points));
114 cp->p_max = (num >= 0 ? num : 0);
116 cp->points = (struct coordinate GPHUGE *)
117 gp_alloc(num * sizeof(struct coordinate), "curve points");
119 /* Initialize various fields */
120 cp->lp_properties = default_lp_properties;
121 default_arrow_style(&(cp->arrow_properties));
122 cp->fill_properties = default_fillstyle;
129 * cp_extend() reallocates a curve_points structure to hold "num"
130 * points. This will either expand or shrink the storage.
133 cp_extend(struct curve_points *cp, int num)
136 #if defined(DOS16) || defined(WIN16)
137 /* Make sure we do not allocate more than 64k points in msdos since
138 * indexing is done with 16-bit int
139 * Leave some bytes for malloc maintainance.
142 int_error(NO_CARET, "Array index must be less than 32k in msdos");
145 if (num == cp->p_max)
149 if (cp->points == NULL) {
150 cp->points = gp_alloc(num * sizeof(cp->points[0]),
153 cp->points = gp_realloc(cp->points, num * sizeof(cp->points[0]),
154 "expanding curve points");
158 if (cp->points != NULL)
166 * cp_free() releases any memory which was previously malloc()'d to hold
167 * curve points (and recursively down the linked list).
169 /* HBB 20000506: instead of risking stack havoc by recursion, operate
172 cp_free(struct curve_points *cp)
175 struct curve_points *next = cp->next;
181 #ifdef EAM_DATASTRINGS
183 free_labels(cp->labels);
184 cp->labels = (struct text_label *)NULL;
193 * In the parametric case we can say plot [a= -4:4] [-2:2] [-1:1] sin(a),a**2
194 * while in the non-parametric case we would say only plot [b= -2:2] [-1:1]
200 int dummy_token = -1;
203 if (!term) /* unknown */
204 int_error(c_token, "use 'set term' to set terminal type first");
211 /* Deactivate if 'set view map' is still running after the previous 'splot': */
212 splot_map_deactivate();
214 if (parametric && strcmp(set_dummy_var[0], "u") == 0)
215 strcpy(set_dummy_var[0], "t");
217 /* initialise the arrays from the 'set' scalars */
219 AXIS_INIT2D(FIRST_X_AXIS, 0);
220 AXIS_INIT2D(FIRST_Y_AXIS, 1);
221 AXIS_INIT2D(SECOND_X_AXIS, 0);
222 AXIS_INIT2D(SECOND_Y_AXIS, 1);
223 AXIS_INIT2D(T_AXIS, 0);
224 AXIS_INIT2D(R_AXIS, 1);
225 AXIS_INIT2D(COLOR_AXIS, 1);
227 t_axis = (parametric || polar) ? T_AXIS : FIRST_X_AXIS;
229 PARSE_NAMED_RANGE(t_axis, dummy_token);
230 if (parametric || polar) /* set optional x ranges */
231 PARSE_RANGE(FIRST_X_AXIS);
233 /* possible reversal of x range *does* matter, even in parametric
235 CHECK_REVERSE(FIRST_X_AXIS);
237 PARSE_RANGE(FIRST_Y_AXIS);
238 CHECK_REVERSE(FIRST_Y_AXIS);
239 PARSE_RANGE(SECOND_X_AXIS);
240 CHECK_REVERSE(SECOND_X_AXIS);
241 PARSE_RANGE(SECOND_Y_AXIS);
242 CHECK_REVERSE(SECOND_Y_AXIS);
244 /* Clear out any tick labels read from data files in previous plot */
245 for (t_axis=0; t_axis<AXIS_ARRAY_SIZE; t_axis++) {
246 struct ticdef *ticdef = &axis_array[t_axis].ticdef;
247 if (ticdef->def.user)
248 ticdef->def.user = prune_dataticks(ticdef->def.user);
249 if (!ticdef->def.user && ticdef->type == TIC_USER)
250 ticdef->type = TIC_COMPUTED;
253 /* use the default dummy variable unless changed */
254 if (dummy_token >= 0)
255 copy_str(c_dummy_var[0], dummy_token, MAX_ID_LEN);
257 (void) strcpy(c_dummy_var[0], set_dummy_var[0]);
262 /* A quick note about boxes style. For boxwidth auto, we cannot
263 * calculate widths yet, since it may be sorted, etc. But if
264 * width is set, we must do it now, before logs of xmin/xmax
266 * We store -1 in point->z as a marker to mean width needs to be
267 * calculated, or 0 to mean that xmin/xmax are set correctly
269 /* current_plot->token is after datafile spec, for error reporting
270 * it will later be moved passed title/with/linetype/pointtype
273 get_data(struct curve_points *current_plot)
275 int i /* num. points ! */ , j;
276 int max_cols, min_cols; /* allowed range of column numbers */
277 double v[MAXDATACOLS];
278 int storetoken = current_plot->token;
280 struct coordinate GPHUGE *cp;
283 TBOOLEAN variable_color = FALSE;
284 double variable_color_value;
285 if ((current_plot->lp_properties.pm3d_color.type == TC_RGB)
286 && (current_plot->lp_properties.pm3d_color.value < 0))
287 variable_color = TRUE;
288 if (current_plot->lp_properties.pm3d_color.type == TC_Z)
289 variable_color = TRUE;
291 /* eval_plots has already opened file */
293 /* HBB 2000504: For most plot styles, the 'z' coordinate is
294 * unused. set it to -1, to account for that. For styles that use
295 * the z coordinate as a real coordinate (i.e. not a width or
296 * 'delta' component, change the setting inside the switch: */
297 current_plot->z_axis = -1;
299 /* HBB NEW 20060427: if there's only one, explicit using column,
300 * it's y data. df_axis[] has to reflect that, so df_readline()
301 * will expect time/date input. */
302 if (df_no_use_specs == 1)
303 df_axis[0] = df_axis[1];
305 switch (current_plot->plot_style) { /* set maximum columns to scan */
310 max_cols = 7; /* HBB FIXME 20060427: what's 7th? */
312 if (df_no_use_specs >= 6) {
313 /* HBB 20060427: signal 3rd and 4th column are absolute x
314 * data --- needed so time/date parsing works */
315 df_axis[2] = df_axis[3] = df_axis[0];
316 /* and 5th and 6th are absolute y data */
317 df_axis[4] = df_axis[5] = df_axis[1];
324 /* HBB 20000504: use 'z' coordinate for y-axis quantity */
325 current_plot->z_axis = current_plot->y_axis;
326 min_cols = max_cols = 5;
327 /* HBB 20060427: signal 3rd and 4th column are absolute y data
328 * --- needed so time/date parsing works */
329 df_axis[2] = df_axis[3] = df_axis[4] = df_axis[1];
333 min_cols = 3; /* HBB 20040520: fixed, was 4 */
336 /* There are four(!) possible cases: */
337 /* 3 cols --> (x,y,dy), auto dx */
338 /* 4 cols, boxwidth==-2 --> (x,y,ylow,yhigh), auto dx */
339 /* 4 cols, boxwidth!=-2 --> (x,y,dy,dx) */
340 /* 5 cols --> (x,y,ylow,yhigh,dx) */
341 if ((df_no_use_specs == 4 && boxwidth == -2)
342 || df_no_use_specs == 5)
343 /* HBB 20060427: signal 3rd and 4th column are absolute y
344 * data --- needed so time/date parsing works */
345 df_axis[2] = df_axis[3] = df_axis[1];
348 case VECTOR: /* x, y, dx, dy, variable_color */
357 if (df_no_use_specs == 4)
358 /* HBB 20060427: signal 3rd and 4th column are absolute x
359 * data --- needed so time/date parsing works */
360 df_axis[2] = df_axis[3] = df_axis[0];
367 if (df_no_use_specs == 4)
368 /* HBB 20060427: signal 3rd and 4th column are absolute y
369 * data --- needed so time/date parsing works */
370 df_axis[2] = df_axis[3] = df_axis[1];
373 #ifdef EAM_HISTOGRAMS
387 case IMPULSES: /* 2 + possible variable color */
394 #ifdef EAM_DATASTRINGS
396 /* 3 column data: X Y Label */
397 /* 4th column allows rgb variable */
417 /* Allow 3rd column because of 'pointsize variable' */
418 /* Allow 4th column because of 'lc rgb variable' */
429 if (current_plot->plot_smooth == SMOOTH_ACSPLINES) {
431 current_plot->z_axis = FIRST_Z_AXIS;
432 df_axis[2] = FIRST_Z_AXIS;
435 if (df_no_use_specs > max_cols)
436 int_error(NO_CARET, "Too many using specs for this style");
438 if (df_no_use_specs > 0 && df_no_use_specs < min_cols)
439 int_error(NO_CARET, "Not enough columns for this style");
443 #ifdef EAM_HISTOGRAMS
444 /* EAM FIXME - There are places in df_readline where it would be really */
445 /* nice to know what kind of plot we are making, so I think that */
446 /* current_plot should be a parameter to df_readline. For now, however, */
447 /* I am using a global variable, and only for HISTOGRAMS. */
448 df_current_plot = (current_plot->plot_style == HISTOGRAMS)
449 ? current_plot : NULL;
452 while ((j = df_readline(v, max_cols)) != DF_EOF) {
455 if (i >= current_plot->p_max) {
456 /* overflow about to occur. Extend size of points[]
457 * array. Double the size, and add 1000 points, to avoid
458 * needlessly small steps. */
459 cp_extend(current_plot, i + i + 1000);
462 /* Allow for optional columns. Currently only used for BOXES, but */
463 /* should be extended to a more general mechanism. */
464 variable_color_value = 0;
465 if (variable_color) {
466 int style = current_plot->plot_style;
467 if ((style == BOXES && j >= 3)
468 || (style == VECTOR && j >= 5))
469 variable_color_value = v[--j];
476 int_error(c_token, "internal error : df_readline returned %d : datafile line %d", j, df_line_number);
480 /* Plot type specific handling of missing points goes here. */
481 #ifdef EAM_HISTOGRAMS
482 if (current_plot->plot_style == HISTOGRAMS) {
483 current_plot->points[i].type = UNDEFINED;
488 /* Jun 2006 - Return to behavior of 3.7 and current docs:
489 * do not interrupt plotted line because of missing data
491 FPRINTF((stderr,"Missing datum %d\n", i));
495 /* NaN or bad result from extended using expression */
496 current_plot->points[i].type = UNDEFINED;
501 #if defined(WITH_IMAGE) && defined(BINARY_DATA_FILE)
502 /* The binary input routines generate DF_FIRST_BLANK at the end
503 * of scan lines, so that the data may be used for the isometric
504 * splots. Rather than turning that off inside the binary
505 * reading routine based upon the plot mode, DF_FIRST_BLANK is
506 * ignored for certain plot types requiring 3D coordinates in
509 if ((current_plot->plot_style == IMAGE) || (current_plot->plot_style == RGBIMAGE))
512 /* break in data, make next point undefined */
513 /* FIXME: We really should distinguish between a blank */
514 /* line and an undefined value on a non-blank line. */
515 current_plot->points[i].type = UNDEFINED;
519 case DF_SECOND_BLANK:
520 /* second blank line. We dont do anything
521 * (we did everything when we got FIRST one)
525 #ifdef EAM_DATASTRINGS
526 case DF_FOUND_KEY_TITLE:
527 df_set_key_title(current_plot);
529 case DF_KEY_TITLE_MISSING:
530 fprintf(stderr,"get_data: key title not found in requested column\n");
533 case 0: /* not blank line, but df_readline couldn't parse it */
536 int_error(current_plot->token,
537 "Bad data on line %d", df_line_number);
541 { /* only one number */
542 /* x is index, assign number to y */
549 #ifdef EAM_HISTOGRAMS
550 if (current_plot->plot_style == HISTOGRAMS) {
551 if (histogram_opts.type == HT_ERRORBARS) {
553 int_error(c_token, "Not enough columns in using specification");
558 int_error(c_token, "Too many columns in using specification");
561 if (histogram_opts.type == HT_STACKED_IN_TOWERS) {
562 histogram_rightmost = current_plot->histogram_sequence
563 + current_plot->histogram->start;
564 current_plot->histogram->end = histogram_rightmost;
565 } else if (v[0] + current_plot->histogram->start > histogram_rightmost) {
566 histogram_rightmost = v[0] + current_plot->histogram->start;
567 current_plot->histogram->end = histogram_rightmost;
569 /* Histogram boxwidths are always absolute */
571 store2d_point(current_plot, i++, v[0], v[1],
572 v[0] - boxwidth / 2, v[0] + boxwidth / 2,
573 v[1]-v[2], v[1]+v[2], 0.0);
575 store2d_point(current_plot, i++, v[0], v[1],
576 v[0] - 0.5, v[0] + 0.5,
577 v[1]-v[2], v[1]+v[2], 0.0); /* EAM DEBUG -1.0 ?? */
581 /* ylow and yhigh are same as y */
583 if ( (current_plot->plot_style == BOXES)
584 && boxwidth > 0 && boxwidth_is_absolute) {
585 /* calculate width now */
586 if (axis_array[current_plot->x_axis].log) {
587 double base = axis_array[current_plot->x_axis].base;
588 store2d_point(current_plot, i++, v[0], v[1],
589 v[0] * pow(base, -boxwidth/2.), v[0] * pow(base, boxwidth/2.),
590 v[1], variable_color_value, 0.0);
592 store2d_point(current_plot, i++, v[0], v[1],
593 v[0] - boxwidth / 2, v[0] + boxwidth / 2,
594 v[1], variable_color_value, 0.0);
596 if (current_plot->plot_style == CANDLESTICKS
597 || current_plot->plot_style == FINANCEBARS) {
598 int_warn(storetoken, "This plot style does not work with 1 or 2 cols. Setting to points");
599 current_plot->plot_style = POINTSTYLE;
601 /* xlow and xhigh are same as x */
602 /* auto width if boxes, else ignored */
603 store2d_point(current_plot, i++, v[0], v[1], v[0], v[0], v[1],
610 /* x, y, ydelta OR x, y, xdelta OR x, y, width */
611 if (current_plot->plot_smooth == SMOOTH_ACSPLINES)
612 store2d_point(current_plot, i++, v[0], v[1], v[0], v[0], v[1],
615 switch (current_plot->plot_style) {
617 int_warn(storetoken, "This plot style does not work with 3 cols. Setting to yerrorbars");
618 current_plot->plot_style = YERRORBARS;
622 current_plot->filledcurves_options.closeto = FILLEDCURVES_BETWEEN;
623 store2d_point(current_plot, i++, v[0], v[1], v[0], v[0],
629 case BOXERROR: /* x, y, dy */
630 /* auto width if boxes, else ignored */
631 store2d_point(current_plot, i++, v[0], v[1], v[0], v[0],
632 v[1] - v[2], v[1] + v[2], -1.0);
637 store2d_point(current_plot, i++, v[0], v[1], v[0] - v[2],
638 v[0] + v[2], v[1], v[1], 0.0);
642 /* calculate xmin and xmax here, so that logs are taken if if necessary */
643 store2d_point(current_plot, i++, v[0], v[1],
644 v[0] - v[2] / 2, v[0] + v[2] / 2,
645 v[1], variable_color_value, 0.0);
648 #ifdef EAM_DATASTRINGS
650 /* Load the coords just as we would have for a point plot */
651 store2d_point(current_plot, i, v[0], v[1], v[0], v[0], v[1],
653 /* Allocate and fill in a text_label structure to match it */
654 store_label(current_plot->labels,
655 &(current_plot->points[i]), i, df_tokens[2], 0.0);
661 case IMAGE: /* x_center y_center z_value */
662 store2d_point(current_plot, i, v[0], v[1], v[0], v[0], v[1],
664 cp = &(current_plot->points[i]);
665 COLOR_STORE_WITH_LOG_AND_UPDATE_RANGE(cp->CRD_COLOR, v[2], cp->type,
666 COLOR_AXIS, NOOP, cp->CRD_COLOR=-VERYLARGE);
671 case POINTSTYLE: /* x, y, variable point size or variable color */
675 store2d_point(current_plot, i++, v[0], v[1], v[0], v[0],
686 /* x, y, ylow, yhigh OR
687 * x, y, xlow, xhigh OR
688 * x, y, xdelta, ydelta OR
689 * x, y, ydelta, width
692 switch (current_plot->plot_style) {
694 int_warn(storetoken, "This plot style does not work with 4 cols. Setting to yerrorbars");
695 current_plot->plot_style = YERRORBARS;
700 store2d_point(current_plot, i++, v[0], v[1], v[0], v[0], v[2],
704 case BOXXYERROR: /* x, y, dx, dy */
707 store2d_point(current_plot, i++, v[0], v[1],
708 v[0] - v[2], v[0] + v[2],
709 v[1] - v[3], v[1] + v[3], 0.0);
714 /* x, y, xmin, xmax */
715 store2d_point(current_plot, i++, v[0], v[1], v[2], v[3],
716 v[1], variable_color_value, 0.0);
721 /* x, y, xmin, xmax */
722 store2d_point(current_plot, i++, v[0], v[1], v[2], v[3],
728 /* x,y, ylow, yhigh --- width automatic */
729 store2d_point(current_plot, i++, v[0], v[1], v[0], v[0],
732 /* x, y, dy, width */
733 store2d_point(current_plot, i++, v[0], v[1],
734 v[0] - v[3] / 2, v[0] + v[3] / 2,
735 v[1] - v[2], v[1] + v[2], 0.0);
740 store2d_point(current_plot, i++, v[0], v[1], v[0], v[0] + v[2],
741 v[1], v[1] + v[3], variable_color_value);
744 case POINTSTYLE: /* x, y, variable point size and variable color */
745 store2d_point(current_plot, i++, v[0], v[1], v[0], v[0],
749 #ifdef EAM_DATASTRINGS
751 /* Load the coords just as we would have for a point plot */
752 store2d_point(current_plot, i, v[0], v[1], v[0], v[0], v[1],
754 /* Allocate and fill in a text_label structure to match it */
755 store_label(current_plot->labels,
756 &(current_plot->points[i]), i, df_tokens[2], v[3]);
767 { /* x, y, ylow, yhigh, width or x open low high close */
768 switch (current_plot->plot_style) {
771 int_warn(storetoken, "Five col. plot style must be boxerrorbars, financebars, candlesticks, or rgbimage. Setting to boxerrorbars");
773 int_warn(storetoken, "Five col. plot style must be boxerrorbars, financebars or candlesticks. Setting to boxerrorbars");
775 current_plot->plot_style = BOXERROR;
778 case BOXERROR: /* x, y, ylow, yhigh, width */
779 store2d_point(current_plot, i++, v[0], v[1],
780 v[0] - v[4] / 2, v[0] + v[4] / 2,
784 case FINANCEBARS: /* x yopen ylow yhigh yclose */
786 store2d_point(current_plot, i++, v[0], v[1], v[0], v[0],
791 case RGBIMAGE: /* x_center y_center r_value g_value b_value (rgb) */
792 store2d_point(current_plot, i, v[0], v[1], v[0], v[0], v[1], v[1], v[2]);
793 /* A slight kludge, but it does in fact do what it is supposed to.
794 * There is only one color axis, but we are storing components in
795 * different variables. Place all components on the same axis.
796 * (That will maintain a consistent mapping amongst the components.)
797 * But then retrieve what was stored and break it back into its
798 * components storing without updating any axes.
800 cp = &(current_plot->points[i]);
801 COLOR_STORE_WITH_LOG_AND_UPDATE_RANGE(cp->CRD_COLOR, v[2], cp->type, COLOR_AXIS, NOOP, cp->CRD_COLOR=-VERYLARGE);
802 v[2] = cp->CRD_COLOR;
803 COLOR_STORE_WITH_LOG_AND_UPDATE_RANGE(cp->CRD_COLOR, v[3], cp->type, COLOR_AXIS, NOOP, cp->CRD_COLOR=-VERYLARGE);
804 v[3] = cp->CRD_COLOR;
805 COLOR_STORE_WITH_LOG_AND_UPDATE_RANGE(cp->CRD_COLOR, v[4], cp->type, COLOR_AXIS, NOOP, cp->CRD_COLOR=-VERYLARGE);
806 v[4] = cp->CRD_COLOR;
818 /* same as six columns. Width ignored */
819 /* eh ? - fall through */
821 /* x, y, xlow, xhigh, ylow, yhigh */
822 switch (current_plot->plot_style) {
824 int_warn(storetoken, "This plot style not work with 6 cols. Setting to xyerrorbars");
825 current_plot->plot_style = XYERRORBARS;
830 store2d_point(current_plot, i++, v[0], v[1], v[2], v[3], v[4],
839 current_plot->p_count = i;
840 cp_extend(current_plot, i); /* shrink to fit */
844 return i; /* i==0 indicates an 'empty' file */
847 /* called by get_data for each point */
850 struct curve_points *current_plot,
851 int i, /* point number */
853 double xlow, double xhigh,
854 double ylow, double yhigh,
855 double width) /* BOXES widths: -1 -> autocalc, 0 -> use xlow/xhigh */
857 struct coordinate GPHUGE *cp = &(current_plot->points[i]);
858 int dummy_type = INRANGE; /* sometimes we dont care about outranging */
860 /* jev -- pass data values thru user-defined function */
861 /* div -- y is dummy variable 2 - copy value there */
865 (void) Gcomplex(&ydata_func.dummy_values[0], y, 0.0);
866 ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
867 evaluate_at(ydata_func.at, &val);
868 y = undefined ? 0.0 : real(&val);
870 (void) Gcomplex(&ydata_func.dummy_values[0], ylow, 0.0);
871 ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
872 evaluate_at(ydata_func.at, &val);
873 ylow = undefined ? 0 : real(&val);
875 (void) Gcomplex(&ydata_func.dummy_values[0], yhigh, 0.0);
876 ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
877 evaluate_at(ydata_func.at, &val);
878 yhigh = undefined ? 0 : real(&val);
880 dummy_type = cp->type = INRANGE;
884 if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MAX) && y > axis_array[R_AXIS].max) {
887 if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MIN)) {
888 /* we store internally as if plotting r(t)-rmin */
889 y -= axis_array[R_AXIS].min;
891 newx = y * cos(x * ang2rad);
892 newy = y * sin(x * ang2rad);
893 #if 0 /* HBB 981118: added polar errorbars */
894 /* only lines and points supported with polar */
895 y = ylow = yhigh = newy;
896 x = xlow = xhigh = newx;
901 if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MAX) && yhigh > axis_array[R_AXIS].max) {
904 if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MIN)) {
905 /* we store internally as if plotting r(t)-rmin */
906 yhigh -= axis_array[R_AXIS].min;
908 newx = yhigh * cos(xhigh * ang2rad);
909 newy = yhigh * sin(xhigh * ang2rad);
913 if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MAX) && ylow > axis_array[R_AXIS].max) {
916 if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MIN)) {
917 /* we store internally as if plotting r(t)-rmin */
918 ylow -= axis_array[R_AXIS].min;
920 newx = ylow * cos(xlow * ang2rad);
921 newy = ylow * sin(xlow * ang2rad);
926 /* return immediately if x or y are undefined
927 * we dont care if outrange for high/low.
928 * BUT if high/low undefined (ie log( < 0 ), no number is stored,
929 * but graphics.c doesn't know.
930 * explicitly store -VERYLARGE;
932 STORE_WITH_LOG_AND_UPDATE_RANGE(cp->x, x, cp->type, current_plot->x_axis, NOOP, return);
933 STORE_WITH_LOG_AND_UPDATE_RANGE(cp->y, y, cp->type, current_plot->y_axis, NOOP, return);
935 switch (current_plot->plot_style) {
936 case POINTSTYLE: /* Only x and y are relevant to axis scaling */
947 case BOXES: /* auto-scale to xlow xhigh ylow yhigh */
949 cp->yhigh = yhigh; /* really variable_color_data */
950 STORE_WITH_LOG_AND_UPDATE_RANGE(cp->xlow, xlow, dummy_type,
951 current_plot->x_axis, NOOP, cp->xlow = -VERYLARGE);
952 STORE_WITH_LOG_AND_UPDATE_RANGE(cp->xhigh, xhigh, dummy_type,
953 current_plot->x_axis, NOOP, cp->xhigh = -VERYLARGE);
955 default: /* auto-scale to xlow xhigh ylow yhigh */
956 STORE_WITH_LOG_AND_UPDATE_RANGE(cp->xlow, xlow, dummy_type,
957 current_plot->x_axis, NOOP, cp->xlow = -VERYLARGE);
958 STORE_WITH_LOG_AND_UPDATE_RANGE(cp->xhigh, xhigh, dummy_type,
959 current_plot->x_axis, NOOP, cp->xhigh = -VERYLARGE);
960 STORE_WITH_LOG_AND_UPDATE_RANGE(cp->ylow, ylow, dummy_type,
961 current_plot->y_axis, NOOP, cp->ylow = -VERYLARGE);
962 STORE_WITH_LOG_AND_UPDATE_RANGE(cp->yhigh, yhigh, dummy_type,
963 current_plot->y_axis, NOOP, cp->yhigh = -VERYLARGE);
967 /* HBB 20010214: if z is not used for some actual value, just
968 * store 'width' to that axis and be done with it */
969 if ((int)current_plot->z_axis != -1)
970 STORE_WITH_LOG_AND_UPDATE_RANGE(cp->z, width, dummy_type, current_plot->z_axis, NOOP, cp->z = -VERYLARGE);
974 /* If we have variable color corresponding to a z-axis value, use it to autoscale */
975 if (current_plot->lp_properties.pm3d_color.type == TC_Z)
976 STORE_WITH_LOG_AND_UPDATE_RANGE(cp->z, cp->z, dummy_type, COLOR_AXIS,
979 } /* store2d_point */
981 #ifdef EAM_HISTOGRAMS
982 /* Since the stored x values for histogrammed data do not correspond exactly */
983 /* to the eventual x coordinates, we need to modify the x axis range bounds. */
984 /* Also the two stacked histogram modes need adjustment of the y axis bounds.*/
986 histogram_range_fiddling(struct curve_points *plot)
991 * EAM FIXME - HT_STACKED_IN_TOWERS forcibly resets xmin, which is only
992 * correct if no other plot came first.
994 switch (histogram_opts.type) {
995 case HT_STACKED_IN_LAYERS:
996 if (axis_array[plot->y_axis].autoscale & AUTOSCALE_MAX) {
997 if (plot->histogram_sequence == 0) {
1000 stackheight = gp_alloc( plot->p_count * sizeof(struct coordinate GPHUGE),
1001 "stackheight array");
1002 for (stack_count=0; stack_count < plot->p_count; stack_count++) {
1003 stackheight[stack_count].yhigh = 0;
1004 stackheight[stack_count].ylow = 0;
1006 } else if (plot->p_count > stack_count) {
1007 stackheight = gp_realloc( stackheight,
1008 plot->p_count * sizeof(struct coordinate GPHUGE),
1009 "stackheight array");
1010 for ( ; stack_count < plot->p_count; stack_count++) {
1011 stackheight[stack_count].yhigh = 0;
1012 stackheight[stack_count].ylow = 0;
1015 for (i=0; i<stack_count; i++) {
1016 if (plot->points[i].type == UNDEFINED)
1018 if (plot->points[i].y >= 0)
1019 stackheight[i].yhigh += plot->points[i].y;
1021 stackheight[i].ylow += plot->points[i].y;
1023 if (axis_array[plot->y_axis].max < stackheight[i].yhigh)
1024 axis_array[plot->y_axis].max = stackheight[i].yhigh;
1025 if (axis_array[plot->y_axis].min > stackheight[i].ylow)
1026 axis_array[plot->y_axis].min = stackheight[i].ylow;
1030 /* fall through to checks on x range */
1033 if (!axis_array[FIRST_X_AXIS].autoscale)
1035 if (axis_array[FIRST_X_AXIS].autoscale & AUTOSCALE_MIN) {
1036 xlow = plot->histogram->start - 1.0;
1037 if (axis_array[FIRST_X_AXIS].min > xlow)
1038 axis_array[FIRST_X_AXIS].min = xlow;
1040 if (axis_array[FIRST_X_AXIS].autoscale & AUTOSCALE_MAX) {
1041 /* FIXME - why did we increment p_count on UNDEFINED points? */
1042 while (plot->points[plot->p_count-1].type == UNDEFINED) {
1045 int_error(NO_CARET,"All points in histogram UNDEFINED");
1047 xhigh = plot->points[plot->p_count-1].x;
1048 xhigh += plot->histogram->start + 1.0;
1049 if (axis_array[FIRST_X_AXIS].max < xhigh)
1050 axis_array[FIRST_X_AXIS].max = xhigh;
1053 case HT_STACKED_IN_TOWERS:
1054 if (axis_array[FIRST_X_AXIS].set_autoscale) {
1056 xhigh = plot->histogram_sequence;
1057 xhigh += plot->histogram->start + 1.0;
1058 if (axis_array[FIRST_X_AXIS].min > xlow)
1059 axis_array[FIRST_X_AXIS].min = xlow;
1060 if (axis_array[FIRST_X_AXIS].max != xhigh)
1061 axis_array[FIRST_X_AXIS].max = xhigh;
1063 if (axis_array[FIRST_Y_AXIS].set_autoscale) {
1065 for (i=0, yhigh=ylow=0.0; i<plot->p_count; i++)
1066 if (plot->points[i].type != UNDEFINED) {
1067 if (plot->points[i].y >= 0)
1068 yhigh += plot->points[i].y;
1070 ylow += plot->points[i].y;
1072 if (axis_array[FIRST_Y_AXIS].set_autoscale & AUTOSCALE_MAX)
1073 if (axis_array[plot->y_axis].max < yhigh)
1074 axis_array[plot->y_axis].max = yhigh;
1075 if (axis_array[FIRST_Y_AXIS].set_autoscale & AUTOSCALE_MIN)
1076 if (axis_array[plot->y_axis].min > ylow)
1077 axis_array[plot->y_axis].min = ylow;
1084 #ifdef EAM_DATASTRINGS
1085 /* store_label() is called by get_data for each point */
1086 /* This routine is exported so it can be shared by plot3d */
1089 struct text_label *listhead,
1090 struct coordinate *cp,
1091 int i, /* point number */
1092 char *string, /* start of label string */
1093 double colorval) /* used if text color derived from palette */
1095 struct text_label *tl = listhead;
1098 /* Walk through list to get to the end. Yes I know this is inefficient */
1099 /* but is anyone really going to plot so many labels that it matters? */
1100 if (!tl) int_error(NO_CARET,"text_label list was not initialized");
1101 while (tl->next) tl = tl->next;
1103 /* Allocate a new label structure and fill it in */
1104 tl->next = gp_alloc(sizeof(struct text_label),"labelpoint label");
1105 memcpy(tl->next,tl,sizeof(text_label));
1107 tl->next = (text_label *)NULL;
1109 tl->place.x = cp->x;
1110 tl->place.y = cp->y;
1111 tl->place.z = cp->z;
1113 /* Check for optional (textcolor palette ...) */
1114 if (tl->textcolor.type == TC_Z)
1115 tl->textcolor.value = colorval;
1116 else if (tl->textcolor.type == TC_RGB && tl->textcolor.value < 0)
1117 tl->textcolor.lt = colorval;
1119 /* Check for null string (no label) */
1124 /* FIXME EAM - this code is ugly but seems to work */
1125 /* We need to handle quoted separators and quoted quotes */
1127 TBOOLEAN in_quote = FALSE;
1128 while (string[textlen]) {
1129 if (string[textlen] == '"')
1130 in_quote = !in_quote;
1131 else if (string[textlen] == df_separator && !in_quote)
1135 while (textlen > 0 && isspace(string[textlen-1]))
1138 /* This is the normal case (no special separator character) */
1139 if (*string == '"') {
1140 for (textlen=1; string[textlen] && string[textlen] != '"'; textlen++);
1142 while (string[textlen] && !isspace(string[textlen]))
1146 /* Strip double quote from both ends */
1147 if (string[0] == '"' && string[textlen-1] == '"')
1148 textlen -= 2, string++;
1150 tl->text = gp_alloc(textlen+1,"labelpoint text");
1151 strncpy( tl->text, string, textlen );
1152 tl->text[textlen] = '\0';
1153 parse_esc(tl->text);
1155 FPRINTF((stderr,"LABELPOINT %f %f \"%s\" \n", tl->place.x, tl->place.y, tl->text));
1161 * print_points: a debugging routine to print out the points of a curve, and
1162 * the curve structure. If curve<0, then we print the list of curves.
1165 #if 0 /* not used */
1166 static char *plot_type_names[] =
1168 "Function", "Data", "3D Function", "3d data"
1170 static char *plot_style_names[] =
1172 "Lines", "Points", "Impulses", "LinesPoints", "Dots", "XErrorbars",
1173 "YErrorbars", "XYErrorbars", "BoxXYError", "Boxes", "Boxerror", "Steps",
1175 "XErrorlines", "YErrorlines", "XYErrorlines"
1177 static char *plot_smooth_names[] =
1179 "None", "Unique", "Frequency", "CSplines", "ACSplines", "Bezier", "SBezier"
1183 print_points(int curve)
1185 struct curve_points *this_plot;
1189 for (this_plot = first_plot, i = 0;
1191 i++, this_plot = this_plot->next) {
1192 printf("Curve %d:\n", i);
1193 if ((int) this_plot->plot_type >= 0 && (int) (this_plot->plot_type) < 4)
1194 printf("Plot type %d: %s\n", (int) (this_plot->plot_type),
1195 plot_type_names[(int) (this_plot->plot_type)]);
1197 printf("Plot type %d: BAD\n", (int) (this_plot->plot_type));
1198 if ((int) this_plot->plot_style >= 0 && (int) (this_plot->plot_style) < 14)
1199 printf("Plot style %d: %s\n", (int) (this_plot->plot_style),
1200 plot_style_names[(int) (this_plot->plot_style)]);
1202 printf("Plot style %d: BAD\n", (int) (this_plot->plot_style));
1203 if ((int) this_plot->plot_smooth >= 0 && (int) (this_plot->plot_smooth) < 6)
1204 printf("Plot smooth style %d: %s\n", (int) (this_plot->plot_style),
1205 plot_smooth_names[(int) (this_plot->plot_smooth)]);
1207 printf("Plot smooth style %d: BAD\n", (int) (this_plot->plot_smooth));
1213 current points %d\n\n",
1215 this_plot->line_type,
1216 this_plot->point_type,
1218 this_plot->p_count);
1221 for (this_plot = first_plot, i = 0;
1222 i < curve && this_plot != NULL;
1223 i++, this_plot = this_plot->next);
1224 if (this_plot == NULL)
1225 printf("Curve %d does not exist; list has %d curves\n", curve, i);
1227 printf("Curve %d, %d points\n", curve, this_plot->p_count);
1228 for (i = 0; i < this_plot->p_count; i++) {
1229 printf("%c x=%g y=%g z=%g xlow=%g xhigh=%g ylow=%g yhigh=%g\n",
1230 this_plot->points[i].type == INRANGE ? 'i'
1231 : this_plot->points[i].type == OUTRANGE ? 'o'
1233 this_plot->points[i].x,
1234 this_plot->points[i].y,
1235 this_plot->points[i].z,
1236 this_plot->points[i].xlow,
1237 this_plot->points[i].xhigh,
1238 this_plot->points[i].ylow,
1239 this_plot->points[i].yhigh);
1245 #endif /* not used */
1250 print_table(struct curve_points *current_plot, int plot_num)
1253 char *buffer = gp_alloc(150, "print_table: output buffer");
1254 FILE *outfile = (table_outfile) ? table_outfile : gpoutfile;
1256 for (curve = 0; curve < plot_num;
1257 curve++, current_plot = current_plot->next) {
1258 struct coordinate GPHUGE *point = NULL;
1260 /* two blank lines between plots in table output by prepending
1262 fprintf(outfile, "\n#Curve %d of %d, %d points\n#x y",
1263 curve, plot_num, current_plot->p_count);
1264 switch (current_plot->plot_style) {
1267 fputs(" xlow xhigh", outfile);
1271 fputs(" ylow yhigh", outfile);
1275 fputs(" xlow xhigh ylow yhigh", outfile);
1279 fputs("open ylow yhigh yclose", outfile);
1285 fputs(" type\n", outfile);
1286 for (i = 0, point = current_plot->points;
1287 i < current_plot->p_count;
1289 /* HBB 20020405: new macro to use the 'set format' string
1290 * specifiers, as it has been documented for ages, but
1291 * never actually done. */
1292 #define OUTPUT_NUMBER(field, axis) \
1293 gprintf(buffer, 150, axis_array[axis].formatstring, \
1294 1.0, point->field); \
1295 fputs(buffer, outfile); \
1296 fputc(' ', outfile);
1298 /* FIXME HBB 20020405: had better use the real x/x2 axes
1300 OUTPUT_NUMBER(x, current_plot->x_axis);
1301 OUTPUT_NUMBER(y, current_plot->y_axis);
1303 switch (current_plot->plot_style) {
1306 OUTPUT_NUMBER(xlow, current_plot->x_axis);
1307 OUTPUT_NUMBER(xhigh, current_plot->x_axis);
1308 /* Hmmm... shouldn't this write out width field of box
1309 * plots, too, if stored? */
1313 OUTPUT_NUMBER(xlow, current_plot->x_axis);
1314 OUTPUT_NUMBER(xhigh, current_plot->x_axis);
1318 OUTPUT_NUMBER(ylow, current_plot->y_axis);
1319 OUTPUT_NUMBER(yhigh, current_plot->y_axis);
1323 OUTPUT_NUMBER(ylow, current_plot->y_axis);
1324 OUTPUT_NUMBER(yhigh, current_plot->y_axis);
1325 OUTPUT_NUMBER(z, current_plot->y_axis);
1329 } /* switch(plot type) */
1330 fprintf(outfile, " %c\n",
1331 current_plot->points[i].type == INRANGE
1332 ? 'i' : current_plot->points[i].type == OUTRANGE
1334 } /* for(point i) */
1336 putc('\n', outfile);
1342 #undef OUTPUT_NUMBER
1344 /* HBB 20010610: mnemonic names for the bits stored in 'uses_axis' */
1345 typedef enum e_uses_axis {
1346 USES_AXIS_FOR_DATA = 1,
1347 USES_AXIS_FOR_FUNC = 2
1351 * This parses the plot command after any range specifications. To support
1352 * autoscaling on the x axis, we want any data files to define the x range,
1353 * then to plot any functions using that range. We thus parse the input
1354 * twice, once to pick up the data files, and again to pick up the functions.
1355 * Definitions are processed twice, but that won't hurt.
1356 * div - okay, it doesn't hurt, but every time an option as added for
1357 * datafiles, code to parse it has to be added here. Change so that
1358 * we store starting-token in the plot structure.
1364 struct curve_points *this_plot, **tp_ptr;
1365 t_uses_axis uses_axis[AXIS_ARRAY_SIZE];
1366 int some_functions = 0;
1367 int plot_num, line_num, point_num, xparam = 0;
1369 char *xtitle = NULL;
1370 int begin_token = c_token; /* so we can rewind for second pass */
1371 legend_key *key = &keyT;
1373 #ifdef EAM_HISTOGRAMS
1374 double newhist_start = 0.0;
1375 int histogram_sequence = -1;
1376 int newhist_color = 0;
1377 int newhist_pattern = LT_UNDEFINED;
1378 histogram_rightmost = 0.0;
1379 free_histlist(&histogram_opts);
1380 init_histogram(NULL,NULL);
1383 uses_axis[FIRST_X_AXIS] =
1384 uses_axis[FIRST_Y_AXIS] =
1385 uses_axis[SECOND_X_AXIS] =
1386 uses_axis[SECOND_Y_AXIS] = 0;
1388 /* Reset first_plot. This is usually done at the end of this function.
1389 * If there is an error within this function, the memory is left allocated,
1390 * since we cannot call cp_free if the list is incomplete. Making sure that
1391 * the list structure is always vaild requires some rewriting */
1394 tp_ptr = &(first_plot);
1396 line_num = 0; /* default line type */
1397 point_num = 0; /* default point type */
1398 pattern_num = default_fillstyle.fillpattern; /* default fill pattern */
1402 /* ** First Pass: Read through data files ***
1403 * This pass serves to set the xrange and to parse the command, as well
1404 * as filling in every thing except the function data. That is done after
1405 * the xrange is defined.
1409 int_error(c_token, "function to plot expected");
1411 #ifdef EAM_HISTOGRAMS
1412 if (almost_equals(c_token,"newhist$ogram")) {
1413 struct lp_style_type lp = DEFAULT_LP_STYLE_TYPE;
1414 struct fill_style_type fs;
1417 histogram_sequence = -1;
1418 free(histogram_title);
1419 histogram_title = NULL;
1421 if (histogram_rightmost > 0)
1422 newhist_start = histogram_rightmost + 2;
1424 lp.l_type = LT_UNDEFINED;
1425 fs.fillpattern = LT_UNDEFINED;
1428 previous_token = c_token;
1430 if (equals(c_token,"at")) {
1433 newhist_start = real(const_express(&a));
1436 /* Store title in temporary variable and then copy into the */
1437 /* new histogram structure when it is allocated. */
1438 if (!histogram_title && isstringvalue(c_token))
1439 histogram_title = try_to_get_string();
1441 /* Allow explicit starting color or pattern for this histogram */
1442 lp_parse(&lp, FALSE, FALSE);
1443 parse_fillstyle(&fs, FS_SOLID, 100, fs.fillpattern, -1);
1445 } while (c_token != previous_token);
1447 newhist_color = lp.l_type;
1448 newhist_pattern = fs.fillpattern;
1450 #endif /* EAM_DATASTRINGS */
1451 if (is_definition(c_token)) {
1456 /* for datafile plot, record datafile spec for title */
1457 int start_token = c_token, end_token;
1460 TBOOLEAN duplication = FALSE;
1461 TBOOLEAN set_smooth = FALSE, set_axes = FALSE, set_title = FALSE;
1462 TBOOLEAN set_with = FALSE, set_lpstyle = FALSE;
1463 TBOOLEAN set_fillstyle = FALSE;
1464 #ifdef EAM_DATASTRINGS
1465 TBOOLEAN set_labelstyle = FALSE;
1470 dummy_func = &plot_func;
1471 /* should this be saved in "this_plot"? */
1472 name_str = string_or_express(NULL);
1475 if (name_str) { /* data file to plot */
1476 if (parametric && xparam)
1477 int_error(c_token, "previous parametric function not fully specified");
1480 this_plot = *tp_ptr;
1481 else { /* no memory malloc()'d there yet */
1482 this_plot = cp_alloc(MIN_CRV_POINTS);
1483 *tp_ptr = this_plot;
1485 this_plot->plot_type = DATA;
1486 this_plot->plot_style = data_style;
1487 this_plot->plot_smooth = SMOOTH_NONE;
1488 this_plot->filledcurves_options.opt_given = 0;
1489 /* default no palette */
1490 this_plot->lp_properties.use_palette = 0;
1492 /* up to MAXDATACOLS cols */
1493 df_set_plot_mode(MODE_PLOT); /* Needed for binary datafiles */
1494 specs = df_open(name_str, MAXDATACOLS);
1496 #ifndef BINARY_DATA_FILE
1497 /* this parses data-file-specific modifiers only */
1498 /* we'll sort points when we know style, if necessary */
1500 int_error(c_token, "This copy of gnuplot was not built with support for 2d binary files");
1502 /* include modifiers in default title */
1503 this_plot->token = end_token = c_token - 1;
1507 /* function to plot */
1510 if (parametric) /* working on x parametric function */
1511 xparam = 1 - xparam;
1513 this_plot = *tp_ptr;
1514 cp_extend(this_plot, samples_1 + 1);
1515 } else { /* no memory malloc()'d there yet */
1516 this_plot = cp_alloc(samples_1 + 1);
1517 *tp_ptr = this_plot;
1519 this_plot->plot_type = FUNC;
1520 this_plot->plot_style = func_style;
1521 this_plot->filledcurves_options.opt_given = 0;
1522 /* default no palette */
1523 this_plot->lp_properties.use_palette = 0;
1524 end_token = c_token - 1;
1525 } /* end of IS THIS A FILE OR A FUNC block */
1528 x_axis = FIRST_X_AXIS;
1529 y_axis = FIRST_Y_AXIS;
1531 /* pm 25.11.2001 allow any order of options */
1532 while (!END_OF_COMMAND) {
1534 /* deal with smooth */
1535 if (almost_equals(c_token, "s$mooth")) {
1542 found_token = lookup_table(plot_smooth_tbl, ++c_token);
1544 switch(found_token) {
1545 case SMOOTH_ACSPLINES:
1547 case SMOOTH_CSPLINES:
1548 case SMOOTH_SBEZIER:
1550 case SMOOTH_FREQUENCY:
1551 this_plot->plot_smooth = found_token;
1555 int_error(c_token, "expecting 'unique', 'frequency', 'acsplines', 'csplines', 'bezier' or 'sbezier'");
1558 this_plot->plot_style = LINES;
1559 c_token++; /* skip format */
1564 /* look for axes/axis */
1565 if (almost_equals(c_token, "ax$es")
1566 || almost_equals(c_token, "ax$is")) {
1571 if (parametric && xparam)
1572 int_error(c_token, "previous parametric function not fully specified");
1575 switch(lookup_table(&plot_axes_tbl[0],c_token)) {
1577 x_axis = FIRST_X_AXIS;
1578 y_axis = FIRST_Y_AXIS;
1582 x_axis = SECOND_X_AXIS;
1583 y_axis = SECOND_Y_AXIS;
1587 x_axis = FIRST_X_AXIS;
1588 y_axis = SECOND_Y_AXIS;
1592 x_axis = SECOND_X_AXIS;
1593 y_axis = FIRST_Y_AXIS;
1598 int_error(c_token, "axes must be x1y1, x1y2, x2y1 or x2y2");
1605 /* deal with title */
1606 if (almost_equals(c_token, "t$itle")) {
1611 this_plot->title_no_enhanced = !key->enhanced;
1612 /* title can be enhanced if not explicitly disabled */
1615 int_error(c_token, "\"title\" allowed only after parametric function fully specified");
1616 else if (xtitle != NULL)
1617 xtitle[0] = '\0'; /* Remove default title . */
1620 if (!(this_plot->title = try_to_get_string()))
1621 int_error(c_token, "expecting \"title\" for plot");
1626 if (almost_equals(c_token, "not$itle")) {
1632 if (isstringvalue(c_token))
1633 try_to_get_string(); /* ignore optionally given title string */
1634 this_plot->title_is_suppressed = TRUE;
1641 /* deal with style */
1642 if (almost_equals(c_token, "w$ith")) {
1647 if (parametric && xparam)
1648 int_error(c_token, "\"with\" allowed only after parametric function fully specified");
1649 this_plot->plot_style = get_style();
1650 if (this_plot->plot_style == FILLEDCURVES) {
1651 /* read a possible option for 'with filledcurves' */
1652 get_filledcurves_style_options(&this_plot->filledcurves_options);
1654 if ((this_plot->plot_type == FUNC) &&
1655 ((this_plot->plot_style & PLOT_STYLE_HAS_ERRORBAR)
1656 #ifdef EAM_DATASTRINGS
1657 || (this_plot->plot_style == LABELPOINTS)
1661 int_warn(c_token, "This plot style is only for datafiles, reverting to \"points\"");
1662 this_plot->plot_style = POINTSTYLE;
1668 #ifdef EAM_DATASTRINGS
1669 /* Labels can have font and text property info as plot options */
1670 /* In any case we must allocate one instance of the text style */
1671 /* that all labels in the plot will share. */
1672 if (this_plot->plot_style == LABELPOINTS) {
1673 int stored_token = c_token;
1675 if (this_plot->labels == NULL) {
1676 this_plot->labels = new_text_label(-1);
1677 this_plot->labels->pos = JUST_CENTRE;
1678 this_plot->labels->layer = LAYER_PLOTLABELS;
1680 parse_label_options(this_plot->labels);
1681 if (stored_token != c_token) {
1682 if (set_labelstyle) {
1686 set_labelstyle = TRUE;
1691 #endif /* EAM_DATASTRINGS */
1693 /* pick up line/point specs and other style-specific keywords
1694 * - point spec allowed if style uses points, ie style&2 != 0
1695 * - keywords for lt and pt are optional
1697 if (this_plot->plot_style == CANDLESTICKS) {
1698 if (almost_equals(c_token,"whisker$bars")) {
1700 this_plot->arrow_properties.head = BOTH_HEADS;
1702 if (isanumber(c_token) || type_udv(c_token) == INTGR || type_udv(c_token) == CMPLX)
1703 this_plot->arrow_properties.head_length = real(const_express(&a));
1707 if (this_plot->plot_style == VECTOR) {
1708 int stored_token = c_token;
1711 default_arrow_style(&(this_plot->arrow_properties));
1712 if (prefer_line_styles)
1713 lp_use_properties(&(this_plot->arrow_properties.lp_properties),
1716 this_plot->arrow_properties.lp_properties.l_type = line_num;
1719 arrow_parse(&(this_plot->arrow_properties), TRUE);
1720 if (stored_token != c_token) {
1730 int stored_token = c_token;
1731 struct lp_style_type lp = DEFAULT_LP_STYLE_TYPE;
1733 lp.l_type = line_num;
1734 lp.p_type = point_num;
1736 /* user may prefer explicit line styles */
1737 if (prefer_line_styles)
1738 lp_use_properties(&lp, line_num+1, TRUE);
1741 this_plot->plot_style & PLOT_STYLE_HAS_POINT);
1742 if (stored_token != c_token) {
1747 this_plot->lp_properties = lp;
1754 /* Some plots have a fill style as well */
1755 if (this_plot->plot_style & PLOT_STYLE_HAS_FILL){
1756 if (equals(c_token,"fs") || equals(c_token,"fill")) {
1757 int stored_token = c_token;
1758 parse_fillstyle(&this_plot->fill_properties,
1759 default_fillstyle.fillstyle,
1760 default_fillstyle.filldensity,
1762 default_fillstyle.border_linetype);
1763 if (this_plot->plot_style == FILLEDCURVES
1764 && this_plot->fill_properties.fillstyle == FS_EMPTY)
1765 this_plot->fill_properties.fillstyle = FS_SOLID;
1766 set_fillstyle = TRUE;
1767 if (stored_token != c_token)
1772 break; /* unknown option */
1774 } /* while (!END_OF_COMMAND) */
1777 int_error(c_token, "duplicated or contradicting arguments in plot options");
1779 /* set default values for title if this has not been specified */
1780 this_plot->title_is_filename = FALSE;
1782 this_plot->title_no_enhanced = TRUE; /* filename or function cannot be enhanced */
1783 if (key->auto_titles == FILENAME_KEYTITLES) {
1784 m_capture(&(this_plot->title), start_token, end_token);
1786 xtitle = this_plot->title;
1787 this_plot->title_is_filename = TRUE;
1788 } else if (xtitle != NULL)
1792 /* Vectors will be drawn using linetype from arrow style, so we
1793 * copy this to overall plot linetype so that the key sample matches */
1794 if (this_plot->plot_style == VECTOR) {
1796 if (prefer_line_styles)
1797 lp_use_properties(&(this_plot->arrow_properties.lp_properties),
1800 this_plot->arrow_properties.lp_properties.l_type = line_num;
1801 arrow_parse(&this_plot->arrow_properties, TRUE);
1803 this_plot->lp_properties = this_plot->arrow_properties.lp_properties;
1806 /* No line/point style given. As lp_parse also supplies
1807 * the defaults for linewidth and pointsize, call it now
1808 * to define them. */
1809 if (! set_lpstyle) {
1810 this_plot->lp_properties.l_type = line_num;
1811 this_plot->lp_properties.l_width = 1.0;
1812 this_plot->lp_properties.p_type = point_num;
1813 this_plot->lp_properties.p_size = pointsize;
1814 this_plot->lp_properties.use_palette = 0;
1816 /* user may prefer explicit line styles */
1817 if (prefer_line_styles)
1818 lp_use_properties(&this_plot->lp_properties, line_num+1, TRUE);
1820 lp_parse(&this_plot->lp_properties, TRUE,
1821 this_plot->plot_style & PLOT_STYLE_HAS_POINT);
1823 #ifdef BACKWARDS_COMPATIBLE
1824 /* allow old-style syntax - ignore case lt 3 4 for example */
1825 if (!END_OF_COMMAND && isanumber(c_token)) {
1827 this_plot->lp_properties.l_type =
1828 this_plot->lp_properties.p_type =
1829 (int) real(const_express(&t)) - 1;
1831 if (isanumber(c_token))
1832 this_plot->lp_properties.p_type =
1833 (int) real(const_express(&t)) - 1;
1835 #endif /* BACKWARDS_COMPATIBLE */
1839 /* Rule out incompatible line/point/style options */
1840 if (this_plot->plot_type == FUNC) {
1841 if ((this_plot->plot_style & PLOT_STYLE_HAS_POINT)
1842 && (this_plot->lp_properties.p_size == PTSZ_VARIABLE))
1843 this_plot->lp_properties.p_size = 1;
1846 /* Similar argument for check that all fill styles were set */
1847 if (this_plot->plot_style & PLOT_STYLE_HAS_FILL) {
1848 if (! set_fillstyle)
1849 parse_fillstyle(&this_plot->fill_properties,
1850 default_fillstyle.fillstyle,
1851 default_fillstyle.filldensity,
1853 default_fillstyle.border_linetype);
1854 if (this_plot->fill_properties.fillstyle == FS_PATTERN)
1855 pattern_num = this_plot->fill_properties.fillpattern + 1;
1856 if (this_plot->plot_style == FILLEDCURVES
1857 && this_plot->fill_properties.fillstyle == FS_EMPTY)
1858 this_plot->fill_properties.fillstyle = FS_SOLID;
1861 #ifdef EAM_DATASTRINGS
1862 /* If we got this far without initializing the label list, do it now */
1863 if (this_plot->plot_style == LABELPOINTS) {
1864 if (this_plot->labels == NULL) {
1865 this_plot->labels = new_text_label(-1);
1866 this_plot->labels->pos = JUST_CENTRE;
1867 this_plot->labels->layer = LAYER_PLOTLABELS;
1869 this_plot->labels->place.scalex =
1870 (x_axis == SECOND_X_AXIS) ? second_axes : first_axes;
1871 this_plot->labels->place.scaley =
1872 (y_axis == SECOND_Y_AXIS) ? second_axes : first_axes;
1874 #endif /* EAM_DATASTRINGS */
1876 this_plot->x_axis = x_axis;
1877 this_plot->y_axis = y_axis;
1879 #ifdef EAM_HISTOGRAMS
1880 /* Initialize histogram data structure */
1881 if (this_plot->plot_style == HISTOGRAMS) {
1882 if (axis_array[x_axis].log)
1883 int_error(c_token, "Log scale on X is incompatible with histogram plots\n");
1885 if ((histogram_opts.type == HT_STACKED_IN_LAYERS
1886 || histogram_opts.type == HT_STACKED_IN_TOWERS)
1887 && axis_array[y_axis].log)
1888 int_error(c_token, "Log scale on Y is incompatible with stacked histogram plot\n");
1889 this_plot->histogram_sequence = ++histogram_sequence;
1890 /* Current histogram always goes at the front of the list */
1891 if (this_plot->histogram_sequence == 0) {
1892 this_plot->histogram = gp_alloc(sizeof(struct histogram_style), "New histogram");
1893 init_histogram(this_plot->histogram,histogram_title);
1894 histogram_title = NULL;
1895 this_plot->histogram->start = newhist_start;
1896 this_plot->histogram->startcolor = newhist_color;
1897 this_plot->histogram->startpattern = newhist_pattern;
1899 this_plot->histogram = histogram_opts.next;
1900 this_plot->histogram->clustersize++;
1903 /* Normally each histogram gets a new set of colors, but in */
1904 /* 'newhistogram' you can force a starting color instead. */
1905 if (!set_lpstyle && this_plot->histogram->startcolor != LT_UNDEFINED)
1906 this_plot->lp_properties.l_type = this_plot->histogram_sequence
1907 + this_plot->histogram->startcolor;
1908 if (this_plot->histogram->startpattern != LT_UNDEFINED)
1909 this_plot->fill_properties.fillpattern = this_plot->histogram_sequence
1910 + this_plot->histogram->startpattern;
1912 #endif /* EAM_HISTOGRAMS */
1915 /* Styles that use palette */
1916 if (this_plot->plot_style == IMAGE)
1917 this_plot->lp_properties.use_palette = 1;
1918 /* Styles that use colorbus */
1919 if (this_plot->plot_style == IMAGE || this_plot->plot_style == RGBIMAGE)
1921 #endif /* WITH_IMAGE */
1923 /* we can now do some checks that we deferred earlier */
1925 if (this_plot->plot_type == DATA) {
1927 /* Error check to handle missing or unreadable file */
1928 if (this_plot->plot_style & PLOT_STYLE_HAS_POINT)
1931 this_plot->plot_type = NODATA;
1932 goto SKIPPED_EMPTY_FILE;
1934 if (! (uses_axis[x_axis] & USES_AXIS_FOR_DATA)
1935 && X_AXIS.autoscale) {
1936 if (X_AXIS.autoscale & AUTOSCALE_MIN)
1937 X_AXIS.min = VERYLARGE;
1938 if (X_AXIS.autoscale & AUTOSCALE_MAX)
1939 X_AXIS.max = -VERYLARGE;
1941 if (X_AXIS.is_timedata) {
1943 int_error(c_token, "Need full using spec for x time data");
1945 if (Y_AXIS.is_timedata) {
1947 int_error(c_token, "Need using spec for y time data");
1949 /* need other cols, but I'm lazy */
1950 df_axis[0] = x_axis;
1951 df_axis[1] = y_axis;
1953 /* separate record of datafile and func */
1954 uses_axis[x_axis] |= USES_AXIS_FOR_DATA;
1955 uses_axis[y_axis] |= USES_AXIS_FOR_DATA;
1956 } else if (!parametric || !xparam) {
1957 /* for x part of a parametric function, axes are
1959 /* separate record of data and func */
1960 uses_axis[x_axis] |= USES_AXIS_FOR_FUNC;
1961 uses_axis[y_axis] |= USES_AXIS_FOR_FUNC;
1966 && this_plot->plot_style != IMAGE
1967 && this_plot->plot_style != RGBIMAGE
1968 /* don't increment the default line/point properties if
1969 * this_plot is an image */
1970 #endif /* WITH_IMAGE */
1972 if (this_plot->plot_style & PLOT_STYLE_HAS_POINT)
1976 if (this_plot->plot_type == DATA) {
1977 /* actually get the data now */
1978 if (get_data(this_plot) == 0) {
1979 /* EAM 2005 - warn, but keep going */
1980 int_warn(c_token-1,"Skipping data file with no valid points");
1981 this_plot->plot_type = NODATA;
1982 goto SKIPPED_EMPTY_FILE;
1985 #ifdef EAM_HISTOGRAMS
1986 /* Fiddle the auto-scaling data for histograms */
1987 if (this_plot->plot_style == HISTOGRAMS)
1988 histogram_range_fiddling(this_plot);
1989 #endif /* EAM_HISTOGRAMS */
1992 switch (this_plot->plot_smooth) {
1993 /* sort and average, if the style requires */
1995 case SMOOTH_FREQUENCY:
1996 case SMOOTH_CSPLINES:
1997 case SMOOTH_ACSPLINES:
1998 case SMOOTH_SBEZIER:
1999 sort_points(this_plot);
2000 cp_implode(this_plot);
2006 switch (this_plot->plot_smooth) {
2007 /* create new data set by evaluation of
2008 * interpolation routines */
2009 case SMOOTH_FREQUENCY:
2010 gen_interp_frequency(this_plot);
2012 case SMOOTH_CSPLINES:
2013 case SMOOTH_ACSPLINES:
2015 case SMOOTH_SBEZIER:
2016 gen_interp(this_plot);
2023 /* now that we know the plot style, adjust the x- and yrange */
2024 /* adjust_range(this_plot); no longer needed */
2027 /* Images are defined by a grid representing centers of pixels.
2028 * Compensate for extent of the image so `set autoscale fix`
2029 * uses outer edges of outer pixels in axes adjustment.
2031 if ((this_plot->plot_style == IMAGE || this_plot->plot_style == RGBIMAGE))
2032 UPDATE_AXES_FOR_PLOT_IMAGE(this_plot, IC_PALETTE);
2038 /* Note position in command line for second pass */
2039 this_plot->token = c_token;
2040 tp_ptr = &(this_plot->next);
2044 if (equals(c_token, ","))
2050 if (parametric && xparam)
2051 int_error(NO_CARET, "parametric function not fully specified");
2054 /*** Second Pass: Evaluate the functions ***/
2056 * Everything is defined now, except the function data. We expect
2057 * no syntax errors, etc, since the above parsed it all. This
2058 * makes the code below simpler. If y is autoscaled, the yrange
2059 * may still change. we stored last token of each plot, so we
2060 * dont need to do everything again */
2062 /* parametric or polar fns can still affect x ranges */
2063 if (!parametric && !polar) {
2064 /* If we were expecting to autoscale on X but found no usable
2065 * points in the data files, then the axis limits are still sitting
2066 * at +/- VERYLARGE. The default range for bare functions is [-10:10].
2067 * Or we could give up and fall through to "x range invalid".
2069 if (some_functions && uses_axis[FIRST_X_AXIS])
2070 if (axis_array[FIRST_X_AXIS].max == -VERYLARGE ||
2071 axis_array[FIRST_X_AXIS].min == VERYLARGE) {
2072 axis_array[FIRST_X_AXIS].min = -10;
2073 axis_array[FIRST_X_AXIS].max = 10;
2076 /* check that xmin -> xmax is not too small */
2077 axis_checked_extend_empty_range(FIRST_X_AXIS, "x range is invalid");
2079 if (uses_axis[SECOND_X_AXIS] & USES_AXIS_FOR_DATA) {
2080 /* check that x2min -> x2max is not too small */
2081 axis_checked_extend_empty_range(SECOND_X_AXIS, "x2 range is invalid");
2082 } else if (axis_array[SECOND_X_AXIS].autoscale) {
2083 /* copy x1's range */
2084 if (axis_array[SECOND_X_AXIS].autoscale & AUTOSCALE_MIN)
2085 axis_array[SECOND_X_AXIS].min = axis_array[FIRST_X_AXIS].min;
2086 if (axis_array[SECOND_X_AXIS].autoscale & AUTOSCALE_MAX)
2087 axis_array[SECOND_X_AXIS].max = axis_array[FIRST_X_AXIS].max;
2090 if (some_functions) {
2092 /* call the controlled variable t, since x_min can also mean
2094 double t_min = 0., t_max = 0., t_step = 0.;
2096 if (parametric || polar) {
2097 if (! (uses_axis[FIRST_X_AXIS] & USES_AXIS_FOR_DATA)) {
2098 /* these have not yet been set to full width */
2099 if (axis_array[FIRST_X_AXIS].autoscale & AUTOSCALE_MIN)
2100 axis_array[FIRST_X_AXIS].min = VERYLARGE;
2101 if (axis_array[FIRST_X_AXIS].autoscale & AUTOSCALE_MAX)
2102 axis_array[FIRST_X_AXIS].max = -VERYLARGE;
2104 if (! (uses_axis[SECOND_X_AXIS] & USES_AXIS_FOR_DATA)) {
2105 if (axis_array[SECOND_X_AXIS].autoscale & AUTOSCALE_MIN)
2106 axis_array[SECOND_X_AXIS].min = VERYLARGE;
2107 if (axis_array[SECOND_X_AXIS].autoscale & AUTOSCALE_MAX)
2108 axis_array[SECOND_X_AXIS].max = -VERYLARGE;
2112 /* FIXME HBB 20000430: here and elsewhere, the code explicitly
2113 * assumes that the dummy variables (t, u, v) cannot possibly
2114 * be logscaled in parametric or polar mode. Does this
2116 if (parametric || polar) {
2117 t_min = axis_array[T_AXIS].min;
2118 t_max = axis_array[T_AXIS].max;
2119 t_step = (t_max - t_min) / (samples_1 - 1);
2121 /* else we'll do it on each plot (see below) */
2123 tp_ptr = &(first_plot);
2125 this_plot = first_plot;
2126 c_token = begin_token; /* start over */
2128 /* Read through functions */
2130 if (is_definition(c_token)) {
2133 struct at_type *at_ptr;
2136 /* HBB 20000820: now globals in 'axis.c' */
2137 x_axis = this_plot->x_axis;
2138 y_axis = this_plot->y_axis;
2142 dummy_func = &plot_func;
2143 /* WARNING: do NOT free name_str */
2144 /* FIXME: should this be saved in "this_plot"? */
2145 name_str = string_or_express(&at_ptr);
2147 if (!name_str) { /* function to plot */
2148 if (parametric) { /* toggle parametric axes */
2149 xparam = 1 - xparam;
2151 plot_func.at = at_ptr;
2153 if (!parametric && !polar) {
2156 axis_unlog_interval(x_axis, &t_min, &t_max, 1);
2157 t_step = (t_max - t_min) / (samples_1 - 1);
2159 for (i = 0; i < samples_1; i++) {
2162 double t = t_min + i * t_step;
2163 /* parametric/polar => NOT a log quantity */
2164 double x = (!parametric && !polar)
2165 ? AXIS_DE_LOG_VALUE(x_axis, t) : t;
2167 (void) Gcomplex(&plot_func.dummy_values[0], x, 0.0);
2168 evaluate_at(plot_func.at, &a);
2170 if (undefined || (fabs(imag(&a)) > zero)) {
2171 this_plot->points[i].type = UNDEFINED;
2176 /* width of box not specified */
2177 this_plot->points[i].z = -1.0;
2178 /* for the moment */
2179 this_plot->points[i].type = INRANGE;
2182 /* we cannot do range-checking now, since for
2183 * the x function we did not know which axes
2185 * DO NOT TAKE LOGS YET - do it in parametric_fixup
2187 /* ignored, actually... */
2188 this_plot->points[i].x = t;
2189 this_plot->points[i].y = temp;
2190 if (boxwidth >= 0 && boxwidth_is_absolute )
2191 this_plot->points[i].z = 0;
2194 if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MAX) && temp > axis_array[R_AXIS].max)
2195 this_plot->points[i].type = OUTRANGE;
2196 if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MIN))
2197 temp -= axis_array[R_AXIS].min;
2198 y = temp * sin(x * ang2rad);
2199 x = temp * cos(x * ang2rad);
2200 if (boxwidth >= 0 && boxwidth_is_absolute) {
2202 int dmy_type = INRANGE;
2203 this_plot->points[i].z = 0;
2204 if (axis_array[this_plot->x_axis].log) {
2205 double base = axis_array[this_plot->x_axis].base;
2206 xlow = x * pow(base, -boxwidth/2.);
2207 xhigh = x * pow(base, boxwidth/2.);
2209 xlow = x - boxwidth/2;
2210 xhigh = x + boxwidth/2;
2212 STORE_WITH_LOG_AND_UPDATE_RANGE( this_plot->points[i].xlow, xlow, dmy_type, x_axis, NOOP, NOOP );
2214 STORE_WITH_LOG_AND_UPDATE_RANGE( this_plot->points[i].xhigh, xhigh, dmy_type, x_axis, NOOP, NOOP );
2217 STORE_WITH_LOG_AND_UPDATE_RANGE(this_plot->points[i].x, x, this_plot->points[i].type, x_axis, NOOP, goto come_here_if_undefined);
2218 STORE_WITH_LOG_AND_UPDATE_RANGE(this_plot->points[i].y, y, this_plot->points[i].type, y_axis, NOOP, goto come_here_if_undefined);
2219 } else { /* neither parametric or polar */
2220 /* If non-para, it must be INRANGE */
2221 /* logscale ? log(x) : x */
2222 this_plot->points[i].x = t;
2223 if (boxwidth >= 0 && boxwidth_is_absolute) {
2225 int dmy_type = INRANGE;
2226 this_plot->points[i].z = 0;
2227 if (axis_array[this_plot->x_axis].log) {
2228 double base = axis_array[this_plot->x_axis].base;
2229 xlow = x * pow(base, -boxwidth/2.);
2230 xhigh = x * pow(base, boxwidth/2.);
2232 xlow = x - boxwidth/2;
2233 xhigh = x + boxwidth/2;
2235 STORE_WITH_LOG_AND_UPDATE_RANGE( this_plot->points[i].xlow, xlow, dmy_type, x_axis, NOOP, NOOP );
2237 STORE_WITH_LOG_AND_UPDATE_RANGE( this_plot->points[i].xhigh, xhigh, dmy_type, x_axis, NOOP, NOOP );
2239 STORE_WITH_LOG_AND_UPDATE_RANGE(this_plot->points[i].y, temp, this_plot->points[i].type, y_axis + (x_axis - y_axis) * xparam, NOOP, goto come_here_if_undefined);
2241 /* could not use a continue in this case */
2242 come_here_if_undefined:
2243 ; /* ansi requires a statement after a label */
2246 } /* loop over samples_1 */
2247 this_plot->p_count = i; /* samples_1 */
2249 /* skip all modifers func / whole of data plots */
2250 c_token = this_plot->token;
2253 tp_ptr = &(this_plot->next);
2254 this_plot = this_plot->next;
2257 if (equals(c_token, ","))
2262 /* when step debugging, set breakpoint here to get through
2263 * the 'read function' loop above quickly */
2265 /* Now actually fix the plot pairs to be single plots
2266 * also fixes up polar&¶metric fn plots */
2267 parametric_fixup(first_plot, &plot_num);
2268 /* we omitted earlier check for range too small */
2269 axis_checked_extend_empty_range(FIRST_X_AXIS, NULL);
2270 if (uses_axis[SECOND_X_AXIS]) {
2271 axis_checked_extend_empty_range(SECOND_X_AXIS, NULL);
2274 } /* some_functions */
2275 /* throw out all curve_points at end of list, that we don't need */
2280 /* if first_plot is NULL, we have no functions or data at all. This can
2281 * happen, if you type "plot x=5", since x=5 is a variable assignment */
2283 if (plot_num == 0 || first_plot == NULL) {
2284 int_error(c_token, "no functions or data to plot");
2287 if (!uses_axis[FIRST_X_AXIS] && !uses_axis[SECOND_X_AXIS])
2288 if (first_plot->plot_type == NODATA)
2289 int_error(NO_CARET,"No data in plot");
2291 if (uses_axis[FIRST_X_AXIS]) {
2292 if (axis_array[FIRST_X_AXIS].max == -VERYLARGE ||
2293 axis_array[FIRST_X_AXIS].min == VERYLARGE)
2294 int_error(NO_CARET, "all points undefined!");
2295 axis_revert_and_unlog_range(FIRST_X_AXIS);
2297 if (uses_axis[SECOND_X_AXIS]) {
2298 if (axis_array[SECOND_X_AXIS].max == -VERYLARGE ||
2299 axis_array[SECOND_X_AXIS].min == VERYLARGE)
2300 int_error(NO_CARET, "all points undefined!");
2301 axis_revert_and_unlog_range(SECOND_X_AXIS);
2303 assert(uses_axis[FIRST_X_AXIS]);
2304 if (axis_array[SECOND_X_AXIS].autoscale & AUTOSCALE_MIN)
2305 axis_array[SECOND_X_AXIS].min = axis_array[FIRST_X_AXIS].min;
2306 if (axis_array[SECOND_X_AXIS].autoscale & AUTOSCALE_MAX)
2307 axis_array[SECOND_X_AXIS].max = axis_array[FIRST_X_AXIS].max;
2308 if (! axis_array[SECOND_X_AXIS].autoscale)
2309 axis_revert_and_unlog_range(SECOND_X_AXIS);
2311 if (! uses_axis[FIRST_X_AXIS]) {
2312 assert(uses_axis[SECOND_X_AXIS]);
2313 if (axis_array[FIRST_X_AXIS].autoscale & AUTOSCALE_MIN)
2314 axis_array[FIRST_X_AXIS].min = axis_array[SECOND_X_AXIS].min;
2315 if (axis_array[FIRST_X_AXIS].autoscale & AUTOSCALE_MAX)
2316 axis_array[FIRST_X_AXIS].max = axis_array[SECOND_X_AXIS].max;
2320 if (uses_axis[FIRST_Y_AXIS]) {
2321 axis_checked_extend_empty_range(FIRST_Y_AXIS, "all points y value undefined!");
2322 axis_revert_and_unlog_range(FIRST_Y_AXIS);
2324 if (uses_axis[SECOND_Y_AXIS]) {
2325 axis_checked_extend_empty_range(SECOND_Y_AXIS, "all points y2 value undefined!");
2326 axis_revert_and_unlog_range(SECOND_Y_AXIS);
2328 /* else we want to copy y2 range */
2329 assert(uses_axis[FIRST_Y_AXIS]);
2330 if (axis_array[SECOND_Y_AXIS].autoscale & AUTOSCALE_MIN)
2331 axis_array[SECOND_Y_AXIS].min = axis_array[FIRST_Y_AXIS].min;
2332 if (axis_array[SECOND_Y_AXIS].autoscale & AUTOSCALE_MAX)
2333 axis_array[SECOND_Y_AXIS].max = axis_array[FIRST_Y_AXIS].max;
2334 /* Log() fixup is only necessary if the range was *not* copied from
2335 * the (already logarithmized) yrange */
2336 if (! axis_array[SECOND_Y_AXIS].autoscale)
2337 axis_revert_and_unlog_range(SECOND_Y_AXIS);
2339 if (! uses_axis[FIRST_Y_AXIS]) {
2340 assert(uses_axis[SECOND_Y_AXIS]);
2341 if (axis_array[FIRST_Y_AXIS].autoscale & AUTOSCALE_MIN)
2342 axis_array[FIRST_Y_AXIS].min = axis_array[SECOND_Y_AXIS].min;
2343 if (axis_array[FIRST_Y_AXIS].autoscale & AUTOSCALE_MAX)
2344 axis_array[FIRST_Y_AXIS].max = axis_array[SECOND_Y_AXIS].max;
2348 /* FIXME HBB 20000502: this seems to have been replaced by newer code,
2349 * in the meantime? --> disable it */
2350 AXIS_WRITEBACK(FIRST_X_AXIS);
2351 AXIS_WRITEBACK(FIRST_Y_AXIS);
2352 AXIS_WRITEBACK(SECOND_X_AXIS);
2353 AXIS_WRITEBACK(SECOND_Y_AXIS);
2357 /* the following ~5 lines were moved from the end of the
2358 * function to here, as do_plot calles term->text, which
2359 * itself might process input events in mouse enhanced
2360 * terminals. For redrawing to work, line capturing and
2361 * setting the plot_num must already be done before
2362 * entering do_plot(). Thu Jan 27 23:56:24 2000 (joze) */
2363 /* if we get here, all went well, so record this line for replot */
2364 if (plot_token != -1) {
2365 /* note that m_capture also frees the old replot_line */
2366 m_capture(&replot_line, plot_token, c_token - 1);
2371 print_table(first_plot, plot_num);
2373 START_LEAK_CHECK(); /* check for memory leaks in this routine */
2375 /* do_plot now uses axis_array[] */
2376 do_plot(first_plot, plot_num);
2380 /* after do_plot(), axis_array[].min and .max
2381 * contain the plotting range actually used (rounded
2382 * to tic marks, not only the min/max data values)
2383 * --> save them now for writeback if requested
2385 SAVE_WRITEBACK_ALL_AXES;
2386 /* update GPVAL_ variables available to user */
2387 update_gpval_variables(1);
2390 cp_free(first_plot);
2396 * The hardest part of this routine is collapsing the FUNC plot types in the
2397 * list (which are garanteed to occur in (x,y) pairs while preserving the
2398 * non-FUNC type plots intact. This means we have to work our way through
2399 * various lists. Examples (hand checked): start_plot:F1->F2->NULL ==>
2400 * F2->NULL start_plot:F1->F2->F3->F4->F5->F6->NULL ==> F2->F4->F6->NULL
2401 * start_plot:F1->F2->D1->D2->F3->F4->D3->NULL ==> F2->D1->D2->F4->D3->NULL
2405 parametric_fixup(struct curve_points *start_plot, int *plot_num)
2407 struct curve_points *xp, *new_list = NULL, *free_list = NULL;
2408 struct curve_points **last_pointer = &new_list;
2414 * Ok, go through all the plots and move FUNC types together. Note: this
2415 * originally was written to look for a NULL next pointer, but gnuplot
2416 * wants to be sticky in grabbing memory and the right number of items in
2417 * the plot list is controlled by the plot_num variable.
2419 * Since gnuplot wants to do this sticky business, a free_list of
2420 * curve_points is kept and then tagged onto the end of the plot list as
2421 * this seems more in the spirit of the original memory behavior than
2422 * simply freeing the memory. I'm personally not convinced this sort of
2423 * concern is worth it since the time spent computing points seems to
2424 * dominate any garbage collecting that might be saved here...
2426 new_list = xp = start_plot;
2429 while (++curve <= *plot_num) {
2430 if (xp->plot_type == FUNC) {
2431 /* Here's a FUNC parametric function defined as two parts. */
2432 struct curve_points *yp = xp->next;
2436 assert(xp->p_count == yp->p_count);
2438 /* because syntax is plot x(t), y(t) axes ..., only
2439 * the y function axes are correct
2444 * Go through all the points assigning the y's from xp to be
2445 * the x's for yp. In polar mode, we need to check max's and
2449 for (i = 0; i < yp->p_count; ++i) {
2451 double r = yp->points[i].y;
2452 double t = xp->points[i].y * ang2rad;
2454 if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MAX) && r > axis_array[R_AXIS].max)
2455 yp->points[i].type = OUTRANGE;
2456 if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MIN)) {
2457 /* store internally as if plotting r(t)-rmin */
2458 r -= axis_array[R_AXIS].min;
2462 if (boxwidth >= 0 && boxwidth_is_absolute) {
2463 int dmy_type = INRANGE;
2464 STORE_WITH_LOG_AND_UPDATE_RANGE( yp->points[i].xlow, x - boxwidth/2, dmy_type, xp->x_axis, NOOP, NOOP );
2466 STORE_WITH_LOG_AND_UPDATE_RANGE( yp->points[i].xhigh, x + boxwidth/2, dmy_type, xp->x_axis, NOOP, NOOP );
2468 /* we hadn't done logs when we stored earlier */
2469 STORE_WITH_LOG_AND_UPDATE_RANGE(yp->points[i].x, x, yp->points[i].type, xp->x_axis, NOOP, NOOP);
2470 STORE_WITH_LOG_AND_UPDATE_RANGE(yp->points[i].y, y, yp->points[i].type, xp->y_axis, NOOP, NOOP);
2472 double x = xp->points[i].y;
2473 double y = yp->points[i].y;
2475 if (boxwidth >= 0 && boxwidth_is_absolute) {
2476 int dmy_type = INRANGE;
2477 STORE_WITH_LOG_AND_UPDATE_RANGE( yp->points[i].xlow, x - boxwidth/2, dmy_type, yp->x_axis, NOOP, NOOP );
2479 STORE_WITH_LOG_AND_UPDATE_RANGE( yp->points[i].xhigh, x + boxwidth/2, dmy_type, yp->x_axis, NOOP, NOOP );
2481 STORE_WITH_LOG_AND_UPDATE_RANGE(yp->points[i].x, x, yp->points[i].type, yp->x_axis, NOOP, NOOP);
2482 STORE_WITH_LOG_AND_UPDATE_RANGE(yp->points[i].y, y, yp->points[i].type, yp->y_axis, NOOP, NOOP);
2486 /* Ok, fix up the title to include both the xp and yp plots. */
2487 if (xp->title && xp->title[0] != '\0' && yp->title) {
2488 tlen = strlen(yp->title) + strlen(xp->title) + 3;
2489 new_title = gp_alloc(tlen, "string");
2490 strcpy(new_title, xp->title);
2491 strcat(new_title, ", ");
2492 strcat(new_title, yp->title);
2494 yp->title = new_title;
2496 /* move xp to head of free list */
2497 xp->next = free_list;
2500 /* append yp to new_list */
2502 last_pointer = &(yp->next);
2505 } else { /* data plot */
2506 assert(*last_pointer == xp);
2507 last_pointer = &(xp->next);
2510 } /* loop over plots */
2512 first_plot = new_list;
2514 /* Ok, stick the free list at the end of the curve_points plot list. */
2515 *last_pointer = free_list;