uves_plot.c

00001 /*                                                                              *
00002  *   This file is part of the ESO UVES Pipeline                                 *
00003  *   Copyright (C) 2004,2005 European Southern Observatory                      *
00004  *                                                                              *
00005  *   This library is free software; you can redistribute it and/or modify       *
00006  *   it under the terms of the GNU General Public License as published by       *
00007  *   the Free Software Foundation; either version 2 of the License, or          *
00008  *   (at your option) any later version.                                        *
00009  *                                                                              *
00010  *   This program is distributed in the hope that it will be useful,            *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of             *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
00013  *   GNU General Public License for more details.                               *
00014  *                                                                              *
00015  *   You should have received a copy of the GNU General Public License          *
00016  *   along with this program; if not, write to the Free Software                *
00017  *   Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA       *
00018  *                                                                              */
00019 
00020 /*
00021  * $Author: jmlarsen $
00022  * $Date: 2007/08/21 13:08:26 $
00023  * $Revision: 1.32 $
00024  * $Name: uves-3_4_5 $
00025  * $Log: uves_plot.c,v $
00026  * Revision 1.32  2007/08/21 13:08:26  jmlarsen
00027  * Removed irplib_access module, largely deprecated by CPL-4
00028  *
00029  * Revision 1.31  2007/06/06 08:17:33  amodigli
00030  * replace tab with 4 spaces
00031  *
00032  * Revision 1.30  2007/05/23 13:03:19  jmlarsen
00033  * Added missing include directive
00034  *
00035  * Revision 1.29  2007/05/22 11:31:35  jmlarsen
00036  * Removed image plotting functionality
00037  *
00038  * Revision 1.28  2007/05/22 08:44:37  jmlarsen
00039  * Don't rely on popen/pclose
00040  *
00041  * Revision 1.27  2007/04/24 09:41:35  jmlarsen
00042  * Removed deprecated irplib_string_concatenate_all
00043  *
00044  * Revision 1.26  2007/01/15 08:48:41  jmlarsen
00045  * Shortened lines
00046  *
00047  * Revision 1.25  2006/11/15 15:02:15  jmlarsen
00048  * Implemented const safe workarounds for CPL functions
00049  *
00050  * Revision 1.23  2006/11/15 14:04:08  jmlarsen
00051  * Removed non-const version of parameterlist_get_first/last/next which is 
00052  * already in CPL, added const-safe wrapper, unwrapper and deallocator functions
00053  *
00054  * Revision 1.22  2006/11/13 14:23:55  jmlarsen
00055  * Removed workarounds for CPL const bugs
00056  *
00057  * Revision 1.21  2006/11/06 15:19:41  jmlarsen
00058  * Removed unused include directives
00059  *
00060  * Revision 1.20  2006/09/20 12:53:57  jmlarsen
00061  * Replaced stringcat functions with uves_sprintf()
00062  *
00063  * Revision 1.19  2006/08/23 15:09:23  jmlarsen
00064  * Added uves_plot_bivectors
00065  *
00066  * Revision 1.18  2006/08/18 07:07:43  jmlarsen
00067  * Switched order of cpl_calloc arguments
00068  *
00069  * Revision 1.17  2006/08/17 13:56:53  jmlarsen
00070  * Reduced max line length
00071  *
00072  * Revision 1.16  2006/06/01 14:43:17  jmlarsen
00073  * Added missing documentation
00074  *
00075  * Revision 1.15  2006/05/12 15:07:35  jmlarsen
00076  * Implemented 3 sigma clipping to have better ranges for plots
00077  *
00078  * Revision 1.14  2006/04/24 09:22:53  jmlarsen
00079  * Renamed shadowing variable
00080  *
00081  * Revision 1.13  2006/02/21 14:26:54  jmlarsen
00082  * Minor changes
00083  *
00084  * Revision 1.12  2005/12/19 16:17:56  jmlarsen
00085  * Replaced bool -> int
00086  *
00087  */
00088 
00089 #ifdef HAVE_CONFIG_H
00090 #  include <config.h>
00091 #endif
00092 
00093 /*----------------------------------------------------------------------------*/
00115 /*----------------------------------------------------------------------------*/
00116 
00117 /* If we can link to setenv but it is not declared, then declare it manually */
00118 #if defined HAVE_SETENV && HAVE_SETENV
00119 #if defined HAVE_DECL_SETENV && !HAVE_DECL_SETENV
00120 int setenv(const char *name, const char *value, int overwrite);
00121 #endif
00122 #endif
00123 
00124 /*-----------------------------------------------------------------------------
00125                                 Includes
00126  -----------------------------------------------------------------------------*/
00127 
00128 #include <uves_plot.h>
00129 
00130 #include <uves_dump.h>
00131 #include <uves_utils_wrappers.h>
00132 #include <uves_error.h>
00133 #include <uves_msg.h>
00134 
00135 #include <irplib_plot.h>
00136 #include <irplib_utils.h>
00137 
00138 #include <cpl.h>
00139 
00140 #include <stdarg.h>
00141 #include <stdio.h>
00142 #include <string.h>
00143 #include <stdlib.h>   /* setenv */
00144 
00145 /*-----------------------------------------------------------------------------
00146                             Functions prototypes
00147  -----------------------------------------------------------------------------*/
00148 static char *title_string(const char *title, int npoints);
00149 /*-----------------------------------------------------------------------------
00150                             Defines
00151  -----------------------------------------------------------------------------*/
00152 #define MAXTITLELENGTH 10000
00153 #define RECOVER_FROM_ERROR(EXTERNAL_COMMAND) do {  \
00154     if (cpl_error_get_code() != CPL_ERROR_NONE)    \
00155     {                                              \
00156        uves_msg_error("Could not send plot to "    \
00157               "command '%s': "             \
00158                "%s in '%s'",               \
00159                        EXTERNAL_COMMAND,           \
00160                cpl_error_get_message(),    \
00161                cpl_error_get_where());     \
00162        cpl_error_reset();                          \
00163        goto cleanup;                               \
00164     } } while (false)
00165 
00166 
00167 static char title[MAXTITLELENGTH];
00168 static bool plotting_enabled = false;           /* If caller forgets to call 
00169                            the initializer, plotting
00170                            will be disabled */
00171 static const char *plotter = "";
00172 
00175 /*-----------------------------------------------------------------------------
00176                         Implementation
00177  -----------------------------------------------------------------------------*/
00178 
00179 /*----------------------------------------------------------------------------*/
00191 /*----------------------------------------------------------------------------*/
00192 cpl_error_code
00193 uves_plot_initialize(const char *plotter_command)
00194 {
00195     char *test_cmd = NULL;
00196     char *first_word = NULL;
00197 
00198     plotting_enabled = (strcmp(plotter_command, "no") != 0);
00199     
00200     /* Note that 'setenv' is *not* ANSI C. If it does not exist, tell user to
00201      *  define the environment variable him-/herself.
00202      */
00203 
00204     if (plotting_enabled)
00205     {
00206         const char *env = "IRPLIB_PLOTTER";
00207 
00208         /* Check if 'which x' returns non-zero.
00209            x is the first word of plotting command.
00210            Note: this assumes the environment understands
00211            'which' and '> /dev/null'. If not,
00212            plotting will be disabled.
00213         */
00214         first_word = uves_sprintf("%s ", plotter_command);
00215         
00216         assure( strtok(first_word, " ") != NULL, CPL_ERROR_ILLEGAL_OUTPUT,
00217             "Error splitting string '%s'", first_word);
00218         
00219         test_cmd = uves_sprintf("which %s > /dev/null", first_word);
00220         
00221 #if defined HAVE_SETENV && HAVE_SETENV
00222 
00223         if (setenv(env, plotter_command, 1) != 0)
00224         {
00225             uves_msg_warning("Could not set environment variable '%s'. "
00226                      "Plotting disabled!", env);
00227             plotting_enabled = false;
00228         }
00229         /* popen may return non-NULL even when the external command
00230            is not available. This causes the recipe to crash when writing
00231            to an invalid FILE pointer.
00232            Therefore, check (using 'which') that the
00233            command is available.
00234         */
00235         else if (system(test_cmd) != 0)
00236         {
00237             uves_msg_debug("Command '%s' returned non-zero", test_cmd);
00238             uves_msg_warning("Command '%s' failed. Plotting disabled!", test_cmd);
00239             plotting_enabled = false;
00240         }
00241         else
00242         {
00243             /* Setenv succeeded, remember command */
00244             uves_msg_debug("setenv %s='%s' succeeded", env, plotter_command);
00245             uves_msg_debug("Command '%s' returned zero", test_cmd);
00246 
00247             plotter = plotter_command;
00248         }
00249 #else
00250         uves_msg_warning("setenv() is not available on this platform. You have to manually "
00251                  "set the environment variable '%s' to '%s'", env, plotter_command);
00252 
00253         plotter = plotter_command;
00254 
00255 #endif
00256     }   
00257    
00258   cleanup:
00259     cpl_free(test_cmd);
00260     cpl_free(first_word);
00261 
00262     return cpl_error_get_code();
00263 }
00264 
00265 /*----------------------------------------------------------------------------*/
00280 /*----------------------------------------------------------------------------*/
00281 cpl_error_code
00282 uves_plot_image_rows(const cpl_image *image, int first_row, int last_row, int step, 
00283              const char *xtitle, const char *ytitle, const char *format, ...)
00284 {
00285     va_list al;
00286     
00287     char *pre = NULL;
00288     char *options = NULL;
00289     const char *post = "";
00290     cpl_image *thresholded = NULL;
00291 
00292     assure( image != NULL, CPL_ERROR_NULL_INPUT, "Null image");
00293     if (xtitle == NULL) xtitle = "";
00294     if (ytitle == NULL) ytitle = "";
00295     assure( 1 <= first_row && first_row <= last_row && 
00296         last_row <= cpl_image_get_size_y(image), 
00297         CPL_ERROR_ILLEGAL_INPUT,
00298         "Illegal rows: %d - %d; rows in image = %d", 
00299         first_row, last_row, cpl_image_get_size_y(image));
00300     
00301     assure( step >= 1, CPL_ERROR_ILLEGAL_INPUT,
00302         "Illegal step size: %d", step);
00303 
00304     if (plotting_enabled)
00305     {
00306         const char *pre_format;
00307         int row;
00308         
00309         /* Create pre string */
00310         pre_format = "set grid; set xlabel '%s'; set ylabel '%s';";
00311         pre = cpl_calloc(strlen(pre_format) + 
00312                  strlen(xtitle) + strlen(ytitle) + 1,
00313                  sizeof(char));
00314         sprintf(pre, pre_format, xtitle, ytitle);
00315 
00316         
00317         va_start(al, format);
00318         vsnprintf(title, MAXTITLELENGTH - 1, format, al);
00319         va_end(al);
00320         title[MAXTITLELENGTH - 1] = '\0';
00321         
00322         options = title_string(title, cpl_image_get_size_x(image));
00323 
00324         /* Threshold each row */
00325         thresholded = cpl_image_duplicate(image);
00326         for (row = first_row; row <= last_row; row++)
00327         {
00328             int nx = cpl_image_get_size_x(thresholded);
00329             double median = cpl_image_get_median_window(thresholded,
00330                                 1, first_row,
00331                                 nx, last_row);
00332             double stdev = cpl_image_get_stdev_window(thresholded,
00333                                   1, first_row,
00334                                   nx, last_row);
00335 
00336             double locut = median - 3*stdev;
00337             double hicut = median + 3*stdev;
00338             
00339             int x, pis_rejected;
00340 
00341             for (x = 1; x <= nx; x++)
00342             {
00343                 double data = 
00344                 cpl_image_get(thresholded, x, row, &pis_rejected);
00345                 if (data < locut) data = locut;
00346                 if (data > hicut) data = hicut;
00347                 cpl_image_set(thresholded, x, row, data);
00348             }
00349         }
00350         
00351         irplib_image_row_plot(pre,
00352                   (strcmp(options, "t '%s'") == 0) ? "" : options, 
00353                   post, 
00354                   thresholded,
00355                   first_row, last_row, step);
00356         
00357         RECOVER_FROM_ERROR(plotter);
00358     }
00359         
00360   cleanup:
00361     uves_free_image(&thresholded);
00362     cpl_free(pre);
00363     cpl_free(options);
00364 
00365     return cpl_error_get_code();
00366 }
00367 
00368 /*----------------------------------------------------------------------------*/
00386 /*----------------------------------------------------------------------------*/
00387 cpl_error_code
00388 uves_plot_image_columns(const cpl_image *image, int first_column, int last_column, int step,
00389             const char *xtitle, const char *ytitle, const char *format, ...)
00390 {
00391     va_list al;
00392     
00393     char *pre = NULL;
00394     char *options = NULL;
00395     const char *post = "";
00396     cpl_image *thresholded = NULL;
00397 
00398     assure( image != NULL, CPL_ERROR_NULL_INPUT, "Null image");
00399     if (xtitle == NULL) xtitle = "";
00400     if (ytitle == NULL) ytitle = "";
00401     assure( 1 <= first_column && first_column <= last_column &&
00402         last_column <= cpl_image_get_size_x(image), 
00403         CPL_ERROR_ILLEGAL_INPUT,
00404         "Illegal columns: %d - %d; columns in image = %d", 
00405         first_column, last_column, cpl_image_get_size_x(image));
00406     
00407     assure( step >= 1, CPL_ERROR_ILLEGAL_INPUT,
00408         "Illegal step size: %d", step);
00409     
00410     if (plotting_enabled)
00411     {
00412         const char *pre_format;
00413         int col;
00414 
00415         /* Create pre string */
00416         pre_format = "set grid; set xlabel '%s'; set ylabel '%s';";
00417         pre = cpl_calloc(strlen(pre_format) + 
00418                  strlen(xtitle) + strlen(ytitle) + 1,
00419                  sizeof(char));
00420         sprintf(pre, pre_format, xtitle, ytitle);
00421         
00422         va_start(al, format);
00423         vsnprintf(title, MAXTITLELENGTH - 1, format, al);
00424         va_end(al);
00425         title[MAXTITLELENGTH - 1] = '\0';
00426         
00427         options = title_string(title, cpl_image_get_size_y(image));
00428 
00429         /* Threshold each column */
00430         thresholded = cpl_image_duplicate(image);
00431         for (col = first_column; col <= last_column; col++)
00432         {
00433             int ny = cpl_image_get_size_x(thresholded);
00434             double median = cpl_image_get_median_window(thresholded,
00435                                 first_column, 1,
00436                                 last_column, ny);
00437             double stdev = cpl_image_get_stdev_window(thresholded,
00438                                   first_column, 1,
00439                                   last_column, ny);
00440 
00441             double locut = median - 3*stdev;
00442             double hicut = median + 3*stdev;
00443             
00444             int y, pis_rejected;
00445 
00446             for (y = 1; y <= ny; y++)
00447             {
00448                 double data = cpl_image_get(thresholded, col, y, &pis_rejected);
00449                 if (data < locut) data = locut;
00450                 if (data > hicut) data = hicut;
00451                 cpl_image_set(thresholded, col, y, data);
00452             }
00453         }
00454         
00455         
00456         check( irplib_image_col_plot(pre,
00457                      (strcmp(options, "t '%s'") == 0) ? "" : options, 
00458                      post, 
00459                      image,
00460                      first_column, last_column, step), 
00461            "Error plotting image");
00462         
00463         RECOVER_FROM_ERROR(plotter);
00464     }
00465     
00466   cleanup:
00467     uves_free_image(&thresholded);
00468     cpl_free(pre);
00469     cpl_free(options);
00470 
00471     return cpl_error_get_code();
00472 }
00473 
00474 /*----------------------------------------------------------------------------*/
00488 /*----------------------------------------------------------------------------*/
00489 void
00490 uves_plot_bivectors(cpl_bivector **bivectors, char **titles, 
00491             int N, const char *xtitle,
00492             const char *ytitle)
00493 {
00494     char *pre = NULL;
00495     char **options = NULL;
00496     const char *post = "";
00497 
00498     options = cpl_calloc(N, sizeof(char *)); /* Initialized to NULL */
00499     assure_mem( options );
00500 
00501     if (plotting_enabled)
00502     {
00503         int npoints, i;
00504         cpl_bivector *temp;
00505         char *temps;
00506 
00507         /* Create options strings */
00508         
00509         npoints = 0;
00510         for (i = 0; i < N; i++)
00511         {
00512             npoints += cpl_bivector_get_size(bivectors[i]);
00513         }
00514         for (i = 0; i < N; i++)
00515         {        
00516             options[i] = title_string(titles[i], npoints);
00517         }
00518         
00519         
00520         {
00521         double datamax = cpl_vector_get_max(cpl_bivector_get_y(bivectors[0]));
00522         double datamin = cpl_vector_get_min(cpl_bivector_get_y(bivectors[0]));
00523 
00524         double locut = datamin - 0.2*(datamax-datamin);
00525         double hicut = datamax + 0.2*(datamax-datamin);
00526         
00527         for (i = 0; i < N; i++)
00528             {
00529             int j;
00530             for (j = 0; j < cpl_bivector_get_size(bivectors[i]); j++)
00531                 {
00532                 if (cpl_bivector_get_y_data(bivectors[i])[j] < locut)
00533                     {
00534                     cpl_bivector_get_y_data(bivectors[i])[j] = locut;
00535                     }
00536                 if (cpl_bivector_get_y_data(bivectors[i])[j] > hicut)
00537                     {
00538                     cpl_bivector_get_y_data(bivectors[i])[j] = hicut;
00539                     }
00540                 }
00541             }
00542         }
00543 
00544         /* Swap first/last bivectors */
00545         temp = bivectors[0];
00546         bivectors[0] = bivectors[N-1];
00547         bivectors[N-1] = temp;
00548         
00549         temps = options[0];
00550         options[0] = options[N-1];
00551         options[N-1] = temps;
00552         
00553         pre = uves_sprintf(
00554         "set grid; set xlabel '%s'; set ylabel '%s';", xtitle, ytitle);
00555         
00556         irplib_bivectors_plot(pre,
00557                   (const char **)options,
00558                   post,
00559                   (const cpl_bivector **)bivectors, N);
00560         
00561         RECOVER_FROM_ERROR(plotter);
00562     }
00563 
00564   cleanup:
00565     cpl_free(pre);
00566     {
00567     int i;
00568     for (i = 0; i < N; i++)
00569         {        
00570         cpl_free(options[i]);
00571         }
00572     }
00573     cpl_free(options);
00574     return;
00575 }
00576 
00577 /*----------------------------------------------------------------------------*/
00593 /*----------------------------------------------------------------------------*/
00594 cpl_error_code
00595 uves_plot_table(const cpl_table *table, const char *colx, const char *coly, 
00596         const char *format, ...)
00597 {
00598     va_list al;
00599     
00600     char *pre = NULL;
00601     char *options = NULL;
00602     const char *post = "";
00603     cpl_table *thresholded = NULL;
00604 
00605     assure( table != NULL, CPL_ERROR_NULL_INPUT, "Null table");
00606     assure( colx  != NULL, CPL_ERROR_NULL_INPUT, "Null x column");
00607     assure( coly  != NULL, CPL_ERROR_NULL_INPUT, "Null y column");
00608     assure( cpl_table_has_column(table, colx), CPL_ERROR_ILLEGAL_INPUT,
00609         "No such column: '%s'", colx);
00610     assure( cpl_table_has_column(table, coly), CPL_ERROR_ILLEGAL_INPUT,
00611         "No such column: '%s'", coly);
00612     
00613     assure( cpl_table_get_column_type(table, colx) == CPL_TYPE_INT    ||
00614         cpl_table_get_column_type(table, colx) == CPL_TYPE_FLOAT  ||
00615         cpl_table_get_column_type(table, colx) == CPL_TYPE_DOUBLE, 
00616         CPL_ERROR_TYPE_MISMATCH,
00617         "Column '%s' has type '%s'. Numerical type expected",
00618         colx,
00619         uves_tostring_cpl_type(cpl_table_get_column_type(table, colx)));
00620     
00621     assure( cpl_table_get_column_type(table, coly) == CPL_TYPE_INT    ||
00622         cpl_table_get_column_type(table, coly) == CPL_TYPE_FLOAT  ||
00623         cpl_table_get_column_type(table, coly) == CPL_TYPE_DOUBLE, 
00624         CPL_ERROR_TYPE_MISMATCH,
00625         "Column '%s' has type '%s'. Numerical type expected",
00626         coly,
00627         uves_tostring_cpl_type(cpl_table_get_column_type(table, coly)));
00628     
00629     if (plotting_enabled)
00630     {
00631         const char *pre_format;
00632 
00633         /* Create options string */
00634         va_start(al, format);
00635         vsnprintf(title, MAXTITLELENGTH - 1, format, al);
00636         va_end(al);
00637         title[MAXTITLELENGTH - 1] = '\0';
00638         
00639         options = title_string(title, cpl_table_get_nrow(table));
00640         
00641         /* Create pre string */
00642         pre_format = "set grid; set xlabel '%s'; set ylabel '%s';";
00643         pre = cpl_calloc(strlen(pre_format) + strlen(colx) + strlen(coly) + 1, 
00644                  sizeof(char));  
00645                              /* It's a couple of bytes more than enough */
00646         sprintf(pre, pre_format, colx, coly);
00647 
00648 
00649         /* Threshold y-values to median +- 3 sigma before plotting */
00650         {
00651         double median, sigma, locut, hicut;
00652         int i;
00653         
00654         median = cpl_table_get_column_median(table, coly);
00655         sigma  = cpl_table_get_column_stdev(table, coly);
00656         
00657         locut = median - 3*sigma;
00658         hicut = median + 3*sigma;
00659         
00660         /* Copy the data we need, then threshold */
00661         thresholded = cpl_table_new(cpl_table_get_nrow(table));
00662         cpl_table_duplicate_column(thresholded, coly, table, coly);
00663         cpl_table_duplicate_column(thresholded, colx, table, colx);
00664 
00665         for (i = 0; i < cpl_table_get_nrow(thresholded); i++)
00666             {
00667             double data = cpl_table_get(thresholded, coly, i, NULL); /* polymorphic */
00668             
00669             if (data < locut && data > hicut)
00670                 {
00671                 cpl_table_set_invalid(thresholded, coly, i);
00672                 }
00673             }
00674 
00675         }
00676 
00677         irplib_table_plot(pre,
00678                   (strcmp(options, "t '%s'") == 0) ? "" : options, 
00679                   post,
00680                   thresholded, colx, coly);
00681 
00682         RECOVER_FROM_ERROR(plotter);
00683     }
00684 
00685   cleanup:
00686     uves_free_table(&thresholded);
00687     cpl_free(pre);
00688     cpl_free(options);
00689 
00690     return cpl_error_get_code();
00691 }
00692 
00693 
00694 /*----------------------------------------------------------------------------*/
00704 /*----------------------------------------------------------------------------*/
00705 static char *
00706 title_string(const char *plot_title, int npoints)
00707 {
00708     /* Option to choose plotting style
00709      * depending on the number of points 
00710      */
00711     const char *options = (npoints > 100) ?
00712     "w points pointsize 1" :
00713     "w linespoints pointsize 1";
00714     /* If less than, say, 100 points, connect them with lines */
00715 
00716     size_t length = strlen("t '' ") + strlen(plot_title) + strlen(options) + 1;
00717     char *result = cpl_calloc(length, sizeof(char));
00718     
00719     snprintf(result, length, "t '%s' %s", plot_title, options);
00720     
00721     return result;
00722 }
00723 

Generated on Thu Nov 15 14:32:29 2007 for UVES Pipeline Reference Manual by  doxygen 1.5.1