├── .gitignore ├── GPL.txt ├── changelog.txt ├── examples ├── interactions │ ├── .gitignore │ ├── interaction-example.pro │ ├── main.cpp │ ├── mainwindow.cpp │ ├── mainwindow.h │ └── mainwindow.ui ├── plots │ ├── .gitignore │ ├── balboa.jpg │ ├── main.cpp │ ├── mainwindow.cpp │ ├── mainwindow.h │ ├── mainwindow.ui │ ├── plot-examples.pro │ ├── screenshots │ │ ├── .gitignore │ │ └── create-thumbs.py │ ├── solarpanels.jpg │ └── sun.png ├── scrollbar-axis-range-control │ ├── .gitignore │ ├── main.cpp │ ├── mainwindow.cpp │ ├── mainwindow.h │ ├── mainwindow.ui │ └── scrollbar-axis-range-control.pro └── text-document-integration │ ├── .gitignore │ ├── main.cpp │ ├── mainwindow.cpp │ ├── mainwindow.h │ ├── mainwindow.ui │ ├── qcpdocumentobject.cpp │ ├── qcpdocumentobject.h │ └── text-document-integration.pro ├── qcustomplot.cpp └── qcustomplot.h /.gitignore: -------------------------------------------------------------------------------- 1 | # common 2 | *~ 3 | *.a 4 | *.core 5 | *.moc 6 | *.o 7 | *.obj 8 | *.orig 9 | *.rej 10 | *.so 11 | *_pch.h.cpp 12 | *_resource.rc 13 | *.qm 14 | .#* 15 | *.*# 16 | tags 17 | .DS_Store 18 | *.debug 19 | Makefile* 20 | *.prl 21 | *.app 22 | moc_*.cpp 23 | ui_*.h 24 | qrc_*.cpp 25 | Thumbs.db 26 | # KDE 27 | .directory 28 | 29 | # python temporary files 30 | *.pyc 31 | 32 | # nsis files... 33 | nsis/dlls/* 34 | nsis/*.exe 35 | 36 | # qtcreator generated files 37 | *.pro.user* 38 | *.qmlproject.user* 39 | *.pluginspec 40 | 41 | # xemacs temporary files 42 | *.flc 43 | 44 | # Vim temporary files 45 | .*.swp 46 | 47 | # Visual Studio generated files 48 | *.ib_pdb_index 49 | *.idb 50 | *.ilk 51 | *.pdb 52 | *.sln 53 | *.suo 54 | *.vcproj 55 | *.vcxproj* 56 | *vcproj.*.*.user 57 | *vcxproj.*.*.user 58 | *.ncb 59 | *.opensdf 60 | *.sdf 61 | 62 | # MinGW generated files 63 | *.Debug 64 | *.Release 65 | 66 | # Directories to ignore 67 | # --------------------- 68 | 69 | temp 70 | debug 71 | lib/* 72 | lib64/* 73 | release 74 | doc/html/* 75 | ipch/* 76 | 77 | .rcc 78 | .pch 79 | 80 | -------------------------------------------------------------------------------- /GPL.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /changelog.txt: -------------------------------------------------------------------------------- 1 | #### Version 1.3.0 released on 27.12.14 #### 2 | 3 | Added features: 4 | - New plottable class QCPFinancial allows display of candlestick/ohlc data 5 | - New class QCPBarsGroup allows horizontal grouping of multiple QCPBars plottables 6 | - Added QCPBars feature allowing non-zero base values (see property QCPBars::setBaseValue) 7 | - Added QCPBars width type, for more flexible bar widths (see property QCPBars::setWidthType) 8 | - New QCPCurve optimization algorithm, fixes bug which caused line flicker at deep zoom into curve segment 9 | - Item positions can now have different position types and anchors for their x and y coordinates (QCPItemPosition::setTypeX/Y, setParentAnchorX/Y) 10 | - QCPGraph and QCPCurve can now display gaps in their lines, when inserting quiet NaNs as values (std::numeric_limits::quiet_NaN()) 11 | - QCPAxis now supports placing the tick labels inside the axis rect, for particularly space saving plots (QCPAxis::setTickLabelSide) 12 | Added features after beta: 13 | - Made code compatible with QT_NO_CAST_FROM_ASCII, QT_NO_CAST_TO_ASCII 14 | - Added compatibility with QT_NO_KEYWORDS after sending code files through a simple reg-ex script 15 | - Added possibility to inject own QCPAxis(-subclasses) via second, optional QCPAxisRect::addAxis parameter 16 | - Added parameter to QCPItemPixmap::setScaled to specify transformation mode 17 | 18 | Bugfixes: 19 | - Fixed bug in QCPCurve rendering of very zoomed-in curves (via new optimization algorithm) 20 | - Fixed conflict with MSVC-specific keyword "interface" in text-document-integration example 21 | - Fixed QCPScatterStyle bug ignoring the specified pen in the custom scatter shape constructor 22 | - Fixed bug (possible crash) during QCustomPlot teardown, when a QCPLegend that has no parent layout (i.e. was removed from layout manually) gets deleted 23 | Bugfixes after beta: 24 | - Fixed bug of QCPColorMap/QCPColorGradient colors being off by one color sampling step (only noticeable in special cases) 25 | - Fixed bug of QCPGraph adaptive sampling on vertical key axis, causing staggered look 26 | - Fixed low (float) precision in QCPCurve optimization algorithm, by not using QVector2D anymore 27 | 28 | Other: 29 | - Qt 5.3 and Qt 5.4 compatibility 30 | 31 | #### Version 1.2.1 released on 07.04.14 #### 32 | 33 | Bugfixes: 34 | - Fixed regression which garbled date-time tick labels on axes, if setTickLabelType is ltDateTime and setNumberFormat contains the "b" option 35 | 36 | #### Version 1.2.0 released on 14.03.14 #### 37 | 38 | Added features: 39 | - Adaptive Sampling for QCPGraph greatly improves performance for high data densities (see QCPGraph::setAdaptiveSampling) 40 | - QCPColorMap plottable with QCPColorScale layout element allows plotting of 2D color maps 41 | - QCustomPlot::savePdf now has additional optional parameters pdfCreator and pdfTitle to set according PDF metadata fields 42 | - QCustomPlot::replot now allows specifying whether the widget update is immediate (repaint) or queued (update) 43 | - QCPRange operators +, -, *, / with double operand for range shifting and scaling, and ==, != for range comparison 44 | - Layers now have a visibility property (QCPLayer::setVisible) 45 | - static functions QCPAxis::opposite and QCPAxis::orientation now offer more convenience when handling axis types 46 | - added notification signals for selectability change (selectableChanged) on all objects that have a selected/selectable property 47 | - added notification signal for QCPAxis scaleType property 48 | - added notification signal QCPLayerable::layerChanged 49 | 50 | Bugfixes: 51 | - Fixed assert halt, when QCPAxis auto tick labels not disabled but nevertheless a custom non-number tick label ending in "e" given 52 | - Fixed painting glitches when QCustomPlot resized inside a QMdiArea or under certain conditions inside a QLayout 53 | - If changing QCPAxis::scaleType and thus causing range sanitizing and a range modification, rangeChanged wouldn't be emitted 54 | - Fixed documentation bug that caused indentation to be lost in code examples 55 | Bugfixes after beta: 56 | - Fixed bug that caused crash if clicked-on legend item is removed in mousePressEvent. 57 | - On some systems, font size defaults to -1, which used to cause a debug output in QCPAxisPainterPrivate::TickLabelDataQCP. Now it's checked before setting values based on the default font size. 58 | - When using multiple axes on one side, setting one to invisible didn't properly compress the freed space. 59 | - Fixed bug that allowed selection of plottables when clicking in the bottom or top margin of a QCPAxisRect (outside the inner rect) 60 | 61 | Other: 62 | - In method QCPAbstractPlottable::getKeyRange/getValueRange, renamed parameter "validRange" to "foundRange", to better reflect its meaning (and contrast it from QCPRange::validRange) 63 | - QCPAxis low-level axis painting methods exported to QCPAxisPainterPrivate 64 | 65 | #### Version 1.1.1 released on 09.12.13 #### 66 | 67 | Bugfixes: 68 | - Fixed bug causing legends blocking input events from reaching underlying axis rect even if legend is invisible 69 | - Added missing Q_PROPERTY for QCPAxis::setDateTimeSpec 70 | - Fixed behaviour of QCPAxisRect::setupFullAxesBox (now transfers more properties from bottom/left to top/right axes and sets visibility of bottom/left axes to true) 71 | - Made sure PDF export doesn't default to grayscale output on some systems 72 | 73 | Other: 74 | - Plotting hint QCP::phForceRepaint is now enabled on all systems (and not only on windows) by default 75 | - Documentation improvements 76 | 77 | #### Version 1.1.0 released on 04.11.13 #### 78 | 79 | Added features: 80 | - Added QCPRange::expand and QCPRange::expanded 81 | - Added QCPAxis::rescale to rescale axis to all associated plottables 82 | - Added QCPAxis::setDateTimeSpec/dateTimeSpec to allow axis labels either in UTC or local time 83 | - QCPAxis now additionally emits a rangeChanged signal overload that provides the old range as second parameter 84 | 85 | Bugfixes: 86 | - Fixed QCustomPlot::rescaleAxes not rescaling properly if first plottable has an empty range 87 | - QCPGraph::rescaleAxes/rescaleKeyAxis/rescaleValueAxis are no longer virtual (never were in base class, was a mistake) 88 | - Fixed bugs in QCPAxis::items and QCPAxisRect::items not properly returning associated items and potentially stalling 89 | 90 | Other: 91 | - Internal change from QWeakPointer to QPointer, thus got rid of deprecated Qt functionality 92 | - Qt5.1 and Qt5.2 (beta1) compatibility 93 | - Release packages now extract to single subdirectory and don't place multiple files in current working directory 94 | 95 | #### Version 1.0.1 released on 05.09.13 #### 96 | 97 | Bugfixes: 98 | - using define flag QCUSTOMPLOT_CHECK_DATA caused debug output when data was correct, instead of invalid (fixed QCP::isInvalidData) 99 | - documentation images are now properly shown when viewed with Qt Assistant 100 | - fixed various documentation mistakes 101 | 102 | Other: 103 | - Adapted documentation style sheet to better match Qt5 documentation 104 | 105 | #### Version 1.0.0 released on 01.08.13 #### 106 | 107 | Quick Summary: 108 | - Layout system for multiple axis rects in one plot 109 | - Multiple axes per side 110 | - Qt5 compatibility 111 | - More flexible and consistent scatter configuration with QCPScatterStyle 112 | - Various interface cleanups/refactoring 113 | - Pixmap-cached axis labels for improved replot performance 114 | 115 | Changes that break backward compatibility: 116 | - QCustomPlot::axisRect() changed meaning due to the extensive changes to how axes and axis rects are handled 117 | it now returns a pointer to a QCPAxisRect and takes an integer index as parameter. 118 | - QCPAxis constructor changed to now take QCPAxisRect* as parent 119 | - setAutoMargin, setMarginLeft/Right/Top/Bottom removed due to the axis rect changes (see QCPAxisRect::setMargins/setAutoMargins) 120 | - setAxisRect removed due to the axis rect changes 121 | - setAxisBackground(-Scaled/-ScaledMode) now moved to QCPAxisRect as setBackground(-Scaled/ScaledMode) (access via QCustomPlot::axisRects()) 122 | - QCPLegend now is a QCPLayoutElement 123 | - QCPAbstractPlottable::drawLegendIcon parameter "rect" changed from QRect to QRectF 124 | - QCPAbstractLegendItem::draw second parameter removed (position/size now handled via QCPLayoutElement base class) 125 | - removed QCPLegend::setMargin/setMarginLeft/Right/Top/Bottom (now inherits the capability from QCPLayoutElement::setMargins) 126 | - removed QCPLegend::setMinimumSize (now inherits the capability from QCPLayoutElement::setMinimumSize) 127 | - removed enum QCPLegend::PositionStyle, QCPLegend::positionStyle/setPositionStyle/position/setPosition (replaced by capabilities of QCPLayoutInset) 128 | - QCPLegend transformed to work with new layout system (almost everything changed) 129 | - removed entire title interface: QCustomPlot::setTitle/setTitleFont/setTitleColor/setTitleSelected/setTitleSelectedFont/setTitleSelectedColor and 130 | the QCustomPlot::iSelectTitle interaction flag (all functionality is now given by the layout element "QCPPlotTitle" which can be added to the plot layout) 131 | - selectTest functions now take two additional parameters: bool onlySelectable and QVariant *details=0 132 | - selectTest functions now ignores visibility of objects and (if parameter onlySelectable is true) does not anymore ignore selectability of the object 133 | - moved QCustomPlot::Interaction/Interactions to QCP namespace as QCP::Interaction/Interactions 134 | - moved QCustomPlot::setupFullAxesBox() to QCPAxisRect::setupFullAxesBox. Now also accepts parameter to decide whether to connect opposite axis ranges 135 | - moved range dragging/zooming interface from QCustomPlot to QCPAxisRect (setRangeDrag, setRangeZoom, setRangeDragAxes, setRangeZoomAxes,...) 136 | - rangeDrag/Zoom is now set to Qt::Horizontal|Qt::Vertical instead of 0 by default, on the other hand, iRangeDrag/Zoom is unset in interactions by 137 | default (this makes enabling dragging/zooming easier by just adding the interaction flags) 138 | - QCPScatterStyle takes over everything related to handling scatters in all plottables 139 | - removed setScatterPen/Size on QCPGraph and QCPCurve, removed setOutlierPen/Size on QCPStatisticalBox (now handled via QCPScatterStyle) 140 | - modified setScatterStyle on QCPGraph and QCPCurve, and setOutlierStyle on QCPStatisticalBox, to take QCPScatterStyle 141 | - axis grid and subgrid are now reachable via the QCPGrid *QCPAxis::grid() method. (e.g. instead of xAxis->setGrid(true), write xAxis->grid()->setVisible(true)) 142 | 143 | Added features: 144 | - Axis tick labels are now pixmap-cached, thus increasing replot performance (in usual setups by about 24%). See plotting hint phCacheLabels which is set by default 145 | - Advanced layout system, including the classes QCPLayoutElement, QCPLayout, QCPLayoutGrid, QCPLayoutInset, QCPAxisRect 146 | - QCustomPlot::axisRects() returns all the axis rects in the QCustomPlot. 147 | - QCustomPlot::plotLayout() returns the top level layout (initially a QCPLayoutGrid with one QCPAxisRect inside) 148 | - QCPAxis now may have an offset to the axis rect (setOffset) 149 | - Multiple axes per QCPAxisRect side are now supported (see QCPAxisRect::addAxis) 150 | - QCustomPlot::toPixmap renders the plot into a pixmap and returns it 151 | - When setting tick label rotation to +90 or -90 degrees on a vertical axis, the labels are now centered vertically on the tick height 152 | (This allows space saving vertical tick labels by having the text direction parallel to the axis) 153 | - Substantially increased replot performance when using very large manual tick vectors (> 10000 ticks) via QCPAxis::setTickVector 154 | - QCPAxis and QCPAxisRect now allow easy access to all plottables(), graphs() and items() that are associated with them 155 | - Added QCustomPlot::hasItem method for consistency with plottable interface, hasPlottable 156 | - Added QCPAxisRect::setMinimumMargins as replacement for hardcoded minimum axis margin (15 px) when auto margin is enabled 157 | - Added Flags type QCPAxis::AxisTypes (from QCPAxis::AxisType), used in QCPAxisRect interface 158 | - Automatic margin calculation can now be enabled/disabled on a per-side basis, see QCPAxisRect::setAutoMargins 159 | - QCPAxisRect margins of multiple axis rects can be coupled via QCPMarginGroup 160 | - Added new default layers "background" and "legend" (QCPAxisRect draws its background on the "background" layer, QCPLegend is on the "legend" layer by default) 161 | - Custom scatter style via QCP::ssCustom and respective setCustomScatter functions that take a QPainterPath 162 | - Filled scatters via QCPScatterStyle::setBrush 163 | Added features after beta: 164 | - Added QCustomPlot::toPainter method, to allow rendering with existing painter 165 | - QCPItemEllipse now provides a center anchor 166 | 167 | Bugfixes: 168 | - Fixed compile error on ARM 169 | - Wrong legend icons were displayed if using pixmaps for scatters that are smaller than the legend icon rect 170 | - Fixed clipping inaccuracy for rotated tick labels (were hidden too early, because the non-rotated bounding box was used) 171 | - Fixed bug that caused wrong clipping of axis ticks and subticks when the ticks were given manually by QCPAxis::setTickVector 172 | - Fixed Qt5 crash when dragging graph out of view (iterator out of bounds in QCPGraph::getVisibleDataBounds) 173 | - Fixed QCPItemText not scaling properly when using scaled raster export 174 | Bugfixes after beta: 175 | - Fixed bug that clipped the rightmost pixel column of tick labels when caching activated (only visible on windows for superscript exponents) 176 | - Restored compatibility to Qt4.6 177 | - Restored support for -no-RTTI compilation 178 | - Empty manual tick labels are handled more gracefully (no QPainter qDebug messages anymore) 179 | - Fixed type ambiguity in QCPLineEnding::draw causing compile error on ARM 180 | - Fixed bug of grid layouts not propagating the minimum size from their child elements to the parent layout correctly 181 | - Fixed bug of child elements (e.g. axis rects) of inset layouts not properly receiving mouse events 182 | 183 | Other: 184 | - Opened up non-amalgamated project structure to public via git repository 185 | 186 | #### Version released on 09.06.12 #### 187 | 188 | Quick Summary: 189 | - Items (arrows, text,...) 190 | - Layers (easier control over rendering order) 191 | - New antialiasing system (Each objects controls own antialiasing with setAntialiased) 192 | - Performance Improvements 193 | - improved pixel-precise drawing 194 | - easier shared library creation/usage 195 | 196 | Changes that (might) break backward compatibility: 197 | - enum QCPGraph::ScatterSymbol was moved to QCP namespace (now QCP::ScatterSymbol). 198 | This replace should fix your code: "QCPGraph::ss" -> "QCP::ss" 199 | - enum QCustomPlot::AntialiasedElement and flag QCustomPlot::AntialiasedElements was moved to QCP namespace 200 | This replace should fix your code: "QCustomPlot::ae" -> "QCP::ae" 201 | - the meaning of QCustomPlot::setAntialiasedElements has changed slightly: It is now an override to force elements to be antialiased. If you want to force 202 | elements to not be drawn antialiased, use the new setNotAntialiasedElements. If an element is mentioned in neither of those functions, it now controls 203 | its antialiasing itself via its "setAntialiased" function(s). (e.g. QCPAxis::setAntialiased(bool), QCPAbstractPlottable::setAntialiased(bool), 204 | QCPAbstractPlottable::setAntialiasedScatters(bool), etc.) 205 | - QCPAxis::setTickVector and QCPAxis::setTickVectorLabels no longer take a pointer but a const reference of the respective QVector as parameter. 206 | (handing over a pointer didn't give any noticeable performance benefits but was inconsistent with the rest of the interface) 207 | - Equally QCPAxis::tickVector and QCPAxis::tickVectorLabels don't return by pointer but by value now 208 | - QCustomPlot::savePngScaled was removed, its purpose is now included as optional parameter "scale" of savePng. 209 | - If you have derived from QCPAbstractPlottable: all selectTest functions now consistently take the argument "const QPointF &pos" which is the test point in pixel coordinates. 210 | (the argument there was "double key, double value" in plot coordinates, before). 211 | - QCPAbstractPlottable, QCPAxis and QCPLegend now inherit from QCPLayerable 212 | - If you have derived from QCPAbstractPlottable: the draw method signature has changed from "draw (..) const" to "draw (..)", i.e. the method 213 | is not const anymore. This allows the draw function of your plottable to perform buffering/caching operations, if necessary. 214 | 215 | Added features: 216 | - Item system: QCPAbstractItem, QCPItemAnchor, QCPItemPosition, QCPLineEnding. Allows placing of lines, arrows, text, pixmaps etc. 217 | - New Items: QCPItemStraightLine, QCPItemLine, QCPItemCurve, QCPItemEllipse, QCPItemRect, QCPItemPixmap, QCPItemText, QCPItemBracket, QCPItemTracer 218 | - QCustomPlot::addItem/itemCount/item/removeItem/selectedItems 219 | - signals QCustomPlot::itemClicked/itemDoubleClicked 220 | - the QCustomPlot interactions property now includes iSelectItems (for selection of QCPAbstractItem) 221 | - QCPLineEnding. Represents the different styles a line/curve can end (e.g. different arrows, circle, square, bar, etc.), see e.g. QCPItemCurve::setHead 222 | - Layer system: QCPLayerable, QCPLayer. Allows more sophisticated control over drawing order and a kind of grouping. 223 | - QCPAbstractPlottable, QCPAbstractItem, QCPAxis, QCPGrid, QCPLegend are layerables and derive from QCPLayerable 224 | - QCustomPlot::addLayer/moveLayer/removeLayer/setCurrentLayer/layer/currentLayer/layerCount 225 | - Initially there are three layers: "grid", "main", and "axes". The "main" layer is initially empty and set as current layer, so new plottables/items are put there. 226 | - QCustomPlot::viewport now makes the previously inaccessible viewport rect read-only-accessible (needed that for item-interface) 227 | - PNG export now allows transparent background by calling QCustomPlot::setColor(Qt::transparent) before savePng 228 | - QCPStatisticalBox outlier symbols may now be all scatter symbols, not only hardcoded circles. 229 | - perfect precision of scatter symbol/error bar drawing and clipping in both antialiased and non-antialiased mode, by introducing QCPPainter 230 | that works around some QPainter bugs/inconveniences. Further, more complex symbols like ssCrossSquare used to look crooked, now they look good. 231 | - new antialiasing control system: Each drawing element now has its own "setAntialiased" function to control whether it is drawn antialiased. 232 | - QCustomPlot::setAntialiasedElements and QCustomPlot::setNotAntialiasedElements can be used to override the individual settings. 233 | - Subclasses of QCPAbstractPlottable can now use the convenience functions like applyFillAntialiasingHint or applyScattersAntialiasingHint to 234 | easily make their drawing code comply with the overall antialiasing system. 235 | - QCustomPlot::setNoAntialiasingOnDrag allows greatly improved performance and responsiveness by temporarily disabling all antialiasing while 236 | the user is dragging axis ranges 237 | - QCPGraph can now show scatter symbols at data points and hide its line (see QCPGraph::setScatterStyle, setScatterSize, setScatterPixmap, setLineStyle) 238 | - Grid drawing code was sourced out from QCPAxis to QCPGrid. QCPGrid is mainly an internal class and every QCPAxis owns one. The grid interface still 239 | works through QCPAxis and hasn't changed. The separation allows the grid to be drawn on a different layer as the axes, such that e.g. a graph can 240 | be above the grid but below the axes. 241 | - QCustomPlot::hasPlottable(plottable), returns whether the QCustomPlot contains the plottable 242 | - QCustomPlot::setPlottingHint/setPlottingHints, plotting hints control details about the plotting quality/speed 243 | - export to jpg and bmp added (QCustomPlot::saveJpg/saveBmp), as well as control over compression quality for png and jpg 244 | - multi-select-modifier may now be specified with QCustomPlot::setMultiSelectModifier and is not fixed to Ctrl anymore 245 | 246 | Bugfixes: 247 | - fixed QCustomPlot ignores replot after it had size (0,0) even if size becomes valid again 248 | - on Windows, a repaint used to be delayed during dragging/zooming of a complex plot, until the drag operation was done. 249 | This was fixed, i.e. repaints are forced after a replot() call. See QCP::phForceRepaint and setPlottingHints. 250 | - when using the raster paintengine and exporting to scaled PNG, pen widths are now scaled correctly (QPainter bug workaround via QCPPainter) 251 | - PDF export now respects QCustomPlot background color (QCustomPlot::setColor), also Qt::transparent 252 | - fixed a bug on QCPBars and QCPStatisticalBox where auto-rescaling of axis would fail when all data is very small (< 1e-11) 253 | - fixed mouse event propagation bug that prevented range dragging from working on KDE (GNU/Linux) 254 | - fixed a compiler warning on 64-bit systems due to pointer cast to int instead of quintptr in a qDebug output 255 | 256 | Other: 257 | - Added support for easier shared library creation (including examples for compiling and using QCustomPlot as shared library) 258 | - QCustomPlot now has the Qt::WA_OpaquePaintEvent widget attribute (gives slightly improved performance). 259 | - QCP::aeGraphs (enum QCP::AntialiasedElement, previously QCustomPlot::aeGraphs) has been marked deprecated since version 02.02.12 and 260 | was now removed. Use QCP::aePlottables instead. 261 | - optional performance-quality-tradeoff for solid graph lines (see QCustomPlot::setPlottingHints). 262 | - marked data classes and QCPRange as Q_MOVABLE_TYPE 263 | - replaced usage of own macro FUNCNAME with Qt macro Q_FUNC_INFO 264 | - QCustomPlot now returns a minimum size hint of 50*50 265 | 266 | #### Version released on 31.03.12 #### 267 | 268 | Changes that (might) break backward compatibility: 269 | - QCPAbstractLegendItem now inherits from QObject 270 | - mousePress, mouseMove and mouseRelease signals are now emitted before and not after any QCustomPlot processing (range dragging, selecting, etc.) 271 | 272 | Added features: 273 | - Interaction system: now allows selecting of objects like plottables, axes, legend and plot title, see QCustomPlot::setInteractions documentation 274 | - Interaction system for plottables: 275 | - setSelectable, setSelected, setSelectedPen, setSelectedBrush, selectTest on QCPAbstractPlottable and all derived plottables 276 | - setSelectionTolerance on QCustomPlot 277 | - selectedPlottables and selectedGraphs on QCustomPlot (returns the list of currently selected plottables/graphs) 278 | - Interaction system for axes: 279 | - setSelectable, setSelected, setSelectedBasePen, setSelectedTickPen, setSelectedSubTickPen, setSelectedLabelFont, setSelectedTickLabelFont, 280 | setSelectedLabelColor, setSelectedTickLabelColor, selectTest on QCPAxis 281 | - selectedAxes on QCustomPlot (returns a list of the axes that currently have selected parts) 282 | - Interaction system for legend: 283 | - setSelectable, setSelected, setSelectedBorderPen, setSelectedIconBorderPen, setSelectedBrush, setSelectedFont, setSelectedTextColor, selectedItems on QCPLegend 284 | - setSelectedFont, setSelectedTextColor, setSelectable, setSelected on QCPAbstractLegendItem 285 | - selectedLegends on QCustomPlot 286 | - Interaction system for title: 287 | - setSelectedTitleFont, setSelectedTitleColor, setTitleSelected on QCustomPlot 288 | - new signals in accordance with the interaction system: 289 | - selectionChangedByUser on QCustomPlot 290 | - selectionChanged on QCPAbstractPlottable 291 | - selectionChanged on QCPAxis 292 | - selectionChanged on QCPLegend and QCPAbstractLegendItem 293 | - plottableClick, legendClick, axisClick, titleClick, plottableDoubleClick, legendDoubleClick, axisDoubleClick, titleDoubleClick on QCustomPlot 294 | - QCustomPlot::deselectAll (deselects everything, i.e. axes and plottables) 295 | - QCPAbstractPlottable::pixelsToCoords (inverse function to the already existing coordsToPixels function) 296 | - QCPRange::contains(double value) 297 | - QCPAxis::setLabelColor and setTickLabelColor 298 | - QCustomPlot::setTitleColor 299 | - QCustomPlot now emits beforeReplot and afterReplot signals. Note that it is safe to make two customPlots mutually call eachothers replot functions 300 | in one of these slots, it will not cause an infinite loop. (usefull for synchronizing axes ranges between two customPlots, because setRange alone doesn't replot) 301 | - If the Qt version is 4.7 or greater, the tick label strings in date-time-mode now support sub-second accuracy (e.g. with format like "hh:mm:ss.zzz"). 302 | 303 | Bugfixes: 304 | - tick labels/margins should no longer oscillate by one pixel when dragging range or replotting repeatedly while changing e.g. data. This 305 | was caused by a bug in Qt's QFontMetrics::boundingRect function when the font has an integer point size (probably some rounding problem). 306 | The fix hence consists of creating a temporary font (only for bounding-box calculation) which is 0.05pt larger and thus avoiding the 307 | jittering rounding outcome. 308 | - tick label, axis label and plot title colors used to be undefined. This was fixed by providing explicit color properties. 309 | 310 | Other: 311 | - fixed some glitches in the documentation 312 | - QCustomPlot::replot and QCustomPlot::rescaleAxes are now slots 313 | 314 | #### Version released on 02.02.12 #### 315 | 316 | Changes that break backward compatibility: 317 | - renamed all secondary classes from QCustomPlot[...] to QCP[...]: 318 | QCustomPlotAxis -> QCPAxis 319 | QCustomPlotGraph -> QCPGraph 320 | QCustomPlotRange -> QCPRange 321 | QCustomPlotData -> QCPData 322 | QCustomPlotDataMap -> QCPDataMap 323 | QCustomPlotLegend -> QCPLegend 324 | QCustomPlotDataMapIterator -> QCPDataMapIterator 325 | QCustomPlotDataMutableMapIterator -> QCPDataMutableMapIterator 326 | A simple search and replace on all code files should make your code run again, e.g. consider the regex "QCustomPlot(?=[AGRDL])" -> "QCP". 327 | Make sure not to just replace "QCustomPlot" with "QCP" because the main class QCustomPlot hasn't changed to QCP. 328 | This change was necessary because class names became unhandy, pardon my bad naming decision in the beginning. 329 | - QCPAxis::tickLength() and QCPAxis::subTickLength() now each split into two functions for inward and outward ticks (tickLengthIn/tickLengthOut). 330 | - QCPLegend now uses QCPAbstractLegendItem to carry item data (before, the legend was passed QCPGraphs directly) 331 | - QCustomPlot::addGraph() now doesn't return the index of the created graph anymore, but a pointer to the created QCPGraph. 332 | - QCustomPlot::setAutoAddGraphToLegend is replaced by setAutoAddPlottableToLegend 333 | 334 | Added features: 335 | - Reversed axis range with QCPAxis::setRangeReversed(bool) 336 | - Tick labels are now only drawn if not clipped by the viewport (widget border) on the sides (e.g. left and right on a horizontal axis). 337 | - Zerolines. Like grid lines only with a separate pen (QCPAxis::setZeroLinePen), at tick position zero. 338 | - Outward ticks. QCPAxis::setTickLength/setSubTickLength now accepts two arguments for inward and outward tick length. This doesn't break 339 | backward compatibility because the second argument (outward) has default value zero and thereby a call with one argument hasn't changed its meaning. 340 | - QCPGraph now inherits from QCPAbstractPlottable 341 | - QCustomPlot::addPlottable/plottable/removePlottable/clearPlottables added to interface with the new QCPAbstractPlottable-based system. The simpler interface 342 | which only acts on QCPGraphs (addGraph, graph, removeGraph, etc.) was adapted internally and is kept for backward compatibility and ease of use. 343 | - QCPLegend items for plottables (e.g. graphs) can automatically wrap their texts to fit the widths, see QCPLegend::setMinimumSize and QCPPlottableLegendItem::setTextWrap. 344 | - QCustomPlot::rescaleAxes. Adapts axis ranges to show all plottables/graphs, by calling QCPAbstractPlottable::rescaleAxes on all plottables in the plot. 345 | - QCPCurve. For plotting of parametric curves. 346 | - QCPBars. For plotting of bar charts. 347 | - QCPStatisticalBox. For statistical box plots. 348 | 349 | Bugfixes: 350 | - Fixed QCustomPlot::removeGraph(int) not being able to remove graph index 0 351 | - made QCustomPlot::replot() abort painting when painter initialization fails (e.g. because width/height of QCustomPlot is zero) 352 | - The distance of the axis label from the axis ignored the tick label padding, this could have caused overlapping axis labels and tick labels 353 | - fixed memory leak in QCustomPlot (dtor didn't delete legend) 354 | - fixed bug that prevented QCPAxis::setRangeLower/Upper from setting the value to exactly 0. 355 | 356 | Other: 357 | - Changed default error bar handle size (QCustomPlotGraph::setErrorBarSize) from 4 to 6. 358 | - Removed QCustomPlotDataFetcher. Was deprecated and not used class. 359 | - Extended documentation, especially class descriptions. 360 | 361 | #### Version released on 15.01.12 #### 362 | 363 | Changes that (might) break backward compatibility: 364 | - QCustomPlotGraph now inherits from QObject 365 | 366 | Added features: 367 | - Added axis background pixmap (QCustomPlot::setAxisBackground, setAxisBackgroundScaled, setAxisBackgroundScaledMode) 368 | - Added width and height parameter on PDF export function QCustomPlot::savePdf(). This now allows PDF export to 369 | have arbitrary dimensions, independent of the current geometry of the QCustomPlot. 370 | - Added overload of QCustomPlot::removeGraph that takes QCustomPlotGraph* as parameter, instead the index of the graph 371 | - Added all enums to the Qt meta system via Q_ENUMS(). The enums can now be transformed 372 | to QString values easily with the Qt meta system, which makes saving state e.g. as XML 373 | significantly nicer. 374 | - added typedef QMapIterator QCustomPlotDataMapIterator 375 | and typedef QMutableMapIterator QCustomPlotDataMutableMapIterator 376 | for improved information hiding, when using iterators outside QCustomPlot code 377 | 378 | Bugfixes: 379 | - Fixed savePngScaled. Axis/label drawing functions used to reset the painter transform 380 | and thereby break savePngScaled. Now they buffer the current transform and restore it afterwards. 381 | - Fixed some glitches in the doxygen comments (affects documentation only) 382 | 383 | Other: 384 | - Changed the default tickLabelPadding of top axis from 3 to 6 pixels. Looks better. 385 | - Changed the default QCustomPlot::setAntialiasedElements setting: Graph fills are now antialiased 386 | by default. That's a bit slower, but makes fill borders look better. 387 | 388 | #### Version released on 19.11.11 #### 389 | 390 | Changes that break backward compatibility: 391 | - QCustomPlotAxis: tickFont and setTickFont renamed to tickLabelFont and setTickLabelFont (for naming consistency) 392 | 393 | Other: 394 | - QCustomPlotAxis: Added rotated tick labels, see setTickLabelRotation 395 | 396 | -------------------------------------------------------------------------------- /examples/interactions/.gitignore: -------------------------------------------------------------------------------- 1 | interaction-example -------------------------------------------------------------------------------- /examples/interactions/interaction-example.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2012-03-04T23:24:55 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport 9 | 10 | TARGET = interaction-example 11 | TEMPLATE = app 12 | 13 | SOURCES += main.cpp\ 14 | mainwindow.cpp \ 15 | ../../qcustomplot.cpp 16 | 17 | HEADERS += mainwindow.h \ 18 | ../../qcustomplot.h 19 | 20 | FORMS += mainwindow.ui 21 | 22 | -------------------------------------------------------------------------------- /examples/interactions/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "mainwindow.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /examples/interactions/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | 4 | MainWindow::MainWindow(QWidget *parent) : 5 | QMainWindow(parent), 6 | ui(new Ui::MainWindow) 7 | { 8 | srand(QDateTime::currentDateTime().toTime_t()); 9 | ui->setupUi(this); 10 | 11 | ui->customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectAxes | 12 | QCP::iSelectLegend | QCP::iSelectPlottables); 13 | ui->customPlot->xAxis->setRange(-8, 8); 14 | ui->customPlot->yAxis->setRange(-5, 5); 15 | ui->customPlot->axisRect()->setupFullAxesBox(); 16 | 17 | ui->customPlot->plotLayout()->insertRow(0); 18 | ui->customPlot->plotLayout()->addElement(0, 0, new QCPPlotTitle(ui->customPlot, "Interaction Example")); 19 | 20 | ui->customPlot->xAxis->setLabel("x Axis"); 21 | ui->customPlot->yAxis->setLabel("y Axis"); 22 | ui->customPlot->legend->setVisible(true); 23 | QFont legendFont = font(); 24 | legendFont.setPointSize(10); 25 | ui->customPlot->legend->setFont(legendFont); 26 | ui->customPlot->legend->setSelectedFont(legendFont); 27 | ui->customPlot->legend->setSelectableParts(QCPLegend::spItems); // legend box shall not be selectable, only legend items 28 | 29 | addRandomGraph(); 30 | addRandomGraph(); 31 | addRandomGraph(); 32 | addRandomGraph(); 33 | 34 | // connect slot that ties some axis selections together (especially opposite axes): 35 | connect(ui->customPlot, SIGNAL(selectionChangedByUser()), this, SLOT(selectionChanged())); 36 | // connect slots that takes care that when an axis is selected, only that direction can be dragged and zoomed: 37 | connect(ui->customPlot, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(mousePress())); 38 | connect(ui->customPlot, SIGNAL(mouseWheel(QWheelEvent*)), this, SLOT(mouseWheel())); 39 | 40 | // make bottom and left axes transfer their ranges to top and right axes: 41 | connect(ui->customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), ui->customPlot->xAxis2, SLOT(setRange(QCPRange))); 42 | connect(ui->customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), ui->customPlot->yAxis2, SLOT(setRange(QCPRange))); 43 | 44 | // connect some interaction slots: 45 | connect(ui->customPlot, SIGNAL(titleDoubleClick(QMouseEvent*,QCPPlotTitle*)), this, SLOT(titleDoubleClick(QMouseEvent*,QCPPlotTitle*))); 46 | connect(ui->customPlot, SIGNAL(axisDoubleClick(QCPAxis*,QCPAxis::SelectablePart,QMouseEvent*)), this, SLOT(axisLabelDoubleClick(QCPAxis*,QCPAxis::SelectablePart))); 47 | connect(ui->customPlot, SIGNAL(legendDoubleClick(QCPLegend*,QCPAbstractLegendItem*,QMouseEvent*)), this, SLOT(legendDoubleClick(QCPLegend*,QCPAbstractLegendItem*))); 48 | 49 | // connect slot that shows a message in the status bar when a graph is clicked: 50 | connect(ui->customPlot, SIGNAL(plottableClick(QCPAbstractPlottable*,QMouseEvent*)), this, SLOT(graphClicked(QCPAbstractPlottable*))); 51 | 52 | // setup policy and connect slot for context menu popup: 53 | ui->customPlot->setContextMenuPolicy(Qt::CustomContextMenu); 54 | connect(ui->customPlot, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequest(QPoint))); 55 | } 56 | 57 | MainWindow::~MainWindow() 58 | { 59 | delete ui; 60 | } 61 | 62 | void MainWindow::titleDoubleClick(QMouseEvent* event, QCPPlotTitle* title) 63 | { 64 | Q_UNUSED(event) 65 | // Set the plot title by double clicking on it 66 | bool ok; 67 | QString newTitle = QInputDialog::getText(this, "QCustomPlot example", "New plot title:", QLineEdit::Normal, title->text(), &ok); 68 | if (ok) 69 | { 70 | title->setText(newTitle); 71 | ui->customPlot->replot(); 72 | } 73 | } 74 | 75 | void MainWindow::axisLabelDoubleClick(QCPAxis *axis, QCPAxis::SelectablePart part) 76 | { 77 | // Set an axis label by double clicking on it 78 | if (part == QCPAxis::spAxisLabel) // only react when the actual axis label is clicked, not tick label or axis backbone 79 | { 80 | bool ok; 81 | QString newLabel = QInputDialog::getText(this, "QCustomPlot example", "New axis label:", QLineEdit::Normal, axis->label(), &ok); 82 | if (ok) 83 | { 84 | axis->setLabel(newLabel); 85 | ui->customPlot->replot(); 86 | } 87 | } 88 | } 89 | 90 | void MainWindow::legendDoubleClick(QCPLegend *legend, QCPAbstractLegendItem *item) 91 | { 92 | // Rename a graph by double clicking on its legend item 93 | Q_UNUSED(legend) 94 | if (item) // only react if item was clicked (user could have clicked on border padding of legend where there is no item, then item is 0) 95 | { 96 | QCPPlottableLegendItem *plItem = qobject_cast(item); 97 | bool ok; 98 | QString newName = QInputDialog::getText(this, "QCustomPlot example", "New graph name:", QLineEdit::Normal, plItem->plottable()->name(), &ok); 99 | if (ok) 100 | { 101 | plItem->plottable()->setName(newName); 102 | ui->customPlot->replot(); 103 | } 104 | } 105 | } 106 | 107 | void MainWindow::selectionChanged() 108 | { 109 | /* 110 | normally, axis base line, axis tick labels and axis labels are selectable separately, but we want 111 | the user only to be able to select the axis as a whole, so we tie the selected states of the tick labels 112 | and the axis base line together. However, the axis label shall be selectable individually. 113 | 114 | The selection state of the left and right axes shall be synchronized as well as the state of the 115 | bottom and top axes. 116 | 117 | Further, we want to synchronize the selection of the graphs with the selection state of the respective 118 | legend item belonging to that graph. So the user can select a graph by either clicking on the graph itself 119 | or on its legend item. 120 | */ 121 | 122 | // make top and bottom axes be selected synchronously, and handle axis and tick labels as one selectable object: 123 | if (ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spAxis) || ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spTickLabels) || 124 | ui->customPlot->xAxis2->selectedParts().testFlag(QCPAxis::spAxis) || ui->customPlot->xAxis2->selectedParts().testFlag(QCPAxis::spTickLabels)) 125 | { 126 | ui->customPlot->xAxis2->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels); 127 | ui->customPlot->xAxis->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels); 128 | } 129 | // make left and right axes be selected synchronously, and handle axis and tick labels as one selectable object: 130 | if (ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spAxis) || ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spTickLabels) || 131 | ui->customPlot->yAxis2->selectedParts().testFlag(QCPAxis::spAxis) || ui->customPlot->yAxis2->selectedParts().testFlag(QCPAxis::spTickLabels)) 132 | { 133 | ui->customPlot->yAxis2->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels); 134 | ui->customPlot->yAxis->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels); 135 | } 136 | 137 | // synchronize selection of graphs with selection of corresponding legend items: 138 | for (int i=0; icustomPlot->graphCount(); ++i) 139 | { 140 | QCPGraph *graph = ui->customPlot->graph(i); 141 | QCPPlottableLegendItem *item = ui->customPlot->legend->itemWithPlottable(graph); 142 | if (item->selected() || graph->selected()) 143 | { 144 | item->setSelected(true); 145 | graph->setSelected(true); 146 | } 147 | } 148 | } 149 | 150 | void MainWindow::mousePress() 151 | { 152 | // if an axis is selected, only allow the direction of that axis to be dragged 153 | // if no axis is selected, both directions may be dragged 154 | 155 | if (ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spAxis)) 156 | ui->customPlot->axisRect()->setRangeDrag(ui->customPlot->xAxis->orientation()); 157 | else if (ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spAxis)) 158 | ui->customPlot->axisRect()->setRangeDrag(ui->customPlot->yAxis->orientation()); 159 | else 160 | ui->customPlot->axisRect()->setRangeDrag(Qt::Horizontal|Qt::Vertical); 161 | } 162 | 163 | void MainWindow::mouseWheel() 164 | { 165 | // if an axis is selected, only allow the direction of that axis to be zoomed 166 | // if no axis is selected, both directions may be zoomed 167 | 168 | if (ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spAxis)) 169 | ui->customPlot->axisRect()->setRangeZoom(ui->customPlot->xAxis->orientation()); 170 | else if (ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spAxis)) 171 | ui->customPlot->axisRect()->setRangeZoom(ui->customPlot->yAxis->orientation()); 172 | else 173 | ui->customPlot->axisRect()->setRangeZoom(Qt::Horizontal|Qt::Vertical); 174 | } 175 | 176 | void MainWindow::addRandomGraph() 177 | { 178 | int n = 50; // number of points in graph 179 | double xScale = (rand()/(double)RAND_MAX + 0.5)*2; 180 | double yScale = (rand()/(double)RAND_MAX + 0.5)*2; 181 | double xOffset = (rand()/(double)RAND_MAX - 0.5)*4; 182 | double yOffset = (rand()/(double)RAND_MAX - 0.5)*5; 183 | double r1 = (rand()/(double)RAND_MAX - 0.5)*2; 184 | double r2 = (rand()/(double)RAND_MAX - 0.5)*2; 185 | double r3 = (rand()/(double)RAND_MAX - 0.5)*2; 186 | double r4 = (rand()/(double)RAND_MAX - 0.5)*2; 187 | QVector x(n), y(n); 188 | for (int i=0; icustomPlot->addGraph(); 195 | ui->customPlot->graph()->setName(QString("New graph %1").arg(ui->customPlot->graphCount()-1)); 196 | ui->customPlot->graph()->setData(x, y); 197 | ui->customPlot->graph()->setLineStyle((QCPGraph::LineStyle)(rand()%5+1)); 198 | if (rand()%100 > 75) 199 | ui->customPlot->graph()->setScatterStyle(QCPScatterStyle((QCPScatterStyle::ScatterShape)(rand()%9+1))); 200 | QPen graphPen; 201 | graphPen.setColor(QColor(rand()%245+10, rand()%245+10, rand()%245+10)); 202 | graphPen.setWidthF(rand()/(double)RAND_MAX*2+1); 203 | ui->customPlot->graph()->setPen(graphPen); 204 | ui->customPlot->replot(); 205 | } 206 | 207 | void MainWindow::removeSelectedGraph() 208 | { 209 | if (ui->customPlot->selectedGraphs().size() > 0) 210 | { 211 | ui->customPlot->removeGraph(ui->customPlot->selectedGraphs().first()); 212 | ui->customPlot->replot(); 213 | } 214 | } 215 | 216 | void MainWindow::removeAllGraphs() 217 | { 218 | ui->customPlot->clearGraphs(); 219 | ui->customPlot->replot(); 220 | } 221 | 222 | void MainWindow::contextMenuRequest(QPoint pos) 223 | { 224 | QMenu *menu = new QMenu(this); 225 | menu->setAttribute(Qt::WA_DeleteOnClose); 226 | 227 | if (ui->customPlot->legend->selectTest(pos, false) >= 0) // context menu on legend requested 228 | { 229 | menu->addAction("Move to top left", this, SLOT(moveLegend()))->setData((int)(Qt::AlignTop|Qt::AlignLeft)); 230 | menu->addAction("Move to top center", this, SLOT(moveLegend()))->setData((int)(Qt::AlignTop|Qt::AlignHCenter)); 231 | menu->addAction("Move to top right", this, SLOT(moveLegend()))->setData((int)(Qt::AlignTop|Qt::AlignRight)); 232 | menu->addAction("Move to bottom right", this, SLOT(moveLegend()))->setData((int)(Qt::AlignBottom|Qt::AlignRight)); 233 | menu->addAction("Move to bottom left", this, SLOT(moveLegend()))->setData((int)(Qt::AlignBottom|Qt::AlignLeft)); 234 | } else // general context menu on graphs requested 235 | { 236 | menu->addAction("Add random graph", this, SLOT(addRandomGraph())); 237 | if (ui->customPlot->selectedGraphs().size() > 0) 238 | menu->addAction("Remove selected graph", this, SLOT(removeSelectedGraph())); 239 | if (ui->customPlot->graphCount() > 0) 240 | menu->addAction("Remove all graphs", this, SLOT(removeAllGraphs())); 241 | } 242 | 243 | menu->popup(ui->customPlot->mapToGlobal(pos)); 244 | } 245 | 246 | void MainWindow::moveLegend() 247 | { 248 | if (QAction* contextAction = qobject_cast(sender())) // make sure this slot is really called by a context menu action, so it carries the data we need 249 | { 250 | bool ok; 251 | int dataInt = contextAction->data().toInt(&ok); 252 | if (ok) 253 | { 254 | ui->customPlot->axisRect()->insetLayout()->setInsetAlignment(0, (Qt::Alignment)dataInt); 255 | ui->customPlot->replot(); 256 | } 257 | } 258 | } 259 | 260 | void MainWindow::graphClicked(QCPAbstractPlottable *plottable) 261 | { 262 | ui->statusBar->showMessage(QString("Clicked on graph '%1'.").arg(plottable->name()), 1000); 263 | } 264 | 265 | 266 | 267 | 268 | -------------------------------------------------------------------------------- /examples/interactions/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include "../../qcustomplot.h" 7 | 8 | namespace Ui { 9 | class MainWindow; 10 | } 11 | 12 | class MainWindow : public QMainWindow 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit MainWindow(QWidget *parent = 0); 18 | ~MainWindow(); 19 | 20 | private slots: 21 | void titleDoubleClick(QMouseEvent *event, QCPPlotTitle *title); 22 | void axisLabelDoubleClick(QCPAxis* axis, QCPAxis::SelectablePart part); 23 | void legendDoubleClick(QCPLegend* legend, QCPAbstractLegendItem* item); 24 | void selectionChanged(); 25 | void mousePress(); 26 | void mouseWheel(); 27 | void addRandomGraph(); 28 | void removeSelectedGraph(); 29 | void removeAllGraphs(); 30 | void contextMenuRequest(QPoint pos); 31 | void moveLegend(); 32 | void graphClicked(QCPAbstractPlottable *plottable); 33 | 34 | private: 35 | Ui::MainWindow *ui; 36 | }; 37 | 38 | #endif // MAINWINDOW_H 39 | -------------------------------------------------------------------------------- /examples/interactions/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 621 10 | 515 11 | 12 | 13 | 14 | QCustomPlot Interaction Example 15 | 16 | 17 | 18 | 19 | 20 | 21 | QFrame::StyledPanel 22 | 23 | 24 | QFrame::Sunken 25 | 26 | 27 | 1 28 | 29 | 30 | 0 31 | 32 | 33 | 34 | 0 35 | 36 | 37 | 0 38 | 39 | 40 | 41 | 42 | 43 | 0 44 | 0 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | QFrame::StyledPanel 56 | 57 | 58 | QFrame::Raised 59 | 60 | 61 | 62 | 63 | 64 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 65 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> 66 | p, li { white-space: pre-wrap; } 67 | </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> 68 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Select the axes</span> to drag and zoom them individually.</p> 69 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Double click labels</span> or legend items to set user specified strings.</p> 70 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Left click</span> on graphs or legend to select graphs.</p> 71 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Right click</span> for a popup menu to add/remove graphs and move the legend</p></body></html> 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 0 84 | 0 85 | 621 86 | 25 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | QCustomPlot 96 | QWidget 97 |
../../qcustomplot.h
98 | 1 99 |
100 |
101 | 102 | 103 |
104 | -------------------------------------------------------------------------------- /examples/plots/.gitignore: -------------------------------------------------------------------------------- 1 | plot-examples 2 | -------------------------------------------------------------------------------- /examples/plots/balboa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbzhang800/QCustomPlot/d1d69480e3f7af8959ecd3d3b3c8bbfffc7b1292/examples/plots/balboa.jpg -------------------------------------------------------------------------------- /examples/plots/main.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** ** 3 | ** QCustomPlot, an easy to use, modern plotting widget for Qt ** 4 | ** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** 5 | ** ** 6 | ** This program is free software: you can redistribute it and/or modify ** 7 | ** it under the terms of the GNU General Public License as published by ** 8 | ** the Free Software Foundation, either version 3 of the License, or ** 9 | ** (at your option) any later version. ** 10 | ** ** 11 | ** This program is distributed in the hope that it will be useful, ** 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 14 | ** GNU General Public License for more details. ** 15 | ** ** 16 | ** You should have received a copy of the GNU General Public License ** 17 | ** along with this program. If not, see http://www.gnu.org/licenses/. ** 18 | ** ** 19 | **************************************************************************** 20 | ** Author: Emanuel Eichhammer ** 21 | ** Website/Contact: http://www.qcustomplot.com/ ** 22 | ** Date: 27.12.14 ** 23 | ** Version: 1.3.0 ** 24 | ****************************************************************************/ 25 | 26 | #include 27 | #include "mainwindow.h" 28 | 29 | int main(int argc, char *argv[]) 30 | { 31 | #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) 32 | QApplication::setGraphicsSystem("raster"); 33 | #endif 34 | QApplication a(argc, argv); 35 | MainWindow w; 36 | w.show(); 37 | 38 | return a.exec(); 39 | } 40 | -------------------------------------------------------------------------------- /examples/plots/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** ** 3 | ** QCustomPlot, an easy to use, modern plotting widget for Qt ** 4 | ** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** 5 | ** ** 6 | ** This program is free software: you can redistribute it and/or modify ** 7 | ** it under the terms of the GNU General Public License as published by ** 8 | ** the Free Software Foundation, either version 3 of the License, or ** 9 | ** (at your option) any later version. ** 10 | ** ** 11 | ** This program is distributed in the hope that it will be useful, ** 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 14 | ** GNU General Public License for more details. ** 15 | ** ** 16 | ** You should have received a copy of the GNU General Public License ** 17 | ** along with this program. If not, see http://www.gnu.org/licenses/. ** 18 | ** ** 19 | **************************************************************************** 20 | ** Author: Emanuel Eichhammer ** 21 | ** Website/Contact: http://www.qcustomplot.com/ ** 22 | ** Date: 27.12.14 ** 23 | ** Version: 1.3.0 ** 24 | ****************************************************************************/ 25 | 26 | /************************************************************************************************************ 27 | ** ** 28 | ** This is the example code for QCustomPlot. ** 29 | ** ** 30 | ** It demonstrates basic and some advanced capabilities of the widget. The interesting code is inside ** 31 | ** the "setup(...)Demo" functions of MainWindow. ** 32 | ** ** 33 | ** In order to see a demo in action, call the respective "setup(...)Demo" function inside the ** 34 | ** MainWindow constructor. Alternatively you may call setupDemo(i) where i is the index of the demo ** 35 | ** you want (for those, see MainWindow constructor comments). All other functions here are merely a ** 36 | ** way to easily create screenshots of all demos for the website. I.e. a timer is set to successively ** 37 | ** setup all the demos and make a screenshot of the window area and save it in the ./screenshots ** 38 | ** directory. ** 39 | ** ** 40 | *************************************************************************************************************/ 41 | 42 | #include "mainwindow.h" 43 | #include "ui_mainwindow.h" 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | MainWindow::MainWindow(QWidget *parent) : 51 | QMainWindow(parent), 52 | ui(new Ui::MainWindow) 53 | { 54 | ui->setupUi(this); 55 | setGeometry(400, 250, 542, 390); 56 | 57 | setupDemo(0); 58 | //setupPlayground(ui->customPlot); 59 | // 0: setupQuadraticDemo(ui->customPlot); 60 | // 1: setupSimpleDemo(ui->customPlot); 61 | // 2: setupSincScatterDemo(ui->customPlot); 62 | // 3: setupScatterStyleDemo(ui->customPlot); 63 | // 4: setupScatterPixmapDemo(ui->customPlot); 64 | // 5: setupLineStyleDemo(ui->customPlot); 65 | // 6: setupDateDemo(ui->customPlot); 66 | // 7: setupTextureBrushDemo(ui->customPlot); 67 | // 8: setupMultiAxisDemo(ui->customPlot); 68 | // 9: setupLogarithmicDemo(ui->customPlot); 69 | // 10: setupRealtimeDataDemo(ui->customPlot); 70 | // 11: setupParametricCurveDemo(ui->customPlot); 71 | // 12: setupBarChartDemo(ui->customPlot); 72 | // 13: setupStatisticalDemo(ui->customPlot); 73 | // 14: setupSimpleItemDemo(ui->customPlot); 74 | // 15: setupItemDemo(ui->customPlot); 75 | // 16: setupStyledDemo(ui->customPlot); 76 | // 17: setupAdvancedAxesDemo(ui->customPlot); 77 | // 18: setupColorMapDemo(ui->customPlot); 78 | // 19: setupFinancialDemo(ui->customPlot); 79 | 80 | // for making screenshots of the current demo or all demos (for website screenshots): 81 | //QTimer::singleShot(1500, this, SLOT(allScreenShots())); 82 | //QTimer::singleShot(4000, this, SLOT(screenShot())); 83 | } 84 | 85 | void MainWindow::setupDemo(int demoIndex) 86 | { 87 | switch (demoIndex) 88 | { 89 | case 0: setupQuadraticDemo(ui->customPlot); break; 90 | case 1: setupSimpleDemo(ui->customPlot); break; 91 | case 2: setupSincScatterDemo(ui->customPlot); break; 92 | case 3: setupScatterStyleDemo(ui->customPlot); break; 93 | case 4: setupScatterPixmapDemo(ui->customPlot); break; 94 | case 5: setupLineStyleDemo(ui->customPlot); break; 95 | case 6: setupDateDemo(ui->customPlot); break; 96 | case 7: setupTextureBrushDemo(ui->customPlot); break; 97 | case 8: setupMultiAxisDemo(ui->customPlot); break; 98 | case 9: setupLogarithmicDemo(ui->customPlot); break; 99 | case 10: setupRealtimeDataDemo(ui->customPlot); break; 100 | case 11: setupParametricCurveDemo(ui->customPlot); break; 101 | case 12: setupBarChartDemo(ui->customPlot); break; 102 | case 13: setupStatisticalDemo(ui->customPlot); break; 103 | case 14: setupSimpleItemDemo(ui->customPlot); break; 104 | case 15: setupItemDemo(ui->customPlot); break; 105 | case 16: setupStyledDemo(ui->customPlot); break; 106 | case 17: setupAdvancedAxesDemo(ui->customPlot); break; 107 | case 18: setupColorMapDemo(ui->customPlot); break; 108 | case 19: setupFinancialDemo(ui->customPlot); break; 109 | } 110 | setWindowTitle("QCustomPlot: "+demoName); 111 | statusBar()->clearMessage(); 112 | currentDemoIndex = demoIndex; 113 | ui->customPlot->replot(); 114 | } 115 | 116 | void MainWindow::setupQuadraticDemo(QCustomPlot *customPlot) 117 | { 118 | demoName = "Quadratic Demo"; 119 | // generate some data: 120 | QVector x(101), y(101); // initialize with entries 0..100 121 | for (int i=0; i<101; ++i) 122 | { 123 | x[i] = i/50.0 - 1; // x goes from -1 to 1 124 | y[i] = x[i]*x[i]; // let's plot a quadratic function 125 | } 126 | // create graph and assign data to it: 127 | customPlot->addGraph(); 128 | customPlot->graph(0)->setData(x, y); 129 | // give the axes some labels: 130 | customPlot->xAxis->setLabel("x"); 131 | customPlot->yAxis->setLabel("y"); 132 | // set axes ranges, so we see all data: 133 | customPlot->xAxis->setRange(-1, 1); 134 | customPlot->yAxis->setRange(0, 1); 135 | } 136 | 137 | void MainWindow::setupSimpleDemo(QCustomPlot *customPlot) 138 | { 139 | demoName = "Simple Demo"; 140 | 141 | // add two new graphs and set their look: 142 | customPlot->addGraph(); 143 | customPlot->graph(0)->setPen(QPen(Qt::blue)); // line color blue for first graph 144 | customPlot->graph(0)->setBrush(QBrush(QColor(0, 0, 255, 20))); // first graph will be filled with translucent blue 145 | customPlot->addGraph(); 146 | customPlot->graph(1)->setPen(QPen(Qt::red)); // line color red for second graph 147 | // generate some points of data (y0 for first, y1 for second graph): 148 | QVector x(250), y0(250), y1(250); 149 | for (int i=0; i<250; ++i) 150 | { 151 | x[i] = i; 152 | y0[i] = qExp(-i/150.0)*qCos(i/10.0); // exponentially decaying cosine 153 | y1[i] = qExp(-i/150.0); // exponential envelope 154 | } 155 | // configure right and top axis to show ticks but no labels: 156 | // (see QCPAxisRect::setupFullAxesBox for a quicker method to do this) 157 | customPlot->xAxis2->setVisible(true); 158 | customPlot->xAxis2->setTickLabels(false); 159 | customPlot->yAxis2->setVisible(true); 160 | customPlot->yAxis2->setTickLabels(false); 161 | // make left and bottom axes always transfer their ranges to right and top axes: 162 | connect(customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->xAxis2, SLOT(setRange(QCPRange))); 163 | connect(customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->yAxis2, SLOT(setRange(QCPRange))); 164 | // pass data points to graphs: 165 | customPlot->graph(0)->setData(x, y0); 166 | customPlot->graph(1)->setData(x, y1); 167 | // let the ranges scale themselves so graph 0 fits perfectly in the visible area: 168 | customPlot->graph(0)->rescaleAxes(); 169 | // same thing for graph 1, but only enlarge ranges (in case graph 1 is smaller than graph 0): 170 | customPlot->graph(1)->rescaleAxes(true); 171 | // Note: we could have also just called customPlot->rescaleAxes(); instead 172 | // Allow user to drag axis ranges with mouse, zoom with mouse wheel and select graphs by clicking: 173 | customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables); 174 | } 175 | 176 | void MainWindow::setupSincScatterDemo(QCustomPlot *customPlot) 177 | { 178 | demoName = "Sinc Scatter Demo"; 179 | customPlot->legend->setVisible(true); 180 | customPlot->legend->setFont(QFont("Helvetica",9)); 181 | // set locale to english, so we get english decimal separator: 182 | customPlot->setLocale(QLocale(QLocale::English, QLocale::UnitedKingdom)); 183 | // add confidence band graphs: 184 | customPlot->addGraph(); 185 | QPen pen; 186 | pen.setStyle(Qt::DotLine); 187 | pen.setWidth(1); 188 | pen.setColor(QColor(180,180,180)); 189 | customPlot->graph(0)->setName("Confidence Band 68%"); 190 | customPlot->graph(0)->setPen(pen); 191 | customPlot->graph(0)->setBrush(QBrush(QColor(255,50,30,20))); 192 | customPlot->addGraph(); 193 | customPlot->legend->removeItem(customPlot->legend->itemCount()-1); // don't show two confidence band graphs in legend 194 | customPlot->graph(1)->setPen(pen); 195 | customPlot->graph(0)->setChannelFillGraph(customPlot->graph(1)); 196 | // add theory curve graph: 197 | customPlot->addGraph(); 198 | pen.setStyle(Qt::DashLine); 199 | pen.setWidth(2); 200 | pen.setColor(Qt::red); 201 | customPlot->graph(2)->setPen(pen); 202 | customPlot->graph(2)->setName("Theory Curve"); 203 | // add data point graph: 204 | customPlot->addGraph(); 205 | customPlot->graph(3)->setPen(QPen(Qt::blue)); 206 | customPlot->graph(3)->setLineStyle(QCPGraph::lsNone); 207 | customPlot->graph(3)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCross, 4)); 208 | customPlot->graph(3)->setErrorType(QCPGraph::etValue); 209 | customPlot->graph(3)->setErrorPen(QPen(QColor(180,180,180))); 210 | customPlot->graph(3)->setName("Measurement"); 211 | 212 | // generate ideal sinc curve data and some randomly perturbed data for scatter plot: 213 | QVector x0(250), y0(250); 214 | QVector yConfUpper(250), yConfLower(250); 215 | for (int i=0; i<250; ++i) 216 | { 217 | x0[i] = (i/249.0-0.5)*30+0.01; // by adding a small offset we make sure not do divide by zero in next code line 218 | y0[i] = qSin(x0[i])/x0[i]; // sinc function 219 | yConfUpper[i] = y0[i]+0.15; 220 | yConfLower[i] = y0[i]-0.15; 221 | x0[i] *= 1000; 222 | } 223 | QVector x1(50), y1(50), y1err(50); 224 | for (int i=0; i<50; ++i) 225 | { 226 | // generate a gaussian distributed random number: 227 | double tmp1 = rand()/(double)RAND_MAX; 228 | double tmp2 = rand()/(double)RAND_MAX; 229 | double r = qSqrt(-2*qLn(tmp1))*qCos(2*M_PI*tmp2); // box-muller transform for gaussian distribution 230 | // set y1 to value of y0 plus a random gaussian pertubation: 231 | x1[i] = (i/50.0-0.5)*30+0.25; 232 | y1[i] = qSin(x1[i])/x1[i]+r*0.15; 233 | x1[i] *= 1000; 234 | y1err[i] = 0.15; 235 | } 236 | // pass data to graphs and let QCustomPlot determine the axes ranges so the whole thing is visible: 237 | customPlot->graph(0)->setData(x0, yConfUpper); 238 | customPlot->graph(1)->setData(x0, yConfLower); 239 | customPlot->graph(2)->setData(x0, y0); 240 | customPlot->graph(3)->setDataValueError(x1, y1, y1err); 241 | customPlot->graph(2)->rescaleAxes(); 242 | customPlot->graph(3)->rescaleAxes(true); 243 | // setup look of bottom tick labels: 244 | customPlot->xAxis->setTickLabelRotation(30); 245 | customPlot->xAxis->setAutoTickCount(9); 246 | customPlot->xAxis->setNumberFormat("ebc"); 247 | customPlot->xAxis->setNumberPrecision(1); 248 | customPlot->xAxis->moveRange(-10); 249 | // make top right axes clones of bottom left axes. Looks prettier: 250 | customPlot->axisRect()->setupFullAxesBox(); 251 | } 252 | 253 | void MainWindow::setupScatterStyleDemo(QCustomPlot *customPlot) 254 | { 255 | demoName = "Scatter Style Demo"; 256 | customPlot->legend->setVisible(true); 257 | customPlot->legend->setFont(QFont("Helvetica", 9)); 258 | customPlot->legend->setRowSpacing(-3); 259 | QVector shapes; 260 | shapes << QCPScatterStyle::ssCross; 261 | shapes << QCPScatterStyle::ssPlus; 262 | shapes << QCPScatterStyle::ssCircle; 263 | shapes << QCPScatterStyle::ssDisc; 264 | shapes << QCPScatterStyle::ssSquare; 265 | shapes << QCPScatterStyle::ssDiamond; 266 | shapes << QCPScatterStyle::ssStar; 267 | shapes << QCPScatterStyle::ssTriangle; 268 | shapes << QCPScatterStyle::ssTriangleInverted; 269 | shapes << QCPScatterStyle::ssCrossSquare; 270 | shapes << QCPScatterStyle::ssPlusSquare; 271 | shapes << QCPScatterStyle::ssCrossCircle; 272 | shapes << QCPScatterStyle::ssPlusCircle; 273 | shapes << QCPScatterStyle::ssPeace; 274 | shapes << QCPScatterStyle::ssCustom; 275 | 276 | QPen pen; 277 | // add graphs with different scatter styles: 278 | for (int i=0; iaddGraph(); 281 | pen.setColor(QColor(qSin(i*0.3)*100+100, qSin(i*0.6+0.7)*100+100, qSin(i*0.4+0.6)*100+100)); 282 | // generate data: 283 | QVector x(10), y(10); 284 | for (int k=0; k<10; ++k) 285 | { 286 | x[k] = k/10.0 * 4*3.14 + 0.01; 287 | y[k] = 7*qSin(x[k])/x[k] + (shapes.size()-i)*5; 288 | } 289 | customPlot->graph()->setData(x, y); 290 | customPlot->graph()->rescaleAxes(true); 291 | customPlot->graph()->setPen(pen); 292 | customPlot->graph()->setName(QCPScatterStyle::staticMetaObject.enumerator(QCPScatterStyle::staticMetaObject.indexOfEnumerator("ScatterShape")).valueToKey(shapes.at(i))); 293 | customPlot->graph()->setLineStyle(QCPGraph::lsLine); 294 | // set scatter style: 295 | if (shapes.at(i) != QCPScatterStyle::ssCustom) 296 | { 297 | customPlot->graph()->setScatterStyle(QCPScatterStyle(shapes.at(i), 10)); 298 | } 299 | else 300 | { 301 | QPainterPath customScatterPath; 302 | for (int i=0; i<3; ++i) 303 | customScatterPath.cubicTo(qCos(2*M_PI*i/3.0)*9, qSin(2*M_PI*i/3.0)*9, qCos(2*M_PI*(i+0.9)/3.0)*9, qSin(2*M_PI*(i+0.9)/3.0)*9, 0, 0); 304 | customPlot->graph()->setScatterStyle(QCPScatterStyle(customScatterPath, QPen(Qt::black, 0), QColor(40, 70, 255, 50), 10)); 305 | } 306 | } 307 | // set blank axis lines: 308 | customPlot->rescaleAxes(); 309 | customPlot->xAxis->setTicks(false); 310 | customPlot->yAxis->setTicks(false); 311 | customPlot->xAxis->setTickLabels(false); 312 | customPlot->yAxis->setTickLabels(false); 313 | // make top right axes clones of bottom left axes: 314 | customPlot->axisRect()->setupFullAxesBox(); 315 | } 316 | 317 | void MainWindow::setupLineStyleDemo(QCustomPlot *customPlot) 318 | { 319 | demoName = "Line Style Demo"; 320 | customPlot->legend->setVisible(true); 321 | customPlot->legend->setFont(QFont("Helvetica", 9)); 322 | QPen pen; 323 | QStringList lineNames; 324 | lineNames << "lsNone" << "lsLine" << "lsStepLeft" << "lsStepRight" 325 | << "lsStepCenter" << "lsImpulse"; 326 | // add graphs with different line styles: 327 | for (int i=QCPGraph::lsNone; i<=QCPGraph::lsImpulse; ++i) 328 | { 329 | customPlot->addGraph(); 330 | pen.setColor(QColor(qSin(i*1+1.2)*80+80, qSin(i*0.3+0)*80+80, qSin(i*0.3+1.5)*80+80)); 331 | customPlot->graph()->setPen(pen); 332 | customPlot->graph()->setName(lineNames.at(i-QCPGraph::lsNone)); 333 | customPlot->graph()->setLineStyle((QCPGraph::LineStyle)i); 334 | customPlot->graph()->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 5)); 335 | // generate data: 336 | QVector x(15), y(15); 337 | for (int j=0; j<15; ++j) 338 | { 339 | x[j] = j/15.0 * 5*3.14 + 0.01; 340 | y[j] = 7*qSin(x[j])/x[j] - (i-QCPGraph::lsNone)*5 + (QCPGraph::lsImpulse)*5 + 2; 341 | } 342 | customPlot->graph()->setData(x, y); 343 | customPlot->graph()->rescaleAxes(true); 344 | } 345 | // zoom out a bit: 346 | customPlot->yAxis->scaleRange(1.1, customPlot->yAxis->range().center()); 347 | customPlot->xAxis->scaleRange(1.1, customPlot->xAxis->range().center()); 348 | // set blank axis lines: 349 | customPlot->xAxis->setTicks(false); 350 | customPlot->yAxis->setTicks(true); 351 | customPlot->xAxis->setTickLabels(false); 352 | customPlot->yAxis->setTickLabels(true); 353 | // make top right axes clones of bottom left axes: 354 | customPlot->axisRect()->setupFullAxesBox(); 355 | } 356 | 357 | void MainWindow::setupScatterPixmapDemo(QCustomPlot *customPlot) 358 | { 359 | demoName = "Scatter Pixmap Demo"; 360 | customPlot->axisRect()->setBackground(QPixmap("./solarpanels.jpg")); 361 | customPlot->addGraph(); 362 | customPlot->graph()->setLineStyle(QCPGraph::lsLine); 363 | QPen pen; 364 | pen.setColor(QColor(255, 200, 20, 200)); 365 | pen.setStyle(Qt::DashLine); 366 | pen.setWidthF(2.5); 367 | customPlot->graph()->setPen(pen); 368 | customPlot->graph()->setBrush(QBrush(QColor(255,200,20,70))); 369 | customPlot->graph()->setScatterStyle(QCPScatterStyle(QPixmap("./sun.png"))); 370 | // set graph name, will show up in legend next to icon: 371 | customPlot->graph()->setName("Data from Photovoltaic\nenergy barometer 2011"); 372 | // set data: 373 | QVector year, value; 374 | year << 2005 << 2006 << 2007 << 2008 << 2009 << 2010; 375 | value << 2.17 << 3.42 << 4.94 << 10.38 << 15.86 << 29.33; 376 | customPlot->graph()->setData(year, value); 377 | 378 | // set title of plot: 379 | customPlot->plotLayout()->insertRow(0); 380 | customPlot->plotLayout()->addElement(0, 0, new QCPPlotTitle(customPlot, "Regenerative Energies")); 381 | // set a fixed tick-step to one tick per year value: 382 | customPlot->xAxis->setAutoTickStep(false); 383 | customPlot->xAxis->setTickStep(1); 384 | customPlot->xAxis->setSubTickCount(3); 385 | // other axis configurations: 386 | customPlot->xAxis->setLabel("Year"); 387 | customPlot->yAxis->setLabel("Installed Gigawatts of\nphotovoltaic in the European Union"); 388 | customPlot->xAxis2->setVisible(true); 389 | customPlot->yAxis2->setVisible(true); 390 | customPlot->xAxis2->setTickLabels(false); 391 | customPlot->yAxis2->setTickLabels(false); 392 | customPlot->xAxis2->setTicks(false); 393 | customPlot->yAxis2->setTicks(false); 394 | customPlot->xAxis2->setSubTickCount(0); 395 | customPlot->yAxis2->setSubTickCount(0); 396 | customPlot->xAxis->setRange(2004.5, 2010.5); 397 | customPlot->yAxis->setRange(0, 30); 398 | // setup legend: 399 | customPlot->legend->setFont(QFont(font().family(), 7)); 400 | customPlot->legend->setIconSize(50, 20); 401 | customPlot->legend->setVisible(true); 402 | } 403 | 404 | void MainWindow::setupDateDemo(QCustomPlot *customPlot) 405 | { 406 | demoName = "Date Demo"; 407 | // set locale to english, so we get english month names: 408 | customPlot->setLocale(QLocale(QLocale::English, QLocale::UnitedKingdom)); 409 | // seconds of current time, we'll use it as starting point in time for data: 410 | double now = QDateTime::currentDateTime().toTime_t(); 411 | srand(8); // set the random seed, so we always get the same random data 412 | // create multiple graphs: 413 | for (int gi=0; gi<5; ++gi) 414 | { 415 | customPlot->addGraph(); 416 | QPen pen; 417 | pen.setColor(QColor(0, 0, 255, 200)); 418 | customPlot->graph()->setLineStyle(QCPGraph::lsLine); 419 | customPlot->graph()->setPen(pen); 420 | customPlot->graph()->setBrush(QBrush(QColor(255/4.0*gi,160,50,150))); 421 | // generate random walk data: 422 | QVector time(250), value(250); 423 | for (int i=0; i<250; ++i) 424 | { 425 | time[i] = now + 24*3600*i; 426 | if (i == 0) 427 | value[i] = (i/50.0+1)*(rand()/(double)RAND_MAX-0.5); 428 | else 429 | value[i] = qFabs(value[i-1])*(1+0.02/4.0*(4-gi)) + (i/50.0+1)*(rand()/(double)RAND_MAX-0.5); 430 | } 431 | customPlot->graph()->setData(time, value); 432 | } 433 | // configure bottom axis to show date and time instead of number: 434 | customPlot->xAxis->setTickLabelType(QCPAxis::ltDateTime); 435 | customPlot->xAxis->setDateTimeFormat("MMMM\nyyyy"); 436 | // set a more compact font size for bottom and left axis tick labels: 437 | customPlot->xAxis->setTickLabelFont(QFont(QFont().family(), 8)); 438 | customPlot->yAxis->setTickLabelFont(QFont(QFont().family(), 8)); 439 | // set a fixed tick-step to one tick per month: 440 | customPlot->xAxis->setAutoTickStep(false); 441 | customPlot->xAxis->setTickStep(2628000); // one month in seconds 442 | customPlot->xAxis->setSubTickCount(3); 443 | // apply manual tick and tick label for left axis: 444 | customPlot->yAxis->setAutoTicks(false); 445 | customPlot->yAxis->setAutoTickLabels(false); 446 | customPlot->yAxis->setTickVector(QVector() << 5 << 55); 447 | customPlot->yAxis->setTickVectorLabels(QVector() << "Not so\nhigh" << "Very\nhigh"); 448 | // set axis labels: 449 | customPlot->xAxis->setLabel("Date"); 450 | customPlot->yAxis->setLabel("Random wobbly lines value"); 451 | // make top and right axes visible but without ticks and labels: 452 | customPlot->xAxis2->setVisible(true); 453 | customPlot->yAxis2->setVisible(true); 454 | customPlot->xAxis2->setTicks(false); 455 | customPlot->yAxis2->setTicks(false); 456 | customPlot->xAxis2->setTickLabels(false); 457 | customPlot->yAxis2->setTickLabels(false); 458 | // set axis ranges to show all data: 459 | customPlot->xAxis->setRange(now, now+24*3600*249); 460 | customPlot->yAxis->setRange(0, 60); 461 | // show legend: 462 | customPlot->legend->setVisible(true); 463 | } 464 | 465 | void MainWindow::setupTextureBrushDemo(QCustomPlot *customPlot) 466 | { 467 | demoName = "Texture Brush Demo"; 468 | // add two graphs with a textured fill: 469 | customPlot->addGraph(); 470 | QPen redDotPen; 471 | redDotPen.setStyle(Qt::DotLine); 472 | redDotPen.setColor(QColor(170, 100, 100, 180)); 473 | redDotPen.setWidthF(2); 474 | customPlot->graph(0)->setPen(redDotPen); 475 | customPlot->graph(0)->setBrush(QBrush(QPixmap("./balboa.jpg"))); // fill with texture of specified image 476 | 477 | customPlot->addGraph(); 478 | customPlot->graph(1)->setPen(QPen(Qt::red)); 479 | 480 | // activate channel fill for graph 0 towards graph 1: 481 | customPlot->graph(0)->setChannelFillGraph(customPlot->graph(1)); 482 | 483 | // generate data: 484 | QVector x(250); 485 | QVector y0(250), y1(250); 486 | for (int i=0; i<250; ++i) 487 | { 488 | // just playing with numbers, not much to learn here 489 | x[i] = 3*i/250.0; 490 | y0[i] = 1+qExp(-x[i]*x[i]*0.8)*(x[i]*x[i]+x[i]); 491 | y1[i] = 1-qExp(-x[i]*x[i]*0.4)*(x[i]*x[i])*0.1; 492 | } 493 | 494 | // pass data points to graphs: 495 | customPlot->graph(0)->setData(x, y0); 496 | customPlot->graph(1)->setData(x, y1); 497 | // activate top and right axes, which are invisible by default: 498 | customPlot->xAxis2->setVisible(true); 499 | customPlot->yAxis2->setVisible(true); 500 | // make tick labels invisible on top and right axis: 501 | customPlot->xAxis2->setTickLabels(false); 502 | customPlot->yAxis2->setTickLabels(false); 503 | // set ranges: 504 | customPlot->xAxis->setRange(0, 2.5); 505 | customPlot->yAxis->setRange(0.9, 1.6); 506 | // assign top/right axes same properties as bottom/left: 507 | customPlot->axisRect()->setupFullAxesBox(); 508 | } 509 | 510 | void MainWindow::setupMultiAxisDemo(QCustomPlot *customPlot) 511 | { 512 | customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); 513 | demoName = "Multi Axis Demo"; 514 | 515 | customPlot->setLocale(QLocale(QLocale::English, QLocale::UnitedKingdom)); // period as decimal separator and comma as thousand separator 516 | customPlot->legend->setVisible(true); 517 | QFont legendFont = font(); // start out with MainWindow's font.. 518 | legendFont.setPointSize(9); // and make a bit smaller for legend 519 | customPlot->legend->setFont(legendFont); 520 | customPlot->legend->setBrush(QBrush(QColor(255,255,255,230))); 521 | // by default, the legend is in the inset layout of the main axis rect. So this is how we access it to change legend placement: 522 | customPlot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignBottom|Qt::AlignRight); 523 | 524 | // setup for graph 0: key axis left, value axis bottom 525 | // will contain left maxwell-like function 526 | customPlot->addGraph(customPlot->yAxis, customPlot->xAxis); 527 | customPlot->graph(0)->setPen(QPen(QColor(255, 100, 0))); 528 | customPlot->graph(0)->setBrush(QBrush(QPixmap("./balboa.jpg"))); // fill with texture of specified image 529 | customPlot->graph(0)->setLineStyle(QCPGraph::lsLine); 530 | customPlot->graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, 5)); 531 | customPlot->graph(0)->setName("Left maxwell function"); 532 | 533 | // setup for graph 1: key axis bottom, value axis left (those are the default axes) 534 | // will contain bottom maxwell-like function 535 | customPlot->addGraph(); 536 | customPlot->graph(1)->setPen(QPen(Qt::red)); 537 | customPlot->graph(1)->setBrush(QBrush(QPixmap("./balboa.jpg"))); // same fill as we used for graph 0 538 | customPlot->graph(1)->setLineStyle(QCPGraph::lsStepCenter); 539 | customPlot->graph(1)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, Qt::red, Qt::white, 7)); 540 | customPlot->graph(1)->setErrorType(QCPGraph::etValue); 541 | customPlot->graph(1)->setName("Bottom maxwell function"); 542 | 543 | // setup for graph 2: key axis top, value axis right 544 | // will contain high frequency sine with low frequency beating: 545 | customPlot->addGraph(customPlot->xAxis2, customPlot->yAxis2); 546 | customPlot->graph(2)->setPen(QPen(Qt::blue)); 547 | customPlot->graph(2)->setName("High frequency sine"); 548 | 549 | // setup for graph 3: same axes as graph 2 550 | // will contain low frequency beating envelope of graph 2 551 | customPlot->addGraph(customPlot->xAxis2, customPlot->yAxis2); 552 | QPen blueDotPen; 553 | blueDotPen.setColor(QColor(30, 40, 255, 150)); 554 | blueDotPen.setStyle(Qt::DotLine); 555 | blueDotPen.setWidthF(4); 556 | customPlot->graph(3)->setPen(blueDotPen); 557 | customPlot->graph(3)->setName("Sine envelope"); 558 | 559 | // setup for graph 4: key axis right, value axis top 560 | // will contain parabolically distributed data points with some random perturbance 561 | customPlot->addGraph(customPlot->yAxis2, customPlot->xAxis2); 562 | customPlot->graph(4)->setPen(QColor(50, 50, 50, 255)); 563 | customPlot->graph(4)->setLineStyle(QCPGraph::lsNone); 564 | customPlot->graph(4)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 4)); 565 | customPlot->graph(4)->setName("Some random data around\na quadratic function"); 566 | 567 | // generate data, just playing with numbers, not much to learn here: 568 | QVector x0(25), y0(25); 569 | QVector x1(15), y1(15), y1err(15); 570 | QVector x2(250), y2(250); 571 | QVector x3(250), y3(250); 572 | QVector x4(250), y4(250); 573 | for (int i=0; i<25; ++i) // data for graph 0 574 | { 575 | x0[i] = 3*i/25.0; 576 | y0[i] = qExp(-x0[i]*x0[i]*0.8)*(x0[i]*x0[i]+x0[i]); 577 | } 578 | for (int i=0; i<15; ++i) // data for graph 1 579 | { 580 | x1[i] = 3*i/15.0;; 581 | y1[i] = qExp(-x1[i]*x1[i])*(x1[i]*x1[i])*2.6; 582 | y1err[i] = y1[i]*0.25; 583 | } 584 | for (int i=0; i<250; ++i) // data for graphs 2, 3 and 4 585 | { 586 | x2[i] = i/250.0*3*M_PI; 587 | x3[i] = x2[i]; 588 | x4[i] = i/250.0*100-50; 589 | y2[i] = qSin(x2[i]*12)*qCos(x2[i])*10; 590 | y3[i] = qCos(x3[i])*10; 591 | y4[i] = 0.01*x4[i]*x4[i] + 1.5*(rand()/(double)RAND_MAX-0.5) + 1.5*M_PI; 592 | } 593 | 594 | // pass data points to graphs: 595 | customPlot->graph(0)->setData(x0, y0); 596 | customPlot->graph(1)->setDataValueError(x1, y1, y1err); 597 | customPlot->graph(2)->setData(x2, y2); 598 | customPlot->graph(3)->setData(x3, y3); 599 | customPlot->graph(4)->setData(x4, y4); 600 | // activate top and right axes, which are invisible by default: 601 | customPlot->xAxis2->setVisible(true); 602 | customPlot->yAxis2->setVisible(true); 603 | // set ranges appropriate to show data: 604 | customPlot->xAxis->setRange(0, 2.7); 605 | customPlot->yAxis->setRange(0, 2.6); 606 | customPlot->xAxis2->setRange(0, 3.0*M_PI); 607 | customPlot->yAxis2->setRange(-70, 35); 608 | // set pi ticks on top axis: 609 | QVector piTicks; 610 | QVector piLabels; 611 | piTicks << 0 << 0.5*M_PI << M_PI << 1.5*M_PI << 2*M_PI << 2.5*M_PI << 3*M_PI; 612 | piLabels << "0" << QString::fromUtf8("½π") << QString::fromUtf8("π") << QString::fromUtf8("1½π") << QString::fromUtf8("2π") << QString::fromUtf8("2½π") << QString::fromUtf8("3π"); 613 | customPlot->xAxis2->setAutoTicks(false); 614 | customPlot->xAxis2->setAutoTickLabels(false); 615 | customPlot->xAxis2->setTickVector(piTicks); 616 | customPlot->xAxis2->setTickVectorLabels(piLabels); 617 | // add title layout element: 618 | customPlot->plotLayout()->insertRow(0); 619 | customPlot->plotLayout()->addElement(0, 0, new QCPPlotTitle(customPlot, "Way too many graphs in one plot")); 620 | // set labels: 621 | customPlot->xAxis->setLabel("Bottom axis with outward ticks"); 622 | customPlot->yAxis->setLabel("Left axis label"); 623 | customPlot->xAxis2->setLabel("Top axis label"); 624 | customPlot->yAxis2->setLabel("Right axis label"); 625 | // make ticks on bottom axis go outward: 626 | customPlot->xAxis->setTickLength(0, 5); 627 | customPlot->xAxis->setSubTickLength(0, 3); 628 | // make ticks on right axis go inward and outward: 629 | customPlot->yAxis2->setTickLength(3, 3); 630 | customPlot->yAxis2->setSubTickLength(1, 1); 631 | } 632 | 633 | void MainWindow::setupLogarithmicDemo(QCustomPlot *customPlot) 634 | { 635 | demoName = "Logarithmic Demo"; 636 | customPlot->setNoAntialiasingOnDrag(true); // more performance/responsiveness during dragging 637 | customPlot->addGraph(); 638 | QPen pen; 639 | pen.setColor(QColor(255,170,100)); 640 | pen.setWidth(2); 641 | pen.setStyle(Qt::DotLine); 642 | customPlot->graph(0)->setPen(pen); 643 | customPlot->graph(0)->setName("x"); 644 | 645 | customPlot->addGraph(); 646 | customPlot->graph(1)->setPen(QPen(Qt::red)); 647 | customPlot->graph(1)->setBrush(QBrush(QColor(255, 0, 0, 20))); 648 | customPlot->graph(1)->setErrorType(QCPGraph::etBoth); 649 | customPlot->graph(1)->setName("-sin(x)exp(x)"); 650 | 651 | customPlot->addGraph(); 652 | customPlot->graph(2)->setPen(QPen(Qt::blue)); 653 | customPlot->graph(2)->setBrush(QBrush(QColor(0, 0, 255, 20))); 654 | customPlot->graph(2)->setName(" sin(x)exp(x)"); 655 | 656 | customPlot->addGraph(); 657 | pen.setColor(QColor(0,0,0)); 658 | pen.setWidth(1); 659 | pen.setStyle(Qt::DashLine); 660 | customPlot->graph(3)->setPen(pen); 661 | customPlot->graph(3)->setBrush(QBrush(QColor(0,0,0,15))); 662 | customPlot->graph(3)->setLineStyle(QCPGraph::lsStepCenter); 663 | customPlot->graph(3)->setName("x!"); 664 | 665 | QVector x0(200), y0(200); 666 | QVector x1(200), y1(200); 667 | QVector x2(200), y2(200); 668 | QVector x3(21), y3(21); 669 | for (int i=0; i<200; ++i) 670 | { 671 | x0[i] = i/10.0; 672 | y0[i] = x0[i]; 673 | x1[i] = i/10.0; 674 | y1[i] = -qSin(x1[i])*qExp(x1[i]); 675 | x2[i] = i/10.0; 676 | y2[i] = qSin(x2[i])*qExp(x2[i]); 677 | } 678 | for (int i=0; i<21; ++i) 679 | { 680 | x3[i] = i; 681 | y3[i] = 1; 682 | for (int k=1; k<=i; ++k) y3[i] *= k; // factorial 683 | } 684 | customPlot->graph(0)->setData(x0, y0); 685 | customPlot->graph(1)->setData(x1, y1); 686 | customPlot->graph(2)->setData(x2, y2); 687 | customPlot->graph(3)->setData(x3, y3); 688 | 689 | customPlot->yAxis->grid()->setSubGridVisible(true); 690 | customPlot->xAxis->grid()->setSubGridVisible(true); 691 | customPlot->yAxis->setScaleType(QCPAxis::stLogarithmic); 692 | customPlot->yAxis->setScaleLogBase(100); 693 | customPlot->yAxis->setNumberFormat("eb"); // e = exponential, b = beautiful decimal powers 694 | customPlot->yAxis->setNumberPrecision(0); // makes sure "1*10^4" is displayed only as "10^4" 695 | customPlot->yAxis->setSubTickCount(10); 696 | customPlot->xAxis->setRange(0, 19.9); 697 | customPlot->yAxis->setRange(1e-2, 1e10); 698 | // make range draggable and zoomable: 699 | customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); 700 | 701 | // make top right axes clones of bottom left axes: 702 | customPlot->axisRect()->setupFullAxesBox(); 703 | // connect signals so top and right axes move in sync with bottom and left axes: 704 | connect(customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->xAxis2, SLOT(setRange(QCPRange))); 705 | connect(customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->yAxis2, SLOT(setRange(QCPRange))); 706 | 707 | customPlot->legend->setVisible(true); 708 | customPlot->legend->setBrush(QBrush(QColor(255,255,255,150))); 709 | customPlot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignLeft|Qt::AlignTop); // make legend align in top left corner or axis rect 710 | } 711 | 712 | void MainWindow::setupRealtimeDataDemo(QCustomPlot *customPlot) 713 | { 714 | #if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) 715 | QMessageBox::critical(this, "", "You're using Qt < 4.7, the realtime data demo needs functions that are available with Qt 4.7 to work properly"); 716 | #endif 717 | demoName = "Real Time Data Demo"; 718 | 719 | // include this section to fully disable antialiasing for higher performance: 720 | /* 721 | customPlot->setNotAntialiasedElements(QCP::aeAll); 722 | QFont font; 723 | font.setStyleStrategy(QFont::NoAntialias); 724 | customPlot->xAxis->setTickLabelFont(font); 725 | customPlot->yAxis->setTickLabelFont(font); 726 | customPlot->legend->setFont(font); 727 | */ 728 | customPlot->addGraph(); // blue line 729 | customPlot->graph(0)->setPen(QPen(Qt::blue)); 730 | customPlot->graph(0)->setBrush(QBrush(QColor(240, 255, 200))); 731 | customPlot->graph(0)->setAntialiasedFill(false); 732 | customPlot->addGraph(); // red line 733 | customPlot->graph(1)->setPen(QPen(Qt::red)); 734 | customPlot->graph(0)->setChannelFillGraph(customPlot->graph(1)); 735 | 736 | customPlot->addGraph(); // blue dot 737 | customPlot->graph(2)->setPen(QPen(Qt::blue)); 738 | customPlot->graph(2)->setLineStyle(QCPGraph::lsNone); 739 | customPlot->graph(2)->setScatterStyle(QCPScatterStyle::ssDisc); 740 | customPlot->addGraph(); // red dot 741 | customPlot->graph(3)->setPen(QPen(Qt::red)); 742 | customPlot->graph(3)->setLineStyle(QCPGraph::lsNone); 743 | customPlot->graph(3)->setScatterStyle(QCPScatterStyle::ssDisc); 744 | 745 | customPlot->xAxis->setTickLabelType(QCPAxis::ltDateTime); 746 | customPlot->xAxis->setDateTimeFormat("hh:mm:ss"); 747 | customPlot->xAxis->setAutoTickStep(false); 748 | customPlot->xAxis->setTickStep(2); 749 | customPlot->axisRect()->setupFullAxesBox(); 750 | 751 | // make left and bottom axes transfer their ranges to right and top axes: 752 | connect(customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->xAxis2, SLOT(setRange(QCPRange))); 753 | connect(customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->yAxis2, SLOT(setRange(QCPRange))); 754 | 755 | // setup a timer that repeatedly calls MainWindow::realtimeDataSlot: 756 | connect(&dataTimer, SIGNAL(timeout()), this, SLOT(realtimeDataSlot())); 757 | dataTimer.start(0); // Interval 0 means to refresh as fast as possible 758 | } 759 | 760 | void MainWindow::setupParametricCurveDemo(QCustomPlot *customPlot) 761 | { 762 | demoName = "Parametric Curves Demo"; 763 | 764 | // create empty curve objects and add them to customPlot: 765 | QCPCurve *fermatSpiral1 = new QCPCurve(customPlot->xAxis, customPlot->yAxis); 766 | QCPCurve *fermatSpiral2 = new QCPCurve(customPlot->xAxis, customPlot->yAxis); 767 | QCPCurve *deltoidRadial = new QCPCurve(customPlot->xAxis, customPlot->yAxis); 768 | customPlot->addPlottable(fermatSpiral1); 769 | customPlot->addPlottable(fermatSpiral2); 770 | customPlot->addPlottable(deltoidRadial); 771 | // generate the curve data points: 772 | int pointCount = 500; 773 | QVector x1(pointCount), y1(pointCount); 774 | QVector x2(pointCount), y2(pointCount); 775 | QVector x3(pointCount), y3(pointCount); 776 | for (int i=0; isetData(x1, y1); 789 | fermatSpiral2->setData(x2, y2); 790 | deltoidRadial->setData(x3, y3); 791 | // color the curves: 792 | fermatSpiral1->setPen(QPen(Qt::blue)); 793 | fermatSpiral1->setBrush(QBrush(QColor(0, 0, 255, 20))); 794 | fermatSpiral2->setPen(QPen(QColor(255, 120, 0))); 795 | fermatSpiral2->setBrush(QBrush(QColor(255, 120, 0, 30))); 796 | QRadialGradient radialGrad(QPointF(310, 180), 200); 797 | radialGrad.setColorAt(0, QColor(170, 20, 240, 100)); 798 | radialGrad.setColorAt(0.5, QColor(20, 10, 255, 40)); 799 | radialGrad.setColorAt(1,QColor(120, 20, 240, 10)); 800 | deltoidRadial->setPen(QPen(QColor(170, 20, 240))); 801 | deltoidRadial->setBrush(QBrush(radialGrad)); 802 | // set some basic customPlot config: 803 | customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables); 804 | customPlot->axisRect()->setupFullAxesBox(); 805 | customPlot->rescaleAxes(); 806 | } 807 | 808 | void MainWindow::setupBarChartDemo(QCustomPlot *customPlot) 809 | { 810 | demoName = "Bar Chart Demo"; 811 | // create empty bar chart objects: 812 | QCPBars *regen = new QCPBars(customPlot->xAxis, customPlot->yAxis); 813 | QCPBars *nuclear = new QCPBars(customPlot->xAxis, customPlot->yAxis); 814 | QCPBars *fossil = new QCPBars(customPlot->xAxis, customPlot->yAxis); 815 | customPlot->addPlottable(regen); 816 | customPlot->addPlottable(nuclear); 817 | customPlot->addPlottable(fossil); 818 | // set names and colors: 819 | QPen pen; 820 | pen.setWidthF(1.2); 821 | fossil->setName("Fossil fuels"); 822 | pen.setColor(QColor(255, 131, 0)); 823 | fossil->setPen(pen); 824 | fossil->setBrush(QColor(255, 131, 0, 50)); 825 | nuclear->setName("Nuclear"); 826 | pen.setColor(QColor(1, 92, 191)); 827 | nuclear->setPen(pen); 828 | nuclear->setBrush(QColor(1, 92, 191, 50)); 829 | regen->setName("Regenerative"); 830 | pen.setColor(QColor(150, 222, 0)); 831 | regen->setPen(pen); 832 | regen->setBrush(QColor(150, 222, 0, 70)); 833 | // stack bars ontop of each other: 834 | nuclear->moveAbove(fossil); 835 | regen->moveAbove(nuclear); 836 | 837 | // prepare x axis with country labels: 838 | QVector ticks; 839 | QVector labels; 840 | ticks << 1 << 2 << 3 << 4 << 5 << 6 << 7; 841 | labels << "USA" << "Japan" << "Germany" << "France" << "UK" << "Italy" << "Canada"; 842 | customPlot->xAxis->setAutoTicks(false); 843 | customPlot->xAxis->setAutoTickLabels(false); 844 | customPlot->xAxis->setTickVector(ticks); 845 | customPlot->xAxis->setTickVectorLabels(labels); 846 | customPlot->xAxis->setTickLabelRotation(60); 847 | customPlot->xAxis->setSubTickCount(0); 848 | customPlot->xAxis->setTickLength(0, 4); 849 | customPlot->xAxis->grid()->setVisible(true); 850 | customPlot->xAxis->setRange(0, 8); 851 | 852 | // prepare y axis: 853 | customPlot->yAxis->setRange(0, 12.1); 854 | customPlot->yAxis->setPadding(5); // a bit more space to the left border 855 | customPlot->yAxis->setLabel("Power Consumption in\nKilowatts per Capita (2007)"); 856 | customPlot->yAxis->grid()->setSubGridVisible(true); 857 | QPen gridPen; 858 | gridPen.setStyle(Qt::SolidLine); 859 | gridPen.setColor(QColor(0, 0, 0, 25)); 860 | customPlot->yAxis->grid()->setPen(gridPen); 861 | gridPen.setStyle(Qt::DotLine); 862 | customPlot->yAxis->grid()->setSubGridPen(gridPen); 863 | 864 | // Add data: 865 | QVector fossilData, nuclearData, regenData; 866 | fossilData << 0.86*10.5 << 0.83*5.5 << 0.84*5.5 << 0.52*5.8 << 0.89*5.2 << 0.90*4.2 << 0.67*11.2; 867 | nuclearData << 0.08*10.5 << 0.12*5.5 << 0.12*5.5 << 0.40*5.8 << 0.09*5.2 << 0.00*4.2 << 0.07*11.2; 868 | regenData << 0.06*10.5 << 0.05*5.5 << 0.04*5.5 << 0.06*5.8 << 0.02*5.2 << 0.07*4.2 << 0.25*11.2; 869 | fossil->setData(ticks, fossilData); 870 | nuclear->setData(ticks, nuclearData); 871 | regen->setData(ticks, regenData); 872 | 873 | // setup legend: 874 | customPlot->legend->setVisible(true); 875 | customPlot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignTop|Qt::AlignHCenter); 876 | customPlot->legend->setBrush(QColor(255, 255, 255, 200)); 877 | QPen legendPen; 878 | legendPen.setColor(QColor(130, 130, 130, 200)); 879 | customPlot->legend->setBorderPen(legendPen); 880 | QFont legendFont = font(); 881 | legendFont.setPointSize(10); 882 | customPlot->legend->setFont(legendFont); 883 | customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); 884 | } 885 | 886 | void MainWindow::setupStatisticalDemo(QCustomPlot *customPlot) 887 | { 888 | demoName = "Statistical Demo"; 889 | // create empty statistical box plottables: 890 | QCPStatisticalBox *sample1 = new QCPStatisticalBox(customPlot->xAxis, customPlot->yAxis); 891 | QCPStatisticalBox *sample2 = new QCPStatisticalBox(customPlot->xAxis, customPlot->yAxis); 892 | QCPStatisticalBox *sample3 = new QCPStatisticalBox(customPlot->xAxis, customPlot->yAxis); 893 | customPlot->addPlottable(sample1); 894 | customPlot->addPlottable(sample2); 895 | customPlot->addPlottable(sample3); 896 | QBrush boxBrush(QColor(60, 60, 255, 100)); 897 | boxBrush.setStyle(Qt::Dense6Pattern); // make it look oldschool 898 | sample1->setBrush(boxBrush); 899 | sample2->setBrush(boxBrush); 900 | sample3->setBrush(boxBrush); 901 | 902 | // set data: 903 | sample1->setKey(1); 904 | sample1->setMinimum(1.1); 905 | sample1->setLowerQuartile(1.9); 906 | sample1->setMedian(2.25); 907 | sample1->setUpperQuartile(2.7); 908 | sample1->setMaximum(4.2); 909 | 910 | sample2->setKey(2); 911 | sample2->setMinimum(0.8); 912 | sample2->setLowerQuartile(1.6); 913 | sample2->setMedian(2.2); 914 | sample2->setUpperQuartile(3.2); 915 | sample2->setMaximum(4.9); 916 | sample2->setOutliers(QVector() << 0.7 << 0.39 << 0.45 << 6.2 << 5.84); 917 | 918 | sample3->setKey(3); 919 | sample3->setMinimum(0.2); 920 | sample3->setLowerQuartile(0.7); 921 | sample3->setMedian(1.1); 922 | sample3->setUpperQuartile(1.6); 923 | sample3->setMaximum(2.9); 924 | 925 | // prepare manual x axis labels: 926 | customPlot->xAxis->setSubTickCount(0); 927 | customPlot->xAxis->setTickLength(0, 4); 928 | customPlot->xAxis->setTickLabelRotation(20); 929 | customPlot->xAxis->setAutoTicks(false); 930 | customPlot->xAxis->setAutoTickLabels(false); 931 | customPlot->xAxis->setTickVector(QVector() << 1 << 2 << 3); 932 | customPlot->xAxis->setTickVectorLabels(QVector() << "Sample 1" << "Sample 2" << "Control Group"); 933 | 934 | // prepare axes: 935 | customPlot->yAxis->setLabel(QString::fromUtf8("O₂ Absorption [mg]")); 936 | customPlot->rescaleAxes(); 937 | customPlot->xAxis->scaleRange(1.7, customPlot->xAxis->range().center()); 938 | customPlot->yAxis->setRange(0, 7); 939 | customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); 940 | } 941 | 942 | void MainWindow::setupSimpleItemDemo(QCustomPlot *customPlot) 943 | { 944 | demoName = "Simple Item Demo"; 945 | customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); 946 | 947 | // add the text label at the top: 948 | QCPItemText *textLabel = new QCPItemText(customPlot); 949 | customPlot->addItem(textLabel); 950 | textLabel->setPositionAlignment(Qt::AlignTop|Qt::AlignHCenter); 951 | textLabel->position->setType(QCPItemPosition::ptAxisRectRatio); 952 | textLabel->position->setCoords(0.5, 0); // place position at center/top of axis rect 953 | textLabel->setText("Text Item Demo"); 954 | textLabel->setFont(QFont(font().family(), 16)); // make font a bit larger 955 | textLabel->setPen(QPen(Qt::black)); // show black border around text 956 | 957 | // add the arrow: 958 | QCPItemLine *arrow = new QCPItemLine(customPlot); 959 | customPlot->addItem(arrow); 960 | arrow->start->setParentAnchor(textLabel->bottom); 961 | arrow->end->setCoords(4, 1.6); // point to (4, 1.6) in x-y-plot coordinates 962 | arrow->setHead(QCPLineEnding::esSpikeArrow); 963 | } 964 | 965 | void MainWindow::setupItemDemo(QCustomPlot *customPlot) 966 | { 967 | #if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) 968 | QMessageBox::critical(this, "", "You're using Qt < 4.7, the animation of the item demo needs functions that are available with Qt 4.7 to work properly"); 969 | #endif 970 | 971 | demoName = "Item Demo"; 972 | 973 | customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); 974 | QCPGraph *graph = customPlot->addGraph(); 975 | int n = 500; 976 | double phase = 0; 977 | double k = 3; 978 | QVector x(n), y(n); 979 | for (int i=0; isetData(x, y); 985 | graph->setPen(QPen(Qt::blue)); 986 | graph->rescaleKeyAxis(); 987 | customPlot->yAxis->setRange(-1.45, 1.65); 988 | customPlot->xAxis->grid()->setZeroLinePen(Qt::NoPen); 989 | 990 | // add the bracket at the top: 991 | QCPItemBracket *bracket = new QCPItemBracket(customPlot); 992 | customPlot->addItem(bracket); 993 | bracket->left->setCoords(-8, 1.1); 994 | bracket->right->setCoords(8, 1.1); 995 | bracket->setLength(13); 996 | 997 | // add the text label at the top: 998 | QCPItemText *wavePacketText = new QCPItemText(customPlot); 999 | customPlot->addItem(wavePacketText); 1000 | wavePacketText->position->setParentAnchor(bracket->center); 1001 | wavePacketText->position->setCoords(0, -10); // move 10 pixels to the top from bracket center anchor 1002 | wavePacketText->setPositionAlignment(Qt::AlignBottom|Qt::AlignHCenter); 1003 | wavePacketText->setText("Wavepacket"); 1004 | wavePacketText->setFont(QFont(font().family(), 10)); 1005 | 1006 | // add the phase tracer (red circle) which sticks to the graph data (and gets updated in bracketDataSlot by timer event): 1007 | QCPItemTracer *phaseTracer = new QCPItemTracer(customPlot); 1008 | customPlot->addItem(phaseTracer); 1009 | itemDemoPhaseTracer = phaseTracer; // so we can access it later in the bracketDataSlot for animation 1010 | phaseTracer->setGraph(graph); 1011 | phaseTracer->setGraphKey((M_PI*1.5-phase)/k); 1012 | phaseTracer->setInterpolating(true); 1013 | phaseTracer->setStyle(QCPItemTracer::tsCircle); 1014 | phaseTracer->setPen(QPen(Qt::red)); 1015 | phaseTracer->setBrush(Qt::red); 1016 | phaseTracer->setSize(7); 1017 | 1018 | // add label for phase tracer: 1019 | QCPItemText *phaseTracerText = new QCPItemText(customPlot); 1020 | customPlot->addItem(phaseTracerText); 1021 | phaseTracerText->position->setType(QCPItemPosition::ptAxisRectRatio); 1022 | phaseTracerText->setPositionAlignment(Qt::AlignRight|Qt::AlignBottom); 1023 | phaseTracerText->position->setCoords(1.0, 0.95); // lower right corner of axis rect 1024 | phaseTracerText->setText("Points of fixed\nphase define\nphase velocity vp"); 1025 | phaseTracerText->setTextAlignment(Qt::AlignLeft); 1026 | phaseTracerText->setFont(QFont(font().family(), 9)); 1027 | phaseTracerText->setPadding(QMargins(8, 0, 0, 0)); 1028 | 1029 | // add arrow pointing at phase tracer, coming from label: 1030 | QCPItemCurve *phaseTracerArrow = new QCPItemCurve(customPlot); 1031 | customPlot->addItem(phaseTracerArrow); 1032 | phaseTracerArrow->start->setParentAnchor(phaseTracerText->left); 1033 | phaseTracerArrow->startDir->setParentAnchor(phaseTracerArrow->start); 1034 | phaseTracerArrow->startDir->setCoords(-40, 0); // direction 30 pixels to the left of parent anchor (tracerArrow->start) 1035 | phaseTracerArrow->end->setParentAnchor(phaseTracer->position); 1036 | phaseTracerArrow->end->setCoords(10, 10); 1037 | phaseTracerArrow->endDir->setParentAnchor(phaseTracerArrow->end); 1038 | phaseTracerArrow->endDir->setCoords(30, 30); 1039 | phaseTracerArrow->setHead(QCPLineEnding::esSpikeArrow); 1040 | phaseTracerArrow->setTail(QCPLineEnding(QCPLineEnding::esBar, (phaseTracerText->bottom->pixelPoint().y()-phaseTracerText->top->pixelPoint().y())*0.85)); 1041 | 1042 | // add the group velocity tracer (green circle): 1043 | QCPItemTracer *groupTracer = new QCPItemTracer(customPlot); 1044 | customPlot->addItem(groupTracer); 1045 | groupTracer->setGraph(graph); 1046 | groupTracer->setGraphKey(5.5); 1047 | groupTracer->setInterpolating(true); 1048 | groupTracer->setStyle(QCPItemTracer::tsCircle); 1049 | groupTracer->setPen(QPen(Qt::green)); 1050 | groupTracer->setBrush(Qt::green); 1051 | groupTracer->setSize(7); 1052 | 1053 | // add label for group tracer: 1054 | QCPItemText *groupTracerText = new QCPItemText(customPlot); 1055 | customPlot->addItem(groupTracerText); 1056 | groupTracerText->position->setType(QCPItemPosition::ptAxisRectRatio); 1057 | groupTracerText->setPositionAlignment(Qt::AlignRight|Qt::AlignTop); 1058 | groupTracerText->position->setCoords(1.0, 0.20); // lower right corner of axis rect 1059 | groupTracerText->setText("Fixed positions in\nwave packet define\ngroup velocity vg"); 1060 | groupTracerText->setTextAlignment(Qt::AlignLeft); 1061 | groupTracerText->setFont(QFont(font().family(), 9)); 1062 | groupTracerText->setPadding(QMargins(8, 0, 0, 0)); 1063 | 1064 | // add arrow pointing at group tracer, coming from label: 1065 | QCPItemCurve *groupTracerArrow = new QCPItemCurve(customPlot); 1066 | customPlot->addItem(groupTracerArrow); 1067 | groupTracerArrow->start->setParentAnchor(groupTracerText->left); 1068 | groupTracerArrow->startDir->setParentAnchor(groupTracerArrow->start); 1069 | groupTracerArrow->startDir->setCoords(-40, 0); // direction 30 pixels to the left of parent anchor (tracerArrow->start) 1070 | groupTracerArrow->end->setCoords(5.5, 0.4); 1071 | groupTracerArrow->endDir->setParentAnchor(groupTracerArrow->end); 1072 | groupTracerArrow->endDir->setCoords(0, -40); 1073 | groupTracerArrow->setHead(QCPLineEnding::esSpikeArrow); 1074 | groupTracerArrow->setTail(QCPLineEnding(QCPLineEnding::esBar, (groupTracerText->bottom->pixelPoint().y()-groupTracerText->top->pixelPoint().y())*0.85)); 1075 | 1076 | // add dispersion arrow: 1077 | QCPItemCurve *arrow = new QCPItemCurve(customPlot); 1078 | customPlot->addItem(arrow); 1079 | arrow->start->setCoords(1, -1.1); 1080 | arrow->startDir->setCoords(-1, -1.3); 1081 | arrow->endDir->setCoords(-5, -0.3); 1082 | arrow->end->setCoords(-10, -0.2); 1083 | arrow->setHead(QCPLineEnding::esSpikeArrow); 1084 | 1085 | // add the dispersion arrow label: 1086 | QCPItemText *dispersionText = new QCPItemText(customPlot); 1087 | customPlot->addItem(dispersionText); 1088 | dispersionText->position->setCoords(-6, -0.9); 1089 | dispersionText->setRotation(40); 1090 | dispersionText->setText("Dispersion with\nvp < vg"); 1091 | dispersionText->setFont(QFont(font().family(), 10)); 1092 | 1093 | // setup a timer that repeatedly calls MainWindow::realtimeDataSlot: 1094 | connect(&dataTimer, SIGNAL(timeout()), this, SLOT(bracketDataSlot())); 1095 | dataTimer.start(0); // Interval 0 means to refresh as fast as possible 1096 | } 1097 | 1098 | void MainWindow::setupStyledDemo(QCustomPlot *customPlot) 1099 | { 1100 | demoName = "Styled Demo"; 1101 | 1102 | // prepare data: 1103 | QVector x1(20), y1(20); 1104 | QVector x2(100), y2(100); 1105 | QVector x3(20), y3(20); 1106 | QVector x4(20), y4(20); 1107 | for (int i=0; iaddGraph(); 1130 | graph1->setData(x1, y1); 1131 | graph1->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QPen(Qt::black, 1.5), QBrush(Qt::white), 9)); 1132 | graph1->setPen(QPen(QColor(120, 120, 120), 2)); 1133 | 1134 | QCPGraph *graph2 = customPlot->addGraph(); 1135 | graph2->setData(x2, y2); 1136 | graph2->setPen(Qt::NoPen); 1137 | graph2->setBrush(QColor(200, 200, 200, 20)); 1138 | graph2->setChannelFillGraph(graph1); 1139 | 1140 | QCPBars *bars1 = new QCPBars(customPlot->xAxis, customPlot->yAxis); 1141 | customPlot->addPlottable(bars1); 1142 | bars1->setWidth(9/(double)x3.size()); 1143 | bars1->setData(x3, y3); 1144 | bars1->setPen(Qt::NoPen); 1145 | bars1->setBrush(QColor(10, 140, 70, 160)); 1146 | 1147 | QCPBars *bars2 = new QCPBars(customPlot->xAxis, customPlot->yAxis); 1148 | customPlot->addPlottable(bars2); 1149 | bars2->setWidth(9/(double)x4.size()); 1150 | bars2->setData(x4, y4); 1151 | bars2->setPen(Qt::NoPen); 1152 | bars2->setBrush(QColor(10, 100, 50, 70)); 1153 | bars2->moveAbove(bars1); 1154 | 1155 | // move bars above graphs and grid below bars: 1156 | customPlot->addLayer("abovemain", customPlot->layer("main"), QCustomPlot::limAbove); 1157 | customPlot->addLayer("belowmain", customPlot->layer("main"), QCustomPlot::limBelow); 1158 | graph1->setLayer("abovemain"); 1159 | customPlot->xAxis->grid()->setLayer("belowmain"); 1160 | customPlot->yAxis->grid()->setLayer("belowmain"); 1161 | 1162 | // set some pens, brushes and backgrounds: 1163 | customPlot->xAxis->setBasePen(QPen(Qt::white, 1)); 1164 | customPlot->yAxis->setBasePen(QPen(Qt::white, 1)); 1165 | customPlot->xAxis->setTickPen(QPen(Qt::white, 1)); 1166 | customPlot->yAxis->setTickPen(QPen(Qt::white, 1)); 1167 | customPlot->xAxis->setSubTickPen(QPen(Qt::white, 1)); 1168 | customPlot->yAxis->setSubTickPen(QPen(Qt::white, 1)); 1169 | customPlot->xAxis->setTickLabelColor(Qt::white); 1170 | customPlot->yAxis->setTickLabelColor(Qt::white); 1171 | customPlot->xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); 1172 | customPlot->yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); 1173 | customPlot->xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); 1174 | customPlot->yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); 1175 | customPlot->xAxis->grid()->setSubGridVisible(true); 1176 | customPlot->yAxis->grid()->setSubGridVisible(true); 1177 | customPlot->xAxis->grid()->setZeroLinePen(Qt::NoPen); 1178 | customPlot->yAxis->grid()->setZeroLinePen(Qt::NoPen); 1179 | customPlot->xAxis->setUpperEnding(QCPLineEnding::esSpikeArrow); 1180 | customPlot->yAxis->setUpperEnding(QCPLineEnding::esSpikeArrow); 1181 | QLinearGradient plotGradient; 1182 | plotGradient.setStart(0, 0); 1183 | plotGradient.setFinalStop(0, 350); 1184 | plotGradient.setColorAt(0, QColor(80, 80, 80)); 1185 | plotGradient.setColorAt(1, QColor(50, 50, 50)); 1186 | customPlot->setBackground(plotGradient); 1187 | QLinearGradient axisRectGradient; 1188 | axisRectGradient.setStart(0, 0); 1189 | axisRectGradient.setFinalStop(0, 350); 1190 | axisRectGradient.setColorAt(0, QColor(80, 80, 80)); 1191 | axisRectGradient.setColorAt(1, QColor(30, 30, 30)); 1192 | customPlot->axisRect()->setBackground(axisRectGradient); 1193 | 1194 | customPlot->rescaleAxes(); 1195 | customPlot->yAxis->setRange(0, 2); 1196 | } 1197 | 1198 | void MainWindow::setupAdvancedAxesDemo(QCustomPlot *customPlot) 1199 | { 1200 | demoName = "Advanced Axes Demo"; 1201 | 1202 | // configure axis rect: 1203 | customPlot->plotLayout()->clear(); // clear default axis rect so we can start from scratch 1204 | QCPAxisRect *wideAxisRect = new QCPAxisRect(customPlot); 1205 | wideAxisRect->setupFullAxesBox(true); 1206 | wideAxisRect->axis(QCPAxis::atRight, 0)->setTickLabels(true); 1207 | wideAxisRect->addAxis(QCPAxis::atLeft)->setTickLabelColor(QColor("#6050F8")); // add an extra axis on the left and color its numbers 1208 | QCPLayoutGrid *subLayout = new QCPLayoutGrid; 1209 | customPlot->plotLayout()->addElement(0, 0, wideAxisRect); // insert axis rect in first row 1210 | customPlot->plotLayout()->addElement(1, 0, subLayout); // sub layout in second row (grid layout will grow accordingly) 1211 | //customPlot->plotLayout()->setRowStretchFactor(1, 2); 1212 | // prepare axis rects that will be placed in the sublayout: 1213 | QCPAxisRect *subRectLeft = new QCPAxisRect(customPlot, false); // false means to not setup default axes 1214 | QCPAxisRect *subRectRight = new QCPAxisRect(customPlot, false); 1215 | subLayout->addElement(0, 0, subRectLeft); 1216 | subLayout->addElement(0, 1, subRectRight); 1217 | subRectRight->setMaximumSize(150, 150); // make bottom right axis rect size fixed 150x150 1218 | subRectRight->setMinimumSize(150, 150); // make bottom right axis rect size fixed 150x150 1219 | // setup axes in sub layout axis rects: 1220 | subRectLeft->addAxes(QCPAxis::atBottom | QCPAxis::atLeft); 1221 | subRectRight->addAxes(QCPAxis::atBottom | QCPAxis::atRight); 1222 | subRectLeft->axis(QCPAxis::atLeft)->setAutoTickCount(2); 1223 | subRectRight->axis(QCPAxis::atRight)->setAutoTickCount(2); 1224 | subRectRight->axis(QCPAxis::atBottom)->setAutoTickCount(2); 1225 | subRectLeft->axis(QCPAxis::atBottom)->grid()->setVisible(true); 1226 | // synchronize the left and right margins of the top and bottom axis rects: 1227 | QCPMarginGroup *marginGroup = new QCPMarginGroup(customPlot); 1228 | subRectLeft->setMarginGroup(QCP::msLeft, marginGroup); 1229 | subRectRight->setMarginGroup(QCP::msRight, marginGroup); 1230 | wideAxisRect->setMarginGroup(QCP::msLeft | QCP::msRight, marginGroup); 1231 | // move newly created axes on "axes" layer and grids on "grid" layer: 1232 | foreach (QCPAxisRect *rect, customPlot->axisRects()) 1233 | { 1234 | foreach (QCPAxis *axis, rect->axes()) 1235 | { 1236 | axis->setLayer("axes"); 1237 | axis->grid()->setLayer("grid"); 1238 | } 1239 | } 1240 | 1241 | // prepare data: 1242 | QVector x1a(20), y1a(20); 1243 | QVector x1b(50), y1b(50); 1244 | QVector x2(100), y2(100); 1245 | QVector x3, y3; 1246 | qsrand(3); 1247 | for (int i=0; iaddGraph(wideAxisRect->axis(QCPAxis::atBottom), wideAxisRect->axis(QCPAxis::atLeft)); 1267 | mainGraph1->setData(x1a, y1a); 1268 | mainGraph1->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QPen(Qt::black), QBrush(Qt::white), 6)); 1269 | mainGraph1->setPen(QPen(QColor(120, 120, 120), 2)); 1270 | QCPGraph *mainGraph2 = customPlot->addGraph(wideAxisRect->axis(QCPAxis::atBottom), wideAxisRect->axis(QCPAxis::atLeft, 1)); 1271 | mainGraph2->setData(x1b, y1b); 1272 | mainGraph2->setPen(QPen(QColor("#8070B8"), 2)); 1273 | mainGraph2->setBrush(QColor(110, 170, 110, 30)); 1274 | mainGraph1->setChannelFillGraph(mainGraph2); 1275 | mainGraph1->setBrush(QColor(255, 161, 0, 50)); 1276 | 1277 | QCPGraph *graph2 = customPlot->addGraph(subRectLeft->axis(QCPAxis::atBottom), subRectLeft->axis(QCPAxis::atLeft)); 1278 | graph2->setData(x2, y2); 1279 | graph2->setLineStyle(QCPGraph::lsImpulse); 1280 | graph2->setPen(QPen(QColor("#FFA100"), 1.5)); 1281 | 1282 | QCPBars *bars1 = new QCPBars(subRectRight->axis(QCPAxis::atBottom), subRectRight->axis(QCPAxis::atRight)); 1283 | customPlot->addPlottable(bars1); 1284 | bars1->setWidth(3/(double)x3.size()); 1285 | bars1->setData(x3, y3); 1286 | bars1->setPen(QPen(Qt::black)); 1287 | bars1->setAntialiased(false); 1288 | bars1->setAntialiasedFill(false); 1289 | bars1->setBrush(QColor("#705BE8")); 1290 | bars1->keyAxis()->setAutoTicks(false); 1291 | bars1->keyAxis()->setTickVector(x3); 1292 | bars1->keyAxis()->setSubTickCount(0); 1293 | 1294 | // rescale axes according to graph's data: 1295 | mainGraph1->rescaleAxes(); 1296 | mainGraph2->rescaleAxes(); 1297 | graph2->rescaleAxes(); 1298 | bars1->rescaleAxes(); 1299 | wideAxisRect->axis(QCPAxis::atLeft, 1)->setRangeLower(0); 1300 | } 1301 | 1302 | void MainWindow::setupColorMapDemo(QCustomPlot *customPlot) 1303 | { 1304 | demoName = "Color Map Demo"; 1305 | 1306 | // configure axis rect: 1307 | customPlot->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom); // this will also allow rescaling the color scale by dragging/zooming 1308 | customPlot->axisRect()->setupFullAxesBox(true); 1309 | customPlot->xAxis->setLabel("x"); 1310 | customPlot->yAxis->setLabel("y"); 1311 | 1312 | // set up the QCPColorMap: 1313 | QCPColorMap *colorMap = new QCPColorMap(customPlot->xAxis, customPlot->yAxis); 1314 | customPlot->addPlottable(colorMap); 1315 | int nx = 200; 1316 | int ny = 200; 1317 | colorMap->data()->setSize(nx, ny); // we want the color map to have nx * ny data points 1318 | colorMap->data()->setRange(QCPRange(-4, 4), QCPRange(-4, 4)); // and span the coordinate range -4..4 in both key (x) and value (y) dimensions 1319 | // now we assign some data, by accessing the QCPColorMapData instance of the color map: 1320 | double x, y, z; 1321 | for (int xIndex=0; xIndexdata()->cellToCoord(xIndex, yIndex, &x, &y); 1326 | double r = 3*qSqrt(x*x+y*y)+1e-2; 1327 | z = 2*x*(qCos(r+2)/r-qSin(r+2)/r); // the B field strength of dipole radiation (modulo physical constants) 1328 | colorMap->data()->setCell(xIndex, yIndex, z); 1329 | } 1330 | } 1331 | 1332 | // add a color scale: 1333 | QCPColorScale *colorScale = new QCPColorScale(customPlot); 1334 | customPlot->plotLayout()->addElement(0, 1, colorScale); // add it to the right of the main axis rect 1335 | colorScale->setType(QCPAxis::atRight); // scale shall be vertical bar with tick/axis labels right (actually atRight is already the default) 1336 | colorMap->setColorScale(colorScale); // associate the color map with the color scale 1337 | colorScale->axis()->setLabel("Magnetic Field Strength"); 1338 | 1339 | // set the color gradient of the color map to one of the presets: 1340 | colorMap->setGradient(QCPColorGradient::gpPolar); 1341 | // we could have also created a QCPColorGradient instance and added own colors to 1342 | // the gradient, see the documentation of QCPColorGradient for what's possible. 1343 | 1344 | // rescale the data dimension (color) such that all data points lie in the span visualized by the color gradient: 1345 | colorMap->rescaleDataRange(); 1346 | 1347 | // make sure the axis rect and color scale synchronize their bottom and top margins (so they line up): 1348 | QCPMarginGroup *marginGroup = new QCPMarginGroup(customPlot); 1349 | customPlot->axisRect()->setMarginGroup(QCP::msBottom|QCP::msTop, marginGroup); 1350 | colorScale->setMarginGroup(QCP::msBottom|QCP::msTop, marginGroup); 1351 | 1352 | // rescale the key (x) and value (y) axes so the whole color map is visible: 1353 | customPlot->rescaleAxes(); 1354 | } 1355 | 1356 | void MainWindow::setupFinancialDemo(QCustomPlot *customPlot) 1357 | { 1358 | demoName = "Financial Charts Demo"; 1359 | customPlot->legend->setVisible(true); 1360 | 1361 | // generate two sets of random walk data (one for candlestick and one for ohlc chart): 1362 | int n = 500; 1363 | QVector time(n), value1(n), value2(n); 1364 | QDateTime start = QDateTime(QDate(2014, 6, 11)); 1365 | start.setTimeSpec(Qt::UTC); 1366 | double startTime = start.toTime_t(); 1367 | double binSize = 3600*24; // bin data in 1 day intervals 1368 | time[0] = startTime; 1369 | value1[0] = 60; 1370 | value2[0] = 20; 1371 | qsrand(9); 1372 | for (int i=1; ixAxis, customPlot->yAxis); 1381 | customPlot->addPlottable(candlesticks); 1382 | QCPFinancialDataMap data1 = QCPFinancial::timeSeriesToOhlc(time, value1, binSize, startTime); 1383 | candlesticks->setName("Candlestick"); 1384 | candlesticks->setChartStyle(QCPFinancial::csCandlestick); 1385 | candlesticks->setData(&data1, true); 1386 | candlesticks->setWidth(binSize*0.9); 1387 | candlesticks->setTwoColored(true); 1388 | candlesticks->setBrushPositive(QColor(245, 245, 245)); 1389 | candlesticks->setBrushNegative(QColor(0, 0, 0)); 1390 | candlesticks->setPenPositive(QPen(QColor(0, 0, 0))); 1391 | candlesticks->setPenNegative(QPen(QColor(0, 0, 0))); 1392 | 1393 | // create ohlc chart: 1394 | QCPFinancial *ohlc = new QCPFinancial(customPlot->xAxis, customPlot->yAxis); 1395 | customPlot->addPlottable(ohlc); 1396 | QCPFinancialDataMap data2 = QCPFinancial::timeSeriesToOhlc(time, value2, binSize/3.0, startTime); // divide binSize by 3 just to make the ohlc bars a bit denser 1397 | ohlc->setName("OHLC"); 1398 | ohlc->setChartStyle(QCPFinancial::csOhlc); 1399 | ohlc->setData(&data2, true); 1400 | ohlc->setWidth(binSize*0.2); 1401 | ohlc->setTwoColored(true); 1402 | 1403 | // create bottom axis rect for volume bar chart: 1404 | QCPAxisRect *volumeAxisRect = new QCPAxisRect(customPlot); 1405 | customPlot->plotLayout()->addElement(1, 0, volumeAxisRect); 1406 | volumeAxisRect->setMaximumSize(QSize(QWIDGETSIZE_MAX, 100)); 1407 | volumeAxisRect->axis(QCPAxis::atBottom)->setLayer("axes"); 1408 | volumeAxisRect->axis(QCPAxis::atBottom)->grid()->setLayer("grid"); 1409 | // bring bottom and main axis rect closer together: 1410 | customPlot->plotLayout()->setRowSpacing(0); 1411 | volumeAxisRect->setAutoMargins(QCP::msLeft|QCP::msRight|QCP::msBottom); 1412 | volumeAxisRect->setMargins(QMargins(0, 0, 0, 0)); 1413 | // create two bar plottables, for positive (green) and negative (red) volume bars: 1414 | QCPBars *volumePos = new QCPBars(volumeAxisRect->axis(QCPAxis::atBottom), volumeAxisRect->axis(QCPAxis::atLeft)); 1415 | QCPBars *volumeNeg = new QCPBars(volumeAxisRect->axis(QCPAxis::atBottom), volumeAxisRect->axis(QCPAxis::atLeft)); 1416 | for (int i=0; iaddData(startTime+3600*5.0*i, qAbs(v)); // add data to either volumeNeg or volumePos, depending on sign of v 1420 | } 1421 | customPlot->setAutoAddPlottableToLegend(false); 1422 | customPlot->addPlottable(volumePos); 1423 | customPlot->addPlottable(volumeNeg); 1424 | volumePos->setWidth(3600*4); 1425 | volumePos->setPen(Qt::NoPen); 1426 | volumePos->setBrush(QColor(100, 180, 110)); 1427 | volumeNeg->setWidth(3600*4); 1428 | volumeNeg->setPen(Qt::NoPen); 1429 | volumeNeg->setBrush(QColor(180, 90, 90)); 1430 | 1431 | // interconnect x axis ranges of main and bottom axis rects: 1432 | connect(customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), volumeAxisRect->axis(QCPAxis::atBottom), SLOT(setRange(QCPRange))); 1433 | connect(volumeAxisRect->axis(QCPAxis::atBottom), SIGNAL(rangeChanged(QCPRange)), customPlot->xAxis, SLOT(setRange(QCPRange))); 1434 | // configure axes of both main and bottom axis rect: 1435 | volumeAxisRect->axis(QCPAxis::atBottom)->setAutoTickStep(false); 1436 | volumeAxisRect->axis(QCPAxis::atBottom)->setTickStep(3600*24*4); // 4 day tickstep 1437 | volumeAxisRect->axis(QCPAxis::atBottom)->setTickLabelType(QCPAxis::ltDateTime); 1438 | volumeAxisRect->axis(QCPAxis::atBottom)->setDateTimeSpec(Qt::UTC); 1439 | volumeAxisRect->axis(QCPAxis::atBottom)->setDateTimeFormat("dd. MMM"); 1440 | volumeAxisRect->axis(QCPAxis::atBottom)->setTickLabelRotation(15); 1441 | volumeAxisRect->axis(QCPAxis::atLeft)->setAutoTickCount(3); 1442 | customPlot->xAxis->setBasePen(Qt::NoPen); 1443 | customPlot->xAxis->setTickLabels(false); 1444 | customPlot->xAxis->setTicks(false); // only want vertical grid in main axis rect, so hide xAxis backbone, ticks, and labels 1445 | customPlot->xAxis->setAutoTickStep(false); 1446 | customPlot->xAxis->setTickStep(3600*24*4); // 4 day tickstep 1447 | customPlot->rescaleAxes(); 1448 | customPlot->xAxis->scaleRange(1.025, customPlot->xAxis->range().center()); 1449 | customPlot->yAxis->scaleRange(1.1, customPlot->yAxis->range().center()); 1450 | 1451 | // make axis rects' left side line up: 1452 | QCPMarginGroup *group = new QCPMarginGroup(customPlot); 1453 | customPlot->axisRect()->setMarginGroup(QCP::msLeft|QCP::msRight, group); 1454 | volumeAxisRect->setMarginGroup(QCP::msLeft|QCP::msRight, group); 1455 | } 1456 | 1457 | void MainWindow::realtimeDataSlot() 1458 | { 1459 | // calculate two new data points: 1460 | #if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) 1461 | double key = 0; 1462 | #else 1463 | double key = QDateTime::currentDateTime().toMSecsSinceEpoch()/1000.0; 1464 | #endif 1465 | static double lastPointKey = 0; 1466 | if (key-lastPointKey > 0.01) // at most add point every 10 ms 1467 | { 1468 | double value0 = qSin(key); //qSin(key*1.6+qCos(key*1.7)*2)*10 + qSin(key*1.2+0.56)*20 + 26; 1469 | double value1 = qCos(key); //qSin(key*1.3+qCos(key*1.2)*1.2)*7 + qSin(key*0.9+0.26)*24 + 26; 1470 | // add data to lines: 1471 | ui->customPlot->graph(0)->addData(key, value0); 1472 | ui->customPlot->graph(1)->addData(key, value1); 1473 | // set data of dots: 1474 | ui->customPlot->graph(2)->clearData(); 1475 | ui->customPlot->graph(2)->addData(key, value0); 1476 | ui->customPlot->graph(3)->clearData(); 1477 | ui->customPlot->graph(3)->addData(key, value1); 1478 | // remove data of lines that's outside visible range: 1479 | ui->customPlot->graph(0)->removeDataBefore(key-8); 1480 | ui->customPlot->graph(1)->removeDataBefore(key-8); 1481 | // rescale value (vertical) axis to fit the current data: 1482 | ui->customPlot->graph(0)->rescaleValueAxis(); 1483 | ui->customPlot->graph(1)->rescaleValueAxis(true); 1484 | lastPointKey = key; 1485 | } 1486 | // make key axis range scroll with the data (at a constant range size of 8): 1487 | ui->customPlot->xAxis->setRange(key+0.25, 8, Qt::AlignRight); 1488 | ui->customPlot->replot(); 1489 | 1490 | // calculate frames per second: 1491 | static double lastFpsKey; 1492 | static int frameCount; 1493 | ++frameCount; 1494 | if (key-lastFpsKey > 2) // average fps over 2 seconds 1495 | { 1496 | ui->statusBar->showMessage( 1497 | QString("%1 FPS, Total Data points: %2") 1498 | .arg(frameCount/(key-lastFpsKey), 0, 'f', 0) 1499 | .arg(ui->customPlot->graph(0)->data()->count()+ui->customPlot->graph(1)->data()->count()) 1500 | , 0); 1501 | lastFpsKey = key; 1502 | frameCount = 0; 1503 | } 1504 | } 1505 | 1506 | void MainWindow::bracketDataSlot() 1507 | { 1508 | #if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) 1509 | double secs = 0; 1510 | #else 1511 | double secs = QDateTime::currentDateTime().toMSecsSinceEpoch()/1000.0; 1512 | #endif 1513 | 1514 | // update data to make phase move: 1515 | int n = 500; 1516 | double phase = secs*5; 1517 | double k = 3; 1518 | QVector x(n), y(n); 1519 | for (int i=0; icustomPlot->graph()->setData(x, y); 1525 | 1526 | itemDemoPhaseTracer->setGraphKey((8*M_PI+fmod(M_PI*1.5-phase, 6*M_PI))/k); 1527 | 1528 | ui->customPlot->replot(); 1529 | 1530 | // calculate frames per second: 1531 | double key = secs; 1532 | static double lastFpsKey; 1533 | static int frameCount; 1534 | ++frameCount; 1535 | if (key-lastFpsKey > 2) // average fps over 2 seconds 1536 | { 1537 | ui->statusBar->showMessage( 1538 | QString("%1 FPS, Total Data points: %2") 1539 | .arg(frameCount/(key-lastFpsKey), 0, 'f', 0) 1540 | .arg(ui->customPlot->graph(0)->data()->count()) 1541 | , 0); 1542 | lastFpsKey = key; 1543 | frameCount = 0; 1544 | } 1545 | } 1546 | 1547 | void MainWindow::setupPlayground(QCustomPlot *customPlot) 1548 | { 1549 | Q_UNUSED(customPlot) 1550 | } 1551 | 1552 | MainWindow::~MainWindow() 1553 | { 1554 | delete ui; 1555 | } 1556 | 1557 | void MainWindow::screenShot() 1558 | { 1559 | #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) 1560 | QPixmap pm = QPixmap::grabWindow(qApp->desktop()->winId(), this->x()+2, this->y()+2, this->frameGeometry().width()-4, this->frameGeometry().height()-4); 1561 | #else 1562 | QPixmap pm = qApp->primaryScreen()->grabWindow(qApp->desktop()->winId(), this->x()+2, this->y()+2, this->frameGeometry().width()-4, this->frameGeometry().height()-4); 1563 | #endif 1564 | QString fileName = demoName.toLower()+".png"; 1565 | fileName.replace(" ", ""); 1566 | pm.save("./screenshots/"+fileName); 1567 | qApp->quit(); 1568 | } 1569 | 1570 | void MainWindow::allScreenShots() 1571 | { 1572 | #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) 1573 | QPixmap pm = QPixmap::grabWindow(qApp->desktop()->winId(), this->x()+2, this->y()+2, this->frameGeometry().width()-4, this->frameGeometry().height()-4); 1574 | #else 1575 | QPixmap pm = qApp->primaryScreen()->grabWindow(qApp->desktop()->winId(), this->x()+2, this->y()+2, this->frameGeometry().width()-4, this->frameGeometry().height()-4); 1576 | #endif 1577 | QString fileName = demoName.toLower()+".png"; 1578 | fileName.replace(" ", ""); 1579 | pm.save("./screenshots/"+fileName); 1580 | 1581 | if (currentDemoIndex < 19) 1582 | { 1583 | if (dataTimer.isActive()) 1584 | dataTimer.stop(); 1585 | dataTimer.disconnect(); 1586 | delete ui->customPlot; 1587 | ui->customPlot = new QCustomPlot(ui->centralWidget); 1588 | ui->verticalLayout->addWidget(ui->customPlot); 1589 | setupDemo(currentDemoIndex+1); 1590 | // setup delay for demos that need time to develop proper look: 1591 | int delay = 250; 1592 | if (currentDemoIndex == 10) // Next is Realtime data demo 1593 | delay = 12000; 1594 | else if (currentDemoIndex == 15) // Next is Item demo 1595 | delay = 5000; 1596 | QTimer::singleShot(delay, this, SLOT(allScreenShots())); 1597 | } else 1598 | { 1599 | qApp->quit(); 1600 | } 1601 | } 1602 | 1603 | 1604 | 1605 | 1606 | 1607 | 1608 | 1609 | 1610 | 1611 | 1612 | 1613 | 1614 | 1615 | 1616 | 1617 | 1618 | 1619 | 1620 | 1621 | 1622 | 1623 | 1624 | 1625 | 1626 | 1627 | 1628 | 1629 | 1630 | 1631 | 1632 | 1633 | 1634 | 1635 | 1636 | 1637 | 1638 | 1639 | 1640 | 1641 | -------------------------------------------------------------------------------- /examples/plots/mainwindow.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** ** 3 | ** QCustomPlot, an easy to use, modern plotting widget for Qt ** 4 | ** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** 5 | ** ** 6 | ** This program is free software: you can redistribute it and/or modify ** 7 | ** it under the terms of the GNU General Public License as published by ** 8 | ** the Free Software Foundation, either version 3 of the License, or ** 9 | ** (at your option) any later version. ** 10 | ** ** 11 | ** This program is distributed in the hope that it will be useful, ** 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 14 | ** GNU General Public License for more details. ** 15 | ** ** 16 | ** You should have received a copy of the GNU General Public License ** 17 | ** along with this program. If not, see http://www.gnu.org/licenses/. ** 18 | ** ** 19 | **************************************************************************** 20 | ** Author: Emanuel Eichhammer ** 21 | ** Website/Contact: http://www.qcustomplot.com/ ** 22 | ** Date: 27.12.14 ** 23 | ** Version: 1.3.0 ** 24 | ****************************************************************************/ 25 | 26 | /************************************************************************************************************ 27 | ** ** 28 | ** This is the example code for QCustomPlot. ** 29 | ** ** 30 | ** It demonstrates basic and some advanced capabilities of the widget. The interesting code is inside ** 31 | ** the "setup(...)Demo" functions of MainWindow. ** 32 | ** ** 33 | ** In order to see a demo in action, call the respective "setup(...)Demo" function inside the ** 34 | ** MainWindow constructor. Alternatively you may call setupDemo(i) where i is the index of the demo ** 35 | ** you want (for those, see MainWindow constructor comments). All other functions here are merely a ** 36 | ** way to easily create screenshots of all demos for the website. I.e. a timer is set to successively ** 37 | ** setup all the demos and make a screenshot of the window area and save it in the ./screenshots ** 38 | ** directory. ** 39 | ** ** 40 | *************************************************************************************************************/ 41 | 42 | #ifndef MAINWINDOW_H 43 | #define MAINWINDOW_H 44 | 45 | #include 46 | #include 47 | #include "../../qcustomplot.h" // the header file of QCustomPlot. Don't forget to add it to your project, if you use an IDE, so it gets compiled. 48 | 49 | namespace Ui { 50 | class MainWindow; 51 | } 52 | 53 | class MainWindow : public QMainWindow 54 | { 55 | Q_OBJECT 56 | 57 | public: 58 | explicit MainWindow(QWidget *parent = 0); 59 | ~MainWindow(); 60 | 61 | void setupDemo(int demoIndex); 62 | void setupQuadraticDemo(QCustomPlot *customPlot); 63 | void setupSimpleDemo(QCustomPlot *customPlot); 64 | void setupSincScatterDemo(QCustomPlot *customPlot); 65 | void setupScatterStyleDemo(QCustomPlot *customPlot); 66 | void setupLineStyleDemo(QCustomPlot *customPlot); 67 | void setupScatterPixmapDemo(QCustomPlot *customPlot); 68 | void setupDateDemo(QCustomPlot *customPlot); 69 | void setupTextureBrushDemo(QCustomPlot *customPlot); 70 | void setupMultiAxisDemo(QCustomPlot *customPlot); 71 | void setupLogarithmicDemo(QCustomPlot *customPlot); 72 | void setupRealtimeDataDemo(QCustomPlot *customPlot); 73 | void setupParametricCurveDemo(QCustomPlot *customPlot); 74 | void setupBarChartDemo(QCustomPlot *customPlot); 75 | void setupStatisticalDemo(QCustomPlot *customPlot); 76 | void setupSimpleItemDemo(QCustomPlot *customPlot); 77 | void setupItemDemo(QCustomPlot *customPlot); 78 | void setupStyledDemo(QCustomPlot *customPlot); 79 | void setupAdvancedAxesDemo(QCustomPlot *customPlot); 80 | void setupColorMapDemo(QCustomPlot *customPlot); 81 | void setupFinancialDemo(QCustomPlot *customPlot); 82 | 83 | void setupPlayground(QCustomPlot *customPlot); 84 | 85 | private slots: 86 | void realtimeDataSlot(); 87 | void bracketDataSlot(); 88 | void screenShot(); 89 | void allScreenShots(); 90 | 91 | private: 92 | Ui::MainWindow *ui; 93 | QString demoName; 94 | QTimer dataTimer; 95 | QCPItemTracer *itemDemoPhaseTracer; 96 | int currentDemoIndex; 97 | }; 98 | 99 | #endif // MAINWINDOW_H 100 | -------------------------------------------------------------------------------- /examples/plots/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 548 10 | 420 11 | 12 | 13 | 14 | QCustomPlot plot examples 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | QCustomPlot 29 | QWidget 30 |
../../qcustomplot.h
31 | 1 32 |
33 |
34 | 35 | 36 |
37 | -------------------------------------------------------------------------------- /examples/plots/plot-examples.pro: -------------------------------------------------------------------------------- 1 | # 2 | # QCustomPlot Plot Examples 3 | # 4 | 5 | QT += core gui 6 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport 7 | 8 | TARGET = plot-examples 9 | TEMPLATE = app 10 | 11 | SOURCES += main.cpp\ 12 | mainwindow.cpp \ 13 | ../../qcustomplot.cpp 14 | 15 | HEADERS += mainwindow.h \ 16 | ../../qcustomplot.h 17 | 18 | FORMS += mainwindow.ui 19 | 20 | -------------------------------------------------------------------------------- /examples/plots/screenshots/.gitignore: -------------------------------------------------------------------------------- 1 | *.png 2 | -------------------------------------------------------------------------------- /examples/plots/screenshots/create-thumbs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os, shutil, distutils.dir_util, sys, subprocess 3 | 4 | os.chdir(sys.path[0]); # change current working dir to script dir 5 | 6 | if not os.path.isdir("./thumbs"): 7 | os.mkdir("./thumbs"); 8 | elif len(os.listdir("./thumbs")) > 0: 9 | if raw_input("Warning: ./thumbs not empty! Continue anyway? (y/n): ") != "y": 10 | sys.exit(); 11 | 12 | #sizes = ["264x200"]; 13 | sizes = ["220x168"]; 14 | 15 | for fileName in os.listdir("./"): 16 | if os.path.isfile(fileName) and "." in fileName and fileName.split(".")[1] == "png": 17 | print "processing "+fileName; 18 | for size in sizes: 19 | subprocess.call("convert -resize "+size+" "+fileName+" -sharpen 0x1 ./thumbs/"+fileName.split(".")[0]+"-thumb.png", shell=True); 20 | #subprocess.call("convert -crop 548x288+0+66 "+fileName+" ./thumbs/"+fileName.split(".")[0]+"-548x288.png", shell=True); 21 | shutil.copy2("./"+fileName, "./thumbs"); 22 | 23 | # f = open("main.cpp", "r"); 24 | # content = f.read(); 25 | # f.close(); 26 | # content = content.replace("q"+name.lower()+"hash.h", "../q"+name.lower()+"hash.h"); 27 | # f = open("main.cpp", "w"); 28 | # f.write(content); 29 | # f.close(); 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /examples/plots/solarpanels.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbzhang800/QCustomPlot/d1d69480e3f7af8959ecd3d3b3c8bbfffc7b1292/examples/plots/solarpanels.jpg -------------------------------------------------------------------------------- /examples/plots/sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbzhang800/QCustomPlot/d1d69480e3f7af8959ecd3d3b3c8bbfffc7b1292/examples/plots/sun.png -------------------------------------------------------------------------------- /examples/scrollbar-axis-range-control/.gitignore: -------------------------------------------------------------------------------- 1 | scrollbar-axis-range-control 2 | -------------------------------------------------------------------------------- /examples/scrollbar-axis-range-control/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /examples/scrollbar-axis-range-control/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** ** 3 | ** QCustomPlot, an easy to use, modern plotting widget for Qt ** 4 | ** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** 5 | ** ** 6 | ** This program is free software: you can redistribute it and/or modify ** 7 | ** it under the terms of the GNU General Public License as published by ** 8 | ** the Free Software Foundation, either version 3 of the License, or ** 9 | ** (at your option) any later version. ** 10 | ** ** 11 | ** This program is distributed in the hope that it will be useful, ** 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 14 | ** GNU General Public License for more details. ** 15 | ** ** 16 | ** You should have received a copy of the GNU General Public License ** 17 | ** along with this program. If not, see http://www.gnu.org/licenses/. ** 18 | ** ** 19 | **************************************************************************** 20 | ** Author: Emanuel Eichhammer ** 21 | ** Website/Contact: http://www.qcustomplot.com/ ** 22 | ** Date: 27.12.14 ** 23 | ** Version: 1.3.0 ** 24 | ****************************************************************************/ 25 | 26 | #include "mainwindow.h" 27 | #include "ui_mainwindow.h" 28 | 29 | MainWindow::MainWindow(QWidget *parent) : 30 | QMainWindow(parent), 31 | ui(new Ui::MainWindow) 32 | { 33 | ui->setupUi(this); 34 | setupPlot(); 35 | 36 | // configure scroll bars: 37 | // Since scroll bars only support integer values, we'll set a high default range of -500..500 and 38 | // divide scroll bar position values by 100 to provide a scroll range -5..5 in floating point 39 | // axis coordinates. if you want to dynamically grow the range accessible with the scroll bar, 40 | // just increase the the minimum/maximum values of the scroll bars as needed. 41 | ui->horizontalScrollBar->setRange(-500, 500); 42 | ui->verticalScrollBar->setRange(-500, 500); 43 | 44 | // create connection between axes and scroll bars: 45 | connect(ui->horizontalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(horzScrollBarChanged(int))); 46 | connect(ui->verticalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(vertScrollBarChanged(int))); 47 | connect(ui->plot->xAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(xAxisChanged(QCPRange))); 48 | connect(ui->plot->yAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(yAxisChanged(QCPRange))); 49 | 50 | // initialize axis range (and scroll bar positions via signals we just connected): 51 | ui->plot->xAxis->setRange(0, 6, Qt::AlignCenter); 52 | ui->plot->yAxis->setRange(0, 10, Qt::AlignCenter); 53 | } 54 | 55 | MainWindow::~MainWindow() 56 | { 57 | delete ui; 58 | } 59 | 60 | void MainWindow::setupPlot() 61 | { 62 | // The following plot setup is mostly taken from the plot demos: 63 | ui->plot->addGraph(); 64 | ui->plot->graph()->setPen(QPen(Qt::blue)); 65 | ui->plot->graph()->setBrush(QBrush(QColor(0, 0, 255, 20))); 66 | ui->plot->addGraph(); 67 | ui->plot->graph()->setPen(QPen(Qt::red)); 68 | QVector x(500), y0(500), y1(500); 69 | for (int i=0; i<500; ++i) 70 | { 71 | x[i] = (i/499.0-0.5)*10; 72 | y0[i] = qExp(-x[i]*x[i]*0.25)*qSin(x[i]*5)*5; 73 | y1[i] = qExp(-x[i]*x[i]*0.25)*5; 74 | } 75 | ui->plot->graph(0)->setData(x, y0); 76 | ui->plot->graph(1)->setData(x, y1); 77 | ui->plot->axisRect()->setupFullAxesBox(true); 78 | ui->plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); 79 | } 80 | 81 | void MainWindow::horzScrollBarChanged(int value) 82 | { 83 | if (qAbs(ui->plot->xAxis->range().center()-value/100.0) > 0.01) // if user is dragging plot, we don't want to replot twice 84 | { 85 | ui->plot->xAxis->setRange(value/100.0, ui->plot->xAxis->range().size(), Qt::AlignCenter); 86 | ui->plot->replot(); 87 | } 88 | } 89 | 90 | void MainWindow::vertScrollBarChanged(int value) 91 | { 92 | if (qAbs(ui->plot->yAxis->range().center()+value/100.0) > 0.01) // if user is dragging plot, we don't want to replot twice 93 | { 94 | ui->plot->yAxis->setRange(-value/100.0, ui->plot->yAxis->range().size(), Qt::AlignCenter); 95 | ui->plot->replot(); 96 | } 97 | } 98 | 99 | void MainWindow::xAxisChanged(QCPRange range) 100 | { 101 | ui->horizontalScrollBar->setValue(qRound(range.center()*100.0)); // adjust position of scroll bar slider 102 | ui->horizontalScrollBar->setPageStep(qRound(range.size()*100.0)); // adjust size of scroll bar slider 103 | } 104 | 105 | void MainWindow::yAxisChanged(QCPRange range) 106 | { 107 | ui->verticalScrollBar->setValue(qRound(-range.center()*100.0)); // adjust position of scroll bar slider 108 | ui->verticalScrollBar->setPageStep(qRound(range.size()*100.0)); // adjust size of scroll bar slider 109 | } 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /examples/scrollbar-axis-range-control/mainwindow.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** ** 3 | ** QCustomPlot, an easy to use, modern plotting widget for Qt ** 4 | ** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** 5 | ** ** 6 | ** This program is free software: you can redistribute it and/or modify ** 7 | ** it under the terms of the GNU General Public License as published by ** 8 | ** the Free Software Foundation, either version 3 of the License, or ** 9 | ** (at your option) any later version. ** 10 | ** ** 11 | ** This program is distributed in the hope that it will be useful, ** 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 14 | ** GNU General Public License for more details. ** 15 | ** ** 16 | ** You should have received a copy of the GNU General Public License ** 17 | ** along with this program. If not, see http://www.gnu.org/licenses/. ** 18 | ** ** 19 | **************************************************************************** 20 | ** Author: Emanuel Eichhammer ** 21 | ** Website/Contact: http://www.qcustomplot.com/ ** 22 | ** Date: 27.12.14 ** 23 | ** Version: 1.3.0 ** 24 | ****************************************************************************/ 25 | 26 | #ifndef MAINWINDOW_H 27 | #define MAINWINDOW_H 28 | 29 | #include 30 | #include "../../qcustomplot.h" 31 | 32 | namespace Ui { 33 | class MainWindow; 34 | } 35 | 36 | class MainWindow : public QMainWindow 37 | { 38 | Q_OBJECT 39 | 40 | public: 41 | explicit MainWindow(QWidget *parent = 0); 42 | ~MainWindow(); 43 | 44 | void setupPlot(); 45 | 46 | private slots: 47 | void horzScrollBarChanged(int value); 48 | void vertScrollBarChanged(int value); 49 | void xAxisChanged(QCPRange range); 50 | void yAxisChanged(QCPRange range); 51 | 52 | private: 53 | Ui::MainWindow *ui; 54 | }; 55 | 56 | #endif // MAINWINDOW_H 57 | -------------------------------------------------------------------------------- /examples/scrollbar-axis-range-control/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 469 10 | 357 11 | 12 | 13 | 14 | QCustomPlot Scrollbar Axis Range Control Demo 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 0 23 | 0 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | Qt::Vertical 32 | 33 | 34 | 35 | 36 | 37 | 38 | Qt::Horizontal 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | Insert Plot 48 | 49 | 50 | 51 | 52 | Save Document... 53 | 54 | 55 | 56 | 57 | 58 | 59 | QCustomPlot 60 | QWidget 61 |
../../qcustomplot.h
62 | 1 63 |
64 |
65 | 66 | 67 |
68 | -------------------------------------------------------------------------------- /examples/scrollbar-axis-range-control/scrollbar-axis-range-control.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2013-07-25T20:43:22 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport 10 | 11 | TARGET = scrollbar-axis-range-control 12 | TEMPLATE = app 13 | 14 | 15 | SOURCES += main.cpp\ 16 | mainwindow.cpp \ 17 | ../../qcustomplot.cpp 18 | 19 | HEADERS += mainwindow.h \ 20 | ../../qcustomplot.h 21 | 22 | FORMS += mainwindow.ui 23 | -------------------------------------------------------------------------------- /examples/text-document-integration/.gitignore: -------------------------------------------------------------------------------- 1 | text-document-integration 2 | -------------------------------------------------------------------------------- /examples/text-document-integration/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /examples/text-document-integration/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** ** 3 | ** QCustomPlot, an easy to use, modern plotting widget for Qt ** 4 | ** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** 5 | ** ** 6 | ** This program is free software: you can redistribute it and/or modify ** 7 | ** it under the terms of the GNU General Public License as published by ** 8 | ** the Free Software Foundation, either version 3 of the License, or ** 9 | ** (at your option) any later version. ** 10 | ** ** 11 | ** This program is distributed in the hope that it will be useful, ** 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 14 | ** GNU General Public License for more details. ** 15 | ** ** 16 | ** You should have received a copy of the GNU General Public License ** 17 | ** along with this program. If not, see http://www.gnu.org/licenses/. ** 18 | ** ** 19 | **************************************************************************** 20 | ** Author: Emanuel Eichhammer ** 21 | ** Website/Contact: http://www.qcustomplot.com/ ** 22 | ** Date: 27.12.14 ** 23 | ** Version: 1.3.0 ** 24 | ****************************************************************************/ 25 | 26 | #include "mainwindow.h" 27 | #include "ui_mainwindow.h" 28 | 29 | MainWindow::MainWindow(QWidget *parent) : 30 | QMainWindow(parent), 31 | ui(new Ui::MainWindow) 32 | { 33 | ui->setupUi(this); 34 | connect(ui->cbUseCurrentSize, SIGNAL(toggled(bool)), ui->sbWidth, SLOT(setDisabled(bool))); 35 | connect(ui->cbUseCurrentSize, SIGNAL(toggled(bool)), ui->sbHeight, SLOT(setDisabled(bool))); 36 | 37 | ui->plot->axisRect()->setMinimumSize(300, 180); 38 | setupPlot(); 39 | 40 | // register the plot document object (only needed once, no matter how many plots will be in the QTextDocument): 41 | QCPDocumentObject *plotObjectHandler = new QCPDocumentObject(this); 42 | ui->textEdit->document()->documentLayout()->registerHandler(QCPDocumentObject::PlotTextFormat, plotObjectHandler); 43 | } 44 | 45 | MainWindow::~MainWindow() 46 | { 47 | delete ui; 48 | } 49 | 50 | void MainWindow::setupPlot() 51 | { 52 | // The following plot setup is taken from the sine demo: 53 | // add two new graphs and set their look: 54 | ui->plot->addGraph(); 55 | ui->plot->graph(0)->setPen(QPen(Qt::blue)); // line color blue for first graph 56 | ui->plot->graph(0)->setBrush(QBrush(QColor(0, 0, 255, 20))); // first graph will be filled with translucent blue 57 | ui->plot->addGraph(); 58 | ui->plot->graph(1)->setPen(QPen(Qt::red)); // line color red for second graph 59 | // generate some points of data (y0 for first, y1 for second graph): 60 | QVector x(250), y0(250), y1(250); 61 | for (int i=0; i<250; ++i) 62 | { 63 | x[i] = i; 64 | y0[i] = qExp(-i/150.0)*qCos(i/10.0); // exponentially decaying cosine 65 | y1[i] = qExp(-i/150.0); // exponential envelope 66 | } 67 | // configure right and top axis to show ticks but no labels: 68 | // (see QCPAxisRect::setupFullAxesBox for a quicker method to do this) 69 | ui->plot->xAxis2->setVisible(true); 70 | ui->plot->xAxis2->setTickLabels(false); 71 | ui->plot->yAxis2->setVisible(true); 72 | ui->plot->yAxis2->setTickLabels(false); 73 | // make left and bottom axes always transfer their ranges to right and top axes: 74 | connect(ui->plot->xAxis, SIGNAL(rangeChanged(QCPRange)), ui->plot->xAxis2, SLOT(setRange(QCPRange))); 75 | connect(ui->plot->yAxis, SIGNAL(rangeChanged(QCPRange)), ui->plot->yAxis2, SLOT(setRange(QCPRange))); 76 | // pass data points to graphs: 77 | ui->plot->graph(0)->setData(x, y0); 78 | ui->plot->graph(1)->setData(x, y1); 79 | // let the ranges scale themselves so graph 0 fits perfectly in the visible area: 80 | ui->plot->graph(0)->rescaleAxes(); 81 | // same thing for graph 1, but only enlarge ranges (in case graph 1 is smaller than graph 0): 82 | ui->plot->graph(1)->rescaleAxes(true); 83 | // Note: we could have also just called customPlot->rescaleAxes(); instead 84 | // Allow user to drag axis ranges with mouse, zoom with mouse wheel and select graphs by clicking: 85 | ui->plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables); 86 | } 87 | 88 | void MainWindow::on_actionInsert_Plot_triggered() 89 | { 90 | QTextCursor cursor = ui->textEdit->textCursor(); 91 | 92 | // insert the current plot at the cursor position. QCPDocumentObject::generatePlotFormat creates a 93 | // vectorized snapshot of the passed plot (with the specified width and height) which gets inserted 94 | // into the text document. 95 | double width = ui->cbUseCurrentSize->isChecked() ? 0 : ui->sbWidth->value(); 96 | double height = ui->cbUseCurrentSize->isChecked() ? 0 : ui->sbHeight->value(); 97 | cursor.insertText(QString(QChar::ObjectReplacementCharacter), QCPDocumentObject::generatePlotFormat(ui->plot, width, height)); 98 | 99 | ui->textEdit->setTextCursor(cursor); 100 | } 101 | 102 | void MainWindow::on_actionSave_Document_triggered() 103 | { 104 | QString fileName = QFileDialog::getSaveFileName(this, "Save document...", qApp->applicationDirPath(), "*.pdf"); 105 | if (!fileName.isEmpty()) 106 | { 107 | QPrinter printer; 108 | printer.setFullPage(true); 109 | printer.setPaperSize(QPrinter::A4); 110 | printer.setOrientation(QPrinter::Portrait); 111 | printer.setOutputFormat(QPrinter::PdfFormat); 112 | printer.setOutputFileName(fileName); 113 | ui->textEdit->document()->print(&printer); 114 | } 115 | } 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /examples/text-document-integration/mainwindow.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** ** 3 | ** QCustomPlot, an easy to use, modern plotting widget for Qt ** 4 | ** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** 5 | ** ** 6 | ** This program is free software: you can redistribute it and/or modify ** 7 | ** it under the terms of the GNU General Public License as published by ** 8 | ** the Free Software Foundation, either version 3 of the License, or ** 9 | ** (at your option) any later version. ** 10 | ** ** 11 | ** This program is distributed in the hope that it will be useful, ** 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 14 | ** GNU General Public License for more details. ** 15 | ** ** 16 | ** You should have received a copy of the GNU General Public License ** 17 | ** along with this program. If not, see http://www.gnu.org/licenses/. ** 18 | ** ** 19 | **************************************************************************** 20 | ** Author: Emanuel Eichhammer ** 21 | ** Website/Contact: http://www.qcustomplot.com/ ** 22 | ** Date: 27.12.14 ** 23 | ** Version: 1.3.0 ** 24 | ****************************************************************************/ 25 | 26 | #ifndef MAINWINDOW_H 27 | #define MAINWINDOW_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include "qcpdocumentobject.h" 33 | 34 | namespace Ui { 35 | class MainWindow; 36 | } 37 | 38 | class MainWindow : public QMainWindow 39 | { 40 | Q_OBJECT 41 | 42 | public: 43 | explicit MainWindow(QWidget *parent = 0); 44 | ~MainWindow(); 45 | 46 | void setupPlot(); 47 | 48 | private slots: 49 | void on_actionInsert_Plot_triggered(); 50 | void on_actionSave_Document_triggered(); 51 | 52 | private: 53 | Ui::MainWindow *ui; 54 | }; 55 | 56 | #endif // MAINWINDOW_H 57 | -------------------------------------------------------------------------------- /examples/text-document-integration/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 786 10 | 440 11 | 12 | 13 | 14 | QCustomPlot Document Insertion Demo 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 400 23 | 0 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 0 35 | 0 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | <html><head/><body><p>Size of plot<br/>in document:</p></body></html> 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 0 54 | 0 55 | 56 | 57 | 58 | 1 59 | 60 | 61 | 9999 62 | 63 | 64 | 480 65 | 66 | 67 | 68 | 69 | 70 | 71 | x 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 0 80 | 0 81 | 82 | 83 | 84 | 1 85 | 86 | 87 | 9999 88 | 89 | 90 | 340 91 | 92 | 93 | 94 | 95 | 96 | 97 | Use current 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | TopToolBarArea 110 | 111 | 112 | false 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | Insert Plot 121 | 122 | 123 | 124 | 125 | Save Document... 126 | 127 | 128 | 129 | 130 | 131 | 132 | QCustomPlot 133 | QWidget 134 |
../../qcustomplot.h
135 | 1 136 |
137 |
138 | 139 | 140 |
141 | -------------------------------------------------------------------------------- /examples/text-document-integration/qcpdocumentobject.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** ** 3 | ** QCustomPlot, an easy to use, modern plotting widget for Qt ** 4 | ** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** 5 | ** ** 6 | ** This program is free software: you can redistribute it and/or modify ** 7 | ** it under the terms of the GNU General Public License as published by ** 8 | ** the Free Software Foundation, either version 3 of the License, or ** 9 | ** (at your option) any later version. ** 10 | ** ** 11 | ** This program is distributed in the hope that it will be useful, ** 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 14 | ** GNU General Public License for more details. ** 15 | ** ** 16 | ** You should have received a copy of the GNU General Public License ** 17 | ** along with this program. If not, see http://www.gnu.org/licenses/. ** 18 | ** ** 19 | **************************************************************************** 20 | ** Author: Emanuel Eichhammer ** 21 | ** Website/Contact: http://www.qcustomplot.com/ ** 22 | ** Date: 27.12.14 ** 23 | ** Version: 1.3.0 ** 24 | ****************************************************************************/ 25 | 26 | #include "qcpdocumentobject.h" 27 | 28 | QCPDocumentObject::QCPDocumentObject(QObject *parent) : 29 | QObject(parent) 30 | { 31 | } 32 | 33 | QSizeF QCPDocumentObject::intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format) 34 | { 35 | Q_UNUSED(doc) 36 | Q_UNUSED(posInDocument) 37 | QPicture pic = qvariant_cast(format.property(PicturePropertyId)); 38 | if (pic.isNull()) 39 | { 40 | qDebug() << Q_FUNC_INFO << "Plot object is empty"; 41 | return QSizeF(10, 10); 42 | } else 43 | return QSizeF(pic.boundingRect().size()); 44 | } 45 | 46 | void QCPDocumentObject::drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format) 47 | { 48 | Q_UNUSED(doc) 49 | Q_UNUSED(posInDocument) 50 | QPicture pic = qvariant_cast(format.property(PicturePropertyId)); 51 | if (pic.isNull()) 52 | return; 53 | 54 | QSize finalSize = pic.boundingRect().size(); 55 | finalSize.scale(rect.size().toSize(), Qt::KeepAspectRatio); 56 | double scaleFactor = finalSize.width()/(double)pic.boundingRect().size().width(); 57 | painter->save(); 58 | painter->scale(scaleFactor, scaleFactor); 59 | painter->setClipRect(rect); 60 | painter->drawPicture(rect.topLeft(), pic); 61 | painter->restore(); 62 | } 63 | 64 | QTextCharFormat QCPDocumentObject::generatePlotFormat(QCustomPlot *plot, int width, int height) 65 | { 66 | QPicture picture; 67 | QCPPainter qcpPainter; 68 | qcpPainter.begin(&picture); 69 | plot->toPainter(&qcpPainter, width, height); 70 | qcpPainter.end(); 71 | 72 | QTextCharFormat result; 73 | result.setObjectType(QCPDocumentObject::PlotTextFormat); 74 | result.setProperty(QCPDocumentObject::PicturePropertyId, QVariant::fromValue(picture)); 75 | return result; 76 | } 77 | -------------------------------------------------------------------------------- /examples/text-document-integration/qcpdocumentobject.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** ** 3 | ** QCustomPlot, an easy to use, modern plotting widget for Qt ** 4 | ** Copyright (C) 2011, 2012, 2013, 2014 Emanuel Eichhammer ** 5 | ** ** 6 | ** This program is free software: you can redistribute it and/or modify ** 7 | ** it under the terms of the GNU General Public License as published by ** 8 | ** the Free Software Foundation, either version 3 of the License, or ** 9 | ** (at your option) any later version. ** 10 | ** ** 11 | ** This program is distributed in the hope that it will be useful, ** 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 14 | ** GNU General Public License for more details. ** 15 | ** ** 16 | ** You should have received a copy of the GNU General Public License ** 17 | ** along with this program. If not, see http://www.gnu.org/licenses/. ** 18 | ** ** 19 | **************************************************************************** 20 | ** Author: Emanuel Eichhammer ** 21 | ** Website/Contact: http://www.qcustomplot.com/ ** 22 | ** Date: 27.12.14 ** 23 | ** Version: 1.3.0 ** 24 | ****************************************************************************/ 25 | 26 | #ifndef QCPDOCUMENTOBJECT_H 27 | #define QCPDOCUMENTOBJECT_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "../../qcustomplot.h" 35 | 36 | class QCPDocumentObject : public QObject, public QTextObjectInterface 37 | { 38 | Q_OBJECT 39 | Q_INTERFACES(QTextObjectInterface) 40 | 41 | public: 42 | enum { PlotTextFormat = QTextFormat::UserObject + 3902 }; // if your application already uses the id (QTextFormat::UserObject + 3902), just change the id here 43 | enum { PicturePropertyId = 1 }; 44 | 45 | explicit QCPDocumentObject(QObject *parent = 0); 46 | QSizeF intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format); 47 | void drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format); 48 | 49 | static QTextCharFormat generatePlotFormat(QCustomPlot *plot, int width=0, int height=0); 50 | 51 | }; 52 | Q_DECLARE_METATYPE(QPicture) 53 | 54 | #endif // QCPDOCUMENTOBJECT_H 55 | -------------------------------------------------------------------------------- /examples/text-document-integration/text-document-integration.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2013-07-06T18:51:44 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport 10 | 11 | TARGET = text-document-integration 12 | TEMPLATE = app 13 | 14 | 15 | SOURCES += main.cpp\ 16 | mainwindow.cpp \ 17 | qcpdocumentobject.cpp \ 18 | ../../qcustomplot.cpp 19 | 20 | HEADERS += mainwindow.h \ 21 | qcpdocumentobject.h \ 22 | ../../qcustomplot.h 23 | 24 | FORMS += mainwindow.ui 25 | --------------------------------------------------------------------------------