13#ifndef PLOT_HISTOGRAM_HPP
14#define PLOT_HISTOGRAM_HPP
27#include "attributes.hpp"
33#ifndef PLOT_WIREFRAME_DEFINED
34#define PLOT_WIREFRAME_DEFINED
38 struct wireframe {
using value_type = tag::wireframe_t; };
44 struct bins {
using value_type = tag::bins_t; std::size_t value; };
49 template <
class... opt_t>
50 std::size_t bins_of(std::size_t n,
const opt_t&... opts){
51 using bins_t =
typename arg::tpos<tag::bins_t, opt_t...>;
52 if constexpr( bins_t::present ){
53 auto tuple = std::forward_as_tuple(opts...);
54 std::size_t b = std::get<bins_t::position>(tuple).value;
58 return static_cast<std::size_t
>(std::ceil(std::log2(
double(n)))) + 1;
61 template <
class... opt_t>
62 struct histogram_view {
63 using value_type = tag::view_t;
64 std::vector<double> values;
65 std::tuple<opt_t...> opts;
67 std::pair<std::size_t,std::size_t> natural()
const {
68 return std::apply([](
const auto&... o){
69 return impl::natural_size(std::size_t{640}, std::size_t{400}, o...); }, opts);
71 void draw_into(canvas_t& cv,
float x,
float y,
float w,
float h)
const {
72 std::apply([&](
const auto&... o){
73 const theme_t& th = impl::resolve_theme(o...);
74 auto [title, xl, yl] = impl::texts(o...);
75 const std::size_t nb = impl::bins_of(values.size(), o...);
76 constexpr bool wire = arg::tpos<tag::wireframe_t, opt_t...>::present;
78 auto [vmn, vmx] = impl::minmax_of(values);
79 if( vmx <= vmn ) vmx = vmn + 1.0;
80 const double width = (vmx - vmn) /
double(nb);
82 std::vector<double> counts(nb, 0.0);
83 for(
double v : values){
84 std::size_t b =
static_cast<std::size_t
>((v - vmn) / width);
85 if( b >= nb ) b = nb - 1;
89 for(
double c : counts) if( c > cmax ) cmax = c;
90 if( cmax <= 0.0 ) cmax = 1.0;
92 impl::scale_t sx = impl::make_scale(vmn, vmx,
false, 10.0);
93 impl::scale_t sy = impl::make_scale(0.0, cmax,
false, 10.0);
94 impl::render_panel_into(cv, x, y,
95 static_cast<std::size_t
>(w),
static_cast<std::size_t
>(h),
96 th, sx, sy, title, xl, yl, {},
97 [&](impl::canvas_t& c,
auto px,
auto py){
98 using attribute_t = plot::attribute::element_t;
99 std::uint32_t col = th.series.empty()? th.fg : th.series[0];
100 const float y0 = py(0.0);
101 for(std::size_t b=0;b<nb;++b){
102 double lo = vmn + double(b) * width;
103 double hi = vmn + double(b+1) * width;
104 float xl0 = px(lo), xr0 = px(hi);
105 float yt = py(counts[b]);
106 float bw = xr0 - xl0;
107 if( bw < 1.0f ) bw = 1.0f;
108 if constexpr( wire ){
110 attribute_t a; a.color = plot::attribute::color_t{ col };
111 a.stroke = plot::attribute::stroke_t{1.0f, 1.5f, {}, {}, {}};
112 float lx = xl0 + 0.5f, rx = lx + (bw - 1.0f);
113 std::vector<float> X{lx, rx, rx, lx, lx};
114 std::vector<float> Y{yt, yt, y0, y0, yt};
115 c.poly_line(X, Y, a);
117 attribute_t a; a.color = plot::attribute::color_t{ col };
119 c.rect(xl0 + 0.5f, yt, bw - 1.0f, y0 - yt, 0, 0, a);
129 template <
class... opt_t>
130 impl::histogram_view<opt_t...> histogram(std::vector<double> values, opt_t... opts){
131 return impl::histogram_view<opt_t...>{ std::move(values), std::make_tuple(opts...) };