Wt examples  3.3.4
ChartsExample.C
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium.
3  *
4  * See the LICENSE file for terms of use.
5  */
6 
7 #include <math.h>
8 #include <fstream>
9 
10 #include "ChartsExample.h"
11 #include "ChartConfig.h"
12 #include "CsvUtil.h"
13 
14 #include <Wt/WApplication>
15 #include <Wt/WDate>
16 #include <Wt/WEnvironment>
17 #include <Wt/WItemDelegate>
18 #include <Wt/WStandardItemModel>
19 #include <Wt/WText>
20 
21 #include <Wt/WBorderLayout>
22 #include <Wt/WFitLayout>
23 
24 #include <Wt/WStandardItem>
25 #include <Wt/WTableView>
26 
27 #include <Wt/Chart/WCartesianChart>
28 #include <Wt/Chart/WPieChart>
29 
30 using namespace Wt;
31 using namespace Wt::Chart;
32 
33 namespace {
34 
35  /*
36  * A standard item which converts text edits to numbers
37  */
38  class NumericItem : public WStandardItem {
39  public:
40  virtual NumericItem *clone() const {
41  return new NumericItem();
42  }
43 
44  virtual void setData(const boost::any &data, int role = UserRole) {
45  boost::any dt;
46 
47  if (role == EditRole) {
48  std::string s = Wt::asString(data).toUTF8();
49  char *endptr;
50  double d = strtod(s.c_str(), &endptr);
51  if (*endptr == 0)
52  dt = boost::any(d);
53  else
54  dt = data;
55  }
56 
57  WStandardItem::setData(data, role);
58  }
59  };
60 
61  /*
62  * Reads a CSV file as an (editable) standard item model.
63  */
64  WAbstractItemModel *readCsvFile(const std::string &fname,
65  WContainerWidget *parent)
66  {
67  WStandardItemModel *model = new WStandardItemModel(0, 0, parent);
68  model->setItemPrototype(new NumericItem());
69  std::ifstream f(fname.c_str());
70 
71  if (f) {
72  readFromCsv(f, model);
73 
74  for (int row = 0; row < model->rowCount(); ++row)
75  for (int col = 0; col < model->columnCount(); ++col) {
76  model->item(row, col)->setFlags(ItemIsSelectable | ItemIsEditable);
77 
78  /*
79  Example of tool tips (disabled here because they are not updated
80  when editing data)
81  */
82 
83  /*
84  WString toolTip = asString(model->headerData(col)) + ": "
85  + asString(model->item(row, col)->data(DisplayRole), "%.f");
86  model->item(row, col)->setToolTip(toolTip);
87  */
88  }
89 
90  return model;
91  } else {
92  WString error(WString::tr("error-missing-data"));
93  error.arg(fname, UTF8);
94  new WText(error, parent);
95  return 0;
96  }
97  }
98 }
99 
101  : WContainerWidget(root)
102 {
103  new WText(WString::tr("introduction"), this);
104 
105  new CategoryExample(this);
106  new TimeSeriesExample(this);
107  new ScatterPlotExample(this);
108  new PieExample(this);
109 }
110 
112  WContainerWidget(parent)
113 {
114  new WText(WString::tr("category chart"), this);
115 
116  WAbstractItemModel *model
117  = readCsvFile(WApplication::appRoot() + "category.csv", this);
118 
119  if (!model)
120  return;
121 
122  // Show a view that allows editing of the model.
123  WContainerWidget *w = new WContainerWidget(this);
124  WTableView *table = new WTableView(w);
125 
126  table->setMargin(10, Top | Bottom);
127  table->setMargin(WLength::Auto, Left | Right);
128 
129  table->setModel(model);
130  table->setSortingEnabled(true);
131  table->setColumnResizeEnabled(true);
132  // table->setSelectionMode(ExtendedSelection);
133  table->setAlternatingRowColors(true);
134  table->setColumnAlignment(0, AlignCenter);
135  table->setHeaderAlignment(0, AlignCenter);
136  table->setRowHeight(22);
137 
138  // Editing does not really work without Ajax, it would require an
139  // additional button somewhere to confirm the edited value.
140  if (WApplication::instance()->environment().ajax()) {
141  table->resize(600, 20 + 5*22);
142  table->setEditTriggers(WAbstractItemView::SingleClicked);
143  } else {
144  table->resize(600, WLength::Auto);
145  table->setEditTriggers(WAbstractItemView::NoEditTrigger);
146  }
147 
148  // We use a single delegate for all items which rounds values to
149  // the closest integer value.
150  WItemDelegate *delegate = new WItemDelegate(this);
151  delegate->setTextFormat("%.f");
152  table->setItemDelegate(delegate);
153 
154  table->setColumnWidth(0, 80);
155  for (int i = 1; i < model->columnCount(); ++i)
156  table->setColumnWidth(i, 120);
157 
158  /*
159  * Create the category chart.
160  */
161  WCartesianChart *chart = new WCartesianChart(this);
162  // chart->setPreferredMethod(WPaintedWidget::PngImage);
163  chart->setModel(model); // set the model
164  chart->setXSeriesColumn(0); // set the column that holds the categories
165  chart->setLegendEnabled(true); // enable the legend
166 
167  // Automatically layout chart (space for axes, legend, ...)
168  chart->setAutoLayoutEnabled(true);
169 
170  /*
171  * Add all (but first) column as bar series
172  */
173  for (int i = 1; i < model->columnCount(); ++i) {
174  WDataSeries s(i, BarSeries);
175  s.setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 3));
176  chart->addSeries(s);
177  }
178 
179  chart->resize(800, 400);
180 
181  chart->setMargin(10, Top | Bottom);
182  chart->setMargin(WLength::Auto, Left | Right);
183 
184  /*
185  * Provide a widget to manipulate chart properties
186  */
187  new ChartConfig(chart, this);
188 }
189 
191  WContainerWidget(parent)
192 {
193  new WText(WString::tr("scatter plot"), this);
194 
195  WAbstractItemModel *model = readCsvFile(
196  WApplication::appRoot() + "timeseries.csv", this);
197 
198  if (!model)
199  return;
200 
201  /*
202  * Parses the first column as dates, to be able to use a date scale
203  */
204  for (int i = 0; i < model->rowCount(); ++i) {
205  WString s = asString(model->data(i, 0));
206  WDate d = WDate::fromString(s, "dd/MM/yy");
207  model->setData(i, 0, d);
208  }
209 
210  // Show a view that allows editing of the model.
211  WContainerWidget *w = new WContainerWidget(this);
212  WTableView *table = new WTableView(w);
213 
214  table->setMargin(10, Top | Bottom);
215  table->setMargin(WLength::Auto, Left | Right);
216 
217  table->setModel(model);
218  table->setSortingEnabled(false); // Does not make much sense for time series
219  table->setColumnResizeEnabled(true);
221  table->setAlternatingRowColors(true);
222  table->setColumnAlignment(0, AlignCenter);
223  table->setHeaderAlignment(0, AlignCenter);
224  table->setRowHeight(22);
225 
226  // Editing does not really work without Ajax, it would require an
227  // additional button somewhere to confirm the edited value.
228  if (WApplication::instance()->environment().ajax()) {
229  table->resize(800, 20 + 5*22);
230  table->setEditTriggers(WAbstractItemView::SingleClicked);
231  } else {
232  table->resize(800, 20 + 5*22 + 25);
233  table->setEditTriggers(WAbstractItemView::NoEditTrigger);
234  }
235 
236  WItemDelegate *delegate = new WItemDelegate(this);
237  delegate->setTextFormat("%.1f");
238  table->setItemDelegate(delegate);
239  table->setItemDelegateForColumn(0, new WItemDelegate(this));
240 
241  table->setColumnWidth(0, 80);
242  for (int i = 1; i < model->columnCount(); ++i)
243  table->setColumnWidth(i, 90);
244 
245  /*
246  * Create the scatter plot.
247  */
248  WCartesianChart *chart = new WCartesianChart(this);
249  //chart->setPreferredMethod(WPaintedWidget::PngImage);
250  //chart->setBackground(gray);
251  chart->setModel(model); // set the model
252  chart->setXSeriesColumn(0); // set the column that holds the X data
253  chart->setLegendEnabled(true); // enable the legend
254 
255  chart->setType(ScatterPlot); // set type to ScatterPlot
256  chart->axis(XAxis).setScale(DateScale); // set scale of X axis to DateScale
257 
258  // Automatically layout chart (space for axes, legend, ...)
259  chart->setAutoLayoutEnabled();
260 
261  /*
262  * Add first two columns as line series
263  */
264  for (int i = 1; i < 3; ++i) {
265  WDataSeries s(i, LineSeries);
266  s.setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 3));
267  chart->addSeries(s);
268  }
269 
270  chart->resize(800, 400); // WPaintedWidget must be given explicit size
271 
272  chart->setMargin(10, Top | Bottom); // add margin vertically
273  chart->setMargin(WLength::Auto, Left | Right); // center horizontally
274 
275  new ChartConfig(chart, this);
276 }
277 
279  WContainerWidget(parent)
280 {
281  new WText(WString::tr("scatter plot 2"), this);
282 
283  WStandardItemModel *model = new WStandardItemModel(40, 2, this);
284  model->setItemPrototype(new NumericItem());
285  model->setHeaderData(0, WString("X"));
286  model->setHeaderData(1, WString("Y = sin(X)"));
287 
288  for (unsigned i = 0; i < 40; ++i) {
289  double x = (static_cast<double>(i) - 20) / 4;
290 
291  model->setData(i, 0, x);
292  model->setData(i, 1, sin(x));
293  }
294 
295  /*
296  * Create the scatter plot.
297  */
298  WCartesianChart *chart = new WCartesianChart(this);
299  chart->setModel(model); // set the model
300  chart->setXSeriesColumn(0); // set the column that holds the X data
301  chart->setLegendEnabled(true); // enable the legend
302 
303  chart->setType(ScatterPlot); // set type to ScatterPlot
304 
305  // Typically, for mathematical functions, you want the axes to cross
306  // at the 0 mark:
307  chart->axis(XAxis).setLocation(ZeroValue);
308  chart->axis(YAxis).setLocation(ZeroValue);
309 
310  // Automatically layout chart (space for axes, legend, ...)
311  chart->setAutoLayoutEnabled();
312 
313  // Add the curves
314  WDataSeries s(1, CurveSeries);
315  s.setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 3));
316  chart->addSeries(s);
317 
318  chart->resize(800, 300); // WPaintedWidget must be given explicit size
319 
320  chart->setMargin(10, Top | Bottom); // add margin vertically
321  chart->setMargin(WLength::Auto, Left | Right); // center horizontally
322 
323  ChartConfig *config = new ChartConfig(chart, this);
324  config->setValueFill(ZeroValueFill);
325 }
326 
328  WContainerWidget(parent)
329 {
330  new WText(WString::tr("pie chart"), this);
331 
332  WStandardItemModel *model = new WStandardItemModel(this);
333  model->setItemPrototype(new NumericItem());
334 
335  //headers
336  model->insertColumns(model->columnCount(), 2);
337  model->setHeaderData(0, WString("Item"));
338  model->setHeaderData(1, WString("Sales"));
339 
340  //data
341  model->insertRows(model->rowCount(), 6);
342  int row = 0;
343  model->setData(row, 0, WString("Blueberry"));
344  model->setData(row, 1, 120);
345  // model->setData(row, 1, WString("Blueberry"), ToolTipRole);
346  row++;
347  model->setData(row, 0, WString("Cherry"));
348  model->setData(row, 1, 30);
349  row++;
350  model->setData(row, 0, WString("Apple"));
351  model->setData(row, 1, 260);
352  row++;
353  model->setData(row, 0, WString("Boston Cream"));
354  model->setData(row, 1, 160);
355  row++;
356  model->setData(row, 0, WString("Other"));
357  model->setData(row, 1, 40);
358  row++;
359  model->setData(row, 0, WString("Vanilla Cream"));
360  model->setData(row, 1, 120);
361  row++;
362 
363  //set all items to be editable and selectable
364  for (int row = 0; row < model->rowCount(); ++row)
365  for (int col = 0; col < model->columnCount(); ++col)
366  model->item(row, col)->setFlags(ItemIsSelectable | ItemIsEditable);
367 
368  WContainerWidget *w = new WContainerWidget(this);
369  WTableView* table = new WTableView(w);
370 
371  table->setMargin(10, Top | Bottom);
372  table->setMargin(WLength::Auto, Left | Right);
373  table->setSortingEnabled(true);
374  table->setModel(model);
375  table->setColumnWidth(1, 100);
376  table->setRowHeight(22);
377 
378  if (WApplication::instance()->environment().ajax()) {
379  table->resize(150 + 100 + 14, 20 + 6 * 22);
380  table->setEditTriggers(WAbstractItemView::SingleClicked);
381  } else {
382  table->resize(150 + 100 + 14, WLength::Auto);
383  table->setEditTriggers(WAbstractItemView::NoEditTrigger);
384  }
385 
386  /*
387  * Create the pie chart.
388  */
389  WPieChart *chart = new WPieChart(this);
390  chart->setModel(model); // set the model
391  chart->setLabelsColumn(0); // set the column that holds the labels
392  chart->setDataColumn(1); // set the column that holds the data
393 
394  // configure location and type of labels
396 
397  // enable a 3D and shadow effect
398  chart->setPerspectiveEnabled(true, 0.2);
399  chart->setShadowEnabled(true);
400 
401  // explode the first item
402  chart->setExplode(0, 0.3);
403 
404  chart->resize(800, 300); // WPaintedWidget must be given an explicit size
405 
406  chart->setMargin(10, Top | Bottom); // add margin vertically
407  chart->setMargin(WLength::Auto, Left | Right); // center horizontally
408 }
409 
void setExplode(int modelRow, double factor)
A Widget that demonstrates a scatter plot.
Definition: ChartsExample.h:49
void setTextFormat(const WString &format)
ChartsExample(Wt::WContainerWidget *root)
Constructor.
virtual bool insertColumns(int column, int count, const WModelIndex &parent=WModelIndex())
virtual void setMargin(const WLength &margin, WFlags< Side > sides=All)
WString asString(const boost::any &v, const WString &formatString=WString())
void setLabelsColumn(int column)
virtual void setColumnWidth(int column, const WLength &width)
A Widget that demonstrates a Pie chart.
Definition: ChartsExample.h:59
void setLocation(AxisValue value)
void addSeries(const WDataSeries &series)
WAxis & axis(Axis axis)
virtual bool insertRows(int row, int count, const WModelIndex &parent=WModelIndex())
void setDisplayLabels(WFlags< LabelOption > options)
void setShadow(const WShadow &shadow)
void setItemDelegate(WAbstractItemDelegate *delegate)
virtual boost::any data(const WModelIndex &index, int role=DisplayRole) const =0
void setType(ChartType type)
void setSelectionMode(SelectionMode mode)
virtual void resize(const WLength &width, const WLength &height)
CategoryExample(Wt::WContainerWidget *parent)
Creates the category chart example.
virtual int rowCount(const WModelIndex &parent=WModelIndex()) const =0
void setPerspectiveEnabled(bool enabled, double height=1.0)
virtual void resize(const WLength &width, const WLength &height)
void setItemPrototype(WStandardItem *item)
std::string toUTF8() const
A Widget that demonstrates a category chart.
Definition: ChartsExample.h:39
A widget that demonstrates a times series chart.
Definition: ChartsExample.h:29
void setModel(WAbstractItemModel *model)
void setScale(AxisScale scale)
static WString tr(const char *key)
void setXSeriesColumn(int modelColumn)
virtual void setMargin(const WLength &margin, WFlags< Side > sides=All)=0
TimeSeriesExample(Wt::WContainerWidget *parent)
Creates the time series scatter plot example.
void setValueFill(Wt::Chart::FillRangeType fill)
Definition: ChartConfig.C:388
virtual int columnCount(const WModelIndex &parent=WModelIndex()) const =0
void setEditTriggers(WFlags< EditTrigger > editTriggers)
void setShadowEnabled(bool enabled)
void setColumnResizeEnabled(bool enabled)
void setAutoLayoutEnabled(bool enabled=true)
virtual void setData(const boost::any &data, int role=UserRole)
virtual void setAlternatingRowColors(bool enable)
virtual bool setHeaderData(int section, Orientation orientation, const boost::any &value, int role=EditRole)
void setDataColumn(int modelColumn)
virtual void setHeaderAlignment(int column, WFlags< AlignmentFlag > alignment)
virtual void setRowHeight(const WLength &rowHeight)
void setLegendEnabled(bool enabled)
void setSortingEnabled(bool enabled)
void setItemDelegateForColumn(int column, WAbstractItemDelegate *delegate)
void setFlags(WFlags< ItemFlag > flags)
PieExample(Wt::WContainerWidget *parent)
Creates the pie chart example.
A class that allows configuration of a cartesian chart.
Definition: ChartConfig.h:37
void readFromCsv(std::istream &f, Wt::WAbstractItemModel *model, int numRows, bool firstLineIsHeaders)
Utility function that reads a model from a CSV file.
Definition: CsvUtil.C:55
virtual bool setData(const WModelIndex &index, const boost::any &value, int role=EditRole)
virtual void setModel(WAbstractItemModel *model)
WStandardItem * item(int row, int column=0) const
ScatterPlotExample(Wt::WContainerWidget *parent)
Creates the scatter plot example.
virtual void setColumnAlignment(int column, AlignmentFlag alignment)

Generated on Sun Apr 24 2016 for the C++ Web Toolkit (Wt) by doxygen 1.8.11