Skip to content
Snippets Groups Projects
Histogram.h 6.11 KiB
Newer Older
  • Learn to ignore specific revisions
  • Dmitri Naumov's avatar
    Dmitri Naumov committed
    /**
     * \file
     * \author Dmitrij Naumov
    
     * \brief Implementation of Histogram class.
     *
    
    Dmitri Naumov's avatar
    Dmitri Naumov committed
     * \copyright
    
     * Copyright (c) 2012-2019, OpenGeoSys Community (http://www.opengeosys.org)
    
    Dmitri Naumov's avatar
    Dmitri Naumov committed
     *            Distributed under a Modified BSD License.
     *              See accompanying file LICENSE.txt or
     *              http://www.opengeosys.org/project/license
    
    #include <fstream>
    
    #include <iosfwd>
    #include <iterator>
    #include <utility>
    
    Tom Fischer's avatar
    Tom Fischer committed
    #include <logog/include/logog.hpp>
    
    namespace BaseLib
    
    {
    /** Basic Histogram implementation.
     *
     * Creates histogram from input data of type \c T.
     */
    template <typename T>
    class Histogram
    {
    
    Dmitri Naumov's avatar
    Dmitri Naumov committed
    public:
    
        using Data =
            typename std::vector<double>;  /// Underlying input data vector type.
    
    Dmitri Naumov's avatar
    Dmitri Naumov committed
    
    public:
    
        /** Creates histogram of the given element in the range \c [first, last).
         *
         * Input data is copied into \c std::vector.
         *
    
         * \param first Range of elements to create histogram from.
         * \param last Range of elements to create histogram from.
    
         * \param nr_bins Number of bins in histogram.
         * \param computeHistogram Compute histogram if set. If not set user must
         *        call \c update() before accessing data.
         */
        template <typename InputIterator>
        Histogram(InputIterator first, InputIterator last, const int nr_bins = 16,
                  const bool computeHistogram = true )
            : _data(first, last), _nr_bins(nr_bins)
        {
            init(computeHistogram);
        }
    
        /** Creates histogram from \c std::vector.
         * \param data Input vector.
         * \param nr_bins Number of bins in histogram.
         * \param computeHistogram Compute histogram if set. If not set user must call
         * \c update() before accessing data.
         */
    
        Histogram(std::vector<T> data, const unsigned int nr_bins = 16,
    
                  const bool computeHistogram = true)
    
            : _data(std::move(data)), _nr_bins(nr_bins)
    
        {
            init(computeHistogram);
        }
    
        /** Updates histogram using sorted \c _data vector.
         *
         * Start histogram creation with first element. Then find first element in
         * the next histogram bin. Number of elments in the bin is the difference
         * between these two iterators.
         * \verbatim
           [0.1, 0.2, ..., 0.7 , ..., 0.7+binWidth = 0.9,  1.0  , ..., last]
                           it             itEnd - 1      itEnd
           \endverbatim
         */
        void update()
        {
            if (!_dirty)
    
                return;
    
    
            _bin_width = (_max - _min) / _nr_bins;
    
    
            auto it = _data.begin();
    
            for (unsigned int bin = 0; bin < _nr_bins; bin++)
            {
    
                auto itEnd = std::upper_bound(it, _data.end(),
                                              _min + (bin + 1) * _bin_width);
    
                _histogram[bin] = std::distance(it, itEnd);
                it = itEnd;
            }
            _dirty = false;
        }
    
        void setMinimum(const T& minimum) { _min = minimum; _dirty = true; }
        void setMaximum(const T& maximum) { _max = maximum; _dirty = true; }
    
        const Data& getSortedData() const { return _data; }
        const std::vector<std::size_t>& getBinCounts() const { return _histogram; }
    
    Norihiro Watanabe's avatar
    Norihiro Watanabe committed
        const unsigned int& getNumberOfBins() const { return _nr_bins; }
    
        const T& getMinimum() const { return _min; }
        const T& getMaximum() const { return _max; }
        const T& getBinWidth() const { return _bin_width; }
    
        void
        prettyPrint(std::ostream& os, const unsigned int line_width = 16) const
        {
            const std::size_t count_max =
                    *std::max_element(_histogram.begin(), _histogram.end());
            for (unsigned int bin = 0; bin < _nr_bins; ++bin)
            {
                os << "[" << _min + bin * _bin_width << ", " << _min +
                        (bin + 1) * _bin_width << ")\t";
                os << _histogram[bin] << "\t";
    
                const int n_stars =
                        std::ceil(line_width * ((double)_histogram[bin] / count_max));
                for (int star = 0; star < n_stars; star++)
    
                    os << "*";
    
                os << "\n";
            }
        }
    
        int write(std::string const& file_name, std::string const& data_set_name, std::string const& param_name) const
        {
            if (file_name.empty())
            {
                ERR ("No file name specified.");
                return 1;
            }
    
            std::ofstream out (file_name);
            if (!out)
            {
                ERR("Error writing histogram: Could not open file.");
                return 1;
            }
    
            out << "# Histogram for parameter " << param_name << " of data set " << data_set_name << "\n";
    
    Norihiro Watanabe's avatar
    Norihiro Watanabe committed
            std::size_t const n_bins = this->getNumberOfBins();
    
            std::vector<std::size_t> const& bin_cnts(this->getBinCounts());
            double const min (this->getMinimum());
            double const bin_width (this->getBinWidth());
    
            for (std::size_t k(0); k < n_bins; k++)
    
            {
                out << min + k * bin_width << " " << bin_cnts[k] << "\n";
            }
    
            out.close ();
            return 0;
        }
    
    Dmitri Naumov's avatar
    Dmitri Naumov committed
    protected:
    
        /** Initialize class members after constructor call.
         */
        void init(const bool computeHistogram = true)
        {
            std::sort(_data.begin(), _data.end());
            _histogram.resize(_nr_bins);
            _min = _data.front();
            _max = _data.back();
            _bin_width = (_max - _min) / _nr_bins;
    
            _dirty = true;
            if (computeHistogram)
    
                update();
    
        }
    
        Data _data;
        const unsigned int _nr_bins;
        std::vector<std::size_t> _histogram;
        T _min, _max; ///< Minimum and maximum input data values.
        T _bin_width;
    
    Dmitri Naumov's avatar
    Dmitri Naumov committed
    
    private:
    
        bool _dirty; ///< When set \c update() will recompute histogram.
    
    };
    
    /** Writes histogram to output stream.
     *
     * Writes histogram properties in this order:
     * number of bins, minimum, maximum, bin0 count, ..., binN-1 count.
     */
    template <typename T>
    std::ostream&
    operator<<(std::ostream& os, const Histogram<T>& h)
    {
    
    Norihiro Watanabe's avatar
    Norihiro Watanabe committed
        os << h.getNumberOfBins() << " "
    
           << h.getMinimum() << " "
           << h.getMaximum() << " ";
        std::copy(h.getBinCounts().begin(), h.getBinCounts().end(),
                  std::ostream_iterator<T>(os, " "));
        return os << std::endl;
    
    }   // namespace BaseLib