summaryrefslogtreecommitdiffstats
path: root/examples/datavisualization/graphgallery/doc/src/graphgallery.qdoc
blob: 240fb3590a80fd533597aac9cd021352449e621a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only

/*!
    \example graphgallery
    \meta tags {DataVisualization, Q3DBars, Bar Graph, Custom Proxy, Q3DScatter, Scatter Graph, Custom Input Handler}
    \meta category {Graphics}
    \title Graph Gallery
    \ingroup qtdatavisualization_examples
    \brief Gallery of Bar, Scatter, and Surface graphs.

    \e {Graph Gallery} demonstrates all three graph types and some of their special features.
    The graphs have their own tabs in the application.

    \image qmlgraphgallery-example.png

    \include examples-run.qdocinc

    \section1 Bar Graph

    In the \uicontrol {Bar Graph} tab, create a 3D bar graph using Q3DBars and combine the use of
    widgets to adjust various bar graph qualities. The example shows how to:

    \list
        \li Create an application with Q3DBars and some widgets
        \li Use QBar3DSeries and QBarDataProxy to set data to the graph
        \li Adjust some graph and series properties using widget controls
        \li Select a row or a column by clicking an axis label
        \li Create a custom proxy to use with Q3DBars
    \endlist

    For information about interacting with the graph, see
    \l{Qt Data Visualization Interacting with Data}{this page}.

    \section2 Creating the Application

    First, in \c{bargraph.cpp}, instantiate Q3DBars and a window container for it:

    \snippet graphgallery/bargraph.cpp 0

    The call to QWidget::createWindowContainer is required, as all data visualization graph classes
    (Q3DBars, Q3DScatter, Q3DSurface) inherit QWindow. This is the only way to use a class that
    inherits QWindow as a widget.

    Then, create horizontal and vertical layouts. Add the graph and the vertical layout to the
    horizontal one:

    \snippet graphgallery/bargraph.cpp 1

    Next, create another class to handle the data addition and other interaction with the
    graph:

    \snippet graphgallery/bargraph.cpp 2

    \section2 Setting up the Bar Graph

    Set up the graph in the constructor of the \c GraphModifier class:

    \snippet graphgallery/graphmodifier.cpp 0

    First, create the axes and the series into member variables to support changing them easily:

    \snippet graphgallery/graphmodifier.cpp 1

    Then, set some visual qualities for the graph:

    \snippet graphgallery/graphmodifier.cpp 2

    Set up the axes and make them the active axes of the graph:

    \snippet graphgallery/graphmodifier.cpp 3

    Give axis labels a small autorotation angle with setLabelAutoRotation() to make them orient
    slightly toward the camera. This improves axis label readability at extreme camera angles.

    Next, initialize the visual properties of the series. Note that the second series is initially
    not visible:

    \snippet graphgallery/graphmodifier.cpp 4

    Add the series to the graph:

    \snippet graphgallery/graphmodifier.cpp 5

    Finally, set the camera angle by calling the same method the camera angle change button
    in the UI uses to cycle through various camera angles:

    \snippet graphgallery/graphmodifier.cpp 6

    The camera is controlled via the scene object of the graph:

    \snippet graphgallery/graphmodifier.cpp 7

    For more information about using scene and cameras, see Q3DScene and Q3DCamera.

    \section2 Adding Data to the Graph

    At the end of the constructor, call a method that sets up the data:

    \snippet graphgallery/graphmodifier.cpp 8

    This method adds data to the proxies of the two series:

    \snippet graphgallery/graphmodifier.cpp 9a
    \dots 0
    \snippet graphgallery/graphmodifier.cpp 9b

    \section2 Using Widgets to Control the Graph

    Continue by adding some widgets in \c{bargraph.cpp}. Add a slider:

    \snippet graphgallery/bargraph.cpp 3

    Use the slider to rotate the graph instead of just using a mouse or touch. Add it to the
    vertical layout:

    \snippet graphgallery/bargraph.cpp 4

    Then, connect it to a method in \c GraphModifier:

    \snippet graphgallery/bargraph.cpp 5

    Create a slot in \c GraphModifier for the signal connection. The camera is controlled via the
    scene object. This time, specify the actual camera position along the orbit around the center
    point, instead of specifying a preset camera angle:

    \snippet graphgallery/graphmodifier.cpp 10

    You can now use the slider to rotate the graph.

    Add more widgets to the vertical layout to control:

    \list
        \li Graph rotation
        \li Label style
        \li Camera preset
        \li Background visibility
        \li Grid visibility
        \li Bar shading smoothness
        \li Visibility of the second bar series
        \li Value axis direction
        \li Axis title visibility and rotation
        \li Data range to be shown
        \li Bar style
        \li Selection mode
        \li Theme
        \li Shadow quality
        \li Font
        \li Font size
        \li Axis label rotation
        \li Data mode
    \endlist

    Some widget controls are intentionally disabled when in the \uicontrol {Custom Proxy Data}
    data mode.

    \section2 Selecting a Row or Column by Clicking an Axis Label

    Selection by axis label is default functionality for bar graphs. As an example, you can select
    rows by clicking an axis label in the following way:

    \list 1
        \li Change selection mode to \c SelectionRow
        \li Click a year label
        \li The row with the clicked year is selected
    \endlist

    The same method works with \c SelectionSlice and \c SelectionItem flags, as long as
    either \c SelectionRow or \c SelectionColumn is set as well.

    \section2 Zooming to Selection

    As an example of adjusting the camera target, implement an animation of zooming to
    selection via a button press. Animation initializations are done in the constructor:

    \snippet graphgallery/graphmodifier.cpp 11

    Function \c{GraphModifier::zoomToSelectedBar()} contains the zooming functionality.
    QPropertyAnimation \c m_animationCameraTarget targets Q3DCamera::target property,
    which takes a value normalized to the range (-1, 1).

    Figure out where the selected bar is relative to axes, and use that as the end value for
    \c{m_animationCameraTarget}:

    \snippet graphgallery/graphmodifier.cpp 12
    \dots 0
    \snippet graphgallery/graphmodifier.cpp 13

    Then, rotate the camera so that it always points approximately to the center of
    the graph at the end of the animation:

    \snippet graphgallery/graphmodifier.cpp 14

    \section2 Custom Proxy for Data

    By toggling \uicontrol {Custom Proxy Data} data mode on, a custom dataset and the corresponding
    proxy are taken into use.

    Define a simple flexible data set, \c{VariantDataSet}, where each data item is
    a variant list. Each item can have multiple values, identified by their index in
    the list. In this case, the data set is storing monthly rainfall data, where the value in
    index zero is the year, the value in index one is the month, and the value in index two is
    the amount of rainfall in that month.

    The custom proxy is similar to itemmodel-based proxies provided by Qt Data Visualization, and
    it requires mapping to interpret the data.

    \section3 VariantDataSet

    Define the data items as QVariantList objects. Add functionality for clearing the data set and
    querying for a reference to the data contained in the set. Also, add signals to be emitted when
    data is added or the set is cleared:

    \snippet graphgallery/variantdataset.h 0
    \dots 0
    \codeline
    \snippet graphgallery/variantdataset.h 1

    \section3 VariantBarDataProxy

    Subclass \c VariantBarDataProxy from QBarDataProxy and provide a simple API of getters and
    setters for the data set and the mapping:

    \snippet graphgallery/variantbardataproxy.h 0
    \dots 0
    \codeline
    \snippet graphgallery/variantbardataproxy.h 1

    The proxy listens for the changes in the data set and the mapping, and resolves the data set
    if any changes are detected. This is not a particularly efficient implementation, as any change
    will cause re-resolving of the entire data set, but that is not an issue for this example.

    In \c resolveDataSet() method, sort the variant data values into rows and columns based on the
    mapping. This is very similar to how QItemModelBarDataProxy handles mapping, except you use
    list indexes instead of item model roles here. Once the values are sorted, generate
    \c QBarDataArray out of them, and call the \c resetArray() method in the parent class:

    \snippet graphgallery/variantbardataproxy.cpp 0

    \section3 VariantBarDataMapping

    Store the mapping information between \c VariantDataSet data item indexes and rows, columns,
    and values of \c QBarDataArray in \c VariantBarDataMapping. It contains the lists of rows and
    columns to be included in the resolved data:

    \snippet graphgallery/variantbardatamapping.h 0
    \dots 0
    \codeline
    \snippet graphgallery/variantbardatamapping.h 1
    \dots 0
    \codeline
    \snippet graphgallery/variantbardatamapping.h 2
    \dots 0
    \codeline
    \snippet graphgallery/variantbardatamapping.h 3

    The primary way to use a \c VariantBarDataMapping object is to give the mappings in the
    constructor, though you can use the \c remap() method to set them later, either individually or
    all together. Emit a signal if mapping changes. The outcome is a simplified version of the
    mapping functionality of QItemModelBarDataProxy, adapted to work with variant lists instead of
    item models.

    \section3 RainfallData

    Handle the setup of QBar3DSeries with the custom proxy in the \c RainfallData class:

    \snippet graphgallery/rainfalldata.cpp 0

    Populate the variant data set in the \c addDataSet() method:

    \snippet graphgallery/rainfalldata.cpp 1
    \dots

    Add the data set to the custom proxy and set the mapping:

    \snippet graphgallery/rainfalldata.cpp 2

    Finally, add a function for getting the created series for displaying:

    \snippet graphgallery/rainfalldata.h 0

    \section1 Scatter Graph

    In the \uicontrol {Scatter Graph} tab, create a 3D scatter graph using Q3DScatter.
    The example shows how to:

    \list
        \li Set up Q3DScatter graph
        \li Use QScatterDataProxy to set data to the graph
        \li Create a custom input handler by extending Q3DInputHandler
    \endlist

    For basic application creation, see \l {Bar Graph}.

    \section2 Setting up the Scatter Graph

    First, set up some visual qualities for the graph in the constructor of the
    \c ScatterDataModifier:

    \snippet graphgallery/scatterdatamodifier.cpp 0

    None of these are mandatory, but are used to override graph defaults. You can try how it looks
    with the preset defaults by commenting out the block above.

    Next, create a QScatterDataProxy and the associated QScatter3DSeries. Set a custom label format
    and mesh smoothing for the series and add it to the graph:

    \snippet graphgallery/scatterdatamodifier.cpp 1

    \section2 Adding Scatter Data

    The last thing to do in the \c ScatterDataModifier constructor is to add data to the graph:

    \snippet graphgallery/scatterdatamodifier.cpp 2

    The actual data addition is done in \c addData() method. First, configure the axes:

    \snippet graphgallery/scatterdatamodifier.cpp 3

    You could do this also in the constructor of \c {ScatterDataModifier}. Doing it here
    keeps the constructor simpler and the axes' configuration near the data.

    Next, create a data array and populate it:

    \snippet graphgallery/scatterdatamodifier.cpp 4
    \dots
    \snippet graphgallery/scatterdatamodifier.cpp 5

    Finally, tell the proxy to start using the data we gave it:

    \snippet graphgallery/scatterdatamodifier.cpp 6

    Now, the graph has the data and is ready for use. For information about adding widgets
    to control the graph, see \l {Using Widgets to Control the Graph}.

    \section2 Replacing Default Input Handling

    Initialize \c m_inputHandler in the constructor with a pointer to the scatter graph instance:

    \snippet graphgallery/scatterdatamodifier.cpp 7

    Replace the default input handling mechanism by setting the active input handler of
    Q3DScatter to \c {AxesInputHandler}, which implements the custom behavior:

    \snippet graphgallery/scatterdatamodifier.cpp 8

    The input handler needs access to the axes of the graph, so pass them to it:

    \snippet graphgallery/scatterdatamodifier.cpp 9

    \section2 Extending Mouse Event Handling

    First, inherit the custom input handler from Q3DInputHandler instead of QAbstract3DInputHandler
    to keep all the functionality of the default input handling, and to add the custom
    functionality on top of it:

    \snippet graphgallery/axesinputhandler.h 0

    Start extending the default functionality by re-implementing some of the mouse events.
    First, extend \c {mousePressEvent}. Add a \c{m_mousePressed} flag for the left mouse button
    to it, and keep the rest of the default functionality:

    \snippet graphgallery/axesinputhandler.cpp 0

    Next, modify \c mouseReleaseEvent to clear the flag, and reset the internal state:

    \snippet graphgallery/axesinputhandler.cpp 1

    Then, modify \c {mouseMoveEvent}. Check if \c m_mousePressed flag is \c {true} and
    the internal state is something other than \c StateNormal. If so, set the input positions
    for mouse movement distance calculations, and call the axis dragging function (see
    \l {Implementing Axis Dragging} for details):

    \snippet graphgallery/axesinputhandler.cpp 2

    \section2 Implementing Axis Dragging

    First, start listening to the selection signal from the graph. Do that in the
    constructor, and connect it to the \c handleElementSelected method:

    \snippet graphgallery/axesinputhandler.cpp 3

    In \c {handleElementSelected}, check the type of the selection, and set the internal state
    based on it:

    \snippet graphgallery/axesinputhandler.cpp 4

    The actual dragging logic is implemented in the \c handleAxisDragging method, which is called
    from \c {mouseMoveEvent}, if the required conditions are met:

    \snippet graphgallery/axesinputhandler.cpp 5

    In \c {handleAxisDragging}, first get the scene orientation from the active camera:

    \snippet graphgallery/axesinputhandler.cpp 6

    Then, calculate the modifiers for mouse movement direction based on the orientation:

    \snippet graphgallery/axesinputhandler.cpp 7

    After that, calculate the mouse movement, and modify it based on the y rotation of the
    camera:

    \snippet graphgallery/axesinputhandler.cpp 8

    Then, apply the moved distance to the correct axis:

    \snippet graphgallery/axesinputhandler.cpp 9

    Finally, add a function for setting the dragging speed:

    \snippet graphgallery/axesinputhandler.h 1

    This is needed, as the mouse movement distance is absolute in screen coordinates, and you
    need to adjust it to the axis range. The larger the value, the slower the dragging will be.
    Note that in this example, the scene zoom level is not taken into account when determining the
    drag speed, so you'll notice changes in the range adjustment as you change the zoom level.

    You could also adjust the modifier automatically based on the axis range and camera zoom level.

    \section1 Example Contents
*/