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

Generated on 9 Mar 2012 for UVES Pipeline Reference Manual by  doxygen 1.6.1