UVES Pipeline Reference Manual  5.5.5b3
uves_plot.c
1 /* *
2  * This file is part of the ESO UVES Pipeline *
3  * Copyright (C) 2004,2005 European Southern Observatory *
4  * *
5  * This library is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the Free Software *
17  * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA *
18  * */
19 
20 /*
21  * $Author: amodigli $
22  * $Date: 2012-03-02 16:49:48 $
23  * $Revision: 1.38 $
24  * $Name: not supported by cvs2svn $
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30 
31 /*----------------------------------------------------------------------------*/
53 /*----------------------------------------------------------------------------*/
54 
55 /* If we can link to setenv but it is not declared, then declare it manually */
56 #if defined HAVE_SETENV && HAVE_SETENV
57 #if defined HAVE_DECL_SETENV && !HAVE_DECL_SETENV
58 int setenv(const char *name, const char *value, int overwrite);
59 #endif
60 #endif
61 
62 /*-----------------------------------------------------------------------------
63  Includes
64  -----------------------------------------------------------------------------*/
65 
66 #include <uves_plot.h>
67 
68 #include <uves_dump.h>
69 #include <uves_utils_wrappers.h>
70 #include <uves_error.h>
71 #include <uves_msg.h>
72 
73 #include <irplib_utils.h>
74 
75 #include <cpl.h>
76 
77 #include <stdarg.h>
78 #include <stdio.h>
79 #include <string.h>
80 #include <stdlib.h> /* setenv */
81 
82 /*-----------------------------------------------------------------------------
83  Functions prototypes
84  -----------------------------------------------------------------------------*/
85 static char *title_string(const char *title, int npoints);
86 /*-----------------------------------------------------------------------------
87  Defines
88  -----------------------------------------------------------------------------*/
89 #define MAXTITLELENGTH 10000
90 #define RECOVER_FROM_ERROR(EXTERNAL_COMMAND) do { \
91  if (cpl_error_get_code() != CPL_ERROR_NONE) \
92  { \
93  uves_msg_error("Could not send plot to " \
94  "command '%s': " \
95  "%s in '%s'", \
96  EXTERNAL_COMMAND, \
97  cpl_error_get_message(), \
98  cpl_error_get_where()); \
99  cpl_error_reset(); \
100  goto cleanup; \
101  } } while (false)
102 
103 
104 static char title[MAXTITLELENGTH];
105 static bool plotting_enabled = false; /* If caller forgets to call
106  the initializer, plotting
107  will be disabled */
108 static const char *plotter = "";
109 
112 /*-----------------------------------------------------------------------------
113  Implementation
114  -----------------------------------------------------------------------------*/
115 
116 /*----------------------------------------------------------------------------*/
128 /*----------------------------------------------------------------------------*/
129 cpl_error_code
130 uves_plot_initialize(const char *plotter_command)
131 {
132  char *test_cmd = NULL;
133  char *first_word = NULL;
134 
135  plotting_enabled = (strcmp(plotter_command, "no") != 0);
136 
137  /* Note that 'setenv' is *not* ANSI C. If it does not exist, tell user to
138  * define the environment variable him-/herself.
139  */
140 
141  if (plotting_enabled)
142  {
143  const char *env = "CPL_PLOTTER";
144 
145  /* Check if 'which x' returns non-zero.
146  x is the first word of plotting command.
147  Note: this assumes the environment understands
148  'which' and '> /dev/null'. If not,
149  plotting will be disabled.
150  */
151  first_word = uves_sprintf("%s ", plotter_command);
152 
153  assure( strtok(first_word, " ") != NULL, CPL_ERROR_ILLEGAL_OUTPUT,
154  "Error splitting string '%s'", first_word);
155 
156  test_cmd = uves_sprintf("which %s > /dev/null", first_word);
157 
158 #if defined HAVE_SETENV && HAVE_SETENV
159 
160  if (setenv(env, plotter_command, 1) != 0)
161  {
162  uves_msg_warning("Could not set environment variable '%s'. "
163  "Plotting disabled!", env);
164  plotting_enabled = false;
165  }
166  /* popen may return non-NULL even when the external command
167  is not available. This causes the recipe to crash when writing
168  to an invalid FILE pointer.
169  Therefore, check (using 'which') that the
170  command is available.
171  */
172  else if (system(test_cmd) != 0)
173  {
174  uves_msg_debug("Command '%s' returned non-zero", test_cmd);
175  uves_msg_warning("Command '%s' failed. Plotting disabled!", test_cmd);
176  plotting_enabled = false;
177  }
178  else
179  {
180  /* Setenv succeeded, remember command */
181  uves_msg_debug("setenv %s='%s' succeeded", env, plotter_command);
182  uves_msg_debug("Command '%s' returned zero", test_cmd);
183 
184  plotter = plotter_command;
185  }
186 #else
187  uves_msg_warning("setenv() is not available on this platform. You have to manually "
188  "set the environment variable '%s' to '%s'", env, plotter_command);
189 
190  plotter = plotter_command;
191 
192 #endif
193  }
194 
195  cleanup:
196  cpl_free(test_cmd);
197  cpl_free(first_word);
198 
199  return cpl_error_get_code();
200 }
201 
202 /*----------------------------------------------------------------------------*/
217 /*----------------------------------------------------------------------------*/
218 cpl_error_code
219 uves_plot_image_rows(const cpl_image *image, int first_row, int last_row, int step,
220  const char *xtitle, const char *ytitle, const char *format, ...)
221 {
222  va_list al;
223 
224  char *pre = NULL;
225  char *options = NULL;
226  const char *post = "";
227  cpl_image *thresholded = NULL;
228 
229  assure( image != NULL, CPL_ERROR_NULL_INPUT, "Null image");
230  if (xtitle == NULL) xtitle = "";
231  if (ytitle == NULL) ytitle = "";
232  assure( 1 <= first_row && first_row <= last_row &&
233  last_row <= cpl_image_get_size_y(image),
234  CPL_ERROR_ILLEGAL_INPUT,
235  "Illegal rows: %d - %d; rows in image = %" CPL_SIZE_FORMAT "",
236  first_row, last_row, cpl_image_get_size_y(image));
237 
238  assure( step >= 1, CPL_ERROR_ILLEGAL_INPUT,
239  "Illegal step size: %d", step);
240 
241  if (plotting_enabled)
242  {
243  const char *pre_format;
244  int row;
245 
246  /* Create pre string */
247  pre_format = "set grid; set xlabel '%s'; set ylabel '%s';";
248  pre = cpl_calloc(strlen(pre_format) +
249  strlen(xtitle) + strlen(ytitle) + 1,
250  sizeof(char));
251  sprintf(pre, pre_format, xtitle, ytitle);
252 
253 
254  va_start(al, format);
255  vsnprintf(title, MAXTITLELENGTH - 1, format, al);
256  va_end(al);
257  title[MAXTITLELENGTH - 1] = '\0';
258 
259  options = title_string(title, cpl_image_get_size_x(image));
260 
261  /* Threshold each row */
262  thresholded = cpl_image_duplicate(image);
263  for (row = first_row; row <= last_row; row++)
264  {
265  int nx = cpl_image_get_size_x(thresholded);
266  double median = cpl_image_get_median_window(thresholded,
267  1, first_row,
268  nx, last_row);
269  double stdev = cpl_image_get_stdev_window(thresholded,
270  1, first_row,
271  nx, last_row);
272 
273  double locut = median - 3*stdev;
274  double hicut = median + 3*stdev;
275 
276  int x, pis_rejected;
277 
278  for (x = 1; x <= nx; x++)
279  {
280  double data =
281  cpl_image_get(thresholded, x, row, &pis_rejected);
282  if (data < locut) data = locut;
283  if (data > hicut) data = hicut;
284  cpl_image_set(thresholded, x, row, data);
285  }
286  }
287 
288  cpl_plot_image_row(pre,
289  (strcmp(options, "t '%s'") == 0) ? "" : options,
290  post,
291  thresholded,
292  first_row, last_row, step);
293 
294  RECOVER_FROM_ERROR(plotter);
295  }
296 
297  cleanup:
298  uves_free_image(&thresholded);
299  cpl_free(pre);
300  cpl_free(options);
301 
302  return cpl_error_get_code();
303 }
304 
305 /*----------------------------------------------------------------------------*/
323 /*----------------------------------------------------------------------------*/
324 cpl_error_code
325 uves_plot_image_columns(const cpl_image *image, int first_column, int last_column, int step,
326  const char *xtitle, const char *ytitle, const char *format, ...)
327 {
328  va_list al;
329 
330  char *pre = NULL;
331  char *options = NULL;
332  const char *post = "";
333  cpl_image *thresholded = NULL;
334 
335  assure( image != NULL, CPL_ERROR_NULL_INPUT, "Null image");
336  if (xtitle == NULL) xtitle = "";
337  if (ytitle == NULL) ytitle = "";
338  assure( 1 <= first_column && first_column <= last_column &&
339  last_column <= cpl_image_get_size_x(image),
340  CPL_ERROR_ILLEGAL_INPUT,
341  "Illegal columns: %d - %d; columns in image = %" CPL_SIZE_FORMAT "",
342  first_column, last_column, cpl_image_get_size_x(image));
343 
344  assure( step >= 1, CPL_ERROR_ILLEGAL_INPUT,
345  "Illegal step size: %d", step);
346 
347  if (plotting_enabled)
348  {
349  const char *pre_format;
350  int col;
351 
352  /* Create pre string */
353  pre_format = "set grid; set xlabel '%s'; set ylabel '%s';";
354  pre = cpl_calloc(strlen(pre_format) +
355  strlen(xtitle) + strlen(ytitle) + 1,
356  sizeof(char));
357  sprintf(pre, pre_format, xtitle, ytitle);
358 
359  va_start(al, format);
360  vsnprintf(title, MAXTITLELENGTH - 1, format, al);
361  va_end(al);
362  title[MAXTITLELENGTH - 1] = '\0';
363 
364  options = title_string(title, cpl_image_get_size_y(image));
365 
366  /* Threshold each column */
367  thresholded = cpl_image_duplicate(image);
368  for (col = first_column; col <= last_column; col++)
369  {
370  int ny = cpl_image_get_size_x(thresholded);
371  double median = cpl_image_get_median_window(thresholded,
372  first_column, 1,
373  last_column, ny);
374  double stdev = cpl_image_get_stdev_window(thresholded,
375  first_column, 1,
376  last_column, ny);
377 
378  double locut = median - 3*stdev;
379  double hicut = median + 3*stdev;
380 
381  int y, pis_rejected;
382 
383  for (y = 1; y <= ny; y++)
384  {
385  double data = cpl_image_get(thresholded, col, y, &pis_rejected);
386  if (data < locut) data = locut;
387  if (data > hicut) data = hicut;
388  cpl_image_set(thresholded, col, y, data);
389  }
390  }
391 
392 
393  check( cpl_plot_image_col(pre,
394  (strcmp(options, "t '%s'") == 0) ? "" : options,
395  post,
396  image,
397  first_column, last_column, step),
398  "Error plotting image");
399 
400  RECOVER_FROM_ERROR(plotter);
401  }
402 
403  cleanup:
404  uves_free_image(&thresholded);
405  cpl_free(pre);
406  cpl_free(options);
407 
408  return cpl_error_get_code();
409 }
410 
411 /*----------------------------------------------------------------------------*/
425 /*----------------------------------------------------------------------------*/
426 void
427 uves_plot_bivectors(cpl_bivector **bivectors, char **titles,
428  int N, const char *xtitle,
429  const char *ytitle)
430 {
431  char *pre = NULL;
432  char **options = NULL;
433  const char *post = "";
434 
435  options = cpl_calloc(N, sizeof(char *)); /* Initialized to NULL */
436  assure_mem( options );
437 
438  if (plotting_enabled)
439  {
440  int npoints, i;
441  cpl_bivector *temp;
442  char *temps;
443 
444  /* Create options strings */
445 
446  npoints = 0;
447  for (i = 0; i < N; i++)
448  {
449  npoints += cpl_bivector_get_size(bivectors[i]);
450  }
451  for (i = 0; i < N; i++)
452  {
453  options[i] = title_string(titles[i], npoints);
454  }
455 
456 
457  {
458  double datamax = cpl_vector_get_max(cpl_bivector_get_y(bivectors[0]));
459  double datamin = cpl_vector_get_min(cpl_bivector_get_y(bivectors[0]));
460 
461  double locut = datamin - 0.2*(datamax-datamin);
462  double hicut = datamax + 0.2*(datamax-datamin);
463 
464  for (i = 0; i < N; i++)
465  {
466  int j;
467  for (j = 0; j < cpl_bivector_get_size(bivectors[i]); j++)
468  {
469  if (cpl_bivector_get_y_data(bivectors[i])[j] < locut)
470  {
471  cpl_bivector_get_y_data(bivectors[i])[j] = locut;
472  }
473  if (cpl_bivector_get_y_data(bivectors[i])[j] > hicut)
474  {
475  cpl_bivector_get_y_data(bivectors[i])[j] = hicut;
476  }
477  }
478  }
479  }
480 
481  /* Swap first/last bivectors */
482  temp = bivectors[0];
483  bivectors[0] = bivectors[N-1];
484  bivectors[N-1] = temp;
485 
486  temps = options[0];
487  options[0] = options[N-1];
488  options[N-1] = temps;
489 
490  pre = uves_sprintf(
491  "set grid; set xlabel '%s'; set ylabel '%s';", xtitle, ytitle);
492 
493  cpl_plot_bivectors(pre,
494  (const char **)options,
495  post,
496  (const cpl_bivector **)bivectors, N);
497 
498  RECOVER_FROM_ERROR(plotter);
499  }
500 
501  cleanup:
502  cpl_free(pre);
503  {
504  int i;
505  for (i = 0; i < N; i++)
506  {
507  cpl_free(options[i]);
508  }
509  }
510  cpl_free(options);
511  return;
512 }
513 
514 /*----------------------------------------------------------------------------*/
530 /*----------------------------------------------------------------------------*/
531 cpl_error_code
532 uves_plot_table(const cpl_table *table, const char *colx, const char *coly,
533  const char *format, ...)
534 {
535  va_list al;
536 
537  char *pre = NULL;
538  char *options = NULL;
539  const char *post = "";
540  cpl_table *thresholded = NULL;
541 
542  assure( table != NULL, CPL_ERROR_NULL_INPUT, "Null table");
543  assure( colx != NULL, CPL_ERROR_NULL_INPUT, "Null x column");
544  assure( coly != NULL, CPL_ERROR_NULL_INPUT, "Null y column");
545  assure( cpl_table_has_column(table, colx), CPL_ERROR_ILLEGAL_INPUT,
546  "No such column: '%s'", colx);
547  assure( cpl_table_has_column(table, coly), CPL_ERROR_ILLEGAL_INPUT,
548  "No such column: '%s'", coly);
549 
550  assure( cpl_table_get_column_type(table, colx) == CPL_TYPE_INT ||
551  cpl_table_get_column_type(table, colx) == CPL_TYPE_FLOAT ||
552  cpl_table_get_column_type(table, colx) == CPL_TYPE_DOUBLE,
553  CPL_ERROR_TYPE_MISMATCH,
554  "Column '%s' has type '%s'. Numerical type expected",
555  colx,
556  uves_tostring_cpl_type(cpl_table_get_column_type(table, colx)));
557 
558  assure( cpl_table_get_column_type(table, coly) == CPL_TYPE_INT ||
559  cpl_table_get_column_type(table, coly) == CPL_TYPE_FLOAT ||
560  cpl_table_get_column_type(table, coly) == CPL_TYPE_DOUBLE,
561  CPL_ERROR_TYPE_MISMATCH,
562  "Column '%s' has type '%s'. Numerical type expected",
563  coly,
564  uves_tostring_cpl_type(cpl_table_get_column_type(table, coly)));
565 
566  if (plotting_enabled)
567  {
568  const char *pre_format;
569 
570  /* Create options string */
571  va_start(al, format);
572  vsnprintf(title, MAXTITLELENGTH - 1, format, al);
573  va_end(al);
574  title[MAXTITLELENGTH - 1] = '\0';
575 
576  options = title_string(title, cpl_table_get_nrow(table));
577 
578  /* Create pre string */
579  pre_format = "set grid; set xlabel '%s'; set ylabel '%s';";
580  pre = cpl_calloc(strlen(pre_format) + strlen(colx) + strlen(coly) + 1,
581  sizeof(char));
582  /* It's a couple of bytes more than enough */
583  sprintf(pre, pre_format, colx, coly);
584 
585 
586  /* Threshold y-values to median +- 3 sigma before plotting */
587  {
588  double median, sigma, locut, hicut;
589  int i;
590 
591  median = cpl_table_get_column_median(table, coly);
592  sigma = cpl_table_get_column_stdev(table, coly);
593 
594  locut = median - 3*sigma;
595  hicut = median + 3*sigma;
596 
597  /* Copy the data we need, then threshold */
598  thresholded = cpl_table_new(cpl_table_get_nrow(table));
599  cpl_table_duplicate_column(thresholded, coly, table, coly);
600  cpl_table_duplicate_column(thresholded, colx, table, colx);
601 
602  for (i = 0; i < cpl_table_get_nrow(thresholded); i++)
603  {
604  double data = cpl_table_get(thresholded, coly, i, NULL); /* polymorphic */
605 
606  if (data < locut && data > hicut)
607  {
608  cpl_table_set_invalid(thresholded, coly, i);
609  }
610  }
611 
612  }
613 
614  cpl_plot_column(pre,
615  (strcmp(options, "t '%s'") == 0) ? "" : options,
616  post,
617  thresholded, colx, coly);
618 
619  RECOVER_FROM_ERROR(plotter);
620  }
621 
622  cleanup:
623  uves_free_table(&thresholded);
624  cpl_free(pre);
625  cpl_free(options);
626 
627  return cpl_error_get_code();
628 }
629 
630 
631 /*----------------------------------------------------------------------------*/
641 /*----------------------------------------------------------------------------*/
642 static char *
643 title_string(const char *plot_title, int npoints)
644 {
645  /* Option to choose plotting style
646  * depending on the number of points
647  */
648  const char *options = (npoints > 100) ?
649  "w points pointsize 1" :
650  "w linespoints pointsize 1";
651  /* If less than, say, 100 points, connect them with lines */
652 
653  size_t length = strlen("t '' ") + strlen(plot_title) + strlen(options) + 1;
654  char *result = cpl_calloc(length, sizeof(char));
655 
656  snprintf(result, length, "t '%s' %s", plot_title, options);
657 
658  return result;
659 }
660 
#define uves_msg_warning(...)
Print an warning message.
Definition: uves_msg.h:87
#define assure_mem(PTR)
Definition: uves_error.h:181
const char * uves_tostring_cpl_type(cpl_type t)
Convert a CPL type to a string.
Definition: uves_dump.c:378
#define uves_msg_debug(...)
Print a debug message.
Definition: uves_msg.h:97
#define check(CMD,...)
Definition: uves_error.h:198