Skip to content
Snippets Groups Projects
plot.cpp 16.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • Wuttke, Joachim's avatar
    ..  
    Wuttke, Joachim committed
    //***************************************************************************//
    
    //* FRIDA: fast reliable interactive data analysis                          *//
    
    Wuttke, Joachim's avatar
    ..  
    Wuttke, Joachim committed
    //* (C) Joachim Wuttke 1990-, v2(C++) 2001-                                 *//
    //* http://apps.jcns.fz-juelich.de/frida                                    *//
    //***************************************************************************//
    
    //! \file  plot.cpp
    
    //! \brief NPlot: plot data and curves
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    #include <string>
    
    #include <memory>
    #include <math.h>
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    #include "defs.hpp"
    #include "list.hpp"
    #include "olf.hpp"
    #include "mem.hpp"
    #include "jsel.hpp"
    #include "zentry.hpp"
    #include "dualplot.hpp"
    #include "plot.hpp"
    #include "curve.hpp"
    
    //**************************************************************************//
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    //*  Subroutines: determine data ranges                                    *//
    
    //**************************************************************************//
    
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    //! Loop over selected data files to determine x range.
    
    void determine_Xrange( CPlot* plot, CList* JSel )
    {
        double inf, sup;
        NOlm::IterateD fiter;
        const vector<double> *vx;
        bool first = true;
        POld fd;
        while((fd=fiter())) {
            JSel->evaluate( 0, fd->nJ()-1 );
    
            for ( int iv=0; iv<JSel->size(); ++iv ) {
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                vx = &( fd->VS( JSel->V[iv] )->x );
    
                for ( int i=0; i<vx->size(); ++i ){
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                    if ( plot->X.logflag && (*vx)[i]<=0 )
                        continue;
                    if ( first ){
                        inf = (*vx)[i];
                        sup = (*vx)[i];
                        first = false;
                    } else {
                        if ( (*vx)[i]<inf ) inf = (*vx)[i];
                        if ( (*vx)[i]>sup ) sup = (*vx)[i];
                    }
                }
            }
        }
        if ( first )
            throw "x range is empty";
        plot->X.setRoundedLimits( "x", inf, sup );
    }
    
    //! Loop over selected files to determine y range for current x range.
    
    void determine_Yrange( CPlot* plot, CList* JSel )
    {
    
        double inf=INFINITY, sup=-INFINITY;
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
        NOlm::IterateO iter;
        POlo f;
        while( (f=iter()) ){
    
            int k = iter.k();
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            POlc fc = P2C( f );
            if ( fc && fc->kconv!=-1 )
                continue;
            POld fd = P2D( f );
            JSel->evaluate( 0, f->nJ()-1 );
    
            for ( int iv=0; iv<JSel->size(); ++iv ){ 
    
                int j = JSel->V[iv];
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                PSpec s;
                if ( fd ){
                    s = fd->VS(j);
                } else {
                    s = PSpec( new CSpec ); 
                    plot->X.set_xgrid( s->x, 97 );
                    fc->curve_val_vec( &(s->y), s->x, k, j );
                }
    
                for ( int i=0; i<s->size(); i++ ) {
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                    if ( !plot->X.contains( s->x[i] ) )
                        continue;
                    if ( plot->Y.logflag && s->y[i]<=0 )
                        continue;
    
                    if (s->y[i]<inf) inf=s->y[i];
                    if (s->y[i]>sup) sup=s->y[i];
    
        if ( inf==INFINITY || sup==-INFINITY )
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            throw "y range is empty";
        plot->Y.setRoundedLimits( "y", inf, sup );
    }
    
    
    //**************************************************************************//
    //*  Subroutines: plot one scan                                            *//
    //**************************************************************************//
    
    //! Plot scan j of data file fd; return number of points plotted.
    
    
    int plot_data( CPlot* plot, POld fd, int k, int j, int pstyle )
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    {
        const PSpec s = fd->VS(j);
    
        int n=s->x.size();
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
        if ( n!=s->y.size() )
            throw "BUG: plot: x.size<>y.size";
        // Filter: x,y -> xp,yp if inside frame
    
        int np=0, nxl=0, nxh=0, nyl=0, nyh=0;
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
        vector<double> xp, yp, dyp;
    
        for ( int i=0; i<n; i++ ) {
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            double x = s->x[i];
            if ( !plot->X.contains(x) ) {
                if ( x<=plot->X.inf ){
                    x = plot->X.inf;
                    nxl++;
                }
                if ( x>=plot->X.sup ){
                    x = plot->X.sup;
                    nxh++;
                }
                if ( !plot->X.force )
                    continue;
            }
            double y = s->y[i];
            if ( !plot->Y.contains(y) ) {
                if ( y<=plot->Y.inf ){
                    y = plot->Y.inf;
                    nyl++;
                }
                if ( y>=plot->Y.sup ){
                    y = plot->Y.sup;
                    nyh++;
                }
                if ( !plot->Y.force )
                    continue;
            }
            if ( np==plot->maxpoints && np<n ) {
                cout << "reached maxpoints at " << s->x[i] << "\n";
            }
            xp.push_back( x );
            yp.push_back( y );
            if ( s->dy.size() )
                dyp.push_back( s->dy[i] );
            np = xp.size();
            if ( np > plot->maxpoints ) // continue in large steps
                i += plot->maxpoints;
        }
        if ( np==0 ) {
            cout << "file " << k << " spec " << j << " all " << n <<
                " points outside plot range:\n";
            if ( nxl )
                cout << "  " << nxl << " points < xmin\n";
            if ( nxh )
                cout << "  " << nxh << " points > xmax\n";
            if ( nyl )
                cout << "  " << nyl << " points < ymin\n";
            if ( nyh )
                cout << "  " << nyh << " points > ymax\n";
        } else {
            plot->addSpec(
    
                false, true, pstyle, xp, yp, dyp, fd->V[j]->z,
    
                fd->xco.str_std(), fd->yco.str_std(),
    
                "data file " + S(k) + " spectrum "+S(j) );
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
        }
        return np;
    }
    
    //! Plot scan j of convolved curve file fc; return number of points plotted.
    
    
    int plot_curve_convolved( CPlot* plot, POlc fc, int k, int j, int cstyle )
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    {
        vector<double> novec;
    
        int kconv, jconv;
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
        PSpec sconv;
    
        NCurveFile::getConv( &sconv, &kconv, &jconv, k, j );
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
        vector<double> xp, yp;
    
        for ( int i=0; i<sconv->size(); ++i ){
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            double x = sconv->x[i];
            if ( plot->X.contains( x ) )
                xp.push_back( x );
        }
        fc->curve_val_vec( &yp, xp, k, j );
        vector<double> xo, yo;
    
        for ( int i=0; i<xp.size(); ++i ){
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            if ( !( plot->X.contains( xp[i] ) &&
                    plot->Y.contains( yp[i] )   ) )
                continue;
            xo.push_back( xp[i] );
            yo.push_back( yp[i] );
        }
        if ( xo.size()==0 ){
    
            cout << "curve k="<<S(k)<<", j="<<S(j)<<
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                " has no points in plot window\n";
        }
    
        plot->addSpec( true, true, cstyle, xo, yo, novec, fc->V[j]->z,
    
                       fc->xco.str_std(), fc->yco.str_std(),
    
                       "curve file "+S(k)+" spectrum "+S(j) );
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
        return xo.size();
    }
    
    
    //! Plot scan j of curve file fc, using grid from file kd.
    
    
    int plot_curve_to_grid( CPlot* plot, POlc fc, int k, int j, int cstyle )
    
    {
        if( fc->kd==-1 )
            throw "data reference not set, incompatible with cg+";
        POld fd = NOlm::mem_get_D(fc->kd);
        if( !fd )
            throw "data reference not found";
        if( j>=fd->nJ() )
            throw "number of spectra does not match";
        vector<double> *xc = &(fd->VS(j)->x);
        vector<double> novec, yc, xp, yp;
        fc->curve_val_vec( &yc, *xc, k, j );
    
        for ( int i=0; i<xc->size(); ++i ) {
    
            if ( plot->X.contains((*xc)[i]) && plot->Y.contains(yc[i]) ) {
                xp.push_back( (*xc)[i] );
                yp.push_back( yc[i] );
            }
        }
        plot->addSpec( true, true, cstyle, xp, yp, novec, fc->V[j]->z,
                       fc->xco.str_std(), fc->yco.str_std(),
                       "curve file "+S(k)+" spectrum "+S(j) );
        return xp.size();
    }
    
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    //! Plot scan j of non-convolved curve file fc on equidistant grid;
    //! return number of points plotted.
    
    
    int plot_curve_equidist( CPlot* plot, POlc fc, int k, int j, int cstyle )
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    {
        vector<double> novec;
        // equidistant grid
        
    
        int npts = plot->equipoints;
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
        vector<double> xc, yc, xp, yp;
        plot->X.set_xgrid( xc, npts );
        fc->curve_val_vec( &yc, xc, k, j );
    
        for ( int i=0; i<npts; ++i ) {
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            if ( plot->X.contains(xc[i]) && plot->Y.contains(yc[i]) ) {
                xp.push_back( xc[i] );
                yp.push_back( yc[i] );
            }
        }
    
        plot->addSpec( true, true, cstyle, xp, yp, novec, fc->V[j]->z,
    
                       fc->xco.str_std(), fc->yco.str_std(),
    
                       "curve file "+S(k)+" spectrum "+S(j) );
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
        return xp.size();
    }
    
    //! Plot scan j of non-convolved curve file fc, refining the grid where
    //! necessary; return number of points plotted.
    
    
    int plot_curve_refine( CPlot* plot, POlc fc, int k, int j, int cstyle )
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    {
        // refinement cares to:
        // - stop/start line when leaving/reentering/crossing(TODO) the frame
        // - TODO interpolate when crossing the horizontal border
        // - interpolate at discontinuities     
        
        vector<double> xc, yc, xn, yn;
        vector<double> novec;
                    
        // start with equidistant grid:
    
        int npts = plot->equipoints;
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
        plot->X.set_xgrid( xc, npts );
    
        // refinement loop:
        for ( int iref=0; ; ++iref ) {
    
            if ( !xc.size() ){
                if ( !iref )
                    throw "BUG: plot_curve_refine called with xc.size()=0";
                else
                    break; // regular exit
            }
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            // cout << "DEB refinement #" <<iref<< ", xc.size=" <<xc.size()<< "\n";
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            // evaluate curve for grid xc:
            fc->curve_val_vec( &yc, xc, k, j );
    
            // for ( int i=0; i<xc.size(); ++i )
    
            // printf ("DEB xc yc %12.6g %12.6g\n", xc[i], yc[i] );
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    
            // merge xc,yc and xn,yn:
            if ( iref==0 ) {
                xn = xc; yn = yc;
            } else {
                vector<double> xa, ya;
    
                int ic=0, in=0;
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                for ( ; ic<xc.size() && in<xn.size(); ) {
                    if ( plot->X.close_enough( xc[ic], xn[ic], 1e-7 ) ){
                        ++in; // skip new point
                    } else if ( xc[ic]<xn[in] ) {
                        xa.push_back( xc[ic] );
                        ya.push_back( yc[ic] );
                        ++ic;
                    } else {
                        xa.push_back( xn[in] );
                        ya.push_back( yn[in] );
                        ++in;
                    }
                }
                for ( ; ic<xc.size(); ++ic ) {
                    xa.push_back( xc[ic] );
                    ya.push_back( yc[ic] );
                }
                for ( ; in<xn.size(); ++in ) {
                    xa.push_back( xn[in] );
                    ya.push_back( yn[in] );
                }
                xn = xa; yn = ya;
            }
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            // cout << "DEB merger -> " << xn.size() << "\n";
    
            // for ( int i=0; i<xn.size(); ++i )
    
            // printf ("DEB xn yn %12.6g %12.6g\n", xn[i], yn[i] );
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    
            // end of loop
            if ( iref>=10 || xn.size()>=plot->maxpoints )
    
                break; // alternate exit: too many refinements or too many points
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    
            // eliminate points outside y range (except border points):
            vector<double> xa, ya;
            xa.push_back( xn[0] );
            ya.push_back( yn[0] );
    
            for ( int i=1; i<xn.size()-1; ++i) {
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            new_segment:
                xa.push_back( xn[i] );
                ya.push_back( yn[i] );
                if ( !plot->Y.contains(yn[i]) ) {
    
                    for ( int ii=i+1; ii<xn.size()-1; ++ii ) {
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                        if ( plot->Y.contains(yn[ii]) ) {
                            if ( ii-1>i ) {
                                xa.push_back( xn[ii-1] );
                                ya.push_back( yn[ii-1] );
                            }
                            i = ii;
                            goto new_segment;
                        }
                    }
                }
            }
            xa.push_back( xn.back() );
            ya.push_back( yn.back() );
            xn = xa; yn = ya;
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            // cout << "DEB within frame -> " << xn.size() << "\n";
    
            // for ( int i=0; i<xn.size(); ++i )
    
            // printf ("DEB xy %12.6g %12.6g\n", xn[i], yn[i] );
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    
            // set additional base points:
            bool insert_next = false;
            xc.clear();
    
            for ( int i=1; i<xn.size()-1; ++i ) {
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                if ( i<xn.size()-2 ) {
                    double yi = ( (xn[i+1]-xn[i])*yn[i-1] +
                                  (xn[i]-xn[i-1])*yn[i+1] ) /
                        (xn[i+1]-xn[i-1]);
                    if ( !plot->Y.close_enough( yn[i], yi, 0.005 ) ) {
                        xc.push_back( (xn[i-1] + xn[i])/2 );
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                        // cout << "DEB disc " << xc.back() << "\n";
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                        insert_next = true;
                        continue;
                    }
                }
                if ( insert_next ) {
                    xc.push_back( (xn[i-1] + xn[i])/2 );
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                    // cout << "DEB next " << xc.back() << "\n";
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                    insert_next = false;
                    continue;
                }
    
                if ( ( plot->Y.contains(yn[i]) &&
                       !plot->Y.contains(yn[i-1]) ) ||
                     ( !plot->Y.contains(yn[i]) &&
                       plot->Y.contains(yn[i-1]) ) ) {
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                    // cout << "DEB edge " << xc.back() << "\n";
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                    xc.push_back( (xn[i-1] + xn[i])/2 );
                    continue;
                }
            }
            // temporary check
            if( xc.size() )
    
                for ( int i=0; i<xc.size()-1; ++i )
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                    if ( xc[i+1]<=xc[i] )
                        throw "BUG: new base points not sorted at " +
    
                            S(i) + ": " + S(xc[i]) + " " + S(xc[i+1]);
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
        }
    
        // divide into segments and plot:
        vector<double> xa, ya;
        bool first_seg = true;
        npts = 0;
    
        for ( int i=0; i<xn.size(); ++i ) {
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            if ( plot->Y.contains(yn[i]) ) {
                xa.push_back( xn[i] );
                ya.push_back( yn[i] );
            } 
            if ( !plot->Y.contains(yn[i]) || i==xn.size()-1 ) {
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                if ( xa.size() ){
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                    // cout << "DEB segment -> " << xa.size() << "\n";
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                    plot->addSpec(
                        true, first_seg, cstyle, xa, ya,
    
                        novec, fc->V[j]->z, fc->xco.str_std(), fc->yco.str_std(),
    
                        "curve file "+S(k)+ " spectrum "+S(j) );
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                    xa.clear();
                    ya.clear();
                    first_seg = false;
                }
            }
        }
        return npts;
    }
    
    
    
    //**************************************************************************//
    //*  Plot routine is accessible from the main menu                         *//
    //**************************************************************************//
    
    //! Plot set of spectra, or add to open plot.
    
    void NPlot::Plot( class CPlot *plot, bool add, const string& mode )
    
        NOlm::IterateO fiter;
    
        if        ( mode=="ask" ) {
    
            JSelAsk( "Plot which spectra", &jSel, &JSel );
    
        } else if ( mode == "next" ) {
    
            JSel.increment( +1, 0, NOlm::nJ_max()-1 );
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            cout << "plotting spectra " << JSel << "\n";
    
    Wuttke, Joachim's avatar
    c  
    Wuttke, Joachim committed
            jSel = JSel.str();
    
        } else if ( mode == "prev" ) {
    
            JSel.increment( -1, 0, NOlm::nJ_max()-1 );
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            cout << "plotting spectra " << JSel << "\n";
    
    Wuttke, Joachim's avatar
    c  
    Wuttke, Joachim committed
            jSel = JSel.str();
    
        if ( !add ) { // prepare frame (ranges, labels)
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            if (!plot->X.finite())
                determine_Xrange( plot, &JSel );
            if (!plot->Y.finite())
                determine_Yrange( plot, &JSel );
    
    
            // build label: (zur Zeit nur vom ersten File; definiere +=)
    
            CCoord xCo = NOlm::sel_first()->xco;
            CCoord yCo = NOlm::sel_first()->yco;
    
            plot->plotFrame( xCo.str_ps(), yCo.str_ps() );
    
        while( POlo f = fiter() ){
    
            int k = fiter.k();
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            POld fd = P2D( f );
            POlc fc = P2C( f );
    
            for (int i=0; i<f->lDoc.size(); i++)
    
                plot->docTxLine( "  " + f->lDoc[i] );
            if ( fc ) {
                vector<string> vs = fc->infoFile();
    
                for (int i=0; i<vs.size(); i++)
    
                    plot->docTxLine( "  " + vs[i] );
                plot->docTxLine( "  " + fc->infoScanHeader() );
            }
    
    Wuttke, Joachim's avatar
    ..  
    Wuttke, Joachim committed
    
    
            JSel.evaluate( 0, f->nJ()-1 );
    
            for ( int iv=0; iv<JSel.size(); ++iv){
    
                int j = JSel.V[iv];
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                    if ( !plot_data( plot, fd, k, j, pstyle ) )
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                } else if ( fc ) {
                    if        ( fc->kconv!=-1 ) {
                        if ( !plot_curve_convolved( plot, fc, k, j, cstyle ) )
                            continue;
    
                    } else if ( fc->plot_to_grid ) {
                        if ( !plot_curve_to_grid( plot, fc, k, j, cstyle ) )
                            continue;
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                    } else if ( !plot->refine ) {
                        if ( !plot_curve_equidist( plot, fc, k, j, cstyle ) )
                            continue;
                    } else {
                        if ( !plot_curve_refine( plot, fc, k, j, cstyle ) )
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
                } else {
                    throw "PROGRAM ERROR plot: unexpected file type";
                }
    
    
                if        ( fd ) {
                    plot->docPtTxLine( "  " + f->infoLine( j ), pstyle );
                    ++pstyle;
                } else if ( fc ) {
                    plot->docCvTxLine( "  " + f->infoLine( j ), cstyle );
                    ++cstyle;
                }