第二十章:绘制函数图和数据图 习题答案
习题要求所设计的函数类和数据图类
Func_Data_Graph.h
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
using namespace Graph_lib;
namespace Func_Data_Graph {
template<class VType = double>
class Scale {
int cbase;
VType vbase;
double scale;
public:
Scale(int b, VType v, double s)
:cbase{ b }, vbase{ v }, scale{ s }{}
int operator()(VType v) const
{
return cbase + round((v - vbase) * scale);
}
};
//-------------------------------------------------------------------
template<class PrecType = double>
class Func : public Function {
Fct fct;
double r1, r2;
Point cen;
int cnt;
double xs, ys;
PrecType prec;
protected:
void reset();
public:
Func(Fct f, double r1, double r2, Point orig,
int count = 100, double xscale = 25, double yscale = 25,
PrecType prec = PrecType(1));
void reset_function(Fct f);
void reset_range(double r1, double r2);
};
template<class PrecType>
Func<PrecType>::Func(Fct f, double r1, double r2, Point orig,
int count, double xscale, double yscale, PrecType precision)
: Function(f, r1, r2, orig, count, xscale, yscale),
fct{ f }, r1{ r1 }, r2{ r2 }, cen{ orig },
cnt{ count }, xs{ xscale }, ys{ yscale }, prec{ precision}
{ }
template<class PrecType>
void Func<PrecType>::reset()
{
PrecType dist = PrecType(r2 - r1) / cnt;
PrecType r = r1;
int np = number_of_points();
int i;
for (i = 0; i < np; ++i)
{
Point p{ cen.x + int(r * xs), cen.y - int(PrecType(fct(r)) * ys) };
set_point(i, p);
r += dist;
}
for (i = np; i < cnt; ++i)
{
add(Point{ cen.x + int(r * xs), cen.y - int(PrecType(fct(r)) * ys) });
r += dist;
}
}
template<class PrecType>
void Func<PrecType>::reset_function(Fct f)
{
fct = f;
reset();
}
template<class PrecType>
void Func<PrecType>::reset_range(double rg1, double rg2)
{
if (rg2 - rg1 <= 0)
error("bad graphing range");
r1 = rg1;
r2 = rg2;
reset();
}
//------------------------------------------------------------------
class XY_axis : public Shape {
//一个XY坐标轴
Axis x;
Axis y;
Point o; //原点
int xlen; //x轴长度
int ylen;
public:
XY_axis(Point oo, int xlength, int ylength,
const string & xlab = "x", const string & ylab = "y");
void draw_lines() const override;
void move(int dx, int dy) override;
void set_color(Color c);
void set_x_label(const string& lab);
void set_y_label(const string& lab);
};
template<typename DataType>
class Bar : public Graph_lib::Rectangle {
//带标签的柱状图
public:
Bar(Point cen, int width, int height, pair<string, DataType> psd);
void draw_lines() const override;
void move(int dx, int dy) override;
void set_color(Color c);
Text label; //柱体下面的标签
Text data; //柱体上面的数字标识
};
template<typename DataType>
Bar<DataType>::Bar(Point cen, int width, int ytop, pair<string,DataType> psd)
:Rectangle{ Point{cen.x - int(round(width / 2.0)), ytop},
Point{cen.x + int(round(width / 2.0)), cen.y} },
label{ Point{cen.x - int(round(width / 2.0)),cen.y + 15}, psd.first },
data{ Point{cen.x - int(round(width / 2.0)),ytop - 1}, ""}
{
ostringstream oss;
oss << psd.second;
data.set_label(oss.str());
}
template<typename DataType>
void Bar<DataType>::draw_lines() const
{
Rectangle::draw_lines();
label.draw();
data.draw();
}
template<typename DataType>
void Bar< DataType>::move(int dx, int dy)
{
Rectangle::move(dx, dy);
label.move(dx, dy);
data.move(dx, dy);
}
template<typename DataType>
void Bar<DataType>::set_color(Color c)
{
Rectangle::set_color(c);
label.set_color(c);
data.set_color(c);
}
//---------------------------------------------------------------------
template<typename DataType>
//DataType 必须是数字类型
class Histogram : public Shape {
vector<pair<string,DataType>> datas; //(标签,数据)对
XY_axis xy_axis; //一个坐标系
Text title;
Vector_ref<Bar<DataType>> bars; //带标签柱形状集
public:
Histogram(Point xy, int width, int height,
const vector<pair<string,DataType>>vdata, const string& title = "");
void draw_lines() const override;
void move(int dx, int dy) override;
void set_color_all(Color c);
void set_fill_color_bars_all(Color c);
void set_bar_color_by_index(int index, Color c);
void set_bar_fill_color_by_index(int index, Color c);
void set_title(const string& tt);
void set_xaxis_label(const string& xstr);
void set_yaxis_label(const string& ystr);
void set_bar_label_by_index(int index, const string& str);
//...
};
//---------------------------------------------------------------------
template<typename DataType>
Histogram<DataType>::Histogram(Point xy, int width, int height,
const vector<pair<string,DataType>> vdata, const string& tt)
: datas{ vdata },
xy_axis{ Point{ xy.x, xy.y + height - 15 }, width, height - 30 },
title{ Point{xy.x + width / 2, xy.y + 14}, tt }
{
if (datas.size() == 0)
return;
//这里有一个隐含条件,期望datas都是大于零的数
DataType max{ datas[0].second };
for (auto pd : datas)
if (pd.second > max)
max = pd.second;
const int space_for_text{ 15 };
const int axis_ylen = height - 2 * space_for_text;
const int yorig = xy.y + height - space_for_text;
const double xscale{ double(width) / (datas.size() + 1) };
const double yscale{ double(axis_ylen - space_for_text) / max };
Scale<DataType> xs{ xy.x, 0, xscale };
Scale<DataType> ys{ yorig, 0, -yscale };
//计算柱宽,而且每条柱间隔一个柱宽
const int bar_width = round(double(width) / (2 * datas.size()));
for (int i = 0; i < datas.size(); ++i)
{
bars.push_back(new Bar<DataType>{ Point{xs(i + 1),yorig},bar_width,ys(datas[i].second),datas[i] });
bars[bars.size() - 1].set_color(Color::black);
bars[bars.size() - 1].set_fill_color(Color::white);
}
xy_axis.set_color(Color::red);
title.set_color(Color::black);
}
template<typename DataType>
void Histogram<DataType>::draw_lines() const
{
xy_axis.draw();
title.draw();
for (int i = 0; i < bars.size(); ++i)
bars[i].draw();
}
template<typename DataType>
void Histogram<DataType>::move(int dx, int dy)
{
xy_axis.move(dx, dy);
title.move(dx, dy);
for (int i = 0; i < bars.size(); ++i)
bars[i].move(dx, dy);
}
template<typename DataType>
void Histogram<DataType>::set_color_all(Color c)
{
xy_axis.set_color(c);
title.set_color(c);
for (int i = 0; i < bars.size(); ++i)
bars[i].set_color(c);
}
template<typename DataType>
void Histogram<DataType>::set_fill_color_bars_all(Color c)
{
for (int i = 0; i < bars.size(); ++i)
bars[i].set_fill_color(c);
}
template<typename DataType>
void Histogram<DataType>::set_bar_color_by_index(int index, Color c)
{
if (index >= bars.size())
error("Bad index: out of range");
bars[index].set_color(c);
}
template<typename DataType>
void Histogram<DataType>::set_bar_fill_color_by_index(int index, Color c)
{
if (index >= bars.size())
error("Bad index: out of range");
bars[index].set_fill_color(c);
}
template<typename DataType>
void Histogram<DataType>::set_title(const string& tt)
{
title.set_label(tt);
}
template<typename DataType>
void Histogram<DataType>::set_xaxis_label(const string& xlab)
{
xy_axis.set_x_label(xlab);
}
template<typename DataType>
void Histogram<DataType>::set_yaxis_label(const string& ylab)
{
xy_axis.set_y_label(ylab);
}
template<typename DataType>
void Histogram<DataType>::set_bar_label_by_index(int index, const string& lab)
{
if (index >= bars.size())
error("Bad index: out of range");
bars[index].label.set_label(lab);
}
};
Func_Data_Graph.cpp
#include"Func_Data_Graph.h"
namespace Func_Data_Graph {
XY_axis::XY_axis(Point oo, int xlength, int ylength,
const string& xlab, const string& ylab)
:x{Axis::x, oo, xlength, 0, xlab},
y{ Axis::y, oo, ylength, 0, ylab },
o{oo}, xlen{xlength},ylen{ylength}
{
if (xlen <= 0 || ylen <= 0)
error("Bad XY Axis: non-positive length of X or Y axis");
}
void XY_axis::draw_lines() const
{
x.draw();
y.draw();
}
void XY_axis::move(int dx, int dy)
{
x.move(dx, dy);
y.move(dx, dy);
}
void XY_axis::set_color(Color c)
{
Shape::set_color(c);
x.set_color(c);
y.set_color(c);
}
void XY_axis::set_x_label(const string& lab)
{
x.label.set_label(lab);
}
void XY_axis::set_y_label(const string& lab)
{
y.label.set_label(lab);
}
};
20.1 阶乘的迭代实现和递归实现
递归版本代码简单粗暴,但是我选迭代,因为递归时的函数调用花费时间较长,且会占用内存空间,存在耗尽内存资源的风险,而迭代速度快占用空间小,首选。
//阶乘
//迭代版本
int fac_iter(int n)
{
int sum{ 1 };
while (n > 1)
{
sum *= n;
--n;
}
return sum;
}
//递归版本
int fac_recur(int n)
{
return n > 1 ? n * fac_recur(n - 1) : 1;
}
20.2 and 20.3 Func类——可灵活改变的Function类派生类
加了模板参数,另外
template<class PrecType = double>
class Func : public Function {
Fct fct;
double r1, r2;
Point cen;
int cnt;
double xs, ys;
PrecType prec;
protected:
void reset();
public:
Func(Fct f, double r1, double r2, Point orig,
int count = 100, double xscale = 25, double yscale = 25,
PrecType prec = PrecType(1));
void reset_function(Fct f);
void reset_range(double r1, double r2);
};
//------------------------------------------------------------------
template<class PrecType>
Func<PrecType>::Func(Fct f, double r1, double r2, Point orig,
int count, double xscale, double yscale, PrecType precision)
: Function(f, r1, r2, orig, count, xscale, yscale),
fct{ f }, r1{ r1 }, r2{ r2 }, cen{ orig },
cnt{ count }, xs{ xscale }, ys{ yscale }, prec{ precision}
{ }
template<class PrecType>
void Func<PrecType>::reset()
{
PrecType dist = PrecType(r2 - r1) / cnt;
PrecType r = r1;
int np = number_of_points();
int i;
for (i = 0; i < np; ++i)
{
Point p{ cen.x + int(r * xs), cen.y - int(PrecType(fct(r)) * ys) };
set_point(i, p);
r += dist;
}
for (i = np; i < cnt; ++i)
{
add(Point{ cen.x + int(r * xs), cen.y - int(PrecType(fct(r)) * ys) });
r += dist;
}
}
template<class PrecType>
void Func<PrecType>::reset_function(Fct f)
{
fct = f;
reset();
}
template<class PrecType>
void Func<PrecType>::reset_range(double rg1, double rg2)
{
if (rg2 - rg1 <= 0)
error("bad graphing range");
r1 = rg1;
r2 = rg2;
reset();
}
20.4 Trigonometric Function
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Simple_window.h"
#include"../../GUI/Graph.h"
//注意,Graph.h中的 Fct 类型:typedef std::function<double(double)> Fct;
//这个类型是强制类型安全的,而 sin cos 这些三角函数在<cmath>中有两个类型重载,
//这两个重载分别返回和接收float,long double类型,所以会出问题
//考虑用 lambda 并且显示指定返回值
//如果你的Graph.h中的Fct类型定义是 typedef double Fct(double);
// 那就不用多此一举了,直接用 sin cos这样的即可
int main()
try
{
constexpr int xmax = 1200; //窗口大小
constexpr int ymax = 900;
Point tt{ 200,100 };
Simple_window win{ tt, xmax, ymax, "20-4 Trigonometric Function graphs" };
//绘制坐标轴
constexpr double scale{ 50 };
constexpr int xorig{ xmax/2 }; //坐标原点位于窗口中的相对位置
constexpr int yorig{ ymax/2 };
const Point orign{ xorig,yorig };//坐标原点
constexpr int axis_xlen{ xmax - 100 }; //坐标轴长度
constexpr int axis_ylen{ ymax - 100 };
const string xlabel{ "x" };
const string ylabel{ "y" };
Axis x{ Axis::x, Point{xorig - axis_xlen / 2, yorig},axis_xlen,
int(axis_xlen / scale), xlabel };
//x.label.move(-100, 0);
Axis y{ Axis::y, Point{xorig, yorig + axis_ylen / 2}, axis_ylen,
int(axis_ylen / scale), ylabel };
x.set_color(Color::red);
y.set_color(Color::red);
win.attach(x);
win.attach(y);
//绘制函数
constexpr double r_min{ -10 }; //区间为[-10:11)
constexpr double r_max{ 11 };
constexpr int np{ 400 }; //在区间中用到的点的数量
constexpr double xscale{ scale };
constexpr double yscale{ scale };
Function f1{ [](double x)->double {return sin(x); },
r_min,r_max,orign,np,xscale,yscale };
f1.set_color(Color::red);
Function f2{ [](double x)->double {return cos(x); },
r_min,r_max,orign,np,xscale,yscale };
f2.set_color(Color::yellow);
Function f3{ [](double x)->double {return sin(x) + cos(x); },
r_min,r_max,orign,np,xscale,yscale };
f3.set_color(Color::blue);
Function f4{ [](double x)->double {return sin(x)*sin(x) + cos(x)*cos(x); },
r_min,r_max,orign,np,xscale,yscale };
f4.set_color(Color::green);
win.attach(f1);
win.attach(f2);
win.attach(f3);
win.attach(f4);
win.wait_for_button();
return 0;
}
catch (runtime_error& e)
{
cerr << "Runtime error: " << e.what() << '\n';
return 1;
}
catch (...)
{
cerr << "Exception occurred!\n";
return 2;
}
19.5 Leibniz Series
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Simple_window.h"
#include"../../GUI/Graph.h"
template<class VType = double>
class Scale {
int cbase;
VType vbase;
double scale;
public:
Scale(int b, VType v, double s)
:cbase{ b }, vbase{ v }, scale{ s }{}
int operator()(VType v) const
{
return cbase + round((v - vbase) * scale);
}
};
double term_Lebiniz(int n)
{
return (n % 2 ? 1.0 : -1.0) / (2.0 * n - 1.0);
}
int main()
try
{
constexpr int xmax = 1200; //窗口大小
constexpr int ymax = 900;
Point tt{ 200,100 };
Simple_window win{ tt, xmax, ymax, "20-5 Leibniz Series" };
//绘制坐标轴
constexpr double PI = 3.1415926;
constexpr int axis_xlen{ xmax - 100 }; //坐标轴长度
constexpr int xorig{ (xmax - axis_xlen) / 2 }; //坐标原点位于窗口中的相对位置
constexpr int yorig{ ymax / 4 };
constexpr double base_rad{ 0 }; //数据范围,弧度
constexpr double end_rad{ PI / 2 };
constexpr double scale{ axis_xlen / (end_rad - base_rad) };
Scale<double> xs(xorig, base_rad, scale);
const string xlabel{ "x" };
Axis x{ Axis::x, Point{xorig, yorig},axis_xlen, 2, xlabel };
x.set_color(Color::red);
x.label.move(-axis_xlen, 0);
win.attach(x);
Text t1{ Point{xs(PI / 4)-10, yorig + 15},"PI/4" };
Text t2{ Point{xs(PI / 2)-10, yorig + 15},"PI/2" };
t1.set_color(Color::black);
t2.set_color(Color::black);
win.attach(t1);
win.attach(t2);
Line quarterPI{ Point{xs(PI / 4),yorig}, Point{xs(PI / 4),100} };
quarterPI.set_color(Color::blue);
win.attach(quarterPI);
//采用了和书上不太一样的计算级数的方法,节约点计算资源
double sum{ 0.0 };
for (int n = 1; n < 20; ++n)
{
ostringstream oss;
oss << "Leibniz Series approximation; n == " << n;
win.set_label(oss.str());
sum += term_Lebiniz(n);
Mark m{ Point{xs(sum),yorig},'x' };
m.set_color(Color::black);
win.attach(m);
win.wait_for_button();
win.detach(m);
}
win.wait_for_button();
return 0;
}
catch (runtime_error& e)
{
cerr << "Runtime error: " << e.what() << '\n';
return 1;
}
catch (...)
{
cerr << "Exception occurred!\n";
return 2;
}
19.6 and 19.7 Histogram 柱状图
实现
//辅助计算位置的类
template<class VType = double>
class Scale {
int cbase;
VType vbase;
double scale;
public:
Scale(int b, VType v, double s)
:cbase{ b }, vbase{ v }, scale{ s }{}
int operator()(VType v) const
{
return cbase + round((v - vbase) * scale);
}
};
//下面是完整实现
class XY_axis : public Shape {
//一个XY坐标轴
Axis x;
Axis y;
Point o; //原点
int xlen; //x轴长度
int ylen;
public:
XY_axis(Point oo, int xlength, int ylength,
const string & xlab = "x", const string & ylab = "y");
void draw_lines() const override;
void move(int dx, int dy) override;
void set_color(Color c);
void set_x_label(const string& lab);
void set_y_label(const string& lab);
};
XY_axis::XY_axis(Point oo, int xlength, int ylength,
const string& xlab, const string& ylab)
:x{Axis::x, oo, xlength, 0, xlab},
y{ Axis::y, oo, ylength, 0, ylab },
o{oo}, xlen{xlength},ylen{ylength}
{
if (xlen <= 0 || ylen <= 0)
error("Bad XY Axis: non-positive length of X or Y axis");
}
void XY_axis::draw_lines() const
{
x.draw();
y.draw();
}
void XY_axis::move(int dx, int dy)
{
x.move(dx, dy);
y.move(dx, dy);
}
void XY_axis::set_color(Color c)
{
Shape::set_color(c);
x.set_color(c);
y.set_color(c);
}
void XY_axis::set_x_label(const string& lab)
{
x.label.set_label(lab);
}
void XY_axis::set_y_label(const string& lab)
{
y.label.set_label(lab);
}
//----------------------------------------------------------------------------
template<typename DataType>
class Bar : public Graph_lib::Rectangle {
//带标签的柱状图
public:
Bar(Point cen, int width, int height, pair<string, DataType> psd);
void draw_lines() const override;
void move(int dx, int dy) override;
void set_color(Color c);
Text label; //柱体下面的标签
Text data; //柱体上面的数字标识
};
template<typename DataType>
Bar<DataType>::Bar(Point cen, int width, int ytop, pair<string,DataType> psd)
:Rectangle{ Point{cen.x - int(round(width / 2.0)), ytop},
Point{cen.x + int(round(width / 2.0)), cen.y} },
label{ Point{cen.x - int(round(width / 2.0)),cen.y + 15}, psd.first },
data{ Point{cen.x - int(round(width / 2.0)),ytop - 1}, ""}
{
ostringstream oss;
oss << psd.second;
data.set_label(oss.str());
}
template<typename DataType>
void Bar<DataType>::draw_lines() const
{
Rectangle::draw_lines();
label.draw();
data.draw();
}
template<typename DataType>
void Bar< DataType>::move(int dx, int dy)
{
Rectangle::move(dx, dy);
label.move(dx, dy);
data.move(dx, dy);
}
template<typename DataType>
void Bar<DataType>::set_color(Color c)
{
Rectangle::set_color(c);
label.set_color(c);
data.set_color(c);
}
//---------------------------------------------------------------------
template<typename DataType>
//DataType 必须是数字类型
class Histogram : public Shape {
vector<pair<string,DataType>> datas; //(标签,数据)对
XY_axis xy_axis; //一个坐标系
Text title;
Vector_ref<Bar<DataType>> bars; //带标签柱形状集
public:
Histogram(Point xy, int width, int height,
const vector<pair<string,DataType>>vdata, const string& title = "");
void draw_lines() const override;
void move(int dx, int dy) override;
void set_color_all(Color c);
void set_fill_color_bars_all(Color c);
void set_bar_color_by_index(int index, Color c);
void set_bar_fill_color_by_index(int index, Color c);
void set_title(const string& tt);
void set_xaxis_label(const string& xstr);
void set_yaxis_label(const string& ystr);
void set_bar_label_by_index(int index, const string& str);
//...
};
//---------------------------------------------------------------------
template<typename DataType>
Histogram<DataType>::Histogram(Point xy, int width, int height,
const vector<pair<string,DataType>> vdata, const string& tt)
: datas{ vdata },
xy_axis{ Point{ xy.x, xy.y + height - 15 }, width, height - 30 },
title{ Point{xy.x + width / 2, xy.y + 14}, tt }
{
if (datas.size() == 0)
return;
//这里有一个隐含条件,期望datas都是大于零的数
DataType max{ datas[0].second };
for (auto pd : datas)
if (pd.second > max)
max = pd.second;
const int space_for_text{ 15 };
const int axis_ylen = height - 2 * space_for_text;
const int yorig = xy.y + height - space_for_text;
const double xscale{ double(width) / (datas.size() + 1) };
const double yscale{ double(axis_ylen - space_for_text) / max };
Scale<DataType> xs{ xy.x, 0, xscale };
Scale<DataType> ys{ yorig, 0, -yscale };
//计算柱宽,而且每条柱间隔一个柱宽
const int bar_width = round(double(width) / (2 * datas.size()));
for (int i = 0; i < datas.size(); ++i)
{
bars.push_back(new Bar<DataType>{ Point{xs(i + 1),yorig},bar_width,ys(datas[i].second),datas[i] });
bars[bars.size() - 1].set_color(Color::black);
bars[bars.size() - 1].set_fill_color(Color::white);
}
xy_axis.set_color(Color::red);
title.set_color(Color::black);
}
template<typename DataType>
void Histogram<DataType>::draw_lines() const
{
xy_axis.draw();
title.draw();
for (int i = 0; i < bars.size(); ++i)
bars[i].draw();
}
template<typename DataType>
void Histogram<DataType>::move(int dx, int dy)
{
xy_axis.move(dx, dy);
title.move(dx, dy);
for (int i = 0; i < bars.size(); ++i)
bars[i].move(dx, dy);
}
template<typename DataType>
void Histogram<DataType>::set_color_all(Color c)
{
xy_axis.set_color(c);
title.set_color(c);
for (int i = 0; i < bars.size(); ++i)
bars[i].set_color(c);
}
template<typename DataType>
void Histogram<DataType>::set_fill_color_bars_all(Color c)
{
for (int i = 0; i < bars.size(); ++i)
bars[i].set_fill_color(c);
}
template<typename DataType>
void Histogram<DataType>::set_bar_color_by_index(int index, Color c)
{
if (index >= bars.size())
error("Bad index: out of range");
bars[index].set_color(c);
}
template<typename DataType>
void Histogram<DataType>::set_bar_fill_color_by_index(int index, Color c)
{
if (index >= bars.size())
error("Bad index: out of range");
bars[index].set_fill_color(c);
}
template<typename DataType>
void Histogram<DataType>::set_title(const string& tt)
{
title.set_label(tt);
}
template<typename DataType>
void Histogram<DataType>::set_xaxis_label(const string& xlab)
{
xy_axis.set_x_label(xlab);
}
template<typename DataType>
void Histogram<DataType>::set_yaxis_label(const string& ylab)
{
xy_axis.set_y_label(ylab);
}
template<typename DataType>
void Histogram<DataType>::set_bar_label_by_index(int index, const string& lab)
{
if (index >= bars.size())
error("Bad index: out of range");
bars[index].label.set_label(lab);
}
测试
#include"Func_Data_Graph.h"
using namespace Func_Data_Graph;
int main()
try
{
constexpr int xmax = 1200; //窗口大小
constexpr int ymax = 900;
Point tt{ 200,100 };
Simple_window win{ tt, xmax, ymax, "Histogram" };
string str{ "" };
vector<pair<string,double>> data;
data.push_back({str,15.2});
data.push_back({ "",73.65 });
data.push_back({ "c",197.56 });
data.push_back({ "d",135.72 });
Histogram<double> hg{ Point{200,100}, 600, 600, data, "title_1"};
win.attach(hg);
win.wait_for_button();
hg.set_fill_color_bars_all(Color::yellow);
win.wait_for_button();
hg.set_color_all(Color::green);
win.wait_for_button();
hg.set_xaxis_label("xxx");
hg.set_yaxis_label("yyy");
win.wait_for_button();
hg.set_title("title_2");
win.wait_for_button();
hg.set_bar_label_by_index(0, "red");
hg.set_bar_fill_color_by_index(0, Color::red);
win.wait_for_button();
hg.set_bar_color_by_index(2, Color::blue);
win.wait_for_button();
return 0;
}
catch (runtime_error& e)
{
cerr << "Runtime error: " << e.what() << '\n';
return 1;
}
catch (...)
{
cerr << "Exception occurred!\n";
return 2;
}
20.8 Height Distribution Histogram
使用了柱状图
#include"Func_Data_Graph.h"
using namespace Func_Data_Graph;
istream& operator>>(istream& is, pair<string, int>& p)
{
char ch1{ 0 }, ch2{ 0 }, ch3{ 0 };
int h{ 0 }, f{ 0 }; //身高和数量
is >> ch1;
if (ch1 != '(')
{
is.unget();
is.clear(ios::failbit);
return is;
}
if (is >> h >> ch2 >> f >> ch3)
{
if (ch2 != ',' || ch3 != ')')
is.clear(ios_base::failbit);
else
{
ostringstream oss;
oss << h;
p.first = oss.str();
p.second = f;
}
}
return is;
}
void read_data(const string& fname, vector<pair<string, int>>& vd)
{
ifstream ifs{ fname };
if (!ifs)
error("can't open ", fname);
while (true)
{
pair<string, int> phd; //身高分布对
if (!(ifs >> phd)) break;
vd.push_back(phd);
}
}
int main()
try
{
constexpr int xmax = 1200; //窗口大小
constexpr int ymax = 900;
Point tt{ 200,100 };
Simple_window win{ tt, xmax, ymax, "" };
string fname{ "heights.txt" };
vector<pair<string, int>> vd;
read_data(fname, vd);
Histogram<int> hg{ Point{200,100}, 800, 600, vd, "Height Distribution" };
win.attach(hg);
win.wait_for_button();
return 0;
}
catch (runtime_error& e)
{
cerr << "Runtime error: " << e.what() << '\n';
return 1;
}
catch (...)
{
cerr << "Exception occurred!\n";
return 2;
}