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

Generated on 28 Feb 2012 for UVES Pipeline Reference Manual by  doxygen 1.6.1