11#ifndef PLOT_DENSITY_HPP
12#define PLOT_DENSITY_HPP
25#include "attributes.hpp"
33 struct bandwidth {
using value_type = tag::bandwidth_t;
double value; };
37 template <
class... opt_t>
38 double bandwidth_of(
const std::vector<double>& v,
const opt_t&... opts){
39 using bw_t =
typename arg::tpos<tag::bandwidth_t, opt_t...>;
40 if constexpr( bw_t::present ){
41 auto tuple = std::forward_as_tuple(opts...);
42 double h = std::get<bw_t::position>(tuple).value;
46 const std::size_t n = v.size();
47 if( n < 2 )
return 1.0;
48 double mean = 0;
for(
double d : v) mean += d; mean /= double(n);
49 double var = 0;
for(
double d : v) var += (d-mean)*(d-mean); var /= double(n-1);
50 double sigma = std::sqrt(var > 0 ? var : 1.0);
51 double h = 1.06 * sigma * std::pow(
double(n), -1.0/5.0);
52 return h > 0 ? h : 1.0;
55 template <
class... opt_t>
57 using value_type = tag::view_t;
58 std::vector<double> values;
59 std::tuple<opt_t...> opts;
61 std::pair<std::size_t,std::size_t> natural()
const {
62 return std::apply([](
const auto&... o){
63 return impl::natural_size(std::size_t{640}, std::size_t{400}, o...); }, opts);
65 void draw_into(canvas_t& cv,
float x,
float y,
float w,
float h)
const {
66 std::apply([&](
const auto&... o){
67 const theme_t& th = impl::resolve_theme(o...);
68 auto [title, xl, yl] = impl::texts(o...);
69 const double bw = impl::bandwidth_of(values, o...);
71 auto [vmn, vmx] = impl::minmax_of(values);
73 double xlo = vmn - 3.0*bw, xhi = vmx + 3.0*bw;
74 if( xhi <= xlo ) xhi = xlo + 1.0;
76 const std::size_t G = 200;
77 std::vector<double> gx(G), gy(G);
78 constexpr double two_pi = 6.283185307179586;
79 const double inv = 1.0 / (std::sqrt(two_pi) * bw * double(values.size() ? values.size() : 1));
81 for(std::size_t g=0; g<G; ++g){
82 double xq = xlo + (xhi - xlo) *
double(g)/double(G-1);
84 for(
double v : values){
85 double u = (xq - v)/bw;
86 acc += std::exp(-0.5*u*u);
88 double dens = acc * inv;
89 gx[g] = xq; gy[g] = dens;
90 if( dens > dmax ) dmax = dens;
92 if( dmax <= 0.0 ) dmax = 1.0;
94 impl::scale_t sx = impl::make_scale(xlo, xhi,
false, 10.0);
95 impl::scale_t sy = impl::make_scale(0.0, dmax,
false, 10.0);
96 impl::render_panel_into(cv, x, y,
97 static_cast<std::size_t
>(w),
static_cast<std::size_t
>(h),
98 th, sx, sy, title, xl, yl, {},
99 [&](impl::canvas_t& c,
auto px,
auto py){
100 using attribute_t = plot::attribute::element_t;
101 std::vector<float> xpx, ypx;
102 for(std::size_t g=0; g<G; ++g){ xpx.push_back(px(gx[g])); ypx.push_back(py(gy[g])); }
104 a.color = plot::attribute::color_t{ th.series.empty()? th.fg : th.series[0] };
105 a.stroke = plot::attribute::stroke_t{1.0f, 1.8f, {}, {}, {}};
106 c.poly_line(xpx, ypx, a);
114 template <
class... opt_t>
115 impl::density_view<opt_t...> density(std::vector<double> values, opt_t... opts){
116 return impl::density_view<opt_t...>{ std::move(values), std::make_tuple(opts...) };