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

Generated on Tue Jun 19 14:39:17 2007 for UVES Pipeline Reference Manual by  doxygen 1.4.6