pax_global_header00006660000000000000000000000064126706072510014520gustar00rootroot0000000000000052 comment=c42149dd5586a89179913f3299fe7a0282e51213 gral-0.11/000077500000000000000000000000001267060725100123665ustar00rootroot00000000000000gral-0.11/.gitignore000066400000000000000000000000761267060725100143610ustar00rootroot00000000000000# Gradle temporary files .gradle # Gradle output folder build gral-0.11/CHANGES.rst000066400000000000000000000052441267060725100141750ustar00rootroot00000000000000GRAL 0.11 (2016-03-11) ====================== Data: - More robust import of CSV/TSV data - Added a name to all data sources Plotting: - Data sources can have multiple renderers of the same type (point, line, area) now, which will allow effects like shadows, etc. - Improved quality of exported bitmap images General: - Switched from ``mvn.erichseifert.de`` to Maven Central - Improved versioning scheme using Git describe - Many clean-ups and bug fixes GRAL 0.10 (2013-12-09) ====================== Plotting: - Replaced all plot settings by regular Java properties General: - Migrated the version control system from Subversion to git - Replaced the Maven build system by Gradle - Various bug fixes GRAL 0.9 (2013-05-12) ===================== Data: - New JDBC data source that can query data from a database connection - Support for arbitrary Comparable values and empty values (``null``) in data sources - Improved statistics (lazy calculation, quartile statistics, etc.) - More flexible parsing of CSV files - All plots are fully serializable Plotting: - Two new plot types: box-and-whisker plot and raster plot - New line renderer for smooth curves - Automatic scaling for axes - Support for secondary axes - Displayed data is clipped to plotting area - Improved color mapping - Font and alignment settings for labels - Improved legends Interaction: - All plots implement support mouse navigation - Interactions can be synchronized between plots - Panning can be restricted to work only horizontally or vertically - Improved concurrency - Localized texts General: - Separate packages for library core and examples - Several fixes to build GRAL with Java 7 - reStructuredText format for documentation instead of DocBook - More example plots - Updated and improved documentation - Various bug fixes GRAL 0.8 (2010-07-31) ===================== Data: - Extensible classes for data import and export - Vertical and horizontal statistics - Plots can be exported as bitmap or vector graphics with VectorGraphics2D - Printing support Plotting: - Added area renderers - Added minor ticks and minor grid lines - Support for error bars - Segment gaps in pie plots - Data sources can be hidden Interaction: - Interactive Swing component General: - Renamed project to GRAL (GRAphing Library) - Using Maven as build system - Added more example plots - Updated and improved documentation GRAL 0.7 (2010-01-04) ===================== First public release as "OpenJChart" supporting x-y plots, bar plots, and pie plots gral-0.11/LICENSE.GPL000066400000000000000000001045131267060725100140200ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . gral-0.11/LICENSE.LGPL000066400000000000000000000167251267060725100141430ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. gral-0.11/README.rst000066400000000000000000000072161267060725100140630ustar00rootroot00000000000000GRAL #### GRAL is a free Java library for displaying plots (graphs, diagrams, and charts). The acronym GRAL simply stands for *GRAphing Library*. Features ======== - Ready-to-use classes for data management - Data processing and filtering (smoothing, rescaling, statistics, histograms) - Many different plot types: xy/scatter plot, bubble plot, line plot, area plot, bar plot, pie plot, donut plot, box-and-whisker plot, raster plot - Legends: horizontal and vertical - Various axis types: linear axes, logarithmic axes, arbitrary number of axes - Several file formats are supported as data sources or data sinks (CSV, bitmap image data, audio file data) - Exporting plots in bitmap and vector file formats (PNG, GIF, JPEG, EPS, PDF, SVG) - Small footprint (about 300 kilobytes) Usage ===== Without build management system ------------------------------- You can just add ``gral-core.jar`` to the classpath of your project. Using GRAL with Maven --------------------- If you want to use GRAL with your Maven project you will have to include it as a dependency in your ``pom.xml``: .. code:: xml de.erichseifert.gral gral-core 0.11 Using GRAL with Gradle ---------------------- .. code:: groovy dependencies { compile group: 'de.erichseifert.gral', name: 'gral-core', version: '0.11' } Using GRAL with sbt ------------------- .. code:: scala libraryDependencies += "de.erichseifert.gral" % "gral-core" % "0.11" Building GRAL from source code ============================== The source package contains all files necessary to build GRAL from scratch using the `Gradle `__ software project management and comprehension tool. Like ``Makefile`` files the ``build.gradle`` files are used by Gradle to generate various distribution or documentation files. Building a JAR file of the library core --------------------------------------- In case you just want to build the core of the library to get started execute the following command in the ``gral-core`` directory:: $ gradle assemble This will generate a JAR archive named ``gral-core`` in the ``build/libs`` directory. This JAR file can be added to the class path of your application. Building a JAR file of the examples ----------------------------------- In case you just want to build the core of the library to get started execute the following command in the ``gral-examples`` directory:: $ gradle assemble This will generate a JAR archive for the examples in the ``build/libs`` directory which can be used together with the library core to run example applications. Building the documentation -------------------------- The GRAL Gradle project offers three sources for documentation: 1. The JavaDoc files that can be generated with:: $ gradle javadoc 2. The reports found in ``build/reports`` containing a project various information like test results, test coverage, etc. To build these files just execute:: $ gradle report 3. A book-like documentation in the reStructuredText format is available in the file ``documentation_en.rst``. Using GRAL in an IDE ==================== The Gradle project can also be used in your favorite development environment like Eclipse or NetBeans. For further information look at the following descriptions on the Gradle website `http://www.gradle.org/tooling` Once you have installed an appropriate Gradle plug-in for your IDE you will be able to import the GRAL project found in this folder. Requirements ============ To build GRAL from source, you need a Gradle version higher than 1.5 and at least Java 6. gral-0.11/build.gradle000066400000000000000000000050151267060725100146460ustar00rootroot00000000000000description = 'Free Java library for displaying plots' allprojects { group = 'de.erichseifert.gral' version = getVersionString() ext.inceptionYear = 2009 } subprojects { apply plugin: 'java' sourceCompatibility = 1.6 targetCompatibility = 1.6 ext { owner1_id = 'eseifert' owner1_name = 'Erich Seifert' owner1_email = 'dev[at]erichseifert.de' owner2_id = 'mseifert' owner2_name = 'Michael Seifert' owner2_email = 'mseifert[at]error-reports.org' website = 'https://github.com/eseifert/gral/' // Determine the location of rt.jar (required for ProGuard) if (System.getProperty('os.name').startsWith('Mac')) { runtimeJar = "${System.getProperty('java.home')}/bundle/Classes/classes.jar" } else { runtimeJar = "${System.getProperty('java.home')}/lib/rt.jar" } } repositories { mavenLocal() mavenCentral() } dependencies { compile(group: 'de.erichseifert.vectorgraphics2d', name: 'VectorGraphics2D', version: '0.10') } apply plugin: 'license' license { header(rootProject.file('config/license-header.txt')) strictCheck(true) mapping { java = 'SLASHSTAR_STYLE' } def currentYear = new GregorianCalendar().get(Calendar.YEAR); ext.year = "${inceptionYear}-${currentYear}" ext.owner1 = owner1_name ext.email1 = owner1_email ext.owner2 = owner2_name ext.email2 = owner2_email // Exlude certain file types from license checking // https://github.com/hierynomus/license-gradle-plugin/issues/9 tasks.withType(nl.javadude.gradle.plugins.license.License).each { licenseTask -> licenseTask.exclude '**.properties' } } apply plugin: 'checkstyle' checkstyle.configFile = new File("${rootDir}/config/checkstyle.xml") apply plugin: 'pmd' pmd { // TODO: Dynamic dependency resolution possible? toolVersion = '5.0.5' ruleSets = ['java-basic'] ignoreFailures = true } task sourceJar(type: Jar) { description = 'Assembles a jar archive containing the source code of the main classes.' group = 'Build' from sourceSets.main.allJava classifier 'sources' } } // Include the License Gradle plugin buildscript { repositories { mavenLocal() jcenter() } dependencies { classpath 'nl.javadude.gradle.plugins:license-gradle-plugin:0.11.+' } } /* * This method must not be named getVersion, because it would * overwrite the implicit getter of the version property in the * current Project object. */ def getVersionString() { def out = new ByteArrayOutputStream() exec { commandLine('git', 'describe', '--tags') standardOutput = out } return out.toString().trim() } gral-0.11/config/000077500000000000000000000000001267060725100136335ustar00rootroot00000000000000gral-0.11/config/checkstyle.xml000066400000000000000000000052711267060725100165200ustar00rootroot00000000000000 gral-0.11/config/license-header.txt000066400000000000000000000013451267060725100172470ustar00rootroot00000000000000GRAL: GRAphing Library for Java(R) (C) Copyright ${year} ${owner1} <${email1}>, ${owner2} <${email2}> This file is part of GRAL. GRAL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GRAL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with GRAL. If not, see . gral-0.11/gral-core/000077500000000000000000000000001267060725100142415ustar00rootroot00000000000000gral-0.11/gral-core/build.gradle000066400000000000000000000053601267060725100165240ustar00rootroot00000000000000description = 'GRAL core' dependencies { testCompile(group: 'junit', name: 'junit', version: '4.12') } buildscript { repositories { mavenCentral() } dependencies { classpath 'net.saliman:gradle-cobertura-plugin:2.2.5' } } apply plugin: 'net.saliman.cobertura' task report { dependsOn = ['cobertura', check] description = 'Generates reports.' group = 'Report' tasks.withType(Pmd).each {pmdTask -> pmdTask.ignoreFailures = true } tasks.withType(Checkstyle).each {checkstyleTask -> checkstyleTask.ignoreFailures = true checkstyleTask.showViolations = false } } task shrinkJar(type: proguard.gradle.ProGuardTask, dependsOn: jar) { description = 'Uses ProGuard to reduce the code size of this project.' group = 'Build' // Configure ProGuard configuration("${projectDir}/src/etc/proguard.conf") target(targetCompatibility.toString()) injars(jar.archivePath) outjars("${libsDir}/shrunk/${jar.archiveName}") libraryjars(runtimeJar) libraryjars(configurations.runtime) } task javadocJar(type: Jar) { description = 'Assembles a jar archive containing the API doc.' group = 'Build' from javadoc classifier 'javadoc' } apply plugin: 'maven' apply plugin: 'signing' artifacts { archives shrinkJar.getOutJarFileCollection().getSingleFile(), sourceJar, javadocJar } signing { sign configurations.archives } uploadArchives { repositories { mavenDeployer { beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2/') { authentication(userName: ossrhUsername, password: ossrhPassword) } snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots/') { authentication(userName: ossrhUsername, password: ossrhPassword) } pom.project { name rootProject.name packaging 'jar' description rootProject.description url website inceptionYear inceptionYear licenses { license { name 'GNU Library or Lesser General Public License (LGPL)' url 'http://www.gnu.org/licenses/lgpl.txt' } } developers { developer { id owner1_id name owner1_name email owner1_email } developer { id owner2_id name owner2_name email owner2_email } } scm { connection 'scm:git:git://github.com/eseifert/gral.git' developerConnection 'scm:git:git@github.com:eseifert/gral.git' url website } issueManagement { system 'GitHub Issues' url website } } } } } signArchives.dependsOn(shrinkJar) // Include the proguard-gradle plugin buildscript { repositories { mavenLocal() mavenCentral() } dependencies { classpath(group: 'net.sf.proguard', name: 'proguard-gradle', version: '5.2.+') } } gral-0.11/gral-core/src/000077500000000000000000000000001267060725100150305ustar00rootroot00000000000000gral-0.11/gral-core/src/etc/000077500000000000000000000000001267060725100156035ustar00rootroot00000000000000gral-0.11/gral-core/src/etc/proguard.conf000066400000000000000000000017751267060725100203070ustar00rootroot00000000000000-renamesourcefileattribute SourceFile -keepattributes Exceptions,InnerClasses,Signature,Deprecated, SourceFile,LineNumberTable,*Annotation*,EnclosingMethod -keep public class * { public protected *; } -keepclassmembernames class * { java.lang.Class class$(java.lang.String); java.lang.Class class$(java.lang.String, boolean); } -keepclasseswithmembernames class * { native ; } -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } -keepclassmembers class * extends de.erichseifert.gral.io.IOCapabilitiesStorage { java.util.Set getCapabilities(); } gral-0.11/gral-core/src/main/000077500000000000000000000000001267060725100157545ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/000077500000000000000000000000001267060725100166755ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/000077500000000000000000000000001267060725100172655ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/000077500000000000000000000000001267060725100217415ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/000077500000000000000000000000001267060725100226665ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/000077500000000000000000000000001267060725100235775ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/AbstractDataSource.java000066400000000000000000000205261267060725100301650ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import de.erichseifert.gral.data.statistics.Statistics; /** * Abstract implementation of the {@code DataSource} interface. * This class provides access to statistical information, * administration and notification of listeners and supports * iteration of data values. */ public abstract class AbstractDataSource implements DataSource, Serializable { /** Version id for serialization. */ private static final long serialVersionUID = 9139975565475816812L; /** Name of the data source. */ private String name; /** Number of columns. */ private int columnCount; /** Data types that are allowed in the respective columns. */ private Class>[] types; /** Set of objects that will be notified of changes to the data values. */ private transient Set dataListeners; /** Statistical description of the data values. */ private transient Statistics statistics; /** * Iterator that returns each row of the DataSource. */ private class DataSourceIterator implements Iterator> { /** Index of current column. */ private int col; /** Index of current row. */ private int row; /** * Initializes a new iterator instance that starts at (0, 0). */ public DataSourceIterator() { col = 0; row = 0; } /** * Returns {@code true} if the iteration has more elements. * (In other words, returns {@code true} if {@code next} * would return an element rather than throwing an exception.) * @return {@code true} if the iterator has more elements. */ public boolean hasNext() { return (col < getColumnCount()) && (row < getRowCount()); } /** * Returns the next element in the iteration. * @return the next element in the iteration. * @exception NoSuchElementException iteration has no more elements. */ public Comparable next() { if (!hasNext()) { throw new NoSuchElementException(); } Comparable value = get(col, row); if (++col >= getColumnCount()) { col = 0; ++row; } return value; } /** * Method that theoretically removes a cell from a data source. * However, this is not supported. */ public void remove() { throw new UnsupportedOperationException(); } } /** * Initializes a new instance with the specified name, number of columns, and * column types. * @param name name of the DataSource * @param types type for each column */ public AbstractDataSource(String name, Class>... types) { this.name = name; setColumnTypes(types); dataListeners = new LinkedHashSet(); } /** * Initializes a new instance with the specified number of columns and * column types. * @param types type for each column */ public AbstractDataSource(Class>... types) { this(null, types); } /** * Retrieves a object instance that contains various statistical * information on the current data source. * @return statistical information */ public Statistics getStatistics() { if (statistics == null) { statistics = new Statistics(this); } return statistics; } /** * Adds the specified {@code DataListener} to this data source. * @param dataListener listener to be added. */ public void addDataListener(DataListener dataListener) { dataListeners.add(dataListener); } /** * Removes the specified {@code DataListener} from this data source. * @param dataListener listener to be removed. */ public void removeDataListener(DataListener dataListener) { dataListeners.remove(dataListener); } /** * Returns an iterator over a set of elements of type T. * * @return an Iterator. */ public Iterator> iterator() { return new DataSourceIterator(); } /** * Notifies all registered listeners that data values have been added. * @param events Event objects describing all values that have been added. */ protected void notifyDataAdded(DataChangeEvent... events) { List listeners = new LinkedList(dataListeners); for (DataListener dataListener : listeners) { dataListener.dataAdded(this, events); } } /** * Notifies all registered listeners that data values have been removed. * @param events Event objects describing all values that have been removed. */ protected void notifyDataRemoved(DataChangeEvent... events) { List listeners = new LinkedList(dataListeners); for (DataListener dataListener : listeners) { dataListener.dataRemoved(this, events); } } /** * Notifies all registered listeners that data values have changed. * @param events Event objects describing all values that have changed. */ protected void notifyDataUpdated(DataChangeEvent... events) { List listeners = new LinkedList(dataListeners); for (DataListener dataListener : listeners) { dataListener.dataUpdated(this, events); } } /** * Returns the column with the specified index. * @param col index of the column to return * @return the specified column of the data source */ public Column getColumn(int col) { return new Column(this, col); } @Override public String getName() { return name; } // Allows DataTable to reuse the name property protected void setName(String name) { this.name = name; } /** * Returns the number of columns of the data source. * @return number of columns in the data source. */ public int getColumnCount() { return columnCount; } /** * Returns the data types of all columns. * @return The data types of all column in the data source */ public Class>[] getColumnTypes() { Class>[] types = Arrays.copyOf(this.types, this.types.length); return types; } /** * Returns whether the column at the specified index contains numbers. * @param columnIndex Index of the column to test. * @return {@code true} if the column is numeric, otherwise {@code false}. */ public boolean isColumnNumeric(int columnIndex) { if (columnIndex < 0 || columnIndex >= types.length) { return false; } Class columnType = types[columnIndex]; return Number.class.isAssignableFrom(columnType); } /** * Sets the data types of all columns. This also changes the number of * columns. * @param types Data types. */ protected void setColumnTypes(Class>... types) { this.types = Arrays.copyOf(types, types.length); columnCount = types.length; } /** * Returns the row with the specified index. * @param row Index of the row to return * @return the Specified row of the data source */ public Row getRow(int row) { return new Row(this, row); } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Normal deserialization in.defaultReadObject(); // Handle transient fields dataListeners = new HashSet(); // Statistics can be omitted. It's created using a lazy getter. } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/Column.java000066400000000000000000000043231267060725100257010ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import de.erichseifert.gral.graphics.Orientation; /** *

Class for accessing a specific column of a data source. The data of the * column can be accessed using the {@code get(int)} method.

* *

Example for accessing value at column 2, row 3 of a data source:

*
 * Column col = new Column(dataSource, 2);
 * Number v = col.get(3);
 * 
* * @see DataSource */ public class Column extends DataAccessor { /** Version id for serialization. */ private static final long serialVersionUID = 7380420622890027262L; /** * Initializes a new instance with the specified data source and column * index. * @param source Data source. * @param col Column index. */ public Column(DataSource source, int col) { super(source, col); } @Override public Comparable get(int row) { DataSource source = getSource(); if (source == null) { return null; } return source.get(getIndex(), row); } @Override public int size() { return getSource().getRowCount(); } @Override public double getStatistics(String key) { return getSource().getStatistics() .get(key, Orientation.VERTICAL, getIndex()); } /** * Returns whether this column only contains numbers. * @return {@code true} if this column is numeric, otherwise {@code false}. */ public boolean isNumeric() { return getSource().isColumnNumeric(getIndex()); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/DataAccessor.java000066400000000000000000000106421267060725100270010ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import java.io.Serializable; import java.text.MessageFormat; import java.util.Iterator; import java.util.Locale; /** * Abstract base for reading substructures of a data source, i.e. columns or * rows. {@code DataAccessor}s are iterable and provide utility methods * for statistics and array conversion. * @see DataSource */ public abstract class DataAccessor implements Iterable>, Serializable { /** Version id for serialization. */ private static final long serialVersionUID = -6977184455447753502L; /** Data source that provides the values that should be accessed. */ private final DataSource source; /** Index of current column or row. */ private final int index; /** * Initializes a new instance with the specified data source and an access * index. * @param source Data source. * @param index Column index. */ public DataAccessor(DataSource source, int index) { this.source = source; this.index = index; } /** * Returns the data source containing this column. * @return Data source containing this column. */ public DataSource getSource() { return source; } /** * Returns the index to access the data source. * @return Data index. */ public int getIndex() { return index; } /** * Returns the value of the data source for the specified index. * @param index Index. * @return Value of the accessed cell. */ public abstract Comparable get(int index); /** * Returns the number of elements in this column. * @return Number of elements */ public abstract int size(); @Override public boolean equals(Object obj) { if (!(obj instanceof DataAccessor)) { return false; } DataAccessor accessor = (DataAccessor) obj; int size = size(); if (accessor.size() != size) { return false; } for (int i = 0; i < size; i++) { Comparable foreignValue = accessor.get(i); Comparable thisValue = get(i); if (foreignValue == null) { if (thisValue != null) { return false; } continue; } if (!foreignValue.equals(thisValue)) { return false; } } return true; } @Override public int hashCode() { return source.hashCode() ^ index; } @Override public String toString() { return String.format(Locale.US, "%s[source=%s,index=%d]", //$NON-NLS-1$ getClass().getName(), getSource(), getIndex()); } /** * Converts the data column to an array. * @param data Optional array as data sink. * If array is {@code null} a new array will be created. * @return Array with row data; */ public Comparable[] toArray(Comparable[] data) { if (data == null) { data = new Comparable[size()]; } if (data.length != size()) { throw new IllegalArgumentException(MessageFormat.format( "Array of size {0,number,integer} does not match {1,number,integer} elements.", //$NON-NLS-1$ data.length, size())); } for (int i = 0; i < data.length; i++) { data[i] = get(i); } return data; } /** * Returns the specified statistical information for this data. * @param key Requested Statistical information. * @return Calculated value. */ public abstract double getStatistics(String key); /** * Returns an iterator over the elements of this object. * @return an iterator. */ public Iterator> iterator() { return new Iterator>() { private int i; public boolean hasNext() { return i < size(); } public Comparable next() { Comparable value = get(i++); return value; } public void remove() { throw new UnsupportedOperationException(); } }; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/DataChangeEvent.java000066400000000000000000000051341267060725100274260ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import java.util.EventObject; /** * Class that stores information on a change of a specific data value in a * data source. * @see DataListener * @see DataSource */ public class DataChangeEvent extends EventObject { /** Version id for serialization. */ private static final long serialVersionUID = -3791650088885473144L; /** Column of the value that has changed. */ private final int col; /** Row of the value that has changed. */ private final int row; /** Value before changes have been applied. */ private final Comparable valOld; /** Changed value. */ private final Comparable valNew; /** * Initializes a new event with data source, position of the data value, * and the values. * @param Data type of the cell that has changed. * @param source Data source. * @param col Columns of the value. * @param row Row of the value. * @param valOld Old value. * @param valNew New value. */ public DataChangeEvent(DataSource source, int col, int row, Comparable valOld, Comparable valNew) { super(source); this.col = col; this.row = row; this.valOld = valOld; this.valNew = valNew; } /** * Returns the column index of the value that was changed. * @return Column index of the changed value. */ public int getCol() { return col; } /** * Returns the row index of the value that was changed. * @return Row index of the changed value. */ public int getRow() { return row; } /** * Returns the old value before it has changed. * @return Value before the change. */ public Comparable getOld() { return valOld; } /** * Returns the new value after the change has been applied. * @return Value after the change. */ public Comparable getNew() { return valNew; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/DataListener.java000066400000000000000000000043011267060725100270170ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; /** * Interface that can be implemented to listen for changes in data sources. * @see DataSource */ public interface DataListener { /** * Method that is invoked when data has been added. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been added. */ void dataAdded(DataSource source, DataChangeEvent... events); /** * Method that is invoked when data has been updated. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been updated. */ void dataUpdated(DataSource source, DataChangeEvent... events); /** * Method that is invoked when data has been removed. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been removed. */ void dataRemoved(DataSource source, DataChangeEvent... events); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/DataSeries.java000066400000000000000000000123031267060725100264650ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import java.io.IOException; import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.List; /** * Class that represents a view on several columns of a {@code DataSource}. * @see DataSource */ public class DataSeries extends AbstractDataSource implements DataListener { /** Version id for serialization. */ private static final long serialVersionUID = 5568085894125740972L; /** Data source that provides the columns for this data series. */ private final DataSource data; /** Columns that should be mapped to the series. */ private final List cols; /** * Constructor without name. The first column will be column * {@code 0}, the second column {@code 1} and so on, * whereas the value of the specified columns is the column number * in the data source. * @param data Data source * @param cols Column numbers */ public DataSeries(DataSource data, int... cols) { this(null, data, cols); } /** * Constructor that initializes a named data series. The first column will * be column {@code 0}, the second column {@code 1} and so on, * whereas the value of the specified columns is the column number in the * data source. * @param name Descriptive name * @param data Data source * @param cols Column numbers */ @SuppressWarnings("unchecked") public DataSeries(String name, DataSource data, int... cols) { super(name); this.data = data; this.cols = new ArrayList(); this.data.addDataListener(this); Class>[] typesOrig = data.getColumnTypes(); Class>[] types; if (cols.length > 0) { types = new Class[cols.length]; int t = 0; for (int colIndex : cols) { this.cols.add(colIndex); types[t++] = typesOrig[colIndex]; } } else { for (int colIndex = 0; colIndex < data.getColumnCount(); colIndex++) { this.cols.add(colIndex); } types = typesOrig; } setColumnTypes(types); } /** * Returns the row with the specified index. * @param col index of the column to return * @param row index of the row to return * @return the specified value of the data cell */ public Comparable get(int col, int row) { try { int dataCol = cols.get(col); return data.get(dataCol, row); } catch (IndexOutOfBoundsException e) { return null; } } @Override public int getColumnCount() { return cols.size(); } /** * Returns the number of rows of the data source. * @return number of rows in the data source. */ public int getRowCount() { return data.getRowCount(); } /** * Method that is invoked when data has been added. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been added. */ public void dataAdded(DataSource source, DataChangeEvent... events) { notifyDataAdded(events); } /** * Method that is invoked when data has been updated. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been updated. */ public void dataUpdated(DataSource source, DataChangeEvent... events) { notifyDataUpdated(events); } /** * Method that is invoked when data has been removed. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been removed. */ public void dataRemoved(DataSource source, DataChangeEvent... events) { notifyDataRemoved(events); } @Override public String toString() { return getName(); } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Normal deserialization in.defaultReadObject(); // Restore listeners data.addDataListener(this); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/DataSource.java000066400000000000000000000057071267060725100265050ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import de.erichseifert.gral.data.statistics.Statistics; /** * Interface for an immutable access to tabular data. * * @see MutableDataSource */ public interface DataSource extends Iterable> { /** * Returns the column with the specified index. * @param col index of the column to return * @return the specified column of the data source */ Column getColumn(int col); /** * Returns the data types of all columns. * @return The data types of all column in the data source */ Class>[] getColumnTypes(); /** * Returns the row with the specified index. * @param row index of the row to return * @return the specified row of the data source */ Row getRow(int row); /** * Returns the value with the specified row and column index. * @param col index of the column to return * @param row index of the row to return * @return the specified value of the data cell */ Comparable get(int col, int row); /** * Retrieves a object instance that contains various statistical * information on the current data source. * @return statistical information */ Statistics getStatistics(); /** * Returns the number of rows of the data source. * @return number of rows in the data source. */ int getRowCount(); /** * Returns the name of this series. * @return a name string */ String getName(); /** * Returns the number of columns of the data source. * @return number of columns in the data source. */ int getColumnCount(); /** * Returns whether the column at the specified index contains numbers. * @param columnIndex Index of the column to test. * @return {@code true} if the column is numeric, otherwise {@code false}. */ boolean isColumnNumeric(int columnIndex); /** * Adds the specified {@code DataListener} to this data source. * @param dataListener listener to be added. */ void addDataListener(DataListener dataListener); /** * Removes the specified {@code DataListener} from this data source. * @param dataListener listener to be removed. */ void removeDataListener(DataListener dataListener); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/DataTable.java000066400000000000000000000221741267060725100262710ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import de.erichseifert.gral.data.comparators.DataComparator; /** * An in-memory, random access implementation of a mutable data source using * arrays to store its values. * * @see DataSource * @see MutableDataSource */ public class DataTable extends AbstractDataSource implements MutableDataSource { /** Version id for serialization. */ private static final long serialVersionUID = 535236774042654449L; /** All values stored as rows of column arrays. */ private final List[]> rows; /** * Comparator class for comparing two arrays containing row data using a * specified set of {@code DataComparator}s. */ private final class RowComparator implements Comparator[]> { /** Rules to use for sorting. */ private final DataComparator[] comparators; /** * Initializes a new instance with a specified set of * {@code DataComparator}s. * @param comparators Set of {@code DataComparator}s to use as rules. */ public RowComparator(DataComparator[] comparators) { this.comparators = comparators; } /** * Compares two rows using the rules defined by the * {@code DataComparator}s of this instance. * @param row1 First row to compare. * @param row2 Second row to compare. * @return A negative number if first argument is less than the second, * zero if first argument is equal to the second, * or a positive integer as the greater than the second. */ public int compare(Comparable[] row1, Comparable[] row2) { for (DataComparator comparator : comparators) { int result = comparator.compare(row1, row2); if (result != 0) { return result; } } return 0; } } /** * Initializes a new instance with the specified number of columns and * column types. * @param types Type for each column */ public DataTable(Class>... types) { super(types); rows = new ArrayList[]>(); } /** * Initializes a new instance with the specified number of columns and * a single column type. * @param cols Number of columns * @param type Data type for all columns */ @SuppressWarnings("unchecked") public DataTable(int cols, Class> type) { this(); Class>[] types = new Class[cols]; Arrays.fill(types, type); setColumnTypes(types); } /** * Initializes a new instance with the column types, and data of another * data source. * @param source Data source to clone. */ public DataTable(DataSource source) { this(source.getColumnTypes()); for (int rowIndex = 0; rowIndex < source.getRowCount(); rowIndex++) { add(source.getRow(rowIndex)); } } /** * Adds a row with the specified comparable values to the table. * The values are added in the order they are specified. If the types of * the table columns and the values do not match, an * {@code IllegalArgumentException} is thrown. * @param values values to be added as a row * @return Index of the row that has been added. */ public int add(Comparable... values) { return add(Arrays.asList(values)); } /** * Adds a row with the specified container's elements to the table. * The values are added in the order they are specified. If the types of * the table columns and the values do not match, an * {@code IllegalArgumentException} is thrown. * @param values values to be added as a row * @return Index of the row that has been added. */ public int add(Collection> values) { DataChangeEvent[] events; if (values.size() != getColumnCount()) { throw new IllegalArgumentException(MessageFormat.format( "Wrong number of columns! Expected {0,number,integer}, got {1,number,integer}.", //$NON-NLS-1$ getColumnCount(), values.size())); } Comparable[] row = new Comparable[values.size()]; events = new DataChangeEvent[row.length]; Class>[] types = getColumnTypes(); int rowIndex = 0; synchronized (rows) { int colIndex = 0; for (Comparable value : values) { if ((value != null) && !(types[colIndex].isAssignableFrom(value.getClass()))) { throw new IllegalArgumentException(MessageFormat.format( "Wrong column type! Expected {0}, got {1}.", //$NON-NLS-1$ types[colIndex], value.getClass())); } row[colIndex] = value; events[colIndex] = new DataChangeEvent(this, colIndex, rows.size(), null, value); colIndex++; } rows.add(row); rowIndex = rows.size(); } notifyDataAdded(events); return rowIndex - 1; } /** * Adds the specified row to the table. * The values are added in the order they are specified. If the types of * the table columns and the values do not match, an * {@code IllegalArgumentException} is thrown. * @param row Row to be added * @return Index of the row that has been added. */ public int add(Row row) { List> values; synchronized (row) { values = new ArrayList>(row.size()); for (Comparable value : row) { values.add(value); } } return add(values); } /** * Removes a specified row from the table. * @param row Index of the row to remove */ public void remove(int row) { DataChangeEvent[] events; synchronized (rows) { Row r = new Row(this, row); events = new DataChangeEvent[getColumnCount()]; for (int col = 0; col < events.length; col++) { events[col] = new DataChangeEvent(this, col, row, r.get(col), null); } rows.remove(row); } notifyDataRemoved(events); } /** * Removes the last row from the table. */ public void removeLast() { DataChangeEvent[] events; synchronized (this) { int row = getRowCount() - 1; Row r = new Row(this, row); events = new DataChangeEvent[getColumnCount()]; for (int col = 0; col < events.length; col++) { events[col] = new DataChangeEvent(this, col, row, r.get(col), null); } rows.remove(row); } notifyDataRemoved(events); } /** * Deletes all rows this table contains. */ public void clear() { DataChangeEvent[] events; synchronized (this) { int cols = getColumnCount(); int rows = getRowCount(); events = new DataChangeEvent[cols*rows]; for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { events[col + row*cols] = new DataChangeEvent( this, col, row, get(col, row), null); } } this.rows.clear(); } notifyDataRemoved(events); } /** * Returns the row with the specified index. * @param col index of the column to return * @param row index of the row to return * @return the specified value of the data cell */ public Comparable get(int col, int row) { Comparable[] r; synchronized (rows) { if (row >= rows.size()) { return null; } r = rows.get(row); } if (r == null) { return null; } return r[col]; } /** * Sets the value of a cell specified by its column and row indexes. * @param Data type of the cell. * @param col Column of the cell to change. * @param row Row of the cell to change. * @param value New value to be set. * @return Old value that was replaced. */ @SuppressWarnings("unchecked") public Comparable set(int col, int row, Comparable value) { Comparable old; DataChangeEvent event = null; synchronized (this) { old = (Comparable) get(col, row); if (old == null || !old.equals(value)) { rows.get(row)[col] = value; event = new DataChangeEvent(this, col, row, old, value); } } if (event != null) { notifyDataUpdated(event); } return old; } /** * Returns the number of rows of the data source. * @return number of rows in the data source. */ public int getRowCount() { return rows.size(); } /** * Sorts the table rows with the specified DataComparators. * The row values are compared in the way the comparators are specified. * @param comparators comparators used for sorting */ public void sort(final DataComparator... comparators) { synchronized (rows) { RowComparator comparator = new RowComparator(comparators); Collections.sort(rows, comparator); } } @Override public void setName(String name) { super.setName(name); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/DummyData.java000066400000000000000000000046541267060725100263400ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import java.util.Arrays; /** * Class that represents a data source containing the same value in each cell. * It can be used for test purposes or for efficiently creating constant data. */ public class DummyData extends AbstractDataSource { /** Version id for serialization. */ private static final long serialVersionUID = 5780257823757438260L; /** Value that will be returned for all positions in this data source. */ private final Comparable value; /** Number of columns. */ private final int cols; /** Number of rows. */ private final int rows; /** * Creates a new instance with the specified number of columns * and rows, which are filled all over with the same specified value. * @param cols Number of columns. * @param rows Number of rows. * @param value Value of the cells. */ @SuppressWarnings("unchecked") public DummyData(int cols, int rows, Comparable value) { value.getClass(); this.cols = cols; this.rows = rows; this.value = value; Class>[] types = new Class[cols]; Arrays.fill(types, value.getClass()); setColumnTypes(types); } /** * Returns the row with the specified index. * @param col index of the column to return * @param row index of the row to return * @return the specified value of the data cell */ public Comparable get(int col, int row) { return value; } @Override public int getColumnCount() { return cols; } /** * Returns the number of rows of the data source. * @return number of rows in the data source. */ public int getRowCount() { return rows; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/EnumeratedData.java000066400000000000000000000131621267060725100273300ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; /** *

Class that creates a new data source which adds a leading column * containing the row number.

* *

Example which creates a two column data source from a one column * histogram:

*
 * DataSource hist = new Histogram1D(data, Orientation.HORIZONTAL, 10);
 * DataSource hist2d = new EnumeratedData(hist);
 * 
* * @see DataSource */ public class EnumeratedData extends AbstractDataSource implements DataListener { /** Version id for serialization. */ private static final long serialVersionUID = -4952487410608980063L; /** Data source which will be used as base for enumeration. */ private final DataSource original; /** Value to start counting from. */ private final double offset; /** Width of enumeration steps. */ private final double steps; /** * Initializes a new data source based on an original data source which * will contain an additional column which enumerates all rows. The * enumeration will start at a specified offset and will have a specified * step size. * @param original Original data source. * @param offset Offset of enumeration * @param steps Scaling of enumeration */ @SuppressWarnings("unchecked") public EnumeratedData(DataSource original, double offset, double steps) { this.original = original; this.offset = offset; this.steps = steps; Class>[] typesOrig = original.getColumnTypes(); Class>[] types = new Class[typesOrig.length + 1]; System.arraycopy(typesOrig, 0, types, 1, typesOrig.length); types[0] = Double.class; setColumnTypes(types); original.addDataListener(this); } /** * Initializes a new data source based on an original data source which * will contain an additional column which enumerates all rows. * @param original Original data source. */ public EnumeratedData(DataSource original) { this(original, 0, 1); } /** * Returns the row with the specified index. * @param col index of the column to return * @param row index of the row to return * @return the specified value of the data cell */ public Comparable get(int col, int row) { if (col < 1) { return row*steps + offset; } return original.get(col - 1, row); } /** * Returns the number of rows of the data source. * @return number of rows in the data source. */ public int getRowCount() { return original.getRowCount(); } /** * Method that is invoked when data has been added. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been added. */ public void dataAdded(DataSource source, DataChangeEvent... events) { notifyDataAdded(takeEvents(events)); } /** * Method that is invoked when data has been updated. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been updated. */ public void dataUpdated(DataSource source, DataChangeEvent... events) { notifyDataUpdated(takeEvents(events)); } /** * Method that is invoked when data has been added. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been removed. */ public void dataRemoved(DataSource source, DataChangeEvent... events) { notifyDataRemoved(takeEvents(events)); } /** * Changes the source and the columns of the specified event objects to * make them look as if they originated from this data source. * @param events Original events. * @return Changed events. */ @SuppressWarnings({ "rawtypes", "unchecked" }) private DataChangeEvent[] takeEvents(DataChangeEvent[] events) { if (events == null || events.length == 0) { return new DataChangeEvent[] { new DataChangeEvent(this, 0, 0, null, null) }; } DataChangeEvent[] eventsTx = new DataChangeEvent[events.length + 1]; for (int i = 0; i < eventsTx.length; i++) { DataChangeEvent event; int col, row; if (i == 0) { // Insert an event for the generated column event = events[0]; col = 0; row = event.getRow(); } else { // Process the columns of the original source event = events[i - 1]; col = event.getCol() + 1; row = event.getRow(); } Comparable valOld = event.getOld(); Comparable valNew = event.getNew(); eventsTx[i] = new DataChangeEvent( this, col, row, valOld, valNew); } return eventsTx; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/JdbcData.java000066400000000000000000000211431267060725100260770ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import java.io.IOException; import java.io.ObjectOutputStream; import java.sql.Connection; import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Time; import java.sql.Timestamp; import java.sql.Types; /** * Data source for database tables accessed through a JDBC connection. */ public class JdbcData extends AbstractDataSource { /** Version id for serialization. */ private static final long serialVersionUID = 5196527358266585129L; /** The JDBC connection. */ private final Connection connection; /** The name of the table containing the data. */ private final String table; /** Flag that tells whether this object uses buffering. */ private boolean buffered; /** Buffered number of rows. Only valid when the object is buffered. */ private int bufferedRowCount; /** Buffered result of the JDBC data query. Only valid when the object is buffered. */ private ResultSet bufferedQuery; /** Last row accessed by the {@link #get(int, int)} method. Only valid when the object is buffered. */ private int bufferedQueryRow; /** * Initializes a new instance to query the data from a specified table * using a specified JDBC connection. It is assumed the table columns * are constant during the connection. * @param connection JDBC connection object. * @param table Properly quoted name of the table. * @param buffered Turns on buffering of JDBC queries. */ @SuppressWarnings("unchecked") public JdbcData(Connection connection, String table, boolean buffered) { this.connection = connection; this.table = table; setBuffered(buffered); try { setColumnTypes(getJdbcColumnTypes()); } catch (SQLException e) { e.printStackTrace(); } } /** * Initializes a new buffered instance to query the data from a specified * table using a specified JDBC connection. * @param connection JDBC connection object. * @param table Properly quoted name of the table. */ public JdbcData(Connection connection, String table) { this(connection, table, true); } /** * Returns the row with the specified index. * @param col index of the column to return * @param row index of the row to return * @return the specified value of the data cell */ public Comparable get(int col, int row) { try { ResultSet result = bufferedQuery; if (!isBuffered() || result == null) { PreparedStatement stmt = connection.prepareStatement( "SELECT * FROM " + table + "", //$NON-NLS-1$ //$NON-NLS-2$ ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); result = stmt.executeQuery(); if (isBuffered()) { bufferedQuery = result; } } if (!isBuffered() || row != bufferedQueryRow) { result.absolute(row + 1); bufferedQueryRow = row; } return jdbcToJavaValue(result, col); } catch (SQLException e) { e.printStackTrace(); return null; } } @Override public int getColumnCount() { if (getColumnTypes() != null) { return getColumnTypes().length; } return 0; } /** * Returns the number of rows of the data source. * @return number of rows in the data source. */ public int getRowCount() { int rowCount = bufferedRowCount; if (!isBuffered() || rowCount < 0) { try { PreparedStatement stmt = connection.prepareStatement( "SELECT COUNT(*) FROM " + table, //$NON-NLS-1$ ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); ResultSet result = stmt.executeQuery(); if (result.first()) { rowCount = result.getInt(1); bufferedRowCount = rowCount; } else { rowCount = 0; } result.close(); } catch (SQLException e) { e.printStackTrace(); rowCount = 0; } } return rowCount; } /** * Fetches the column types as Java {@code Class} objects from the * JDBC table. * @return Column types as Java {@code Class} objects * @throws SQLException if an error occurs during access to JDBC table. */ @SuppressWarnings("unchecked") private Class>[] getJdbcColumnTypes() throws SQLException { PreparedStatement stmt = connection.prepareStatement( "SELECT * FROM " + table + " WHERE 1 = 0"); //$NON-NLS-1$ //$NON-NLS-2$ ResultSetMetaData metadata = stmt.getMetaData(); int colCount = metadata.getColumnCount(); Class[] types = new Class[colCount]; for (int colIndex = 0; colIndex < colCount; colIndex++) { int sqlType = metadata.getColumnType(colIndex + 1); Class> type = null; switch (sqlType) { case Types.TINYINT: type = Byte.class; break; case Types.SMALLINT: type = Short.class; break; case Types.INTEGER: type = Integer.class; break; case Types.BIGINT: type = Long.class; break; case Types.REAL: type = Float.class; break; case Types.FLOAT: case Types.DOUBLE: type = Double.class; break; case Types.DATE: type = Date.class; break; case Types.TIME: type = Time.class; break; case Types.TIMESTAMP: type = Timestamp.class; break; case Types.CHAR: case Types.NCHAR: case Types.VARCHAR: case Types.LONGVARCHAR: case Types.NVARCHAR: case Types.LONGNVARCHAR: type = String.class; default: break; } types[colIndex] = type; } return (Class>[]) types; } /** * Converts a value of a JDBC {@code ResultSet} to a Java compatible * data value. If the data type is unknown {@code null} will be * returned. * @param row ResultSet object. * @param col Column. * @return Converted value. * @throws SQLException if an error occurs during conversion or accessing * the result set. */ private Comparable jdbcToJavaValue(ResultSet row, int col) throws SQLException { // TODO Add getColumn(int).getType() method to Column // AbstractDataSource.getColumnTypes() makes a defensive copy. Class> colType = getColumnTypes()[col]; int sqlCol = col + 1; if (Byte.class.equals(colType)) { return row.getByte(sqlCol); } else if (Short.class.equals(colType)) { return row.getShort(sqlCol); } else if (Integer.class.equals(colType)) { return row.getInt(sqlCol); } else if (Long.class.equals(colType)) { return row.getLong(sqlCol); } else if (Float.class.equals(colType)) { return row.getFloat(sqlCol); } else if (Double.class.equals(colType)) { return row.getDouble(sqlCol); } else if (Date.class.equals(colType)) { return row.getDate(sqlCol); } else if (Time.class.equals(colType)) { return row.getTime(sqlCol); } else if (Timestamp.class.equals(colType)) { return row.getTimestamp(sqlCol); } else if (String.class.equals(colType)) { return row.getString(sqlCol); } else { return null; } } /** * Returns whether this data source is buffered. * @return {@code true} when this object uses buffering, * {@code false} otherwise */ public boolean isBuffered() { return buffered; } /** * Determines whether this data source should buffer intermediate results. * This implies that the data doesn't change during access. * @param buffered {@code true} when this object should use buffering, * {@code false} otherwise */ public void setBuffered(boolean buffered) { this.buffered = buffered; this.bufferedRowCount = -1; this.bufferedQuery = null; this.bufferedQueryRow = -1; } /** * Custom serialization method. * @param out Output stream. * @throws ClassNotFoundException if a deserialized class does not exist. * @throws IOException if there is an error while writing data to the * output stream. */ private void writeObject(ObjectOutputStream out) throws ClassNotFoundException, IOException { throw new UnsupportedOperationException("JDBC data sources cannot be serialized."); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/MutableDataSource.java000066400000000000000000000065741267060725100300220ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import java.util.Collection; import de.erichseifert.gral.data.comparators.DataComparator; /** *

Interface for write access to tabular data. The access includes adding, * modifying, and deleting of the data.

*

All data can be sorted row-wise with the method * {@code sort(DataComparator...)}. For example, this way column 1 could be * sorted ascending and column 3 descending. * * @see DataSource */ public interface MutableDataSource extends DataSource { /** * Adds a row with the specified comparable values. The values are added in * the order they are specified. If the types of the data sink columns and * the values do not match, an {@code IllegalArgumentException} is thrown. * @param values values to be added as a row. * @return Index of the row that has been added. */ int add(Comparable... values); /** * Adds a row with the specified container's elements to the data sink. The * values are added in the order they are specified. If the types of the * data sink columns and the values do not match, an * {@code IllegalArgumentException} is thrown. * @param values values to be added as a row. * @return Index of the row that has been added. */ int add(Collection> values); /** * Adds the specified row to the data sink. The values are added in the * order they are specified. If the types of the data sink columns and the * values do not match, an {@code IllegalArgumentException} is thrown. * @param row Row to be added. * @return Index of the row that has been added. */ int add(Row row); /** * Removes a specified row from the data sink. * @param row Index of the row to remove. */ void remove(int row); /** * Removes the last row from the data sink. */ void removeLast(); /** * Deletes all rows this data sink contains. */ void clear(); /** * Sets the value of a cell specified by its column and row indexes. * @param Data type of the cell. * @param col Column of the cell to change. * @param row Row of the cell to change. * @param value New value to be set. * @return Old value that was replaced. */ Comparable set(int col, int row, Comparable value); /** * Sorts the data sink rows with the specified sorting rules. The row * values are compared in the way the comparators are specified. * @param comparators Comparators used for sorting. */ void sort(final DataComparator... comparators); /** * Sets the name of this series. * @param name name to be set */ void setName(String name); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/Row.java000066400000000000000000000042251267060725100252140ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import de.erichseifert.gral.graphics.Orientation; /** *

Class for easily accessing a row of a data source.

* *

Example:

*
 * Row row = new Row(data, 2);
 * Number value = row.get(3);
 * 
* * @see DataSource */ public class Row extends DataAccessor { /** Version id for serialization. */ private static final long serialVersionUID = 2725146484866525573L; /** * Initializes a new instances with the specified data source and * row index. * @param source Data source. * @param row Row index. */ public Row(DataSource source, int row) { super(source, row); } @Override public Comparable get(int col) { DataSource source = getSource(); if (source == null) { return null; } return source.get(col, getIndex()); } @Override public int size() { return getSource().getColumnCount(); } @Override public double getStatistics(String key) { return getSource().getStatistics() .get(key, Orientation.HORIZONTAL, getIndex()); } /** * Returns whether the column at the specified index contains numbers. * @param columnIndex Index of the column to test. * @return {@code true} if the column is numeric, otherwise {@code false}. */ public boolean isColumnNumeric(int columnIndex) { return getSource().isColumnNumeric(columnIndex); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/RowSubset.java000066400000000000000000000134031267060725100264000ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import java.io.IOException; import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.List; /** *

Abstract class that represents a view on several rows of a data source. * Implementations must implement the method {@code accept(Row)} which * decides whether a specific row should be contained in this filtered data * source.

* *

Example that keeps only every second row:

*
 * DataSource filtered = new RowSubset() {
 *     public boolean accept(Row row) {
 *         return row.getIndex()%2 == 0;
 *     }
 * };
 * 
*/ public abstract class RowSubset extends AbstractDataSource implements DataListener { /** Version id for serialization. */ private static final long serialVersionUID = -5396152732545986903L; /** Original data source. */ private final DataSource original; /** List of row indexes that are stored in this filtered data source. */ private transient List accepted; /** * Creates a new instance with the specified data source. * @param original DataSource to be filtered. */ @SuppressWarnings("unchecked") public RowSubset(DataSource original) { accepted = new ArrayList(); this.original = original; this.original.addDataListener(this); dataUpdated(this.original); } @Override public Row getRow(int row) { int rowOrig = accepted.get(row); return original.getRow(rowOrig); } /** * Returns the row with the specified index. * @param col index of the column to return * @param row index of the row to return * @return the specified value of the data cell */ public Comparable get(int col, int row) { int rowOrig = accepted.get(row); return original.get(col, rowOrig); } @Override public int getColumnCount() { return original.getColumnCount(); } /** * Returns the number of rows of the data source. * @return number of rows in the data source. */ public int getRowCount() { return accepted.size(); } @Override public Class>[] getColumnTypes() { return original.getColumnTypes(); } /** * Method that is invoked when data has been added. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been added. */ public void dataAdded(DataSource source, DataChangeEvent... events) { dataChanged(source, events); notifyDataAdded(events); } /** * Method that is invoked when data has been updated. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been added */ public void dataUpdated(DataSource source, DataChangeEvent... events) { dataChanged(source, events); notifyDataUpdated(events); } /** * Method that is invoked when data has been removed. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been removed. */ public void dataRemoved(DataSource source, DataChangeEvent... events) { dataChanged(source, events); notifyDataRemoved(events); } /** * Method that is invoked when data has been added, updated, or removed. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been changed. */ private void dataChanged(DataSource source, DataChangeEvent... events) { update(); } /** * Updates the list of accepted rows. */ private void update() { accepted.clear(); for (int rowIndex = 0; rowIndex < original.getRowCount(); rowIndex++) { Row row = original.getRow(rowIndex); if (accept(row)) { accepted.add(rowIndex); } } } /** * Tests whether the specified row is accepted by this DataSubset or not. * @param row Row to be tested. * @return True if the row should be kept. */ public abstract boolean accept(Row row); /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Normal deserialization in.defaultReadObject(); // Handle transient fields accepted = new ArrayList(); // Update caches dataUpdated(original); // Restore listeners original.addDataListener(this); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/comparators/000077500000000000000000000000001267060725100261315ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/comparators/Ascending.java000066400000000000000000000050651267060725100306750ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.comparators; /** * Class that represents a {@code DataComparator} for comparing two arrays of * column values at a defined index for ascending order. * @see de.erichseifert.gral.data.DataTable#sort(DataComparator...) */ public class Ascending extends DataComparator { /** Version id for serialization. */ private static final long serialVersionUID = -5206241300478408303L; /** * Creates a new Ascending object for sorting according to the specified * column. * @param col Column index to be compared. */ public Ascending(int col) { super(col); } /** *

Compares the values of two rows at the specified column for order and * returns a corresponding integer:

*
    *
  • a negative value means {@code row1} is smaller than {@code row2}
  • *
  • 0 means {@code row1} is equal to {@code row2}
  • *
  • a positive value means {@code row1} is larger than {@code row2}
  • *
* @param row1 First value * @param row2 Second value * @return An integer number describing the order: * a negative value if {@code row1} is smaller than {@code row2}, * 0 if {@code row1} is equal to {@code row2}, * a positive value if {@code row1} is larger than {@code row2}, */ @SuppressWarnings("unchecked") public int compare(Comparable[] row1, Comparable[] row2) { Comparable value1 = (Comparable) row1[getColumn()]; Comparable value2 = (Comparable) row2[getColumn()]; // null values sort as if larger than non-null values if (value1 == null && value2 == null) { return 0; } else if (value1 == null) { return 1; } else if (value2 == null) { return -1; } return value1.compareTo(value2); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/comparators/DataComparator.java000066400000000000000000000033001267060725100316710ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.comparators; import java.io.Serializable; import java.util.Comparator; /** * Abstract implementation of a {@code Comparator} for arrays of column values. * This class allows to specify the index at which the arrays should be * compared. * @see de.erichseifert.gral.data.DataTable#sort(DataComparator...) */ public abstract class DataComparator implements Comparator[]>, Serializable { /** Version id for serialization. */ private static final long serialVersionUID = -982173906879554838L; /** Column that should be used for comparing. */ private final int column; /** * Constructor. * @param col index of the column to be compared */ public DataComparator(int col) { this.column = col; } /** * Returns the column to be compared. * @return column index */ public int getColumn() { return column; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/comparators/Descending.java000066400000000000000000000050621267060725100310420ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.comparators; /** * Class that represents a {@code DataComparator} for comparing two arrays of * column values at a defined index for descending order. * @see de.erichseifert.gral.data.DataTable#sort(DataComparator...) */ public class Descending extends DataComparator { /** Version id for serialization. */ private static final long serialVersionUID = 6834583772451304014L; /** * Creates a new Descending object sorting according to the specified * column. * @param col Column index to be compared */ public Descending(int col) { super(col); } /** *

Compares the values of two rows at the specified column for order and * returns a corresponding integer:

*
    *
  • a negative value means {@code row1} is larger than {@code row2}
  • *
  • 0 means {@code row1} is equal to {@code row2}
  • *
  • a positive value means {@code row1} is smaller than {@code row2}
  • *
* @param row1 First value * @param row2 Second value * @return An integer number describing the order: * a negative value if {@code row1} is larger than {@code row2}, * 0 if {@code row1} is equal to {@code row2}, * a positive value if {@code row1} is smaller than {@code row2}, */ @SuppressWarnings("unchecked") public int compare(Comparable[] row1, Comparable[] row2) { Comparable value1 = (Comparable) row1[getColumn()]; Comparable value2 = (Comparable) row2[getColumn()]; // null values sort as if larger than non-null values if (value1 == null && value2 == null) { return 0; } else if (value1 == null) { return -1; } else if (value2 == null) { return 1; } return value2.compareTo(value1); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/comparators/package-info.java000077500000000000000000000017061267060725100313270ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Comparators for sorting data sources. */ package de.erichseifert.gral.data.comparators; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/filters/000077500000000000000000000000001267060725100252475ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/filters/Convolution.java000066400000000000000000000072371267060725100304420ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.filters; import java.io.IOException; import java.io.ObjectInputStream; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.util.DataUtils; import de.erichseifert.gral.util.MathUtils; /** *

Class that applies a specified kernel to a data source to convolve it.

*

Functionality includes:

*
    *
  • Getting and setting the {@code Kernel} used for convolution
  • *
*/ public class Convolution extends Filter { /** Version id for serialization. */ private static final long serialVersionUID = 7155205321415314271L; /** Kernel that provides the values to convolve the data source. */ private final Kernel kernel; /** * Initialized a new instance with the specified data source, convolution * kernel, edge handling mode, and columns to be filtered. * @param original DataSource to be filtered. * @param kernel Kernel to be used. * @param mode Mode of filtering. * @param cols Column indexes. */ public Convolution(DataSource original, Kernel kernel, Mode mode, int... cols) { super(original, mode, cols); this.kernel = kernel; filter(); } /** * Returns the kernel. * @return Kernel used for convolution. */ public Kernel getKernel() { return kernel; } @Override protected void filter() { clear(); for (int rowIndex = 0; rowIndex < getRowCount(); rowIndex++) { Double[] filteredRow = new Double[getColumnCountFiltered()]; for (int colIndex = 0; colIndex < filteredRow.length; colIndex++) { int colIndexOriginal = getIndexOriginal(colIndex); filteredRow[colIndex] = convolve(colIndexOriginal, rowIndex); } add(filteredRow); } } /** * Calculates the convolved value of the data with the specified column * and row. * @param col Column index. * @param row Row index. * @return Convolved value using the set kernel. */ private double convolve(int col, int row) { Kernel kernel = getKernel(); if (kernel == null) { Comparable original = getOriginal(col, row); return DataUtils.getValueOrDefault((Number) original, Double.NaN); } double sum = 0.0; for (int k = kernel.getMinIndex(); k <= kernel.getMaxIndex(); k++) { int r = row + k; Comparable original = getOriginal(col, r); double v = DataUtils.getValueOrDefault((Number) original, Double.NaN); if (!MathUtils.isCalculatable(v)) { return v; } sum += kernel.get(k) * v; } return sum; } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Normal deserialization in.defaultReadObject(); // Update caches dataUpdated(this); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/filters/Filter.java000066400000000000000000000253231267060725100273440ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.filters; import java.io.IOException; import java.io.ObjectInputStream; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import de.erichseifert.gral.data.AbstractDataSource; import de.erichseifert.gral.data.DataChangeEvent; import de.erichseifert.gral.data.DataListener; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.util.MathUtils; /** *

Abstract class that provides basic functions for filtering arbitrary * columns of a DataSource, in other words a set of one-dimensional data.

* *

Functionality includes:

*
    *
  • Different modes for filtering (see {@link Mode})
  • *
  • Support for listening for changes of the original data
  • *
  • Filtering of multiple columns
  • *
* *

Values of filtered columns are buffered. Access to unfiltered columns is * delegated to the original data source. Derived classes must make sure the * caches are updated when deserialization is done. This can be done by calling * {@code dataUpdated(this)} in a custom deserialization method.

*/ public abstract class Filter extends AbstractDataSource implements DataListener { /** Version id for serialization. */ private static final long serialVersionUID = -5004453681128601437L; /** Type to define the behavior when engaging the borders of a column, i.e. the filter would need more data values than available. */ public static enum Mode { /** Ignore missing values. */ OMIT, /** Treat missing values as zero. */ ZERO, /** Repeat the last value. */ REPEAT, /** Mirror values at the last value. */ MIRROR, /** Repeat the data. */ CIRCULAR } /** Original data source. */ private final DataSource original; /** Columns that should be filtered. */ private final int[] cols; /** Data that was produced by the filter. */ private transient ArrayList rows; /** Mode for handling. */ private Mode mode; /** * Initializes a new instance with the specified data source, border * handling and columns to be filtered. The columns must be numeric, * otherwise an {@code IllegalArgumentException} is thrown. * @param original Data source to be filtered. * @param mode Border handling mode to be used. * @param cols Indexes of numeric columns to be filtered. */ @SuppressWarnings("unchecked") public Filter(DataSource original, Mode mode, int... cols) { this.rows = new ArrayList(original.getRowCount()); this.original = original; this.mode = mode; this.cols = Arrays.copyOf(cols, cols.length); // A sorted array is necessary for binary search Arrays.sort(this.cols); // Check if columns are numeric Class>[] originalColumnTypes = original.getColumnTypes(); for (int colIndex : this.cols) { if (!original.isColumnNumeric(colIndex)) { throw new IllegalArgumentException(MessageFormat.format( "Column {0,number,integer} isn't numeric and cannot be filtered.", //$NON-NLS-1$ colIndex)); } } Class>[] types = originalColumnTypes; for (int colIndex : this.cols) { types[colIndex] = Double.class; } setColumnTypes(types); this.original.addDataListener(this); dataUpdated(this.original); } /** * Returns the original data source that is filtered. * @return Original data source. */ protected DataSource getOriginal() { return original; } /** * Returns the value of the original data source at the specified column * and row. * @param col Column index. * @param row Row index. * @return Original value. */ protected Comparable getOriginal(int col, int row) { int rowLast = original.getRowCount() - 1; if (row < 0 || row > rowLast) { if (getMode() == Mode.OMIT) { return Double.NaN; } else if (getMode() == Mode.ZERO) { return 0.0; } else if (getMode() == Mode.REPEAT) { row = MathUtils.limit(row, 0, rowLast); } else if (getMode() == Mode.MIRROR) { int rem = Math.abs(row) / rowLast; int mod = Math.abs(row) % rowLast; if ((rem & 1) == 0) { row = mod; } else { row = rowLast - mod; } } else if (getMode() == Mode.CIRCULAR) { if (row >= 0) { row = row % (rowLast + 1); } else { row = (row + 1) % (rowLast + 1) + rowLast; } } } return original.get(col, row); } /** * Clears this Filter. */ protected void clear() { rows.clear(); } /** * Adds the specified row data to this Filter. * @param rowData Row data to be added. */ protected void add(Double[] rowData) { rows.add(rowData); } /** * Adds the specified row data to this Filter. * @param rowData Row to be added. */ protected void add(Number[] rowData) { Double[] doubleData = new Double[rowData.length]; int i = 0; for (Number value : rowData) { doubleData[i++] = value.doubleValue(); } rows.add(doubleData); } /** * Returns the row with the specified index. * @param col index of the column to return * @param row index of the row to return * @return the specified value of the data cell */ public Comparable get(int col, int row) { int colPos = getIndex(col); if (colPos < 0) { return original.get(col, row); } return rows.get(row)[colPos]; } /** * Sets a new value for a specified cell. * @param col Column of the cell. * @param row Row of the cell. * @param value New cell value. * @return The previous value before it has been changed. */ protected Number set(int col, int row, Double value) { int colPos = getIndex(col); if (colPos < 0) { throw new IllegalArgumentException( "Can't set value in unfiltered column."); //$NON-NLS-1$ } Double old = rows.get(row)[colPos]; rows.get(row)[colPos] = value; notifyDataUpdated(new DataChangeEvent(this, col, row, old, value)); return old; } @Override public int getColumnCount() { return original.getColumnCount(); } /** * Returns the number of filtered columns. * @return Number of filtered columns. */ protected int getColumnCountFiltered() { if (cols.length == 0) { return original.getColumnCount(); } return cols.length; } /** * Returns the number of rows of the data source. * @return number of rows in the data source. */ public int getRowCount() { return original.getRowCount(); } /** * Returns the number of filtered rows. * @return Number of filtered rows. */ protected int getRowCountFiltered() { return original.getRowCount(); } /** * Method that is invoked when data has been added. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been added. */ public void dataAdded(DataSource source, DataChangeEvent... events) { dataChanged(source, events); notifyDataAdded(events); } /** * Method that is invoked when data has been updated. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed * @param events Optional event object describing the data values that * have been updated. */ public void dataUpdated(DataSource source, DataChangeEvent... events) { dataChanged(source, events); notifyDataUpdated(events); } /** * Method that is invoked when data has been removed. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed * @param events Optional event object describing the data values that * have been removed. */ public void dataRemoved(DataSource source, DataChangeEvent... events) { dataChanged(source, events); notifyDataRemoved(events); } /** * Method that is invoked when data has been added, updated, or removed. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed * @param events Optional event object describing the data values that * have been removed. */ private void dataChanged(DataSource source, DataChangeEvent... events) { filter(); } /** * Returns the index of the original column using the index of the * filtered column. * @param col Index of the filtered column * @return Index of the original column */ protected int getIndexOriginal(int col) { if (cols.length == 0) { return col; } return cols[col]; } /** * Returns the index of the filtered column using the index of the * original column. * @param col Index of the original column * @return Index of the filtered column */ protected int getIndex(int col) { if (cols.length == 0) { return col; } return Arrays.binarySearch(cols, col); } /** * Returns whether the specified column is filtered. * @param col Column index. * @return True, if the column is filtered. */ protected boolean isFiltered(int col) { return getIndex(col) >= 0; } /** * Invokes the filtering routine. */ protected abstract void filter(); /** * Returns the Mode of this Filter. * @return Mode of filtering. */ public Mode getMode() { return mode; } /** * Sets the Mode the specified value. * @param mode Mode of filtering. */ public void setMode(Mode mode) { this.mode = mode; dataUpdated(this); } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Normal deserialization in.defaultReadObject(); // Handle transient fields rows = new ArrayList(); // Update caches original.addDataListener(this); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/filters/Kernel.java000066400000000000000000000140511267060725100273330ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.filters; import java.io.Serializable; import java.util.Arrays; /** *

Class that represents an one dimensional array of coefficients for a * weighted filtering.

*

Functionality includes:

*
    *
  • Adding of other kernels or scalars
  • *
  • Multiplication with other kernels or scalars
  • *
  • Normalization
  • *
  • Negation
  • *
*/ public class Kernel implements Serializable { /** Version id for serialization. */ private static final long serialVersionUID = 7721293471122850684L; /** Kernel values. */ private final double[] values; /** Index of the kernel's center value. */ private final int offset; /** * Creates a new Kernel object with the specified offset and values. * @param offset Offset to the first item in the kernel. * @param values Array of values in the kernel. */ public Kernel(int offset, double[] values) { this.values = Arrays.copyOf(values, values.length); this.offset = offset; } /** * Creates a new kernel object with the specified values and an offset * being half the size of this kernel (rounded down). * @param values Data values for the kernel. */ public Kernel(double... values) { this(values.length/2, values); } /** * Returns a Kernel of specified variance with binomial coefficients. * @param variance Variance. * @return Kernel. */ public static Kernel getBinomial(double variance) { int size = (int) (variance * 4.0) + 1; return getBinomial(size); } /** * Returns a Kernel of specified size with binomial coefficients. * @param size Size of the Kernel. * @return Kernel. */ public static Kernel getBinomial(int size) { double[] values = new double[size]; values[0] = 1.0; for (int i = 0; i < size - 1; i++) { values[0] /= 2.0; } for (int i = 0; i < size; i++) { for (int j = i; j > 0; j--) { values[j] += values[j - 1]; } } return new Kernel(values); } /** * Returns a Kernel with the specified size and offset, filled with a * single value. * @param size Size. * @param offset Offset. * @param value Value the Kernel is filled with. * @return Kernel. */ public static Kernel getUniform(int size, int offset, double value) { double[] values = new double[size]; Arrays.fill(values, value); return new Kernel(offset, values); } /** * Returns the value at the specified position of this kernel. * If the position exceeds the minimum or maximum index, 0.0 is * returned. * @param i Index to be returned. * @return Value at the specified index. */ public double get(int i) { if (i < getMinIndex() || i > getMaxIndex()) { return 0.0; } return values[i - getMinIndex()]; } /** * Sets the specified index of this kernel to the specified value. * @param i Index to be changed. * @param v Value to be set. */ protected void set(int i, double v) { if (i < getMinIndex() || i > getMaxIndex()) { return; } values[i - getMinIndex()] = v; } /** * Returns the offset of this kernel. * @return Offset. */ public int getOffset() { return offset; } /** * Returns the number of values in this kernel. * @return Number of values. */ public int size() { return values.length; } /** * Returns the index of the "leftmost" value. * @return Minimal index. */ public int getMinIndex() { return -getOffset(); } /** * Returns the index of the "rightmost" value. * @return Maximal index. */ public int getMaxIndex() { return size() - getOffset() - 1; } /** * Returns a new Kernel, where the specified value was added to each of * the items. * @param v Value to be added. * @return Kernel with new values. */ public Kernel add(double v) { for (int i = 0; i < values.length; i++) { values[i] += v; } return this; } /** * Returns a new Kernel, where the specified kernel was added. * @param k Kernel to be added. * @return Kernel with new values. */ public Kernel add(Kernel k) { int min = getMinIndex(); int max = getMaxIndex(); if (size() > k.size()) { min = k.getMinIndex(); max = k.getMaxIndex(); } for (int i = min; i <= max; i++) { set(i, get(i) + k.get(i)); } return this; } /** * Returns a new Kernel, where the specified value was multiplied with * each of the items. * @param v Value to be multiplied. * @return Kernel with new values. */ public Kernel mul(double v) { for (int i = 0; i < values.length; i++) { values[i] *= v; } return this; } /** * Returns a new Kernel, where the specified kernel was multiplied. * @param k Kernel to be multiplied. * @return Kernel with new values. */ public Kernel mul(Kernel k) { int min = getMinIndex(); int max = getMaxIndex(); if (size() > k.size()) { min = k.getMinIndex(); max = k.getMaxIndex(); } for (int i = min; i <= max; i++) { set(i, get(i) * k.get(i)); } return this; } /** * Returns a normalized Kernel so that the sum of all values equals 1. * @return Normalized Kernel. */ public Kernel normalize() { double sum = 0.0; for (double value : values) { sum += value; } return mul(1.0/sum); } /** * Returns a Kernel with all values being negated. * @return Negated Kernel. */ public Kernel negate() { mul(-1.0); return this; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/filters/Median.java000066400000000000000000000126651267060725100273210ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.filters; import java.io.IOException; import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.List; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.util.MathUtils; /** *

Class that calculates the median of a data sequence.

*
    *
  • Setting and getting offset
  • *
  • Setting and getting window size
  • *
*/ public class Median extends Filter { /** Version id for serialization. */ private static final long serialVersionUID = -1645928908580026536L; /** Number of values in the window that will be used to calculate the median. */ private int windowSize; /** Start of the window. */ private int offset; /** * Creates a new Median object with the specified DataSource, window * size, offset, Mode, and columns. * @param original DataSource to be filtered. * @param windowSize Number of rows to be used for the calculation of the * median. * @param offset Offset from the current filtered value to the last value * of the window. * @param mode Mode of filtering. * @param cols Column indexes. */ public Median(DataSource original, int windowSize, int offset, Mode mode, int... cols) { super(original, mode, cols); this.windowSize = windowSize; this.offset = offset; filter(); } @Override protected void filter() { clear(); if (getWindowSize() <= 0) { return; } List> colWindows = new ArrayList>(getColumnCount()); for (int colIndex = 0; colIndex < getColumnCountFiltered(); colIndex++) { int colIndexOriginal = getIndexOriginal(colIndex); List window = new ArrayList(getWindowSize()); colWindows.add(window); // Pre-fill window for (int rowIndex = getOffset() - getWindowSize(); rowIndex < 0; rowIndex++) { Comparable vOrig = getOriginal(colIndexOriginal, rowIndex); double v = ((Number) vOrig).doubleValue(); window.add(v); } } for (int rowIndex = 0; rowIndex < getRowCount(); rowIndex++) { Double[] filteredRow = new Double[getColumnCountFiltered()]; for (int colIndex = 0; colIndex < filteredRow.length; colIndex++) { List window = colWindows.get(colIndex); if (window.size() >= getWindowSize()) { window.remove(0); } int colIndexOriginal = getIndexOriginal(colIndex); Comparable vOrig = getOriginal(colIndexOriginal, rowIndex - getOffset() + getWindowSize()); double v = ((Number) vOrig).doubleValue(); window.add(v); filteredRow[colIndex] = median(window); } add(filteredRow); } } /** * Calculates the median for the specified values in the window. * @param w List of values the median will be calculated for. * @return Median. */ private double median(List w) { if (w.size() == 1) { return w.get(0); } List window = new ArrayList(w.size()); for (Double v : w) { if (!MathUtils.isCalculatable(v)) { return Double.NaN; } window.add(v); } int medianIndex = MathUtils.randomizedSelect( window, 0, window.size() - 1, window.size()/2); double median = window.get(medianIndex); if ((window.size() & 1) == 0) { int medianUpperIndex = MathUtils.randomizedSelect( window, 0, window.size() - 1, window.size()/2 + 1); double medianUpper = window.get(medianUpperIndex); median = (median + medianUpper)/2.0; } return median; } /** * Returns the size of the window which is used to calculate the median. * @return Number of rows used. */ public int getWindowSize() { return windowSize; } /** * Set the size of the window which is used to calculate the median. * @param windowSize Number of rows used. */ public void setWindowSize(int windowSize) { this.windowSize = windowSize; dataUpdated(this); } /** * Returns the offset from the current value used to calculate the * median to the last value of the window. * @return Offset. */ public int getOffset() { return offset; } /** * Sets the offset from the current value used to calculate the * median to the last value of the window. * @param offset Offset. */ public void setOffset(int offset) { this.offset = offset; dataUpdated(this); } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Normal deserialization in.defaultReadObject(); // Update caches dataUpdated(this); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/filters/Resize.java000066400000000000000000000140721267060725100273570ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.filters; import java.io.IOException; import java.io.ObjectInputStream; import java.util.Arrays; import de.erichseifert.gral.data.Column; import de.erichseifert.gral.data.DataAccessor; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.data.Row; /** * Filter to change the size of equally spaced data sources. All columns of the * data sources must be numeric, otherwise an {@code IllegalArgumentException} * will be thrown. The values of the scaled result are created by averaging. */ public class Resize extends Filter { /** Version id for serialization. */ private static final long serialVersionUID = -5601162872352170735L; /** Number of columns. */ private final int cols; /** Number of rows. */ private final int rows; /** * Initializes a new data source from an original data source and a * specified number of rows and columns. * @param data Original data source. * @param cols Number of columns for new data source. * @param rows Number of rows for new data source. */ public Resize(DataSource data, int cols, int rows) { super(data, Mode.ZERO); this.cols = cols; this.rows = rows; filter(); } @Override public int getColumnCount() { if (cols <= 0) { return super.getColumnCount(); } return cols; } @Override public int getRowCount() { if (rows <= 0) { return super.getRowCount(); } return rows; } @Override public Comparable get(int col, int row) { if ((cols <= 0 || cols == getOriginal().getColumnCount()) && (rows <= 0 || rows == getOriginal().getRowCount())) { return getOriginal(col, row); } return super.get(col, row); } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override protected void filter() { clear(); DataSource original = getOriginal(); if ((getRowCount() == original.getRowCount()) && (getColumnCount() == original.getColumnCount())) { return; } DataSource data = original; if (getRowCount() != original.getRowCount()) { Class[] dataTypes = new Class[original.getColumnCount()]; Arrays.fill(dataTypes, Double.class); DataTable avgRows = new DataTable(dataTypes); fillWithEmptyRows(avgRows, getRowCount()); double step = original.getRowCount() / (double) getRowCount(); for (int colIndex = 0; colIndex < original.getColumnCount(); colIndex++) { Column colData = original.getColumn(colIndex); for (int rowIndex = 0; rowIndex < getRowCount(); rowIndex++) { double start = rowIndex*step; double end = (rowIndex + 1)*step; avgRows.set(colIndex, rowIndex, average(colData, start, end)); } } data = avgRows; } if (getColumnCount() != original.getColumnCount()) { Class[] dataTypes = new Class[getColumnCount()]; Arrays.fill(dataTypes, Double.class); DataTable avgCols = new DataTable(dataTypes); fillWithEmptyRows(avgCols, data.getRowCount()); double step = original.getColumnCount() / (double) getColumnCount(); for (int rowIndex = 0; rowIndex < data.getRowCount(); rowIndex++) { Row rowData = data.getRow(rowIndex); for (int colIndex = 0; colIndex < getColumnCount(); colIndex++) { double start = colIndex*step; double end = (colIndex + 1)*step; avgCols.set(colIndex, rowIndex, average(rowData, start, end)); } } data = avgCols; } for (int rowIndex = 0; rowIndex < data.getRowCount(); rowIndex++) { Row row = data.getRow(rowIndex); Comparable[] rowData = row.toArray(null); Double[] rowValues = new Double[rowData.length]; System.arraycopy(rowData, 0, rowValues, 0, rowValues.length); add(rowValues); } } /** * Utility method that fills a data table with empty rows. * @param data Data table that should be filled. * @param count Number of rows that were added. */ private static void fillWithEmptyRows(DataTable data, int count) { while (data.getRowCount() < count) { Double[] emptyRow = new Double[data.getColumnCount()]; Arrays.fill(emptyRow, 0.0); data.add(emptyRow); } } /** * Calculates the arithmetic mean of all values between start and end. * @param data Values. * @param start Start index. * @param end End index. * @return Arithmetic mean. */ private static double average(DataAccessor data, double start, double end) { int startFloor = (int) Math.floor(start); int startCeil = (int) Math.ceil(start); int endFloor = (int) Math.floor(end); int endCeil = (int) Math.ceil(end); double sum = 0.0; for (int i = startFloor; i < endCeil; i++) { Number number = (Number) data.get(i); double val = number.doubleValue(); if (i == startFloor && startCeil != start) { sum += (startCeil - start) * val; } else if (i == endCeil - 1 && endFloor != end) { sum += (end - endFloor) * val; } else { sum += val; } } return sum / (end - start); } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Normal deserialization in.defaultReadObject(); // Update caches dataUpdated(this); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/filters/package-info.java000077500000000000000000000017001267060725100304370ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Classes for filtering data sources. */ package de.erichseifert.gral.data.filters; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/package-info.java000077500000000000000000000017611267060725100267760ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Data model classes. This package contains classes and interfaces for storing data for plots. */ package de.erichseifert.gral.data; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/statistics/000077500000000000000000000000001267060725100257715ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/statistics/Histogram.java000066400000000000000000000105701267060725100305740ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.statistics; import java.io.IOException; import java.io.ObjectInputStream; import de.erichseifert.gral.data.AbstractDataSource; import de.erichseifert.gral.data.DataChangeEvent; import de.erichseifert.gral.data.DataListener; import de.erichseifert.gral.data.DataSource; /** * Abstract base class for histograms. Derived classes must * make sure the {@code getColumnTypes()} method returns a correct array * with column types. * @see AbstractDataSource#setColumnTypes(Class...) */ public abstract class Histogram extends AbstractDataSource implements DataListener { /** Version id for serialization. */ private static final long serialVersionUID = 5031290498142366257L; /** Data source that is used to build the histogram. */ private final DataSource data; /** * Initializes a new histograms with a data source. * @param data Data source to be analyzed. */ @SuppressWarnings("unchecked") public Histogram(DataSource data) { this.data = data; this.data.addDataListener(this); } /** * Recalculates the histogram values. */ protected abstract void rebuildCells(); /** * Method that is invoked when data has been added. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been added. */ public void dataAdded(DataSource source, DataChangeEvent... events) { dataChanged(source, events); notifyDataAdded(events); } /** * Method that is invoked when data has been updated. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been updated. */ public void dataUpdated(DataSource source, DataChangeEvent... events) { dataChanged(source, events); notifyDataUpdated(events); } /** * Method that is invoked when data has been removed. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been removed. */ public void dataRemoved(DataSource source, DataChangeEvent... events) { dataChanged(source, events); notifyDataRemoved(events); } /** * Method that is invoked when data has been added, updated, or removed. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been changed. */ private void dataChanged(DataSource source, DataChangeEvent... events) { rebuildCells(); } /** * Returns the data source associated to this histogram. * @return Data source */ public DataSource getData() { return data; } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Normal deserialization in.defaultReadObject(); // Restore listeners data.addDataListener(this); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/statistics/Histogram1D.java000066400000000000000000000164451267060725100307700ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.statistics; import java.io.IOException; import java.io.ObjectInputStream; import java.text.MessageFormat; import java.util.*; import de.erichseifert.gral.data.DataAccessor; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.graphics.Orientation; /** *

View that aggregates the column values of an other data source into * a histogram with cells. The cells size can be equally sized by defining * a number of cells or breakpoints between histogram cells can be passed * as an array to create unequally sized cells.

*

For ease of use the histogram is a data source itself.

*/ public class Histogram1D extends Histogram { /** Version id for serialization. */ private static final long serialVersionUID = -4841658606362408312L; /** Direction in which all values will be aggregated. */ private final Orientation orientation; /** Intervals that will be used for aggregation. */ private final List breaks; /** Bin cells that store all aggregation counts. */ private final List cellList; /** Minimum values for cells. */ private transient Map cacheMin; /** Maximum values for cells. */ private transient Map cacheMax; private Histogram1D(DataSource data, Orientation orientation) { super(data); this.orientation = orientation; breaks = new ArrayList(); cellList = new ArrayList(); cacheMin = new HashMap(); cacheMax = new HashMap(); } /** * Creates a new Histogram object with the specified DataSource and * cell count. * @param data DataSource so be analyzed. * @param orientation Orientation of the histogram values. * @param breakCount Number of subdivisions for analysis. */ public Histogram1D(DataSource data, Orientation orientation, int breakCount) { this(data, orientation); // Create equally spaced breaks int count = getData().getColumnCount(); if (orientation == Orientation.HORIZONTAL) { count = getData().getRowCount(); } Statistics stats = getData().getStatistics(); for (int index = 0; index < count; index++) { double min = stats.get(Statistics.MIN, orientation, index); double max = stats.get(Statistics.MAX, orientation, index); double delta = (max - min + Double.MIN_VALUE) / breakCount; Number[] breaks = new Double[breakCount + 1]; for (int i = 0; i < breaks.length; i++) { breaks[i] = min + i*delta; } this.breaks.add(breaks); } dataUpdated(getData()); } /** * Initializes a new histogram with the specified data source and * subdivisions at the specified positions. * @param data Data source to be analyzed. * @param orientation Orientation in which the data should be sampled. * @param breaks Values of where a subdivision should occur. */ public Histogram1D(DataSource data, Orientation orientation, Number[]... breaks) { this(data, orientation); int count = getData().getColumnCount(); if (orientation == Orientation.HORIZONTAL) { count = getData().getRowCount(); } if (breaks.length != count) { throw new IllegalArgumentException(MessageFormat.format( "Invalid number of breaks: got {0,number,integer}, expected {1,number,integer}.", //$NON-NLS-1$ breaks.length, count)); } Collections.addAll(this.breaks, breaks); dataUpdated(getData()); } /** * (Re-)populates the cells of this Histogram. */ @Override protected void rebuildCells() { // FIXME Very naive implementation cellList.clear(); cacheMin.clear(); cacheMax.clear(); // Iterate over histogram data sets int breakIndex = 0; for (Number[] brk : breaks) { long[] cells = new long[brk.length - 1]; long colMin = Long.MAX_VALUE; long colMax = Long.MIN_VALUE; DataAccessor data; if (orientation == Orientation.VERTICAL) { data = getData().getColumn(breakIndex); } else { data = getData().getRow(breakIndex); } // Iterate over data cells for (Comparable cell : data) { if (!(cell instanceof Number)) { continue; } Number numericCell = (Number) cell; double val = numericCell.doubleValue(); // Iterate over histogram rows for (int i = 0; i < brk.length - 1; i++) { // Put the value into corresponding class if ((val >= brk[i].doubleValue()) && (val < brk[i + 1].doubleValue())) { cells[i]++; if (cells[i] > colMax) { colMax = cells[i]; } if (cells[i] < colMin) { colMin = cells[i]; } break; } } } cellList.add(cells); cacheMin.put(breakIndex, colMin); cacheMax.put(breakIndex, colMax); breakIndex++; } } /** * Returns the direction in which the histogram values will be accumulated. * @return Horizontal or vertical orientation. */ public Orientation getOrientation() { return orientation; } /** * Returns the minimum and maximum value of the specified cell. * @param col Column index. * @param cell Cell index. * @return Extent of the cell. */ public Number[] getCellLimits(int col, int cell) { Number[] breaks = this.breaks.get(col); Number lower = breaks[cell]; Number upper = breaks[cell + 1]; return new Number[] {lower, upper}; } /** * Returns the row with the specified index. * @param col index of the column to return * @param row index of the row to return * @return the specified value of the data cell */ public Comparable get(int col, int row) { return cellList.get(col)[row]; } /** * Returns the number of rows of the data source. * @return number of rows in the data source. */ public int getRowCount() { int rowCount = 0; for (long[] cells : this.cellList) { rowCount = Math.max(cells.length, rowCount); } return rowCount; } @Override public int getColumnCount() { return cellList.size(); } @Override @SuppressWarnings("unchecked") public Class>[] getColumnTypes() { Class>[] types = new Class[getColumnCount()]; Arrays.fill(types, Long.class); return types; } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Normal deserialization in.defaultReadObject(); // Handle transient fields cacheMin = new HashMap(); cacheMax = new HashMap(); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/statistics/Statistics.java000066400000000000000000000305771267060725100310020ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.statistics; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import de.erichseifert.gral.data.DataChangeEvent; import de.erichseifert.gral.data.DataListener; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.util.DataUtils; import de.erichseifert.gral.util.MathUtils; import de.erichseifert.gral.graphics.Orientation; import de.erichseifert.gral.util.SortedList; /** * A class that computes and stores various statistical information * on a data source. */ public class Statistics implements DataListener { /** Key for specifying the total number of elements. This is the zeroth central moment: E((x - µ)^0) */ public static final String N = "n"; //$NON-NLS-1$ /** Key for specifying the sum of all values. */ public static final String SUM = "sum"; //$NON-NLS-1$ /** Key for specifying the sum of all value squares. */ public static final String SUM2 = "sum2"; //$NON-NLS-1$ /** Key for specifying the sum of all value cubics. */ public static final String SUM3 = "sum3"; //$NON-NLS-1$ /** Key for specifying the sum of all value quads. */ public static final String SUM4 = "sum4"; //$NON-NLS-1$ /** Key for specifying the minimum, i.e. the smallest value. */ public static final String MIN = "min"; //$NON-NLS-1$ /** Key for specifying the maximum, i.e. the largest value. */ public static final String MAX = "max"; //$NON-NLS-1$ /** Key for specifying the arithmetic mean of all values. */ public static final String MEAN = "mean"; //$NON-NLS-1$ /** Key for specifying the sum of squared differences. This is identical to the second central moment: E((x - mean)^2) */ public static final String SUM_OF_DIFF_SQUARES = "M2"; //$NON-NLS-1$ /** Key for specifying the sum of squared differences. This is identical to the third central moment: E((x - mean)^3) */ public static final String SUM_OF_DIFF_CUBICS = "M3"; //$NON-NLS-1$ /** Key for specifying the sum of squared differences. This is identical to the fourth central moment: E((x - mean)^4) */ public static final String SUM_OF_DIFF_QUADS = "M4"; //$NON-NLS-1$ /** Key for specifying the variance of a sample. Formula: {@code 1/(N - 1) * sumOfSquares} */ public static final String VARIANCE = "sample variance"; //$NON-NLS-1$ /** Key for specifying the population variance. Formula: {@code 1/N * sumOfSquares} */ public static final String POPULATION_VARIANCE = "population variance"; //$NON-NLS-1$ /** Key for specifying the skewness. */ public static final String SKEWNESS = "skewness"; //$NON-NLS-1$ /** Key for specifying the kurtosis. */ public static final String KURTOSIS = "kurtosis"; //$NON-NLS-1$ /** Key for specifying the median (or 50% quantile). */ public static final String MEDIAN = "quantile50"; //$NON-NLS-1$ /** Key for specifying the 1st quartile (or 25th quantile). */ public static final String QUARTILE_1 = "quantile25"; //$NON-NLS-1$ /** Key for specifying the 2nd quartile (or 50th quantile). */ public static final String QUARTILE_2 = "quantile50"; //$NON-NLS-1$ /** Key for specifying the 3rd quartile (or 75th quantile). */ public static final String QUARTILE_3 = "quantile75"; //$NON-NLS-1$ /** Data values that are used to build statistical aggregates. */ private final DataSource data; /** Table statistics stored by key. */ private final Map statistics; /** Column statistics stored by key. */ private final ArrayList> statisticsByCol; /** Row statistics stored by key. */ private final ArrayList> statisticsByRow; /** * Initializes a new object with the specified data source. * @param data Data source to be analyzed. */ public Statistics(DataSource data) { statistics = new HashMap(); statisticsByCol = new ArrayList>(data.getColumnCount()); for (int col = 0; col < data.getColumnCount(); col++) { statisticsByCol.add(new HashMap()); } statisticsByRow = new ArrayList>(data.getRowCount()); for (int row = 0; row < data.getRowCount(); row++) { statisticsByRow.add(new HashMap()); } this.data = data; this.data.addDataListener(this); } /** * Utility method that calculates basic statistics like element count, sum, * or mean. * * Notes: Calculation of higher order statistics is based on formulas from * http://people.xiph.org/~tterribe/notes/homs.html * * @param data Data values used to calculate statistics * @param stats A {@code Map} that should store the new statistics. */ private void createBasicStats(Iterable> data, Map stats) { double n = 0.0; double sum = 0.0; double sum2 = 0.0; double sum3 = 0.0; double sum4 = 0.0; double mean = 0.0; double sumOfDiffSquares = 0.0; double sumOfDiffCubics = 0.0; double sumOfDiffQuads = 0.0; for (Comparable cell : data) { if (!(cell instanceof Number)) { continue; } Number numericCell = (Number) cell; if (!MathUtils.isCalculatable(numericCell)) { continue; } double val = numericCell.doubleValue(); if (!stats.containsKey(MIN) || val < stats.get(MIN)) { stats.put(MIN, val); } if (!stats.containsKey(MAX) || val > stats.get(MAX)) { stats.put(MAX, val); } n++; double val2 = val*val; sum += val; sum2 += val2; sum3 += val2*val; sum4 += val2*val2; double delta = val - mean; double deltaN = delta/n; double deltaN2 = deltaN*deltaN; double term1 = delta*deltaN*(n - 1.0); mean += deltaN; sumOfDiffQuads += term1*deltaN2*(n*n - 3.0*n + 3.0) + 6.0*deltaN2*sumOfDiffSquares - 4.0*deltaN*sumOfDiffCubics; sumOfDiffCubics += term1*deltaN*(n - 2.0) - 3.0*deltaN*sumOfDiffSquares; sumOfDiffSquares += term1; } stats.put(N, n); stats.put(SUM, sum); stats.put(SUM2, sum2); stats.put(SUM3, sum3); stats.put(SUM4, sum4); stats.put(MEAN, mean); stats.put(SUM_OF_DIFF_QUADS, sumOfDiffQuads); stats.put(SUM_OF_DIFF_CUBICS, sumOfDiffCubics); stats.put(SUM_OF_DIFF_SQUARES, sumOfDiffSquares); stats.put(VARIANCE, sumOfDiffSquares/(n - 1.0)); stats.put(POPULATION_VARIANCE, sumOfDiffSquares/n); stats.put(SKEWNESS, (sumOfDiffCubics/n)/Math.pow(sumOfDiffSquares/n, 3.0/2.0) - 3.0); stats.put(KURTOSIS, (n*sumOfDiffQuads)/(sumOfDiffSquares*sumOfDiffSquares) - 3.0); } /** * Utility method that calculates quantiles for the given data values and * stores the results in {@code stats}. * @param stats {@code Map} for storing results * @see de.erichseifert.gral.util.MathUtils#quantile(java.util.List,double) */ private void createDistributionStats(Iterable> data, Map stats) { // Create sorted list of data List values = new SortedList(); for (Comparable cell : data) { if (!(cell instanceof Number)) { continue; } Number numericCell = (Number) cell; double value = numericCell.doubleValue(); if (MathUtils.isCalculatable(value)) { values.add(value); } } if (values.size() <= 0) { return; } stats.put(QUARTILE_1, MathUtils.quantile(values, 0.25)); stats.put(QUARTILE_2, MathUtils.quantile(values, 0.50)); stats.put(QUARTILE_3, MathUtils.quantile(values, 0.75)); stats.put(MEDIAN, stats.get(QUARTILE_2)); } /** * Returns the specified information for the whole data source. * @param key Requested information. * @return The value for the specified key as value, or NaN * if the specified statistical value does not exist */ public double get(String key) { return get(data, statistics, key); } /** * Returns the specified information for the offset index in the specified * direction. * @param key Requested information. * @param orientation Direction of the values the statistical is built from. * @param index Column or row index. * @return The value for the specified key as value, or NaN * if the specified statistical value does not exist */ public double get(String key, Orientation orientation, int index) { Map stats; Iterable> statsData; if (orientation == Orientation.VERTICAL) { if (index >= statisticsByCol.size()) { statisticsByCol.add(new HashMap()); } stats = statisticsByCol.get(index); statsData = data.getColumn(index); } else { if (index >= statisticsByRow.size()) { statisticsByRow.add(new HashMap()); } stats = statisticsByRow.get(index); statsData = data.getRow(index); } return get(statsData, stats, key); } /** * Returns the specified information for the specified column or row. * If the specified statistical value does not exist NaN * is returned. * @param data Data values. * @param stats {@code Map} with statistics. * @param key Requested information. * @return The value for the specified key as value, or NaN * if the specified statistical value does not exist */ private double get(Iterable> data, Map stats, String key) { if (!stats.containsKey(key)) { if (MEDIAN.equals(key) || QUARTILE_1.equals(key) || QUARTILE_2.equals(key) || QUARTILE_3.equals(key)) { createDistributionStats(data, stats); } else { createBasicStats(data, stats); } } Double v = stats.get(key); return DataUtils.getValueOrDefault(v, Double.NaN); } /** * Method that is invoked when data has been added. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been added */ public void dataAdded(DataSource source, DataChangeEvent... events) { dataChanged(source, events); } /** * Method that is invoked when data has been updated. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been updated. */ public void dataUpdated(DataSource source, DataChangeEvent... events) { dataChanged(source, events); } /** * Method that is invoked when data has been removed. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been removed. */ public void dataRemoved(DataSource source, DataChangeEvent... events) { dataChanged(source, events); } /** * Method that is invoked when data has been added, updated, or removed. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has changed. * @param events Optional event object describing the data values that * have been removed. */ private void dataChanged(DataSource source, DataChangeEvent... events) { for (DataChangeEvent event : events) { // Mark statistics as invalid invalidate(event.getCol(), event.getRow()); } } /** * Invalidates statistics information for a certain data cell. * @param col Column index of the cell. * @param row Row index of the cell. */ protected void invalidate(int col, int row) { statistics.clear(); if (col < statisticsByCol.size()) { statisticsByCol.get(col).clear(); } if (row < statisticsByRow.size()) { statisticsByRow.get(row).clear(); } } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/data/statistics/package-info.java000077500000000000000000000017011267060725100311620ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Classes for statistical analysis. */ package de.erichseifert.gral.data.statistics; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/000077500000000000000000000000001267060725100244665ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/AbstractDrawable.java000066400000000000000000000066771267060725100305560ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; import java.awt.geom.Dimension2D; import java.awt.geom.Rectangle2D; import java.io.Serializable; /** * Abstract implementation of the {@link Drawable} interface. * This class implements common functionality like the different ways for * getting and setting the bounding rectangle of the drawable object. */ public abstract class AbstractDrawable implements Drawable, Serializable { /** Version id for serialization. */ private static final long serialVersionUID = -684598008467326484L; /** Boundaries of the drawable object. */ private final Rectangle2D bounds; /** * Creates an AbstractDrawable. */ public AbstractDrawable() { bounds = new Rectangle2D.Double(); } /** * Returns the bounds of this {@code Drawable}. * @return a bounding rectangle */ public Rectangle2D getBounds() { Rectangle2D b = new Rectangle2D.Double(); b.setFrame(bounds); return b; } /** * Returns the x-position of the bounds. * @return horizontal position of the upper-left corner of the bounding * rectangle. */ public double getX() { return bounds.getX(); } /** * Returns the y-position of the bounds. * @return vertical position of the upper-left corner of the bounding * rectangle. */ public double getY() { return bounds.getY(); } /** * Returns the width of the bounds. * @return horizontal extent. */ public double getWidth() { return bounds.getWidth(); } /** * Returns the height of the bounds. * @return vertical extent. */ public double getHeight() { return bounds.getHeight(); } /** * Sets the bounds to the specified bounding rectangle. * @param bounds rectangle containing the component. */ public void setBounds(Rectangle2D bounds) { setBounds(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight()); } /** * Sets the bounds to the specified coordinates, width and height. * This method should be used when overriding functionality. * @param x horizontal position of the upper-left corner * @param y vertical position of the upper-left corner * @param width horizontal extent * @param height vertical extent */ public void setBounds(double x, double y, double width, double height) { bounds.setFrame(x, y, width, height); } /** * Returns the preferred size of the {@code Drawable}. * @return horizontal and vertical extent that wants to be reached */ public Dimension2D getPreferredSize() { return new de.erichseifert.gral.graphics.Dimension2D.Double(); } @Override public void setPosition(double x, double y) { bounds.setFrame(x, y, bounds.getWidth(), bounds.getHeight()); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/Container.java000066400000000000000000000072431267060725100272610ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.List; import de.erichseifert.gral.graphics.layout.Layout; /** * An interface that provides functions to build a group of multiple components * of {@link Drawable}. It is also responsible for managing layout of its * components using a {@link Layout} and layout constraints for each component. */ public interface Container extends Iterable { /** * Returns the space that this container must preserve at each of its * edges. * @return The insets of this DrawableContainer */ Insets2D getInsets(); /** * Sets the space that this container must preserve at each of its * edges. * @param insets Insets to be set. */ void setInsets(Insets2D insets); /** * Returns the bounds of this container. * @return bounds */ Rectangle2D getBounds(); /** * Sets the bounds of this container. * @param bounds Bounds */ void setBounds(Rectangle2D bounds); /** * Returns the layout associated with this container. * @return Layout manager */ Layout getLayout(); /** * Recalculates this container's layout. */ void layout(); /** * Sets the layout associated with this container. * @param layout Layout to be set. */ void setLayout(Layout layout); /** * Adds a new component to this container. * @param drawable Component */ void add(Drawable drawable); /** * Adds a new component to this container. * @param drawable Component * @param constraints Additional information (e.g. for layout) */ void add(Drawable drawable, Object constraints); /** * Returns whether the specified {@code Drawable} is stored. * @param drawable Element to be checked. * @return {@code true} if the element is stored in the {@code Container}, * {@code false} otherwise. */ boolean contains(Drawable drawable); /** * Returns the components at the specified point. * The first component in the result {@code List} is the most * specific component, i.e. the component with the deepest nesting level. * If no component could be found an empty {@code List} will be returned. * @param point Two-dimensional point. * @return Components at the specified point, with the deepest nested component first. */ List getDrawablesAt(Point2D point); /** * Returns a list of stored components. * @return Contained drawables. */ List getDrawables(); /** * Return additional information on component * @param drawable Component * @return Information object or {@code null} */ Object getConstraints(Drawable drawable); /** * Removes a component from this container. * @param drawable Component */ void remove(Drawable drawable); /** * Returns the number of components that are stored in this container. * @return total number of components */ int size(); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/Dimension2D.java000066400000000000000000000056541267060725100274560ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; import java.io.Serializable; import java.util.Locale; /** *

Class that stores the horizontal and vertical extent of an object.

*

This implementation adds support of double values to * {@code java.awt.geom.Dimension2D}.

*/ public abstract class Dimension2D extends java.awt.geom.Dimension2D implements Serializable { /** Version id for serialization. */ private static final long serialVersionUID = 6961198271520384282L; /** * Creates a new Dimension2D object. */ public Dimension2D() { } /** * Class that stores double values. */ public static class Double extends Dimension2D { /** Version id for serialization. */ private static final long serialVersionUID = -4341712269787906650L; /** Horizontal extension. */ private double width; /** Vertical extension. */ private double height; /** * Creates a new Dimension2D object with zero width and height. */ public Double() { setSize(0.0, 0.0); } /** * Creates a new Dimension2D object with the specified width and * height. * @param width Width. * @param height Height. */ public Double(double width, double height) { setSize(width, height); } @Override public double getHeight() { return height; } @Override public double getWidth() { return width; } @Override public void setSize(double width, double height) { this.width = width; this.height = height; } @Override public String toString() { return String.format(Locale.US, "%s[width=%f, height=%f]", //$NON-NLS-1$ getClass().getName(), width, height); } @Override public boolean equals(Object obj) { if (!(obj instanceof java.awt.geom.Dimension2D)) { return false; } java.awt.geom.Dimension2D dim = (java.awt.geom.Dimension2D) obj; return (getWidth() == dim.getWidth()) && (getHeight() == dim.getHeight()); } @Override public int hashCode() { long bits = java.lang.Double.doubleToLongBits(getWidth()); bits ^= java.lang.Double.doubleToLongBits(getHeight()) * 31; return ((int) bits) ^ ((int) (bits >> 32)); } } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/Drawable.java000066400000000000000000000055471267060725100270650ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; import java.awt.geom.Dimension2D; import java.awt.geom.Rectangle2D; /** * Interface providing functions for a lightweight component that can be drawn * on the screen. Functions include management of the bounding rectangle, * returning a preferred size for layout operations, or drawing using a * specified context. */ public interface Drawable { /** * Returns the bounds of this {@code Drawable}. * @return a bounding rectangle */ Rectangle2D getBounds(); /** * Sets the bounds to the specified bounding rectangle. * @param bounds rectangle containing the component. */ void setBounds(Rectangle2D bounds); /** * Sets the bounds to the specified coordinates, width and height. * This method should be used when overriding functionality. * @param x horizontal position of the upper-left corner * @param y vertical position of the upper-left corner * @param width horizontal extent * @param height vertical extent */ void setBounds(double x, double y, double width, double height); /** * Returns the x-position of the bounds. * @return horizontal position of the upper-left corner of the bounding * rectangle */ double getX(); /** * Returns the y-position of the bounds. * @return vertical position of the upper-left corner of the bounding * rectangle */ double getY(); /** * Sets the position to the specified coordinates. * @param x Coordinate on the x-axis. * @param y Coordinate on the y-axis. */ void setPosition(double x, double y); /** * Returns the width of the bounds. * @return horizontal extent */ double getWidth(); /** * Returns the height of the bounds. * @return vertical extent */ double getHeight(); /** * Returns the preferred size of the {@code Drawable}. * @return horizontal and vertical extent that wants to be reached */ Dimension2D getPreferredSize(); /** * Draws the {@code Drawable} with the specified drawing context. * @param context Environment used for drawing */ void draw(DrawingContext context); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/DrawableContainer.java000066400000000000000000000156621267060725100307270ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; import java.awt.geom.Dimension2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import de.erichseifert.gral.graphics.layout.Layout; /** * Implementation of {@code Container} that is a {@code Drawable} * itself and stores instances of {@code Drawable} as components. * It takes care of laying out, managing insets for and painting the * components. * * @see Drawable * @see Container */ public class DrawableContainer extends AbstractDrawable implements Container { /** Version id for serialization. */ private static final long serialVersionUID = 3741045651357559308L; /** Empty margins that should be preserved around the contents of this container. */ private final Insets2D insets; /** Object that manages the layout of all container components. */ private Layout layout; /** Elements stored in this container. */ private final Queue components; /** Supplemental information for components, like layout constraints. */ private final Map constraints; /** * Creates a new container for {@code Drawable}s without layout * manager. */ public DrawableContainer() { this(null); } /** * Creates a new container for {@code Drawable}s with the specified * layout manager. * @param layout Layout manager to be set. */ public DrawableContainer(Layout layout) { insets = new Insets2D.Double(); components = new ConcurrentLinkedQueue(); constraints = new HashMap(); this.layout = layout; } /** * Draws the {@code Drawable} with the specified drawing context. * @param context Environment used for drawing. */ public void draw(DrawingContext context) { drawComponents(context); } /** * Invokes the draw method of each {@code Drawable}. * @param context Environment used for drawing. */ protected void drawComponents(DrawingContext context) { for (Drawable d : this) { d.draw(context); } } /** * Adds a new component to this container. * @param drawable Component */ public void add(Drawable drawable) { add(drawable, null); } /** * Adds a new component to this container. * @param drawable Component * @param constraints Additional information (e.g. for layout) */ public void add(Drawable drawable, Object constraints) { if (drawable == this) { throw new IllegalArgumentException( "A container cannot be added to itself."); //$NON-NLS-1$ } this.constraints.put(drawable, constraints); components.add(drawable); layout(); } @Override public boolean contains(Drawable drawable) { return components.contains(drawable); } @Override public List getDrawablesAt(Point2D point) { return getDrawablesAt(this, point, new LinkedList()); } @Override public List getDrawables() { /* * TODO: Size of ArrayList can be different from the number of added components * in concurrent environments. */ List drawableList = new ArrayList(components.size()); drawableList.addAll(components); return drawableList; } private static List getDrawablesAt(Container container, Point2D point, LinkedList previousResults) { if (container instanceof Drawable && container.getBounds().contains(point)) { previousResults.addFirst((Drawable) container); } for (Drawable component : container) { // Check whether the point is in one of the child elements of the container if (component instanceof Container) { getDrawablesAt((Container) component, point, previousResults); } else if (component != null && component.getBounds().contains(point)) { previousResults.addFirst(component); } } return previousResults; } /** * Return additional information on component * @param drawable Component * @return Information object or {@code null} */ public Object getConstraints(Drawable drawable) { return constraints.get(drawable); } /** * Removes a component from this container. * @param drawable Component */ public void remove(Drawable drawable) { components.remove(drawable); constraints.remove(drawable); layout(); } /** * Returns the space that this container must preserve at each of its * edges. * @return The insets of this DrawableContainer */ public Insets2D getInsets() { Insets2D insets = new Insets2D.Double(); insets.setInsets(this.insets); return insets; } /** * Sets the space that this container must preserve at each of its * edges. * @param insets Insets to be set. */ public void setInsets(Insets2D insets) { if (insets == this.insets || this.insets.equals(insets)) { return; } this.insets.setInsets(insets); layout(); } /** * Returns the layout associated with this container. * @return Layout manager */ public Layout getLayout() { return layout; } /** * Sets the layout associated with this container. * @param layout Layout to be set. */ public void setLayout(Layout layout) { this.layout = layout; layout(); } /** * Recalculates this container's layout. */ public void layout() { Layout layout = getLayout(); if (layout != null) { layout.layout(this); } } /** * Returns an iterator over the container's elements. * * @return an Iterator. */ public Iterator iterator() { return components.iterator(); } /** * Returns the number of components that are stored in this container. * @return total number of components */ public int size() { return components.size(); } @Override public void setBounds(Rectangle2D bounds) { super.setBounds(bounds); layout(); } @Override public void setBounds(double x, double y, double width, double height) { super.setBounds(x, y, width, height); layout(); } @Override public Dimension2D getPreferredSize() { Layout layout = getLayout(); if (layout != null) { return layout.getPreferredSize(this); } return super.getPreferredSize(); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/DrawingContext.java000066400000000000000000000054301267060725100302730ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; import java.awt.Graphics2D; /** * Class that stores an object for drawing and additional context information * that may be necessary to determine how to draw the object. This includes * information on drawing quality and the target media (screen, paper, etc.). */ public class DrawingContext { /** * Data type that describes the quality mode of drawing operations. */ public static enum Quality { /** Fast drawing mode. */ DRAFT, /** Standard drawing mode. */ NORMAL, /** High quality drawing mode. */ QUALITY } /** * Data type that describes the type of the drawing target. */ public static enum Target { /** Bitmap drawing target consisting of pixels. */ BITMAP, /** Vector drawing target consisting of lines and curves. */ VECTOR } /** Graphics instance used for drawing. */ private final Graphics2D graphics; /** Quality level used for drawing. */ private final Quality quality; /** Target media. */ private final Target target; /** * Initializes a new context with a {@code Graphics2D} object. * @param graphics Object for drawing geometry. */ public DrawingContext(Graphics2D graphics) { this(graphics, Quality.NORMAL, Target.BITMAP); } /** * Initializes a new context with a {@code Graphics2D} object. * @param graphics Object for drawing geometry. * @param quality Drawing quality. * @param target Target media. */ public DrawingContext(Graphics2D graphics, Quality quality, Target target) { this.graphics = graphics; this.quality = quality; this.target = target; } /** * Returns the object for drawing geometry. * @return Graphics object. */ public Graphics2D getGraphics() { return graphics; } /** * Returns the desired display quality. * @return Display quality mode. */ public Quality getQuality() { return quality; } /** * Returns the drawing target. * @return Drawing target. */ public Target getTarget() { return target; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/Insets2D.java000066400000000000000000000115671267060725100267760ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; import java.io.Serializable; import java.util.Locale; /** * Abstract class that stores insets for all four directions. *

Please use this instead of java.awt.Insets, as the java class does not * support double values.

*/ public abstract class Insets2D implements Serializable { /** Version id for serialization. */ private static final long serialVersionUID = 8685228413052838087L; /** * Creates a new Insets2D object. */ public Insets2D() { } /** * Returns the insets at the top. * @return Top insets. */ public abstract double getTop(); /** * Returns the insets at the left. * @return Left insets. */ public abstract double getLeft(); /** * Returns the insets at the bottom. * @return Bottom insets. */ public abstract double getBottom(); /** * Returns the insets at the right. * @return Right insets. */ public abstract double getRight(); /** * Returns the sum of horizontal insets. * @return Horizontal insets. */ public double getHorizontal() { return getRight() + getLeft(); } /** * Returns the sum of vertical insets. * @return Vertical insets. */ public double getVertical() { return getTop() + getBottom(); } /** * Sets the insets according to the specified insets. * @param insets Insets to be set. */ public abstract void setInsets(Insets2D insets); /** * Sets the insets to the specified values. * @param top Top insets. * @param left Left insets. * @param bottom Bottom insets. * @param right Right insets. */ public abstract void setInsets(double top, double left, double bottom, double right); /** * Class that stores insets as double values. */ public static class Double extends Insets2D { /** Version id for serialization. */ private static final long serialVersionUID = -6637052175330595647L; /** Top. */ private double top; /** Left. */ private double left; /** Bottom. */ private double bottom; /** Right. */ private double right; /** * Creates a new Insets2D object with zero insets. */ public Double() { this(0.0); } /** * Creates a new Insets2D object with the specified insets in all * directions. * @param inset Inset value. */ public Double(double inset) { this(inset, inset, inset, inset); } /** * Creates a new Insets2D object with the specified insets. * @param top Top insets. * @param left Left insets. * @param bottom Bottom insets. * @param right Right insets. */ public Double(double top, double left, double bottom, double right) { setInsets(top, left, bottom, right); } @Override public double getTop() { return top; } @Override public double getLeft() { return left; } @Override public double getBottom() { return bottom; } @Override public double getRight() { return right; } @Override public void setInsets(Insets2D insets) { if (insets == null) { return; } setInsets(insets.getTop(), insets.getLeft(), insets.getBottom(), insets.getRight()); } @Override public void setInsets(double top, double left, double bottom, double right) { this.top = top; this.left = left; this.bottom = bottom; this.right = right; } @Override public String toString() { return String.format(Locale.US, "%s[top=%f, left=%f, bottom=%f, right=%f]", //$NON-NLS-1$ getClass().getName(), top, left, bottom, right); } @Override public boolean equals(Object obj) { if (!(obj instanceof Insets2D)) { return false; } Insets2D insets = (Insets2D) obj; return (getTop() == insets.getTop()) && (getLeft() == insets.getLeft()) && (getBottom() == insets.getBottom()) && (getRight() == insets.getRight()); } @Override public int hashCode() { long bits = java.lang.Double.doubleToLongBits(getTop()); bits += java.lang.Double.doubleToLongBits(getLeft()) * 37; bits += java.lang.Double.doubleToLongBits(getBottom()) * 43; bits += java.lang.Double.doubleToLongBits(getRight()) * 47; return ((int) bits) ^ ((int) (bits >> 32)); } } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/Label.java000066400000000000000000000272001267060725100263510ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Dimension2D; import java.awt.geom.Rectangle2D; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.util.MathUtils; /** * Class that draws a label to a specific location. * A Label is able to manage its settings and to set and get the * displayed text, as well as calculating its bounds. */ public class Label extends AbstractDrawable { /** Version id for serialization. */ private static final long serialVersionUID = 374045708533704103L; /** Text for this label. */ private String text; /** Horizontal label alignment. */ private double alignmentX; /** Vertical label alignment. */ private double alignmentY; /** Font used to display the text of this label. */ private Font font; /** Rotation angle in degrees. */ private double rotation; /** Paint used to draw the shape. */ private Paint color; /** Relative text alignment. */ private double textAlignment; /** Decides whether the text should be wrapped. */ private boolean wordWrapEnabled; /** Paint used to display the background. */ private Paint background; /** Cached outline of the label text with word wrapping. */ private transient Shape outlineWrapped; /** Cached outline of the label text without word wrapping. */ private transient Shape outlineUnwrapped; /** * Initializes a new empty {@code Label} instance. */ public Label() { this(""); //$NON-NLS-1$ } /** * Initializes a new {@code Label} instance with the specified text. * @param text Text to be displayed. */ public Label(String text) { this.text = text; alignmentX = 0.5; alignmentY = 0.5; font = Font.decode(null); rotation = 0.0; color = Color.BLACK; textAlignment = 0.5; wordWrapEnabled = false; } /** * Draws the object with the specified drawing context. * @param context Environment used for drawing */ public void draw(DrawingContext context) { boolean wordWrap = isWordWrapEnabled(); Shape labelShape = getCachedOutline(wordWrap); if (labelShape == null) { return; } Rectangle2D textBounds = labelShape.getBounds2D(); // Rotate label text around its center point double rotation = getRotation(); if (MathUtils.isCalculatable(rotation) && rotation != 0.0) { AffineTransform txLabelText = AffineTransform.getRotateInstance( Math.toRadians(-rotation), textBounds.getCenterX(), textBounds.getCenterY() ); labelShape = txLabelText.createTransformedShape(labelShape); textBounds = labelShape.getBounds2D(); } // Get graphics instance and store state information Graphics2D graphics = context.getGraphics(); AffineTransform txOld = graphics.getTransform(); // Draw background Paint background = getBackground(); if (background != null) { GraphicsUtils.fillPaintedShape(graphics, getBounds(), background, null); } // Calculate absolute text position: // First, move the text to the upper left of the bounding rectangle double shapePosX = getX() - textBounds.getX(); double shapePosY = getY() - textBounds.getY(); // Position the text inside the bounding rectangle using the alignment // settings double alignmentX = getAlignmentX(); double alignmentY = getAlignmentY(); shapePosX += alignmentX*(getWidth() - textBounds.getWidth()); shapePosY += alignmentY*(getHeight() - textBounds.getHeight()); // Apply positioning graphics.translate(shapePosX, shapePosY); // Paint the shape with the color from settings Paint paint = getColor(); GraphicsUtils.fillPaintedShape(graphics, labelShape, paint, null); // Restore previous state graphics.setTransform(txOld); } @Override public Dimension2D getPreferredSize() { Dimension2D d = super.getPreferredSize(); if (getCachedOutline(false) != null) { Shape shape = getTextRectangle(); Rectangle2D bounds = shape.getBounds2D(); double rotation = getRotation(); if (MathUtils.isCalculatable(rotation) && rotation != 0.0) { AffineTransform txLabelText = AffineTransform.getRotateInstance( Math.toRadians(-rotation), bounds.getCenterX(), bounds.getCenterY() ); shape = txLabelText.createTransformedShape(shape); } d.setSize( shape.getBounds2D().getWidth(), shape.getBounds2D().getHeight() ); } return d; } /** * Returns an outline shape for this label. * @param wordWrap Wrap the words of the text to fit the current size. * @return Outline for this label. */ protected Shape getOutline(boolean wordWrap) { Font font = getFont(); float wrappingWidth = 0f; if (wordWrap) { double rotation = Math.toRadians(getRotation()); wrappingWidth = (float) ( Math.abs(Math.cos(rotation))*getWidth() + Math.abs(Math.sin(rotation))*getHeight()); } double alignment = getTextAlignment(); Shape outline = GraphicsUtils.getOutline( getText(), font, wrappingWidth, alignment); return outline; } /** * Returns a cached instance of the outline shape for this label. * @param wordWrap Flag, whether to wrap lines to fit the current size. * @return An instance of the outline shape for this label. */ protected Shape getCachedOutline(boolean wordWrap) { if (!isValid() && getText() != null && !getText().isEmpty()) { outlineWrapped = getOutline(true); outlineUnwrapped = getOutline(false); } if (wordWrap) { return outlineWrapped; } else { return outlineUnwrapped; } } /** * Returns the bounding rectangle of the text without rotation or word * wrapping. * @return Bounding rectangle. */ public Rectangle2D getTextRectangle() { return getCachedOutline(false).getBounds(); } /** * Returns the text of this label. * @return Text. */ public String getText() { return text; } /** * Sets the displayed text to the specified value. * @param text Text to be displayed. */ public void setText(String text) { this.text = text; invalidate(); } /** * Marks the text layout as invalid. It has to be refreshed the next time. */ protected void invalidate() { outlineWrapped = null; outlineUnwrapped = null; } /** * Returns whether the cached values in this label are valid. * @return {@code true} if all cached values are valid, * otherwise {@code false}. */ protected boolean isValid() { boolean wordWrap = isWordWrapEnabled(); if (wordWrap) { return outlineWrapped != null; } else { return outlineUnwrapped != null; } } @Override public void setBounds(double x, double y, double width, double height) { double widthOld = getWidth(); double heightOld = getHeight(); super.setBounds(x, y, width, height); if (width != widthOld || height != heightOld) { invalidate(); } } /** * Returns the horizontal alignment within the bounding rectangle. * 0.0 means left, 1.0 means right. * @return Horizontal label alignment. */ public double getAlignmentX() { return alignmentX; } /** * Sets the horizontal alignment within the bounding rectangle. * 0.0 means left, 1.0 means right. * @param alignmentX Horizontal label alignment. */ public void setAlignmentX(double alignmentX) { this.alignmentX = alignmentX; } /** * Returns the vertical alignment within the bounding rectangle. * 0.0 means top, 1.0 means bottom. * @return Vertical label alignment. */ public double getAlignmentY() { return alignmentY; } /** * Sets the vertical alignment within the bounding rectangle. * 0.0 means top, 1.0 means bottom. * @param alignmentY Vertical label alignment. */ public void setAlignmentY(double alignmentY) { this.alignmentY = alignmentY; } /** * Returns the font used to display the text of this label. * @return Font used for text display. */ public Font getFont() { return font; } /** * Sets the font used to display the text of this label. * @param font Font used for text display. */ public void setFont(Font font) { this.font = font; invalidate(); } /** * Returns the rotation of this label. * The rotation will be counterclockwise. * @return Rotation in degrees. */ public double getRotation() { return rotation; } /** * Sets the rotation of this label. * The rotation will be counterclockwise. * @param angle Rotation in degrees. */ public void setRotation(double angle) { this.rotation = angle; invalidate(); } /** * Returns the paint used to draw the label shape. * @return Paint for shape drawing. */ public Paint getColor() { return color; } /** * Sets the paint used to draw the label shape. * @param color Paint for shape drawing. */ public void setColor(Paint color) { this.color = color; } /** * Returns the alignment of text with multiple lines. * 0.0 means left, 1.0 means right. * @return Relative text alignment. */ public double getTextAlignment() { return textAlignment; } /** * Sets the alignment of text with multiple lines. * 0.0 means left, 1.0 means right. * @param textAlignment Relative text alignment. */ public void setTextAlignment(double textAlignment) { this.textAlignment = textAlignment; invalidate(); } /** * Returns whether words of the text should be wrapped to fit the size of the label. * @return {@code true} if the text should be wrapped, {@code false} otherwise. */ public boolean isWordWrapEnabled() { return wordWrapEnabled; } /** * Sets whether words of the text should be wrapped to fit the size of the label. * @param wordWrapEnabled {@code true} if the text should be wrapped, {@code false} otherwise. */ public void setWordWrapEnabled(boolean wordWrapEnabled) { this.wordWrapEnabled = wordWrapEnabled; invalidate(); } /** * Returns the background color. * @return Background color or {@code null}, if no background is defined. */ public Paint getBackground() { return background; } /** * Sets the background color to the specified value. * @param background Background color. */ public void setBackground(Paint background) { this.background = background; } @Override public boolean equals(Object obj) { if (!(obj instanceof Label)) { return false; } Label label = (Label) obj; return ((getText() == null && label.getText() == null) || getText().equals(label.getText())) && (getAlignmentX() == label.getAlignmentX()) && (getAlignmentY() == label.getAlignmentY()) && ((getFont() == null && label.getFont() == null) || getFont().equals(label.getFont())) && (getRotation() == label.getRotation()) && ((getColor() == null && label.getColor() == null) || getColor().equals(label.getColor())) && (getTextAlignment() == label.getTextAlignment()) && (isWordWrapEnabled() == label.isWordWrapEnabled()) && ((getBackground() == null && label.getBackground() == null) || getBackground().equals(label.getBackground())); } // TODO: Override Object.hashCode() } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/Location.java000066400000000000000000000040051267060725100271000ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; /** * Indicates the location of components. */ public enum Location { /** Central location. */ CENTER(0.5, 0.5), /** Northern location. */ NORTH(0.5, 0.0), /** North-eastern location. */ NORTH_EAST(1.0, 0.0), /** Eastern location. */ EAST(1.0, 0.5), /** South-eastern location. */ SOUTH_EAST(1.0, 1.0), /** Southern location. */ SOUTH(0.5, 1.0), /** South-western location. */ SOUTH_WEST(0.0, 1.0), /** Western location. */ WEST(0.0, 0.5), /** North-western location. */ NORTH_WEST(0.0, 0.0); /** Horizontal alignment. */ private final double alignH; /** Vertical alignment. */ private final double alignV; /** * Constructor that initializes a new location. * @param alignH Horizontal alignment. * @param alignV Vertical alignment. */ Location(double alignH, double alignV) { this.alignH = alignH; this.alignV = alignV; } /** * Returns the horizontal alignment as a double value. * @return horizontal alignment */ public double getAlignmentH() { return alignH; } /** * Returns the vertical alignment as a double value. * @return vertical alignment */ public double getAlignmentV() { return alignV; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/Orientation.java000066400000000000000000000020701267060725100276230ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; /** * Enumeration type to describe the orientation of a arbitrary elements. */ public enum Orientation { /** Horizontal orientation. */ HORIZONTAL, /** Vertical orientation. */ VERTICAL } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/layout/000077500000000000000000000000001267060725100260035ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/layout/AbstractLayout.java000066400000000000000000000027311267060725100316120ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics.layout; public abstract class AbstractLayout implements Layout { private static final long serialVersionUID = 5961215915010787754L; /** Horizontal spacing of components. */ private double gapX; /** Vertical spacing of components. */ private double gapY; public AbstractLayout(double gapX, double gapY) { this.gapX = gapX; this.gapY = gapY; } @Override public double getGapX() { return gapX; } @Override public void setGapX(double gapX) { this.gapX = gapX; } @Override public double getGapY() { return gapY; } @Override public void setGapY(double gapY) { this.gapY = gapY; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/layout/AbstractOrientedLayout.java000066400000000000000000000026621267060725100333070ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics.layout; import de.erichseifert.gral.graphics.Orientation; public abstract class AbstractOrientedLayout extends AbstractLayout implements OrientedLayout { /** Orientation in which elements should be laid out. */ private Orientation orientation; public AbstractOrientedLayout(Orientation orientation, double gapX, double gapY) { super(gapX, gapY); this.orientation = orientation; } @Override public Orientation getOrientation() { return orientation; } @Override public void setOrientation(Orientation orientation) { this.orientation = orientation; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/layout/EdgeLayout.java000066400000000000000000000215151267060725100307140ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics.layout; import java.awt.geom.Dimension2D; import java.awt.geom.Rectangle2D; import java.util.HashMap; import java.util.Map; import de.erichseifert.gral.graphics.Container; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.Insets2D; import de.erichseifert.gral.graphics.Location; /** * Implementation of Layout that arranges a {@link Container}'s components * according to a certain grid. This is similar to Java's * {@link java.awt.BorderLayout}, but also allows components to be placed in * each of the corners. */ public class EdgeLayout extends AbstractLayout { /** Version id for serialization. */ private static final long serialVersionUID = 3661169796145433549L; /** * Initializes a layout manager object with the specified space between the * components. * @param gapH Horizontal gap. * @param gapV Vertical gap. */ public EdgeLayout(double gapH, double gapV) { super(gapH, gapV); } /** * Initializes a layout manager object without space between the * components. */ public EdgeLayout() { this(0.0, 0.0); } /** * Arranges the components of the specified container according to this * layout. * @param container Container to be laid out. */ public void layout(Container container) { // Fetch components Map comps = getComponentsByLocation(container); Drawable north = comps.get(Location.NORTH); Drawable northEast = comps.get(Location.NORTH_EAST); Drawable east = comps.get(Location.EAST); Drawable southEast = comps.get(Location.SOUTH_EAST); Drawable south = comps.get(Location.SOUTH); Drawable southWest = comps.get(Location.SOUTH_WEST); Drawable west = comps.get(Location.WEST); Drawable northWest = comps.get(Location.NORTH_WEST); Drawable center = comps.get(Location.CENTER); // Calculate maximum widths and heights double widthWest = getMaxWidth(northWest, west, southWest); double widthEast = getMaxWidth(northEast, east, southEast); double heightNorth = getMaxHeight(northWest, north, northEast); double heightSouth = getMaxHeight(southWest, south, southEast); double gapWest = (widthWest > 0.0 && center != null) ? getGapX() : 0.0; double gapEast = (widthEast > 0.0 && center != null) ? getGapX() : 0.0; double gapNorth = (heightNorth > 0.0 && center != null) ? getGapY() : 0.0; double gapSouth = (heightSouth > 0.0 && center != null) ? getGapY() : 0.0; Rectangle2D bounds = container.getBounds(); Insets2D insets = container.getInsets(); if (insets == null) { insets = new Insets2D.Double(); } double xWest = bounds.getMinX() + insets.getLeft(); double xCenter = xWest + widthWest + gapWest; double xEast = bounds.getMaxX() - insets.getRight() - widthEast; double yNorth = bounds.getMinY() + insets.getTop(); double yCenter = yNorth + heightNorth + gapNorth; double ySouth = bounds.getMaxY() - insets.getBottom() - heightSouth; double widthAll = widthWest + widthEast; double heightAll = heightNorth + heightSouth; double gapHAll = gapWest + gapEast; double gapVAll = gapNorth - gapSouth; layoutComponent(northWest, xWest, yNorth, widthWest, heightNorth ); layoutComponent(north, xCenter, yNorth, bounds.getWidth() - insets.getHorizontal() - widthAll - gapHAll, heightNorth ); layoutComponent(northEast, xEast, yNorth, widthEast, heightNorth ); layoutComponent(east, xEast, yCenter, widthEast, bounds.getHeight() - insets.getVertical() - heightAll - gapVAll ); layoutComponent(southEast, xEast, ySouth, widthEast, heightSouth ); layoutComponent(south, xCenter, ySouth, bounds.getWidth() - insets.getHorizontal() - widthAll - gapHAll, heightSouth ); layoutComponent(southWest, xWest, ySouth, widthWest, heightSouth ); layoutComponent(west, xWest, yCenter, widthWest, bounds.getHeight() - insets.getVertical() - heightAll - gapVAll ); layoutComponent(center, xCenter, yCenter, bounds.getWidth() - insets.getLeft() - widthAll - insets.getRight() - gapHAll, bounds.getHeight() - insets.getTop() - heightAll - insets.getBottom() - gapVAll ); } /** * Returns the preferred size of the specified container using this layout. * @param container Container whose preferred size is to be returned. * @return Preferred extent of the specified container. */ public Dimension2D getPreferredSize(Container container) { // Fetch components Map comps = getComponentsByLocation(container); Drawable north = comps.get(Location.NORTH); Drawable northEast = comps.get(Location.NORTH_EAST); Drawable east = comps.get(Location.EAST); Drawable southEast = comps.get(Location.SOUTH_EAST); Drawable south = comps.get(Location.SOUTH); Drawable southWest = comps.get(Location.SOUTH_WEST); Drawable west = comps.get(Location.WEST); Drawable northWest = comps.get(Location.NORTH_WEST); Drawable center = comps.get(Location.CENTER); // Calculate maximum widths and heights double widthWest = getMaxWidth(northWest, west, southWest); double widthCenter = getMaxWidth(north, center, south); double widthEast = getMaxWidth(northEast, east, southEast); double heightNorth = getMaxHeight(northWest, north, northEast); double heightCenter = getMaxHeight(west, center, east); double heightSouth = getMaxHeight(southWest, south, southEast); double gapEast = (widthEast > 0.0 && center != null) ? getGapX() : 0.0; double gapWest = (widthWest > 0.0 && center != null) ? getGapX() : 0.0; double gapNorth = (heightNorth > 0.0 && center != null) ? getGapY() : 0.0; double gapSouth = (heightSouth > 0.0 && center != null) ? getGapY() : 0.0; // Calculate preferred dimensions Insets2D insets = container.getInsets(); if (insets == null) { insets = new Insets2D.Double(); } double width = insets.getLeft() + widthEast + gapEast + widthCenter + gapWest + widthWest + insets.getRight(); double height = insets.getTop() + heightNorth + gapNorth + heightCenter + gapSouth + heightSouth + insets.getBottom(); return new de.erichseifert.gral.graphics.Dimension2D.Double( width, height ); } /** * Returns a map all components which are stored with a {@code Location} * constraint in the specified container. * @param container Container which stores the components * @return A map of all components (values) and their constraints (keys) in * the specified container. */ private static Map getComponentsByLocation(Container container) { Map drawablesByLocation = new HashMap(); for (Drawable d: container) { Object constraints = container.getConstraints(d); if (constraints instanceof Location) { drawablesByLocation.put((Location) constraints, d); } } return drawablesByLocation; } /** * Returns the maximum width of an array of Drawables. * @param drawables Drawables to be measured. * @return Maximum horizontal extent. */ private static double getMaxWidth(Drawable... drawables) { double width = 0.0; for (Drawable d : drawables) { if (d == null) { continue; } width = Math.max(width, d.getPreferredSize().getWidth()); } return width; } /** * Returns the maximum height of an array of Drawables. * @param drawables Drawables to be measured. * @return Maximum vertical extent. */ private static double getMaxHeight(Drawable... drawables) { double height = 0.0; for (Drawable d : drawables) { if (d == null) { continue; } height = Math.max(height, d.getPreferredSize().getHeight()); } return height; } /** * Sets the bounds of the specified {@code Drawable} to the specified * values. * @param component {@code Drawable} that should be resized. * @param x X coordinate. * @param y Y coordinate. * @param w Width. * @param h Height. */ private static void layoutComponent(Drawable component, double x, double y, double w, double h) { if (component == null) { return; } component.setBounds(x, y, w, h); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/layout/Layout.java000066400000000000000000000043411267060725100301250ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics.layout; import java.awt.geom.Dimension2D; import java.io.Serializable; import de.erichseifert.gral.graphics.Container; /** * Interface that provides basic functions for arranging a layout. * Functionality includes the arrangement of components and returning the * preferred size of a specified container using this layout. */ public interface Layout extends Serializable { /** * Returns the amount of horizontal space between two layed out components. * @return Space in pixels. */ double getGapX(); /** * Sets the amount of horizontal space between two layed out components. * @param gapX Space in pixels. */ void setGapX(double gapX); /** * Returns the amount of vertical space between two layed out components. * @return Space in pixels. */ double getGapY(); /** * Sets the amount of horizontal space between two layed out components. * @param gapY Space in pixels. */ void setGapY(double gapY); /** * Arranges the components of the specified container according to this * layout. * @param container Container to be laid out. */ void layout(Container container); /** * Returns the preferred size of the specified container using this layout. * @param container Container whose preferred size is to be returned. * @return Preferred extent of the specified container. */ Dimension2D getPreferredSize(Container container); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/layout/OrientedLayout.java000066400000000000000000000024411267060725100316160ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics.layout; import de.erichseifert.gral.graphics.Orientation; /** * Represents a layout with a specific orientation. * @see Orientation */ public interface OrientedLayout extends Layout { /** * Returns the layout direction. * @return Layout orientation. */ Orientation getOrientation(); /** * Sets the layout direction. * @param orientation Layout orientation. */ void setOrientation(Orientation orientation); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/layout/OuterEdgeLayout.java000066400000000000000000000165411267060725100317360ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics.layout; import java.awt.geom.Dimension2D; import java.awt.geom.Rectangle2D; import java.util.HashMap; import java.util.Map; import de.erichseifert.gral.graphics.Container; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.Insets2D; import de.erichseifert.gral.graphics.Location; /** * Implementation of Layout that arranges a {@link Container}'s components * inside or in the regions outside of the container. This is similar to * {@link EdgeLayout}, but also allows components to be placed outside the * container. */ public class OuterEdgeLayout extends AbstractLayout { /** Version id for serialization. */ private static final long serialVersionUID = -2238929452967312857L; /** * Initializes a layout manager object with the specified space between the * container's edges and the components. * @param gap Spacing between the container's edges and the components. */ public OuterEdgeLayout(double gap) { super(gap, gap); } /** * Initializes a layout manager object without space between the * components. */ public OuterEdgeLayout() { this(0.0); } /** * Arranges the components of the specified container according to this * layout. * @param container Container to be laid out. */ public void layout(Container container) { // Fetch components Map comps = getComponentsByLocation(container); Drawable north = comps.get(Location.NORTH); Drawable northEast = comps.get(Location.NORTH_EAST); Drawable east = comps.get(Location.EAST); Drawable southEast = comps.get(Location.SOUTH_EAST); Drawable south = comps.get(Location.SOUTH); Drawable southWest = comps.get(Location.SOUTH_WEST); Drawable west = comps.get(Location.WEST); Drawable northWest = comps.get(Location.NORTH_WEST); Drawable center = comps.get(Location.CENTER); // Calculate maximum widths and heights double widthWest = getMaxWidth(northWest, west, southWest); double widthEast = getMaxWidth(northEast, east, southEast); double heightNorth = getMaxHeight(northWest, north, northEast); double heightSouth = getMaxHeight(southWest, south, southEast); double gapEast = (widthEast > 0.0) ? getGapX() : 0.0; double gapWest = (widthWest > 0.0) ? getGapX() : 0.0; double gapNorth = (heightNorth > 0.0) ? getGapY() : 0.0; double gapSouth = (heightSouth > 0.0) ? getGapY() : 0.0; Rectangle2D bounds = container.getBounds(); Insets2D insets = container.getInsets(); if (insets == null) { insets = new Insets2D.Double(); } double xWest = bounds.getMinX() + insets.getLeft() - gapWest - widthWest; double xCenter = bounds.getMinX() + insets.getLeft(); double xEast = bounds.getMaxX() - insets.getRight() + gapEast; double yNorth = bounds.getMinY() + insets.getTop() - gapNorth - heightNorth; double yCenter = bounds.getMinY() + insets.getTop(); double ySouth = bounds.getMaxY() - insets.getBottom() + gapSouth; layoutComponent(northWest, xWest, yNorth, widthWest, heightNorth ); layoutComponent(north, xCenter, yNorth, bounds.getWidth() - insets.getHorizontal(), heightNorth ); layoutComponent(northEast, xEast, yNorth, widthEast, heightNorth ); layoutComponent(east, xEast, yCenter, widthEast, bounds.getHeight() - insets.getVertical() ); layoutComponent(southEast, xEast, ySouth, widthEast, heightSouth ); layoutComponent(south, xCenter, ySouth, bounds.getWidth() - insets.getHorizontal(), heightSouth ); layoutComponent(southWest, xWest, ySouth, widthWest, heightSouth ); layoutComponent(west, xWest, yCenter, widthWest, bounds.getHeight() - insets.getVertical() ); layoutComponent(center, xCenter + getGapX(), yCenter + getGapY(), bounds.getWidth() - insets.getHorizontal() - 2*getGapX(), bounds.getHeight() - insets.getVertical() - 2*getGapY() ); } /** * Returns the preferred size of the specified container using this layout. * @param container Container whose preferred size is to be returned. * @return Preferred extent of the specified container. */ public Dimension2D getPreferredSize(Container container) { // Fetch components Map comps = getComponentsByLocation(container); Drawable center = comps.get(Location.CENTER); // Calculate preferred dimensions Insets2D insets = container.getInsets(); if (insets == null) { insets = new Insets2D.Double(); } double width = center.getWidth() + insets.getHorizontal() + 2*getGapX(); double height = center.getHeight() + insets.getVertical() + 2*getGapY(); return new de.erichseifert.gral.graphics.Dimension2D.Double( width, height ); } /** * Returns a map all components which are stored with a {@code Location} * constraint in the specified container. * @param container Container which stores the components * @return A map of all components (values) and their constraints (keys) in * the specified container. */ private static Map getComponentsByLocation(Container container) { Map drawablesByLocation = new HashMap(); for (Drawable d: container) { Object constraints = container.getConstraints(d); if (constraints instanceof Location) { drawablesByLocation.put((Location) constraints, d); } } return drawablesByLocation; } /** * Returns the maximum width of an array of Drawables. * @param drawables Drawables to be measured. * @return Maximum horizontal extent. */ private static double getMaxWidth(Drawable... drawables) { double width = 0.0; for (Drawable d : drawables) { if (d == null) { continue; } width = Math.max(width, d.getPreferredSize().getWidth()); } return width; } /** * Returns the maximum height of an array of Drawables. * @param drawables Drawables to be measured. * @return Maximum vertical extent. */ private static double getMaxHeight(Drawable... drawables) { double height = 0.0; for (Drawable d : drawables) { if (d == null) { continue; } height = Math.max(height, d.getPreferredSize().getHeight()); } return height; } /** * Sets the bounds of the specified {@code Drawable} to the specified * values. * @param component {@code Drawable} that should be resized. * @param x X coordinate. * @param y Y coordinate. * @param w Width. * @param h Height. */ private static void layoutComponent(Drawable component, double x, double y, double w, double h) { if (component == null) { return; } component.setBounds(x, y, w, h); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/layout/StackedLayout.java000066400000000000000000000167031267060725100314310ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics.layout; import java.awt.geom.Dimension2D; import java.awt.geom.Rectangle2D; import java.io.Serializable; import de.erichseifert.gral.graphics.Container; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.Insets2D; import de.erichseifert.gral.graphics.Orientation; /** * Class that represents a layout manager which arranges its components * as horizontal or vertical stacks. */ public class StackedLayout extends AbstractOrientedLayout { /** Version id for serialization. */ private static final long serialVersionUID = -3183337606556363756L; /** Default layout behaviour for components. */ private final Constraints defaultConstraints; public static class Constraints implements Serializable { private static final long serialVersionUID = -3375316557720116460L; /** * Whether the component is strechted to the container's width (vertical layout) * or height (horizontal layout). */ private final boolean strechted; /** Horizontal alignment of the component. */ private final double alignmentX; /** Vertical alignment of the component. */ private final double alignmentY; public Constraints(boolean strechted, double alignmentX, double alignmentY) { this.strechted = strechted; this.alignmentX = alignmentX; this.alignmentY = alignmentY; } /** * Returns whether the component is strechted to the container's width (vertical layout) * or height (horizontal orientation). * @return {@code true} if the layed out component should be strechted, {@code false} otherwise. */ public boolean isStrechted() { return strechted; } /** * Returns the relative horizontal position of the component within the container. * This value only has effect, if the components do not fill the width of the container. * @return Relative position of layed out components. */ public double getAlignmentX() { return alignmentX; } /** * Returns the relative vertical position of the components within the container. * This value only has effect, if the components do not fill the height of the container. * @return Relative position of layed out components. */ public double getAlignmentY() { return alignmentY; } } /** * Creates a new StackedLayout object with the specified orientation * and default gap between the components. * @param orientation Orientation in which components are stacked. */ public StackedLayout(Orientation orientation) { this(orientation, 0.0, 0.0); } /** * Creates a new StackedLayout object with the specified orientation * and gap between the components. * @param orientation Orientation in which components are stacked. * @param gapX Horizontal gap between the components. * @param gapY Vertical gap between the components. */ public StackedLayout(Orientation orientation, double gapX, double gapY) { super(orientation, gapX, gapY); defaultConstraints = new Constraints(true, 0.5, 0.5); } /** * Arranges the components of the specified container according to this * layout. * @param container Container to be laid out. */ public void layout(Container container) { Dimension2D size = getPreferredSize(container); Rectangle2D bounds = container.getBounds(); Insets2D insets = container.getInsets(); double xMin = bounds.getMinX() + insets.getLeft(); double yMin = bounds.getMinY() + insets.getTop(); double width = bounds.getWidth() - insets.getLeft() - insets.getRight(); double height = bounds.getHeight() - insets.getTop() - insets.getBottom(); int count = 0; if (getOrientation() == Orientation.HORIZONTAL) { xMin += Math.max(bounds.getWidth() - size.getWidth(), 0.0)*defaultConstraints.getAlignmentX(); for (Drawable component : container) { if (count++ > 0) { xMin += getGapX(); } Dimension2D compBounds = component.getPreferredSize(); Constraints constraints = getConstraints(component, container); double componentHeight; double componentY; if (constraints.isStrechted()) { componentHeight = height; componentY = yMin; } else { componentHeight = Math.min(compBounds.getHeight(), height); componentY = yMin + (height - componentHeight)*constraints.getAlignmentY(); } component.setBounds(xMin, componentY, compBounds.getWidth(), componentHeight); xMin += compBounds.getWidth(); } } else if (getOrientation() == Orientation.VERTICAL) { yMin += Math.max(bounds.getHeight() - size.getHeight(), 0.0)*defaultConstraints.getAlignmentY(); for (Drawable component : container) { if (count++ > 0) { yMin += getGapY(); } Dimension2D compBounds = component.getPreferredSize(); Constraints constraints = getConstraints(component, container); double componentWidth; double componentX; if (constraints.isStrechted()) { componentWidth = width; componentX = xMin; } else { componentWidth = Math.min(compBounds.getWidth(), width); componentX = xMin + (width - componentWidth)*constraints.getAlignmentX(); } component.setBounds(componentX, yMin, componentWidth, compBounds.getHeight()); yMin += compBounds.getHeight(); } } } /** * Returns the preferred size of the specified container using this layout. * @param container Container whose preferred size is to be returned. * @return Preferred extent of the specified container. */ public Dimension2D getPreferredSize(Container container) { Insets2D insets = container.getInsets(); double width = insets.getLeft(); double height = insets.getTop(); int count = 0; if (getOrientation() == Orientation.HORIZONTAL) { double h = 0.0; for (Drawable component : container) { if (count++ > 0) { width += getGapX(); } Dimension2D itemBounds = component.getPreferredSize(); width += itemBounds.getWidth(); h = Math.max(height, itemBounds.getHeight()); } height += h; } else if (getOrientation() == Orientation.VERTICAL) { double w = 0.0; for (Drawable component : container) { if (count++ > 0) { height += getGapY(); } Dimension2D itemBounds = component.getPreferredSize(); w = Math.max(w, itemBounds.getWidth()); height += itemBounds.getHeight(); } width += w; } width += insets.getRight(); height += insets.getBottom(); Dimension2D bounds = new de.erichseifert.gral.graphics.Dimension2D.Double(width, height); return bounds; } private Constraints getConstraints(Drawable component, Container container) { Object constraints = container.getConstraints(component); if (constraints == null || !(constraints instanceof Constraints)) { constraints = defaultConstraints; } return (Constraints) constraints; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/layout/TableLayout.java000066400000000000000000000174461267060725100311070ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics.layout; import java.awt.geom.Dimension2D; import java.awt.geom.Rectangle2D; import java.util.HashMap; import java.util.Map; import de.erichseifert.gral.graphics.Container; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.Insets2D; /** * Implementation of Layout that arranges a {@link Container}'s components * according to a tabular grid with a fixed number of columns. This is similar * to Java's {@link java.awt.GridLayout}, but the cells in the grid may have * different dimensions. */ public class TableLayout extends AbstractLayout { /** Version id for serialization. */ private static final long serialVersionUID = -6738742507926295041L; /** Number of columns. */ private final int cols; /** Index of the column values in the array that is returned by {@link #getInfo(Container)}. */ private static final int COLS = 0; /** Index of the row values in the array that is returned by {@link #getInfo(Container)}. */ private static final int ROWS = 1; /** * Internal data class to store layout related values. */ private static final class Info { /** Map of column/row index and maximal preferred size. */ public final Map sizes; /** Number of columns/rows */ public int size; /** Sum of preferred sizes in horizontal/vertical direction. */ public double sizeSum; /** Sum of insets in horizontal/vertical direction. */ public double insetsSum; /** Sum of gaps in horizontal/vertical direction. */ public double gapSum; /** Mean preferred size in horizontal/vertical direction. */ public double sizeMean; /** Space in horizontal/vertical direction which couldn't be resized because the size limits of some components have been reached. */ public double unsizeableSpace; /** * Initializes a new instance for storing several variables. */ public Info() { sizes = new HashMap(); } } /** * Initializes a layout manager object with the specified number of columns * and the distances between the components. * @param cols Number of columns * @param gapH Horizontal gap. * @param gapV Vertical gap. */ public TableLayout(int cols, double gapH, double gapV) { super(gapH, gapV); if (cols <= 0) { throw new IllegalArgumentException("Invalid number of columns."); } this.cols = cols; } /** * Initializes a layout manager object with the specified number of columns * and no gap between the components. * @param cols Number of columns. */ public TableLayout(int cols) { this(cols, 0.0, 0.0); } /** * Calculates the preferred dimensions for all columns and rows. * @param container The container for which the dimension should be * calculated. * @see #COLS * @see #ROWS */ private Info[] getInfo(Container container) { Info[] infos = new Info[2]; infos[COLS] = new Info(); infos[ROWS] = new Info(); infos[COLS].size = cols; infos[ROWS].size = (int) Math.ceil(container.size() / (double) cols); // Find out the preferred dimensions for each columns and row int compIndex = 0; for (Drawable component : container) { Integer col = compIndex%infos[COLS].size; Integer row = compIndex/infos[COLS].size; Double colWidth = infos[COLS].sizes.get(col); Double rowHeight = infos[ROWS].sizes.get(row); Dimension2D size = component.getPreferredSize(); infos[COLS].sizes.put(col, max(size.getWidth(), colWidth)); infos[ROWS].sizes.put(row, max(size.getHeight(), rowHeight)); compIndex++; } // Calculate container specific variables Rectangle2D bounds = container.getBounds(); Insets2D insets = container.getInsets(); if (insets == null) { insets = new Insets2D.Double(); } infos[COLS].insetsSum = insets.getLeft() + insets.getRight(); infos[ROWS].insetsSum = insets.getTop() + insets.getBottom(); infos[COLS].gapSum = Math.max((infos[COLS].size - 1)*getGapX(), 0.0); infos[ROWS].gapSum = Math.max((infos[ROWS].size - 1)*getGapY(), 0.0); double containerWidth = Math.max(bounds.getWidth() - infos[COLS].insetsSum - infos[COLS].gapSum, 0.0); double containerHeight = Math.max(bounds.getHeight() - infos[ROWS].insetsSum - infos[ROWS].gapSum, 0.0); infos[COLS].sizeMean = (infos[COLS].size > 0) ? containerWidth/infos[COLS].size : 0.0; infos[ROWS].sizeMean = (infos[ROWS].size > 0) ? containerHeight/infos[ROWS].size : 0.0; // Values for columns and rows for (Info info : infos) { info.sizeSum = 0.0; info.unsizeableSpace = 0.0; int sizeable = 0; for (double size : info.sizes.values()) { info.sizeSum += size; if (size >= info.sizeMean) { info.unsizeableSpace += size - info.sizeMean; } else { sizeable++; } } if (sizeable > 0) { info.unsizeableSpace /= sizeable; } } return infos; } /** * Arranges the components of the specified container according to this * layout. * @param container Container to be laid out. */ public void layout(Container container) { Info[] infos = getInfo(container); Rectangle2D bounds = container.getBounds(); Insets2D insets = container.getInsets(); if (insets == null) { insets = new Insets2D.Double(); } Integer lastCol = infos[COLS].size - 1; int compIndex = 0; double x = bounds.getX() + insets.getLeft(); double y = bounds.getY() + insets.getTop(); for (Drawable component : container) { Integer col = compIndex%infos[COLS].size; Integer row = compIndex/infos[COLS].size; double colWidth = infos[COLS].sizes.get(col); double rowHeight = infos[ROWS].sizes.get(row); double w = Math.max(infos[COLS].sizeMean - infos[COLS].unsizeableSpace, colWidth); double h = Math.max(infos[ROWS].sizeMean - infos[ROWS].unsizeableSpace, rowHeight); if (component != null) { component.setBounds(x, y, w, h); } if (col.equals(lastCol)) { x = bounds.getX() + insets.getLeft(); y += h + getGapY(); } else { x += w + getGapX(); } compIndex++; } } /** * Returns the preferred size of the specified container using this layout. * @param container Container whose preferred size is to be returned. * @return Preferred extent of the specified container. */ public Dimension2D getPreferredSize(Container container) { Info[] infos = getInfo(container); return new de.erichseifert.gral.graphics.Dimension2D.Double( infos[COLS].sizeSum + infos[COLS].gapSum + infos[COLS].insetsSum, infos[ROWS].sizeSum + infos[ROWS].gapSum + infos[ROWS].insetsSum ); } /** * Returns the number of desired columns. * @return Number of desired columns. */ public int getColumns() { return cols; } /** * Returns the value that is larger. If both are equal the first value will * be returned. * @param Data type for the values. * @param a First value. * @param b Second value. * @return Larger value. */ private static > T max(T a, T b) { if (a == null || b == null) { if (a == null) { return b; } else { return a; } } if (a.compareTo(b) >= 0) { return a; } return b; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/graphics/package-info.java000066400000000000000000000016551267060725100276640ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Classes for drawing and layout of components. */ package de.erichseifert.gral.graphics; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/000077500000000000000000000000001267060725100232755ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/AbstractIOFactory.java000066400000000000000000000127071267060725100274720ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; /** * Abstract implementation of {@code IOFactory} which provides basic * functionality. * * @param The type of objects which should be produced by this factory */ public abstract class AbstractIOFactory implements IOFactory { private final Map> entries; /** * Constructor that creates a new instance and initializes it with the name * of the corresponding properties file(s). * @param propFileName File name of the properties file(s) * @throws IOException if reading the properties file(s) failed */ @SuppressWarnings("unchecked") protected AbstractIOFactory(String propFileName) throws IOException { entries = new HashMap>(); // Retrieve property-files Enumeration propFiles; propFiles = getClass().getClassLoader().getResources(propFileName); if (!propFiles.hasMoreElements()) { throw new IOException(MessageFormat.format( "Property file not found: {0}", propFileName)); //$NON-NLS-1$ } Properties props = new Properties(); while (propFiles.hasMoreElements()) { URL propURL = propFiles.nextElement(); InputStream stream = null; try { stream = propURL.openStream(); props.load(stream); } finally { if (stream != null) { stream.close(); } } // Parse property files and register entries as items for (Map.Entry prop : props.entrySet()) { String mimeType = (String) prop.getKey(); String className = (String) prop.getValue(); Class clazz; try { clazz = Class.forName(className); } catch (ClassNotFoundException e) { throw new IOException(e); } // FIXME Missing type safety check entries.put(mimeType, (Class) clazz); } } } /** * Returns the capabilities for a specific format. * @param mimeType MIME type of the format * @return Capabilities for the specified format. */ @SuppressWarnings("unchecked") public IOCapabilities getCapabilities(String mimeType) { Class clazz = entries.get(mimeType); try { Method capabilitiesGetter = clazz.getMethod("getCapabilities"); //$NON-NLS-1$ Set capabilities = (Set) capabilitiesGetter.invoke(clazz); for (IOCapabilities c : capabilities) { if (c.getMimeType().equals(mimeType)) { return c; } } } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } /** * Returns a list of capabilities for all supported formats. * @return Supported capabilities. */ public List getCapabilities() { List caps = new ArrayList(entries.size()); for (String mimeType : entries.keySet()) { IOCapabilities capability = getCapabilities(mimeType); if (capability != null) { caps.add(capability); } } return caps; } /** * Returns an array of Strings containing all supported formats. * @return Supported formats. */ public String[] getSupportedFormats() { String[] formats = new String[entries.size()]; entries.keySet().toArray(formats); return formats; } /** * Returns whether the specified MIME type is supported. * @param mimeType MIME type. * @return {@code true} if supported, otherwise {@code false}. */ public boolean isFormatSupported(String mimeType) { return entries.containsKey(mimeType); } /** * Returns the type of factory products for a specified format. * @param type Format. * @return Class type to create new instances. */ protected Class getTypeClass(String type) { return entries.get(type); } /** * Returns an object for reading or writing the specified format. * @param mimeType MIME type. * @return Reader or writer for the specified MIME type. */ public T get(String mimeType) { // TODO Auto-generated method stub return null; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/IOCapabilities.java000066400000000000000000000046221267060725100267650ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io; /** * Class that stores information on a reader or writer * implementation. * @see de.erichseifert.gral.io.data.DataReader * @see de.erichseifert.gral.io.data.DataWriter * @see de.erichseifert.gral.io.plots.DrawableWriter */ public class IOCapabilities { /** Short format name. */ private final String format; /** Long format name. */ private final String name; /** MIME type of format. */ private final String mimeType; /** File extensions commonly used for this format. */ private final String[] extensions; /** * Creates a new {@code IOCapabilities} object with the specified * format, name, MIME-Type and filename extensions. * @param format Format. * @param name Name. * @param mimeType MIME-Type * @param extensions Extensions. */ public IOCapabilities(String format, String name, String mimeType, String[] extensions) { this.format = format; this.name = name; this.mimeType = mimeType; // TODO Check that there is at least one filename extension this.extensions = extensions; } /** * Returns the format. * @return Format. */ public String getFormat() { return format; } /** * Returns the name of the format. * @return Name. */ public String getName() { return name; } /** * Returns the MIME-Type of the format. * @return Format. */ public String getMimeType() { return mimeType; } /** * Returns an array with Strings containing all possible filename * extensions. * @return Filename Extensions. */ public String[] getExtensions() { return extensions; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/IOCapabilitiesStorage.java000066400000000000000000000034511267060725100303110ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io; import java.util.Collections; import java.util.HashSet; import java.util.Set; /** * Abstract class that provides the basic functions to store capabilities of * a reader or a writer implementation. */ public abstract class IOCapabilitiesStorage { /** Set of all registered capabilities. */ private static final Set capabilities = new HashSet(); /** * Initializes a new storage instance. */ protected IOCapabilitiesStorage() { } /** * Returns a {@code Set} with capabilities for all supported formats. * @return Capabilities. */ public static Set getCapabilities() { return Collections.unmodifiableSet(capabilities); } /** * Adds the specified capabilities to the Set of supported formats. * @param capabilities Capabilities to be added. */ protected static void addCapabilities(IOCapabilities capabilities) { IOCapabilitiesStorage.capabilities.add(capabilities); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/IOFactory.java000066400000000000000000000040311267060725100257750ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io; import java.util.List; /** * Interface for factories producing input (reader) or output (writer) classes. * This is be used to create a extensible plug-in system for reading or writing * data. * @param Class of the objects produced by the factory. */ public interface IOFactory { /** * Returns an object for reading or writing the specified format. * @param mimeType MIME type. * @return Reader or writer for the specified MIME type. */ T get(String mimeType); /** * Returns the capabilities for a specific format. * @param mimeType MIME type of the format * @return Capabilities for the specified format. */ IOCapabilities getCapabilities(String mimeType); /** * Returns a list of capabilities for all supported formats. * @return Supported capabilities. */ List getCapabilities(); /** * Returns an array of Strings containing all supported formats. * @return Supported formats. */ String[] getSupportedFormats(); /** * Returns whether the specified MIME type is supported. * @param mimeType MIME type. * @return {@code true} if supported, otherwise {@code false}. */ boolean isFormatSupported(String mimeType); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/data/000077500000000000000000000000001267060725100242065ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/data/AbstractDataReader.java000066400000000000000000000050771267060725100305420ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import java.util.HashMap; import java.util.Map; import de.erichseifert.gral.io.IOCapabilitiesStorage; /** * Base implementation for classes that read data sources from input streams. */ public abstract class AbstractDataReader extends IOCapabilitiesStorage implements DataReader { /** Settings stored as (key, value) pairs. */ private final Map settings; /** Default settings. */ private final Map defaults; /** Data format as MIME type string. */ private final String mimeType; /** * Initializes a new reader with MIME type information. * @param mimeType MIME type */ public AbstractDataReader(String mimeType) { settings = new HashMap(); defaults = new HashMap(); this.mimeType = mimeType; } /** * Returns the MIME type. * @return MIME type string. */ public String getMimeType() { return mimeType; } /** * Returns the setting for the specified key. * @param return type * @param key key of the setting * @return the value of the setting */ @SuppressWarnings("unchecked") public T getSetting(String key) { if (!settings.containsKey(key)) { return (T) defaults.get(key); } return (T) settings.get(key); } /** * Sets the setting for the specified key. * @param value type * @param key key of the setting * @param value value of the setting */ public void setSetting(String key, T value) { settings.put(key, value); } /** * Defines a default value for the setting with the specified key. * @param Data type of value. * @param key Setting key. * @param value Default value. */ protected void setDefault(String key, T value) { defaults.put(key, value); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/data/AbstractDataWriter.java000066400000000000000000000050741267060725100306110ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import java.util.HashMap; import java.util.Map; import de.erichseifert.gral.io.IOCapabilitiesStorage; /** * Base implementation for classes that write data sources to output streams. */ public abstract class AbstractDataWriter extends IOCapabilitiesStorage implements DataWriter { /** Settings stored as (key, value) pairs. */ private final Map settings; /** Default settings. */ private final Map defaults; /** Data format as MIME type string. */ private final String mimeType; /** * Initializes a new writer with MIME type information. * @param mimeType MIME type */ public AbstractDataWriter(String mimeType) { settings = new HashMap(); defaults = new HashMap(); this.mimeType = mimeType; } /** * Returns the MIME type. * @return MIME type string. */ public String getMimeType() { return mimeType; } /** * Returns the setting for the specified key. * @param return type * @param key key of the setting * @return the value of the setting */ @SuppressWarnings("unchecked") public T getSetting(String key) { if (!settings.containsKey(key)) { return (T) defaults.get(key); } return (T) settings.get(key); } /** * Sets the setting for the specified key. * @param value type * @param key key of the setting * @param value value of the setting */ public void setSetting(String key, T value) { settings.put(key, value); } /** * Defines a default value for the setting with the specified key. * @param Data type of value * @param key Setting key * @param value Default value */ protected void setDefault(String key, T value) { defaults.put(key, value); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/data/AudioReader.java000066400000000000000000000063271267060725100272450ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import java.io.IOException; import java.io.InputStream; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.UnsupportedAudioFileException; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.io.IOCapabilities; import de.erichseifert.gral.util.Messages; /** * Class that reads a data source from a binary image file. This class * shouldn't be used directly but using the {@link DataReaderFactory}. */ public class AudioReader extends AbstractDataReader { static { addCapabilities(new IOCapabilities( "WAV", //$NON-NLS-1$ Messages.getString("DataIO.wavDescription"), //$NON-NLS-1$ "audio/wav", //$NON-NLS-1$ new String[] {"wav"} //$NON-NLS-1$ )); } /** * Creates a new instance with the specified MIME type. * @param mimeType MIME type of the file format to be read. */ public AudioReader(String mimeType) { super(mimeType); setDefault("factor", 1.0); //$NON-NLS-1$ setDefault("offset", 0.0); //$NON-NLS-1$ } /** * Returns a data source that was imported. * @param input Input to be read. * @param types Number types for the columns of the data source. * @return DataSource Imported data. * @throws IOException when the file format is not valid or when * experiencing an error during file operations. */ @SuppressWarnings("unchecked") public DataSource read(InputStream input, Class>... types) throws IOException { AudioInputStream audio; try { audio = AudioSystem.getAudioInputStream(input); } catch (UnsupportedAudioFileException e) { throw new IOException(e); } // FIXME Should the types parameter be used? DataTable data = new DataTable(Double.class); double factor = this.getSetting("factor") //$NON-NLS-1$ .doubleValue(); double offset = this.getSetting("offset") //$NON-NLS-1$ .doubleValue(); int sampleSize = audio.getFormat().getSampleSizeInBits(); byte[] samples = new byte[sampleSize/8]; // see: http://www.jsresources.org/faq_audio.html#reconstruct_samples while (audio.read(samples) >= 0) { int b = samples[0]; if (samples.length == 1) { b = b << 8; } else if (samples.length == 2) { b = (b & 0xFF) | (samples[1] << 8); } double v = factor*b + offset; data.add(v); } return data; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/data/CSVReader.java000066400000000000000000000234011267060725100266270ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.MessageFormat; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Scanner; import java.util.regex.Pattern; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.io.IOCapabilities; import de.erichseifert.gral.util.Messages; import de.erichseifert.gral.util.StatefulTokenizer; import de.erichseifert.gral.util.StatefulTokenizer.Token; /** *

Class that creates a {@code DataSource} from file contents which are * separated by a certain delimiter character. The delimiter is chosen based on * the file type but can also be set manually. By default the comma character * will be used as a delimiter for separating columns.

*

{@code CSVReader} instances should be obtained by the * {@link DataReaderFactory} rather than being created manually:

*
 * DataReaderFactory factory = DataReaderFactory.getInstance();
 * DataReader reader = factory.get("text/csv");
 * reader.read(new FileInputStream(filename), Integer.class, Double.class);
 * 
* @see RFC 4180 */ public class CSVReader extends AbstractDataReader { /** Key for specifying a {@link Character} value that defines the delimiting character used to separate columns. */ public static final String SEPARATOR_CHAR = "separator"; //$NON-NLS-1$ static { addCapabilities(new IOCapabilities( "CSV", //$NON-NLS-1$ Messages.getString("DataIO.csvDescription"), //$NON-NLS-1$ "text/csv", //$NON-NLS-1$ new String[] {"csv", "txt"} //$NON-NLS-1$ //$NON-NLS-2$ )); addCapabilities(new IOCapabilities( "TSV", //$NON-NLS-1$ Messages.getString("DataIO.tsvDescription"), //$NON-NLS-1$ "text/tab-separated-values", //$NON-NLS-1$ new String[] { "tsv", "tab", "txt"} //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ )); } /** * Token types for analyzing CSV or TSV input. */ private static enum CSVTokenType { /** Type for text tokens containing empty content. */ EMPTY_SPACE, /** Type for text tokens containing value content. */ TEXT, /** Type for quotes that may wrap value content. */ QUOTE, /** Type for row separators. */ ROW_SEPARATOR, /** Type for column separators. */ COLUMN_SEPARATOR, } /** * */ private static final class CSVTokenizer extends StatefulTokenizer { /** * Initializes a new tokenizer instance with a grammar to analyze CSV * or TSV content. The character that separates columns must be * provided. * @param separator Column separator character. */ public CSVTokenizer(char separator) { addJoinedType(CSVTokenType.TEXT); addIgnoredType(CSVTokenType.QUOTE); // Basic Set of rules for analyzing CSV content putRules( new Rule("\n|\r\n|\r", CSVTokenType.ROW_SEPARATOR), new Rule(Pattern.quote(String.valueOf(separator)), CSVTokenType.COLUMN_SEPARATOR), new Rule("\"", CSVTokenType.QUOTE, "quoted"), new Rule("[ \t]+", CSVTokenType.EMPTY_SPACE), new Rule(".", CSVTokenType.TEXT) ); // Set of rules that is valid inside quoted content putRules("quoted", new Rule("(\")\"", CSVTokenType.TEXT), new Rule("\"", CSVTokenType.QUOTE, "#pop"), new Rule(".", CSVTokenType.TEXT) ); } } /** * Creates a new instance with the specified MIME type. The delimiter is * set depending on the MIME type parameter. By default a comma is used as * a delimiter. * @param mimeType MIME type of the file format to be read. */ public CSVReader(String mimeType) { super(mimeType); if ("text/tab-separated-values".equals(mimeType)) { //$NON-NLS-1$ setDefault(SEPARATOR_CHAR, '\t'); } else { setDefault(SEPARATOR_CHAR, ','); } } /** * Returns a DataSource that was imported. * @param input Input to be read. * @param types Number types for the columns of the DataSource. * @return DataSource Imported data. * @throws IOException when the file format is not valid or when * experiencing an error during file operations. */ public DataSource read(InputStream input, Class>... types) throws IOException { // Read all contents from the input stream Scanner scanner = new Scanner(input).useDelimiter("\\Z"); String content = scanner.next(); // Tokenize the string Character separator = getSetting(SEPARATOR_CHAR); CSVTokenizer tokenizer = new CSVTokenizer(separator); List tokens = tokenizer.tokenize(content); // Add row token if there was no trailing line break Token lastToken = tokens.get(tokens.size() - 1); if (lastToken.getType() != CSVTokenType.ROW_SEPARATOR) { Token eof = new Token(lastToken.getEnd(), lastToken.getEnd(), CSVTokenType.ROW_SEPARATOR, ""); tokens.add(eof); } // Find methods for all column data types that can be used to convert // the text to the column data type Map>, Method> parseMethods = new HashMap>, Method>(); for (Class> type : types) { if (parseMethods.containsKey(type)) { continue; } Method parseMethod = getParseMethod(type); if (parseMethod != null) { parseMethods.put(type, parseMethod); } } // Process the data and store the data. DataTable data = new DataTable(types); List> row = new LinkedList>(); int rowIndex = 0; int colIndex = 0; String cellContent = ""; for (Token token : tokens) { if (token.getType() == CSVTokenType.TEXT || token.getType() == CSVTokenType.EMPTY_SPACE) { // Store the token text cellContent += token.getContent(); } else if (token.getType() == CSVTokenType.COLUMN_SEPARATOR || token.getType() == CSVTokenType.ROW_SEPARATOR) { // Check for a valid number of columns if (colIndex >= types.length) { throw new IllegalArgumentException(MessageFormat.format( "Too many columns in line {0,number,integer}: got {1,number,integer}, but expected {2,number,integer}.", //$NON-NLS-1$ rowIndex + 1, colIndex + 1, types.length)); } // We need to add the cell to the row in both cases because // rows don't have a trailing column token Class> colType = types[colIndex]; Method parseMethod = parseMethods.get(colType); Comparable cell = null; try { cell = (Comparable) parseMethod.invoke( null, cellContent.trim()); } catch (IllegalArgumentException e) { throw new RuntimeException(MessageFormat.format( "Could not invoke method for parsing data type {0} in column {1,number,integer}.", //$NON-NLS-1$ types[colIndex].getSimpleName(), colIndex)); } catch (IllegalAccessException e) { throw new RuntimeException(MessageFormat.format( "Could not access method for parsing data type {0} in column {1,number,integer}.", //$NON-NLS-1$ types[colIndex].getSimpleName(), colIndex)); } catch (InvocationTargetException e) { if (!cellContent.isEmpty()) { throw new IOException(MessageFormat.format( "Type mismatch in line {0,number,integer}, column {1,number,integer}: got \"{2}\", but expected {3} value.", //$NON-NLS-1$ rowIndex + 1, colIndex + 1, cellContent, colType.getSimpleName())); } } row.add(cell); colIndex++; if (token.getType() == CSVTokenType.ROW_SEPARATOR) { // Check for a valid number of columns if (row.size() < types.length) { throw new IllegalArgumentException(MessageFormat.format( "Not enough columns in line {0,number,integer}: got {1,number,integer}, but expected {2,number,integer}.", //$NON-NLS-1$ rowIndex + 1, row.size(), types.length)); } // Add the row to the table data.add(row); rowIndex++; // Start a new row row.clear(); colIndex = 0; } cellContent = ""; } } return data; } /** * Returns a method that can return a parsed value of the specified type. * @param c Desired type. * @return Method that parses a data type. */ private static Method getParseMethod(Class c) { Method parse = null; if (String.class.isAssignableFrom(c)) { try { parse = String.class.getMethod("valueOf", Object.class); } catch (NoSuchMethodException e) { } } else { for (Method m : c.getMethods()) { boolean isStatic = m.toString().contains("static"); //$NON-NLS-1$ if (!isStatic) { continue; } Class[] types = m.getParameterTypes(); boolean hasStringParameter = (types.length == 1) && String.class.equals(types[0]); if (!hasStringParameter) { continue; } // Check method name for a pattern like "parseInt*" for Integer or // "parseSho*" for Short to avoid collisions if (!m.getName().startsWith("parse" + c.getSimpleName().substring(0, 3))) { //$NON-NLS-1$ continue; } parse = m; } } return parse; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/data/CSVWriter.java000066400000000000000000000073351267060725100267110ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.io.IOCapabilities; import de.erichseifert.gral.util.Messages; /** *

Class that writes all values of a {@code DataSource} to a character * separated file. The file then stores the values separated by a certain * delimiter character. The delimiter is chosen based on the file type but can * also be set manually. By default the comma character will be used as a * delimiter for separating columns. Lines end with a carriage return and a * line feed character.

*

{@code CSVWriter} instances should be obtained by the * {@link DataWriterFactory} rather than being created manually:

*
 * DataWriterFactory factory = DataWriterFactory.getInstance();
 * DataWriter writer = factory.get("text/csv");
 * writer.write(data, new FileOutputStream(filename));
 * 
* @see RFC 4180 */ public class CSVWriter extends AbstractDataWriter { /** Key for specifying a {@link Character} value that defines the delimiting character used to separate columns. */ public static final String SEPARATOR_CHAR = CSVReader.SEPARATOR_CHAR; static { addCapabilities(new IOCapabilities( "CSV", //$NON-NLS-1$ Messages.getString("DataIO.csvDescription"), //$NON-NLS-1$ "text/csv", //$NON-NLS-1$ new String[] {"csv", "txt"} //$NON-NLS-1$ //$NON-NLS-2$ )); addCapabilities(new IOCapabilities( "TSV", //$NON-NLS-1$ Messages.getString("DataIO.tsvDescription"), //$NON-NLS-1$ "text/tab-separated-values", //$NON-NLS-1$ new String[] { "tsv", "tab", "txt"} //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ )); } /** * Creates a new instance with the specified MIME-Type. The delimiter is * set depending on the MIME type parameter. By default a comma is used as * a delimiter. * @param mimeType MIME-Type of the output file. */ public CSVWriter(String mimeType) { super(mimeType); if ("text/tab-separated-values".equals(mimeType)) { //$NON-NLS-1$ setDefault(SEPARATOR_CHAR, '\t'); //$NON-NLS-1$ } else { setDefault(SEPARATOR_CHAR, ','); //$NON-NLS-1$ } } /** * Stores the specified data source. * @param data DataSource to be stored. * @param output OutputStream to be written to. * @throws IOException if writing the data failed */ public void write(DataSource data, OutputStream output) throws IOException { Character separator = getSetting(SEPARATOR_CHAR); OutputStreamWriter writer = new OutputStreamWriter(output); int i = 0; int colCount = data.getColumnCount(); for (Comparable cell : data) { writer.write(String.valueOf(cell)); int col = i % colCount; if (col < colCount - 1) { writer.write(separator); } else { writer.write("\r\n"); //$NON-NLS-1$ } i++; } writer.close(); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/data/DataReader.java000066400000000000000000000035421267060725100270510ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import java.io.IOException; import java.io.InputStream; import de.erichseifert.gral.data.DataSource; /** * Interface that provides a function to retrieve a data source. */ public interface DataReader { /** * Returns a data source that contains the imported data. * @param input Input to be read. * @param types Types for the columns of the data source. * @return Imported data. * @throws IOException when the file format is not valid or when * experiencing an error during file operations. */ DataSource read(InputStream input, Class>... types) throws IOException; /** * Returns the setting for the specified key. * @param return type * @param key key of the setting * @return the value of the setting */ T getSetting(String key); /** * Sets the setting for the specified key. * @param value type * @param key key of the setting * @param value value of the setting */ void setSetting(String key, T value); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/data/DataReaderFactory.java000066400000000000000000000065071267060725100304050ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.text.MessageFormat; import de.erichseifert.gral.io.AbstractIOFactory; /** *

A factory class that produces {@code DataReader} instances for a * specified format. The produced readers can be used to retrieve data from * an {@code InputStream} and to get a {@code DataSource} instance.

*

Example usage:

*
 * DataReaderFactory factory = DataReaderFactory.getInstance();
 * DataReader reader = factory.get("text/csv");
 * DataSource = reader.read(new FileInputStream(filename), Double.class);
 * 
*/ public final class DataReaderFactory extends AbstractIOFactory { /** Singleton instance. */ private static DataReaderFactory instance; /** * Constructor that initializes the factory. * @throws IOException if the properties file could not be found. */ private DataReaderFactory() throws IOException { super("datareaders.properties"); //$NON-NLS-1$ } /** * Returns the instance of the factory. * @return Instance of the factory. */ public static DataReaderFactory getInstance() { if (instance == null) { try { instance = new DataReaderFactory(); } catch (IOException e) { throw new RuntimeException(e); } } return instance; } @Override public DataReader get(String mimeType) { DataReader reader = null; Class clazz = getTypeClass(mimeType); //IOCapabilities capabilities = getCapabilities(mimeType); try { if (clazz != null) { Constructor constructor = clazz.getDeclaredConstructor(String.class); reader = constructor.newInstance(mimeType); } } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (reader == null) { throw new IllegalArgumentException(MessageFormat.format( "Unsupported MIME type: {0}", mimeType)); //$NON-NLS-1$ } return reader; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/data/DataWriter.java000066400000000000000000000033061267060725100271210ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import java.io.IOException; import java.io.OutputStream; import de.erichseifert.gral.data.DataSource; /** * Interface that provides a function to store a data source. */ public interface DataWriter { /** * Stores the specified data source. * @param data DataSource to be stored. * @param output OutputStream to be written to. * @throws IOException if writing the data failed */ void write(DataSource data, OutputStream output) throws IOException; /** * Returns the setting for the specified key. * @param return type * @param key key of the setting * @return the value of the setting */ T getSetting(String key); /** * Sets the setting for the specified key. * @param value type * @param key key of the setting * @param value value of the setting */ void setSetting(String key, T value); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/data/DataWriterFactory.java000066400000000000000000000063551267060725100304600ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.text.MessageFormat; import de.erichseifert.gral.io.AbstractIOFactory; /** *

A factory class that produces {@code DataWriter} instances for a * specified format. The produced writers can be used to output a * {@code DataSource} to a data sink.

*

Example usage:

*
 * DataWriterFactory factory = DataWriterFactory.getInstance();
 * DataWriter writer = factory.get("image/png");
 * writer.write(data);
 * 
*/ public final class DataWriterFactory extends AbstractIOFactory { /** Singleton instance. */ private static DataWriterFactory instance; /** * Constructor that initializes the factory. * @throws IOException if the properties file could not be found. */ private DataWriterFactory() throws IOException { super("datawriters.properties"); //$NON-NLS-1$ } /** * Returns the instance of the factory. * @return Instance of the factory. */ public static DataWriterFactory getInstance() { if (instance == null) { try { instance = new DataWriterFactory(); } catch (IOException e) { throw new RuntimeException(e); } } return instance; } @Override public DataWriter get(String mimeType) { DataWriter writer = null; Class clazz = getTypeClass(mimeType); //IOCapabilities capabilities = getCapabilities(mimeType); try { if (clazz != null) { Constructor constructor = clazz.getDeclaredConstructor(String.class); writer = constructor.newInstance(mimeType); } } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (writer == null) { throw new IllegalArgumentException(MessageFormat.format( "Unsupported MIME type: {0}", mimeType)); //$NON-NLS-1$ } return writer; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/data/ImageReader.java000066400000000000000000000101551267060725100272200ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import javax.imageio.ImageIO; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.io.IOCapabilities; import de.erichseifert.gral.util.Messages; /** * Class that reads a data source from a binary image file. This class * shouldn't be used directly but using the {@link DataReaderFactory}. */ public class ImageReader extends AbstractDataReader { static { addCapabilities(new IOCapabilities( "BMP", //$NON-NLS-1$ Messages.getString("ImageIO.bmpDescription"), //$NON-NLS-1$ "image/bmp", //$NON-NLS-1$ new String[] {"bmp", "dib"} //$NON-NLS-1$ //$NON-NLS-2$ )); addCapabilities(new IOCapabilities( "GIF", //$NON-NLS-1$ Messages.getString("ImageIO.gifDescription"), //$NON-NLS-1$ "image/gif", //$NON-NLS-1$ new String[] {"gif"} //$NON-NLS-1$ )); addCapabilities(new IOCapabilities( "JPEG/JFIF", //$NON-NLS-1$ Messages.getString("ImageIO.jpegDescription"), //$NON-NLS-1$ "image/jpeg", //$NON-NLS-1$ new String[] { "jpg", "jpeg", "jpe", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ "jif", "jfif", "jfi"} //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ )); addCapabilities(new IOCapabilities( "PNG", //$NON-NLS-1$ Messages.getString("ImageIO.pngDescription"), //$NON-NLS-1$ "image/png", //$NON-NLS-1$ new String[] {"png"} //$NON-NLS-1$ )); addCapabilities(new IOCapabilities( "WBMP", //$NON-NLS-1$ Messages.getString("ImageIO.wbmpDescription"), //$NON-NLS-1$ "image/vnd.wap.wbmp", //$NON-NLS-1$ new String[] {"wbmp"} //$NON-NLS-1$ )); } /** * Creates a new instance with the specified MIME type. * @param mimeType MIME type of the file format to be read. */ public ImageReader(String mimeType) { super(mimeType); setDefault("factor", 1.0); //$NON-NLS-1$ setDefault("offset", 0.0); //$NON-NLS-1$ } /** * Returns a data source that was imported. * @param input Input to be read. * @param types Number types for the columns of the data source. * @return DataSource Imported data. * @throws IOException when the file format is not valid or when * experiencing an error during file operations. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public DataSource read(InputStream input, Class>... types) throws IOException { BufferedImage image = ImageIO.read(input); int w = image.getWidth(); int h = image.getHeight(); Class[] colTypes = new Class[w]; Arrays.fill(colTypes, Double.class); DataTable data = new DataTable(colTypes); double factor = this.getSetting("factor").doubleValue(); //$NON-NLS-1$ double offset = this.getSetting("offset").doubleValue(); //$NON-NLS-1$ int[] pixelData = new int[w]; Double[] rowData = new Double[w]; for (int y = 0; y < h; y++) { image.getRGB(0, y, pixelData.length, 1, pixelData, 0, 0); for (int x = 0; x < pixelData.length; x++) { //double a = (pixelData[x] >> 24) & 0xFF; double r = (pixelData[x] >> 16) & 0xFF; //double g = (pixelData[x] >> 8) & 0xFF; //double b = (pixelData[x] >> 0) & 0xFF; rowData[x] = r*factor + offset; } data.add(rowData); } return data; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/data/ImageWriter.java000066400000000000000000000106171267060725100272750ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; import java.text.MessageFormat; import java.util.Iterator; import java.util.NoSuchElementException; import javax.imageio.ImageIO; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.io.IOCapabilities; import de.erichseifert.gral.util.MathUtils; import de.erichseifert.gral.util.Messages; /** * Class that writes a data source to a binary image file. This class * shouldn't be used directly but using the {@link DataWriterFactory}. */ public class ImageWriter extends AbstractDataWriter { static { addCapabilities(new IOCapabilities( "BMP", //$NON-NLS-1$ Messages.getString("ImageIO.bmpDescription"), //$NON-NLS-1$ "image/bmp", //$NON-NLS-1$ new String[] {"bmp", "dib"} //$NON-NLS-1$ //$NON-NLS-2$ )); addCapabilities(new IOCapabilities( "GIF", //$NON-NLS-1$ Messages.getString("ImageIO.gifDescription"), //$NON-NLS-1$ "image/gif", //$NON-NLS-1$ new String[] {"gif"} //$NON-NLS-1$ )); addCapabilities(new IOCapabilities( "JPEG/JFIF", //$NON-NLS-1$ Messages.getString("ImageIO.jpegDescription"), //$NON-NLS-1$ "image/jpeg", //$NON-NLS-1$ new String[] { "jpg", "jpeg", "jpe", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ "jif", "jfif", "jfi"} //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ )); addCapabilities(new IOCapabilities( "PNG", //$NON-NLS-1$ Messages.getString("ImageIO.pngDescription"), //$NON-NLS-1$ "image/png", //$NON-NLS-1$ new String[] {"png"} //$NON-NLS-1$ )); addCapabilities(new IOCapabilities( "WBMP", //$NON-NLS-1$ Messages.getString("ImageIO.wbmpDescription"), //$NON-NLS-1$ "image/vnd.wap.wbmp", //$NON-NLS-1$ new String[] {"wbmp"} //$NON-NLS-1$ )); } /** * Creates a new instance with the specified MIME type. * @param mimeType MIME type of the file format to be read. */ public ImageWriter(String mimeType) { super(mimeType); setDefault("factor", 1.0); //$NON-NLS-1$ setDefault("offset", 0.0); //$NON-NLS-1$ } /** * Stores the specified data source. * @param data DataSource to be stored. * @param output OutputStream to be written to. * @throws IOException if writing the data failed */ public void write(DataSource data, OutputStream output) throws IOException { int w = data.getColumnCount(); int h = data.getRowCount(); double factor = this.getSetting("factor").doubleValue(); //$NON-NLS-1$ double offset = this.getSetting("offset").doubleValue(); //$NON-NLS-1$ byte[] pixelData = new byte[w*h]; int pos = 0; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { Comparable cell = data.get(x, y); if (!(cell instanceof Number)) { continue; } Number numericCell = (Number) cell; double value = numericCell.doubleValue()*factor + offset; byte v = (byte) Math.round(MathUtils.limit(value, 0.0, 255.0)); pixelData[pos++] = v; } } BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY); image.getRaster().setDataElements(0, 0, w, h, pixelData); Iterator writers = ImageIO.getImageWritersByMIMEType(getMimeType()); try { javax.imageio.ImageWriter writer = writers.next(); writer.setOutput(ImageIO.createImageOutputStream(output)); writer.write(image); } catch (NoSuchElementException e) { throw new IOException(MessageFormat.format( "No writer found for MIME type {0}.", getMimeType())); //$NON-NLS-1$ } } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/data/package-info.java000077500000000000000000000016751267060725100274110ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Classes for reading and writing data. */ package de.erichseifert.gral.io.data; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/package-info.java000077500000000000000000000016731267060725100264760ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Classes for input and output operations. */ package de.erichseifert.gral.io; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/plots/000077500000000000000000000000001267060725100244365ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/plots/BitmapWriter.java000066400000000000000000000143471267060725100277230ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.plots; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; import java.util.Iterator; import javax.imageio.ImageIO; import javax.imageio.ImageWriter; import javax.imageio.stream.ImageOutputStream; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.io.IOCapabilities; import de.erichseifert.gral.io.IOCapabilitiesStorage; import de.erichseifert.gral.util.Messages; /** * Class that stores {@code Drawable} instances as bitmap graphics. * Supported formats: *
    *
  • Windows Bitmap (BMP)
  • *
  • Graphics Interchange Format (GIF)
  • *
  • JPEG File Interchange Format (JPEG)
  • *
  • Portable Network Graphics (PNG)
  • *
  • Wireless Application Protocol Bitmap (WBMP)
  • *
*

This class shouldn't be used directly but using the * {@link DrawableWriterFactory}.

*/ public class BitmapWriter extends IOCapabilitiesStorage implements DrawableWriter { static { addCapabilities(new IOCapabilities( "BMP", //$NON-NLS-1$ Messages.getString("ImageIO.bmpDescription"), //$NON-NLS-1$ "image/bmp", //$NON-NLS-1$ new String[] {"bmp", "dib"} //$NON-NLS-1$ //$NON-NLS-2$ )); addCapabilities(new IOCapabilities( "GIF", //$NON-NLS-1$ Messages.getString("ImageIO.gifDescription"), //$NON-NLS-1$ "image/gif", //$NON-NLS-1$ new String[] {"gif"} //$NON-NLS-1$ )); addCapabilities(new IOCapabilities( "JPEG/JFIF", //$NON-NLS-1$ Messages.getString("ImageIO.jpegDescription"), //$NON-NLS-1$ "image/jpeg", //$NON-NLS-1$ new String[] { "jpg", "jpeg", "jpe", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ "jif", "jfif", "jfi"} //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ )); addCapabilities(new IOCapabilities( "PNG", //$NON-NLS-1$ Messages.getString("ImageIO.pngDescription"), //$NON-NLS-1$ "image/png", //$NON-NLS-1$ new String[] {"png"} //$NON-NLS-1$ )); addCapabilities(new IOCapabilities( "WBMP", //$NON-NLS-1$ Messages.getString("ImageIO.wbmpDescription"), //$NON-NLS-1$ "image/vnd.wap.wbmp", //$NON-NLS-1$ new String[] {"wbmp"} //$NON-NLS-1$ )); } /** Data format as MIME type string. */ private final String mimeType; /** Bitmap raster format. */ private final int rasterFormat; /** * Creates a new {@code BitmapWriter} object with the specified * MIME-Type. * @param mimeType Output MIME-Type. */ protected BitmapWriter(String mimeType) { this.mimeType = mimeType; boolean isAlphaSupported = "image/png".equals(mimeType); //$NON-NLS-1$ boolean isColorSupported = !"image/vnd.wap.wbmp".equals(mimeType); //$NON-NLS-1$ boolean isGrayscaleSupported = !"image/vnd.wap.wbmp".equals(mimeType); //$NON-NLS-1$ if (isColorSupported) { if (isAlphaSupported) { rasterFormat = BufferedImage.TYPE_INT_ARGB; } else { rasterFormat = BufferedImage.TYPE_INT_RGB; } } else { if (isGrayscaleSupported) { rasterFormat = BufferedImage.TYPE_BYTE_GRAY; } else { rasterFormat = BufferedImage.TYPE_BYTE_BINARY; } } // TODO Option to set transparency // TODO Possibility to choose a background color } /** * Stores the specified {@code Drawable} instance. * @param d {@code Drawable} to be written. * @param destination Stream to write to * @param width Width of the image. * @param height Height of the image. * @throws IOException if writing to stream fails */ public void write(Drawable d, OutputStream destination, double width, double height) throws IOException { write(d, destination, 0.0, 0.0, width, height); } /** * Stores the specified {@code Drawable} instance. * @param d {@code Drawable} to be written. * @param destination Stream to write to * @param x Horizontal position. * @param y Vertical position. * @param width Width of the image. * @param height Height of the image. * @throws IOException if writing to stream fails */ public void write(Drawable d, OutputStream destination, double x, double y, double width, double height) throws IOException { BufferedImage image = new BufferedImage( (int)Math.ceil(width), (int)Math.ceil(height), rasterFormat); Graphics2D imageGraphics = image.createGraphics(); imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); imageGraphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); imageGraphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); imageGraphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); DrawingContext context = new DrawingContext(imageGraphics); Iterator writers = ImageIO.getImageWritersByMIMEType(getMimeType()); if (writers.hasNext()) { ImageWriter writer = writers.next(); ImageOutputStream ios = ImageIO.createImageOutputStream(destination); writer.setOutput(ios); Rectangle2D boundsOld = d.getBounds(); d.setBounds(x, y, width, height); try { d.draw(context); writer.write(image); } finally { d.setBounds(boundsOld); ios.close(); } } } /** * Returns the output format of this writer. * @return String representing the MIME-Type. */ public String getMimeType() { return this.mimeType; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/plots/DrawableWriter.java000066400000000000000000000042661267060725100302270ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.plots; import java.io.IOException; import java.io.OutputStream; import de.erichseifert.gral.graphics.Drawable; /** * Interface providing functions for rendering {@code Drawable} * instances and writing them to an output stream. As an example: a plot * can be saved into a bitmap file. * @see DrawableWriterFactory */ public interface DrawableWriter { /** * Returns the output format of this writer. * @return String representing the MIME-Type. */ public String getMimeType(); /** * Stores the specified {@code Drawable} instance. * @param d {@code Drawable} to be written. * @param destination Stream to write to * @param width Width of the image. * @param height Height of the image. * @throws IOException if writing to stream fails */ public void write(Drawable d, OutputStream destination, double width, double height) throws IOException; /** * Stores the specified {@code Drawable} instance. * @param d {@code Drawable} to be written. * @param destination Stream to write to * @param x Horizontal position. * @param y Vertical position. * @param width Width of the image. * @param height Height of the image. * @throws IOException if writing to stream fails */ public void write(Drawable d, OutputStream destination, double x, double y, double width, double height) throws IOException; } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/plots/DrawableWriterFactory.java000066400000000000000000000064321267060725100315540ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.plots; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.text.MessageFormat; import de.erichseifert.gral.io.AbstractIOFactory; /** *

Class that provides {@code DrawableWriter} implementations for * different file formats.

* *

Example Usage:

*
 * DrawableWriterFactory factory = DrawableWriterFactory.getInstance();
 * DrawableWriter writer = factory.get("application/pdf");
 * writer.write(plot, new FileOutputStream(filename));
 * 
* * @see DrawableWriter */ public final class DrawableWriterFactory extends AbstractIOFactory { /** Singleton instance. */ private static DrawableWriterFactory instance; /** * Constructor that initializes the factory. * @throws IOException if the properties file could not be found. */ private DrawableWriterFactory() throws IOException { super("drawablewriters.properties"); //$NON-NLS-1$ } /** * Returns an instance of this DrawableWriterFactory. * @return Instance. */ public static DrawableWriterFactory getInstance() { if (instance == null) { try { instance = new DrawableWriterFactory(); } catch (IOException e) { throw new RuntimeException(e); } } return instance; } @Override public DrawableWriter get(String mimeType) { DrawableWriter writer = null; Class clazz = getTypeClass(mimeType); //IOCapabilities capabilities = getCapabilities(mimeType); try { if (clazz != null) { Constructor constructor = clazz.getDeclaredConstructor(String.class); writer = constructor.newInstance(mimeType); } } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (writer == null) { throw new IllegalArgumentException(MessageFormat.format( "Unsupported MIME type: {0}", mimeType)); //$NON-NLS-1$ } return writer; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/plots/VectorWriter.java000066400000000000000000000153211267060725100277420ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.plots; import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.graphics.DrawingContext.Quality; import de.erichseifert.gral.graphics.DrawingContext.Target; import de.erichseifert.gral.io.IOCapabilities; import de.erichseifert.gral.io.IOCapabilitiesStorage; import de.erichseifert.gral.util.Messages; /** *

Class that stores {@code Drawable} instances as vector graphics. * This implementation requires the VectorGraphics2D library to provide * support for the following file formats:

*
    *
  • Encapsulated PostScript (EPS)
  • *
  • Portable Document Format (PDF)
  • *
  • Scalable Vector Graphics (SVG)
  • *
* *

If the VectorGraphics2D library isn't available the file formats * aren't registered in the plug-in system. This class shouldn't be used directly * but using the {@link DrawableWriterFactory}.

*/ public class VectorWriter extends IOCapabilitiesStorage implements DrawableWriter { /** Mapping of MIME type string to {@code Graphics2D}lementation. */ private static final Map> graphics; /** Java package that contains the VecorGraphics2D package. */ private static final String VECTORGRAPHICS2D_PACKAGE = "de.erichseifert.vectorgraphics2d"; //$NON-NLS-1$ static { graphics = new HashMap>(); Class cls; try { cls = Class.forName(VECTORGRAPHICS2D_PACKAGE + ".EPSGraphics2D"); //$NON-NLS-1$ addCapabilities(new IOCapabilities( "EPS", //$NON-NLS-1$ Messages.getString("ImageIO.epsDescription"), //$NON-NLS-1$ "application/postscript", //$NON-NLS-1$ new String[] {"eps", "epsf", "epsi"} //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ )); graphics.put("application/postscript", cls); //$NON-NLS-1$ } catch (ClassNotFoundException e) { cls = null; } try { cls = Class.forName(VECTORGRAPHICS2D_PACKAGE + ".PDFGraphics2D"); //$NON-NLS-1$ addCapabilities(new IOCapabilities( "PDF", //$NON-NLS-1$ Messages.getString("ImageIO.pdfDescription"), //$NON-NLS-1$ "application/pdf", //$NON-NLS-1$ new String[] {"pdf"} //$NON-NLS-1$ )); graphics.put("application/pdf", cls); //$NON-NLS-1$ } catch (ClassNotFoundException e) { cls = null; } try { cls = Class.forName(VECTORGRAPHICS2D_PACKAGE + ".SVGGraphics2D"); //$NON-NLS-1$ addCapabilities(new IOCapabilities( "SVG", //$NON-NLS-1$ Messages.getString("ImageIO.svgDescription"), //$NON-NLS-1$ "image/svg+xml", //$NON-NLS-1$ new String[] {"svg", "svgz"} //$NON-NLS-1$ //$NON-NLS-2$ )); graphics.put("image/svg+xml", cls); //$NON-NLS-1$ } catch (ClassNotFoundException e) { cls = null; } } /** Current data format as MIME type string. */ private final String mimeType; /** Current {@code Graphics2D} implementation used for rendering. */ private final Class graphicsClass; /** * Creates a new {@code VectorWriter} object with the specified * MIME-Type. * @param mimeType Output MIME-Type. */ @SuppressWarnings("unchecked") protected VectorWriter(String mimeType) { this.mimeType = mimeType; Class gfxCls; try { gfxCls = (Class) graphics.get(mimeType); } catch (ClassCastException e) { gfxCls = null; } graphicsClass = gfxCls; if (graphicsClass == null) { throw new IllegalArgumentException(MessageFormat.format( "Unsupported file format: {0}", mimeType)); //$NON-NLS-1$ } } /** * Stores the specified {@code Drawable} instance. * @param d {@code Drawable} to be written. * @param destination Stream to write to * @param width Width of the image. * @param height Height of the image. * @throws IOException if writing to stream fails */ public void write(Drawable d, OutputStream destination, double width, double height) throws IOException { write(d, destination, 0.0, 0.0, width, height); } /** * Stores the specified {@code Drawable} instance. * @param d {@code Drawable} to be written. * @param destination Stream to write to * @param x Horizontal position. * @param y Vertical position. * @param width Width of the image. * @param height Height of the image. * @throws IOException if writing to stream fails */ public void write(Drawable d, OutputStream destination, double x, double y, double width, double height) throws IOException { try { // Create instance of export class Constructor constructor = graphicsClass.getConstructor( double.class, double.class, double.class, double.class); Graphics2D g = constructor.newInstance(x, y, width, height); // Output data Rectangle2D boundsOld = d.getBounds(); d.setBounds(x, y, width, height); DrawingContext context = new DrawingContext(g, Quality.QUALITY, Target.VECTOR); d.draw(context); byte[] data = (byte[]) graphicsClass.getMethod( "getBytes").invoke(g); //$NON-NLS-1$ destination.write(data); d.setBounds(boundsOld); } catch (SecurityException e) { throw new IllegalStateException(e); } catch (NoSuchMethodException e) { throw new IllegalStateException(e); } catch (IllegalArgumentException e) { throw new IllegalStateException(e); } catch (InstantiationException e) { throw new IllegalStateException(e); } catch (IllegalAccessException e) { throw new IllegalStateException(e); } catch (InvocationTargetException e) { throw new IllegalStateException(e); } } /** * Returns the output format of this writer. * @return String representing the MIME-Type. */ public String getMimeType() { return mimeType; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/io/plots/package-info.java000077500000000000000000000017461267060725100276400ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Classes for converting instances of {@code Drawable} to various file formats. */ package de.erichseifert.gral.io.plots; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/navigation/000077500000000000000000000000001267060725100250255ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/navigation/AbstractNavigator.java000066400000000000000000000212271267060725100313120ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.navigation; import java.util.HashSet; import java.util.Set; import de.erichseifert.gral.util.PointND; /** * Abstract base class that can be used to control the zoom and panning of an * object. The navigator translates actions to operations on the object. * The class provides implementations for zooming using a zoom factor, * management of listeners, getting and setting a main direction for actions, * and synchronizing actions with another navigator. * * Derived classes must use the methods * {@link #fireCenterChanged(NavigationEvent)} and * {@link #fireZoomChanged(NavigationEvent)} to notify listeners of changes to * the center or zoom level. To avoid loop states these methods must only be * called if a value has really been changed. */ public abstract class AbstractNavigator implements Navigator { /** Default zoom factor. */ public static final double DEFAULT_ZOOM_FACTOR = 1.25; /** Default minimum of zoom factor. */ public static final double DEFAULT_ZOOM_MIN = 1e-2; /** Default maximum of zoom factor. */ public static final double DEFAULT_ZOOM_MAX = 1e+2; /** Object that will be notified on navigation actions. */ private final Set navigationListeners; /** Zoom factor used for zoom in and zoom out actions. */ private double zoomFactor; /** Minimum allowed zoom level. */ private double zoomMin; /** Maximum allowed zoom level. */ private double zoomMax; /** A flag that tells whether to zoom the associated object. */ private boolean zoomable; /** A flag that tells whether to pan the associated object. */ private boolean pannable; /** The current navigation direction. */ private NavigationDirection direction; /** * Initializes a new instance that is responsible for zooming and panning * the axes with the specified names of the specified plot. */ public AbstractNavigator() { navigationListeners = new HashSet(); zoomFactor = DEFAULT_ZOOM_FACTOR; zoomMin = DEFAULT_ZOOM_MIN; zoomMax = DEFAULT_ZOOM_MAX; zoomable = true; pannable = true; } /** * Returns whether the associated object can be zoomed. * @return {@code true} if the object can be zoomed, * {@code false} otherwise. */ public boolean isZoomable() { return zoomable; } /** * Sets whether the associated object can be zoomed. * @param zoomable A value that tells whether it should be possible to zoom * the associated object. */ public void setZoomable(boolean zoomable) { this.zoomable = zoomable; } /** * Increases the current zoom level by the specified zoom factor. */ public void zoomIn() { zoomInAt(null); } /** * Decreases the current zoom level by the specified zoom factor. */ public void zoomOut() { zoomOutAt(null); } @Override public void zoomAt(double zoom, PointND zoomPoint) { if (!isZoomable()) { return; } boolean pan = isPannable() && zoomPoint != null; PointND center = null; if (pan) { center = getCenter(); setCenter(zoomPoint); } setZoom(zoom); if (pan) { setCenter(center); } } @Override public void zoomInAt(PointND zoomPoint) { double zoom = getZoom(); zoomAt(zoom*getZoomFactor(), zoomPoint); } @Override public void zoomOutAt(PointND zoomPoint) { double zoom = getZoom(); zoomAt(zoom/getZoomFactor(), zoomPoint); } /** * Returns whether the associated object can be panned. * @return {@code true} if the object can be panned, * {@code false} otherwise. */ public boolean isPannable() { return pannable; } /** * Sets whether the associated object can be panned. * @param pannable A value that tells whether it should be possible to pan * the associated object. */ public void setPannable(boolean pannable) { this.pannable = pannable; } /** * Returns the factor which is used to change the zoom level on * zoom in/out actions. * @return The current zoom factor. */ public double getZoomFactor() { return zoomFactor; } /** * Sets the factor which should be used to change the zoom level on * zoom in/out actions. * @param factor The new zoom factor. */ public void setZoomFactor(double factor) { zoomFactor = factor; } /** * Returns the minimal zoom factor. * @return Minimal zoom factor. */ public double getZoomMin() { return zoomMin; } /** * Sets the minimal zoom factor. * @param min New minimal zoom factor. */ public void setZoomMin(double min) { this.zoomMin = min; } /** * Returns the minimal zoom factor. * @return Maximal zoom factor. */ public double getZoomMax() { return zoomMax; } /** * Sets the maximal zoom factor. * @param max New maximal zoom factor. */ public void setZoomMax(double max) { this.zoomMax = max; } /** * Adds the specified listener object that gets notified on changes to * navigation information like panning or zooming. * @param l Listener object */ public void addNavigationListener(NavigationListener l) { navigationListeners.add(l); } /** * Removes the specified listener object, i.e. it doesn't get notified on * changes to navigation information like panning or zooming. * @param l Listener object */ public void removeNavigationListener(NavigationListener l) { navigationListeners.remove(l); } /** * Returns the current direction of the components that will be taken into * account for zooming and panning. * @return Direction. */ public NavigationDirection getDirection() { return direction; } /** * Sets the direction of the components that will be taken into account for * zooming and panning. * @param direction Direction. */ public void setDirection(NavigationDirection direction) { this.direction = direction; } /** * Couples the actions of the current and the specified navigator. All * actions applied to this navigator will be also applied to the specified * navigator and vice versa. * @param navigator Navigator which should be bound to this instance. */ public void connect(Navigator navigator) { if (navigator != null && navigator != this) { addNavigationListener(navigator); navigator.addNavigationListener(this); } } /** * Decouples the actions of the current and the connected specified * navigator. All actions will be applied separately to each navigator. * @param navigator Navigator to be bound to this instance. */ public void disconnect(Navigator navigator) { if (navigator != null && navigator != this) { removeNavigationListener(navigator); navigator.removeNavigationListener(this); } } /** * A method that gets called after the center of an object in a connected * {@code PlotNavigator} has changed. * @param event An object describing the change event. */ public void centerChanged(NavigationEvent> event) { if (event.getSource() != this) { setCenter(event.getValueNew()); } } /** * A method that gets called after the zoom level of an object in a * connected {@code PlotNavigator} has changed. * @param event An object describing the change event. */ public void zoomChanged(NavigationEvent event) { if (event.getSource() != this) { setZoom(event.getValueNew()); } } /** * Notifies all navigation listeners that the center of one or more * components have been changed. * @param event An object describing the change event. */ protected void fireCenterChanged(NavigationEvent> event) { for (NavigationListener l : navigationListeners) { l.centerChanged(event); } } /** * Notifies all navigation listeners that the zoom level of all components * has been changed. * @param event An object describing the change event. */ protected void fireZoomChanged(NavigationEvent event) { for (NavigationListener l : navigationListeners) { l.zoomChanged(event); } } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/navigation/Navigable.java000066400000000000000000000022231267060725100275570ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.navigation; /** * Interface for classes that can provide a {@code Navigator} which translates * navigational actions. */ public interface Navigable { /** * Returns a navigator instance that can control the current object. * @return A navigator instance. */ Navigator getNavigator(); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/navigation/NavigationDirection.java000066400000000000000000000020531267060725100316300ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.navigation; /** * Marker interface for implementation specific navigation direction, * such as horizontal, vertical for two dimensional objects. */ public interface NavigationDirection { } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/navigation/NavigationEvent.java000066400000000000000000000040101267060725100307640ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.navigation; /** * Data class that describes a navigational event, like zooming or panning. * * @param Data type of the value that has been changed. */ public class NavigationEvent { /** Object that has caused the change. */ private final Navigator source; /** Value before the change. */ private final T valueOld; /** Value after the change. */ private final T valueNew; /** * Initializes a new instance. * @param source Navigator object that has caused the change. * @param valueOld Value before the change * @param valueNew Value after the change. */ public NavigationEvent(Navigator source, T valueOld, T valueNew) { this.source = source; this.valueOld = valueOld; this.valueNew = valueNew; } /** * Returns the navigator that has caused the change. * @return Navigator object that has caused the change. */ public Navigator getSource() { return source; } /** * Returns the value before the change. * @return Value before the change. */ public T getValueOld() { return valueOld; } /** * Returns the value after the change. * @return Value after the change. */ public T getValueNew() { return valueNew; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/navigation/NavigationListener.java000066400000000000000000000030451267060725100314770ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.navigation; import de.erichseifert.gral.util.PointND; /** * An interface for classes that want to be notified on navigation changes like * panning or zooming. * * @see Navigator */ public interface NavigationListener { /** * A method that gets called after the center of an object in the * {@code PlotNavigator} has changed. * @param event An object describing the change event. */ void centerChanged(NavigationEvent> event); /** * A method that gets called after the zoom level of an object in the * {@code PlotNavigator} has changed. * @param event An object describing the change event. */ void zoomChanged(NavigationEvent event); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/navigation/Navigator.java000066400000000000000000000171271267060725100276320ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.navigation; import de.erichseifert.gral.util.PointND; /** * An interface for translating navigational interactions, such as zooming * panning to control the associated {@link Navigable} object. At the moment * the only supported operations are zooming and panning. * * A navigator stores an default state of the object that can be used to reset * the object's state after actions have been performed. This must be * implemented with the methods {@link #setDefaultState()} and * {@link #reset()}. * * Zooming and panning may be activated and deactivated using the methods * {@link #setZoomable(boolean)} and {@link #setPannable(boolean)}. * * Additionally, the actions can also be bound to a certain direction—like * horizontal or vertical—by the convenience methods {@link #getDirection()} * and {@link #setDirection(NavigationDirection)}. The data type, e.g. an enum * type, for directions must implement the interface * {@link NavigationDirection}. * * Sometimes, actions performed on an object should be applied to another * object synchronously. The methods {@link #connect(Navigator)} and * {@link #disconnect(Navigator)} may be implemented to provide functionality * for this use case. */ public interface Navigator extends NavigationListener { /** * Returns whether the associated object can be zoomed. * @return {@code true} if the object can be zoomed, * {@code false} otherwise. */ boolean isZoomable(); /** * Sets whether the associated object can be zoomed. * @param zoomable A value that tells whether it should be possible to zoom * the associated object. */ void setZoomable(boolean zoomable); /** * Returns the current zoom level of the associated object. * @return Current zoom level. */ double getZoom(); /** * Sets the zoom level of the associated object to the specified value. * @param zoom New zoom level. */ void setZoom(double zoom); /** * Increases the current zoom level by the specified zoom factor. * The zoom will only be changed if the navigator is zoomable. * * @see #isZoomable() * @see #setZoomable(boolean) */ void zoomIn(); /** * Decreases the current zoom level by the specified zoom factor. * The zoom will only be changed if the navigator is zoomable. * * @see #isZoomable() * @see #setZoomable(boolean) */ void zoomOut(); /** * Scale the associated object at the specified point. If zooming is disabled nothing will be done. If panning is * disabled zooming will be applied around the current center. * @param zoom New zoom level. * @param zoomPoint Center point for zooming in world units. */ void zoomAt(double zoom, PointND zoomPoint); /** * Increases the current zoom level by the specified zoom factor and scales * the associated object at the specified point. * @param zoomPoint Center point for zooming in world units. */ void zoomInAt(PointND zoomPoint); /** * Decreases the current zoom level by the specified zoom factor and scales * the associated object at the specified point. * @param zoomPoint Center point for zooming in world units. */ void zoomOutAt(PointND zoomPoint); /** * Returns whether the associated object can be panned. * @return {@code true} if the object can be panned, * {@code false} otherwise. */ boolean isPannable(); /** * Sets whether the associated object can be panned. * @param pannable A value that tells whether it should be possible to pan * the associated object. */ void setPannable(boolean pannable); /** * Returns the current center point. The returned point contains value in * world units. * @return Center point in world units. */ PointND getCenter(); /** * Sets a new center point. The values of the point are in world units. * The center point will only be changed if the navigator is pannable. * @param center New center point in world units. * @see #isPannable() * @see #setPannable(boolean) */ void setCenter(PointND center); /** * Moves the center by the relative values of the specified point. * The values of the point are in screen units. * The center point will only be changed if the navigator is pannable. * @param deltas Relative values to use for panning. * @see #isPannable() * @see #setPannable(boolean) */ void pan(PointND deltas); /** * Sets the current state as the default state of the object. * Resetting the navigator will then return to the default state. */ void setDefaultState(); /** * Sets the object's position and zoom level to the default state. */ void reset(); /** * Returns the factor which is used to change the zoom level on * zoom in/out actions. * @return The current zoom factor. */ double getZoomFactor(); /** * Sets the factor which should be used to change the zoom level on * zoom in/out actions. * @param factor The new zoom factor. */ void setZoomFactor(double factor); /** * Returns the minimal zoom factor. * @return Minimal zoom factor. */ double getZoomMin(); /** * Sets the minimal zoom factor. * @param min New minimal zoom factor. */ void setZoomMin(double min); /** * Returns the minimal zoom factor. * @return Maximal zoom factor. */ double getZoomMax(); /** * Sets the maximal zoom factor. * @param max New maximal zoom factor. */ void setZoomMax(double max); /** * Adds the specified listener object that gets notified on changes to * navigation information like panning or zooming. * @param l Listener object */ void addNavigationListener(NavigationListener l); /** * Removes the specified listener object, i.e. it doesn't get notified on * changes to navigation information like panning or zooming. * @param l Listener object */ void removeNavigationListener(NavigationListener l); /** * Returns the current direction of the components that will be taken into * account for zooming and panning. * @return Direction. */ NavigationDirection getDirection(); /** * Sets the direction of the components that will be taken into account for * zooming and panning. * @param direction Direction. */ void setDirection(NavigationDirection direction); /** * Couples the actions of the current and the specified navigator. All * actions applied to this navigator will be also applied to the specified * navigator and vice versa. * @param navigator Navigator which should be bound to this instance. */ void connect(Navigator navigator); /** * Decouples the actions of the current and the connected specified * navigator. All actions will be applied separately to each navigator. * @param navigator Navigator to be unbound from this instance. */ void disconnect(Navigator navigator); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/navigation/package-info.java000066400000000000000000000016571267060725100302250ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Classes for navigational operations on plots. */ package de.erichseifert.gral.navigation; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/package-info.java000077500000000000000000000016041267060725100260610ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Main classes. */ package de.erichseifert.gral; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/000077500000000000000000000000001267060725100240275ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/AbstractPlot.java000066400000000000000000000600431267060725100272770ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Stroke; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.text.MessageFormat; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import de.erichseifert.gral.data.Column; import de.erichseifert.gral.data.DataChangeEvent; import de.erichseifert.gral.data.DataListener; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.statistics.Statistics; import de.erichseifert.gral.graphics.Container; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawableContainer; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.graphics.layout.EdgeLayout; import de.erichseifert.gral.graphics.Label; import de.erichseifert.gral.graphics.layout.OuterEdgeLayout; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.legends.Legend; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.graphics.Location; import de.erichseifert.gral.util.MathUtils; import de.erichseifert.gral.util.SerializationUtils; /** * Basic implementation of a plot that can listen to changes of data sources * and settings. */ public abstract class AbstractPlot extends DrawableContainer implements Plot, DataListener { /** Version id for serialization. */ private static final long serialVersionUID = -6609155385940228771L; /** Default size of the plot title relative to the size of the base font. */ private static final float DEFAULT_TITLE_FONT_SIZE = 1.5f; /** Default space between layout components relative to the size of the base font. */ private static final float DEFAULT_LAYOUT_GAP = 2f; /** Data sources. */ private final List data; /** Set of all data sources that are visible (not hidden). */ private final Set dataVisible; /** Mapping of axis names to axis objects. */ private final Map axes; /** Mapping of axis names to axis renderer objects. */ private final Map axisRenderers; /** Mapping of axis names to drawable objects. */ private final Map axisDrawables; /** Mapping of data source columns to axes. **/ private final Map mapping; /** Minimum values of axes. **/ private final Map axisMin; /** Maximum values of axes. **/ private final Map axisMax; /** Title text of the plot. */ private final Label title; /** AbstractPlot area used to render the data. */ private PlotArea plotArea; /** Container that will store and layout the plot legend. */ private final Container legendContainer; /** AbstractPlot legend. */ private Legend legend; /** Paint to fill the plot background. */ private Paint background; /** Stroke to draw the plot border. */ private transient Stroke borderStroke; /** Paint to fill the plot border. */ private Paint borderColor; /** Base font which is used as default for other elements of the plot and for calculation of relative sizes. */ private Font font; /** Decides whether a legend will be shown. */ private boolean legendVisible; /** Positioning of the legend. */ private Location legendLocation; /** Distance of the legend to the plot area. */ private double legendDistance; /** * Initializes a new {@code AbstractPlot} instance with the specified data series. * The series will be visible by default. * @param series Initial data series to be displayed. */ public AbstractPlot(DataSource... series) { super(new EdgeLayout()); dataVisible = new HashSet(); axes = new HashMap(); axisRenderers = new HashMap(); axisDrawables = new HashMap(); mapping = new HashMap(); axisMin = new HashMap(); axisMax = new HashMap(); data = new LinkedList(); for (DataSource source : series) { add(source); } // No background or border by default background = null; borderStroke = null; borderColor = Color.BLACK; // Use system standard font as base font font = Font.decode(null); updateBaseFont(); // Create title title = new Label(); title.setFont(font.deriveFont(DEFAULT_TITLE_FONT_SIZE*font.getSize2D())); add(title, Location.NORTH); // Create legend, but don't show it by default legendContainer = new DrawableContainer(new OuterEdgeLayout(0.0)); legendLocation = Location.CENTER; legendDistance = 2.0; legendVisible = false; refreshLegendLayout(); } /** * Draws the {@code Drawable} with the specified drawing context. * @param context Environment used for drawing */ @Override public void draw(DrawingContext context) { Graphics2D graphics = context.getGraphics(); Paint bg = getBackground(); if (bg != null) { GraphicsUtils.fillPaintedShape(graphics, getBounds(), bg, null); } Stroke stroke = getBorderStroke(); if (stroke != null) { Paint fg = getBorderColor(); GraphicsUtils.drawPaintedShape( graphics, getBounds(), fg, null, stroke); } drawComponents(context); } /** * Draws the plot's axes into the specified drawing context. * @param context Environment used for drawing. */ protected void drawAxes(DrawingContext context) { for (Drawable d : axisDrawables.values()) { if (d != null) { d.draw(context); } } } /** * Draws the plot's legend into the specified drawing context. * @param context Environment used for drawing. */ protected void drawLegend(DrawingContext context) { if (!isLegendVisible() || getLegend() == null) { return; } getLegend().draw(context); } @Override public void layout() { super.layout(); layoutAxes(); layoutLegend(); } /** * Calculates the bounds of the axes. */ protected void layoutAxes() { } /** * Calculates the bounds of the legend component. */ protected void layoutLegend() { if (getPlotArea() == null) { return; } Container legendContainer = getLegendContainer(); Rectangle2D plotBounds = getPlotArea().getBounds(); legendContainer.setBounds(plotBounds); } /** * Returns the axis with the specified name. * @param name Name of the axis. * @return Axis. */ public Axis getAxis(String name) { return axes.get(name); } /** * Sets the axis with the specified name and the associated * {@code AxisRenderer}. * @param name Name of the axis. * @param axis Axis. */ public void setAxis(String name, Axis axis) { if (axis == null) { removeAxis(name); } else { axes.put(name, axis); } } /** * Removes the axis with the specified name. * @param name Name of the axis to be removed. */ public void removeAxis(String name) { axes.remove(name); axisRenderers.remove(name); axisDrawables.remove(name); } /** * Returns a collection of all names of the axes stored in this plot. * @return The names of all axes stored in this plot. */ public Collection getAxesNames() { return axes.keySet(); } /** * Creates all axes that are defined by the current plot type. */ protected void createDefaultAxes() { } /** * Creates all axis renderers that are defined by the current plot type. */ protected void createDefaultAxisRenderers() { } /** * Tries to automatically set the ranges of all axes that are set to auto-scale. * @see Axis#setAutoscaled(boolean) */ protected void autoscaleAxes() { if (data.isEmpty()) { return; } for (String axisName : getAxesNames()) { autoscaleAxis(axisName); } } /** * Tries to automatically set the ranges of the axes specified by the name * if it is set to auto-scale. * @param axisName Name of the axis that should be scaled. * @see Axis#setAutoscaled(boolean) */ public void autoscaleAxis(String axisName) { Axis axis = getAxis(axisName); if (axis == null || !axis.isAutoscaled()) { return; } double min = getAxisMin(axisName); double max = getAxisMax(axisName); double margin = 0.0*(max - min); axis.setRange(min - margin, max + margin); } /** * Returns the renderer for the axis with the specified name. * @param axisName Axis name. * @return Instance that renders the axis. */ public AxisRenderer getAxisRenderer(String axisName) { return axisRenderers.get(axisName); } /** * Sets the renderer for the axis with the specified name. * @param axisName Name of the axis to be rendered. * @param renderer Instance to render the axis. */ public void setAxisRenderer(String axisName, AxisRenderer renderer) { Drawable comp = null; if (renderer == null) { axisRenderers.remove(axisName); } else { axisRenderers.put(axisName, renderer); Axis axis = getAxis(axisName); comp = renderer.getRendererComponent(axis); } setAxisComponent(axisName, comp); layout(); } /** * Returns the component that is used to draw the specified axis. * @param axisName Name of the axis. * @return Instance that draws the axis. */ protected Drawable getAxisComponent(String axisName) { return axisDrawables.get(axisName); } /** * Sets the component that should be used for drawing the specified axis. * @param axisName Name of the axis. * @param comp Instance that draws the axis. */ private void setAxisComponent(String axisName, Drawable comp) { if (comp == null) { axisDrawables.remove(axisName); } else { axisDrawables.put(axisName, comp); } } /** * Returns the drawing area of this plot. * @return {@code PlotArea2D}. */ public PlotArea getPlotArea() { return plotArea; } /** * Sets the drawing area to the specified value. * @param plotArea {@code PlotArea2D} to be set. */ protected void setPlotArea(PlotArea plotArea) { if (this.plotArea != null) { remove(this.plotArea); this.plotArea.setBaseFont(null); } this.plotArea = plotArea; if (this.plotArea != null) { this.plotArea.setBaseFont(font); add(this.plotArea, Location.CENTER); } } /** * Returns the title component of this plot. * @return Label representing the title. */ public Label getTitle() { return title; } /** * Returns the object containing the Legend. * @return Container. */ protected Container getLegendContainer() { return legendContainer; } /** * Returns the legend component. * @return Legend. */ public Legend getLegend() { return legend; } /** * Sets the legend to the specified value. * @param legend Legend to be set. */ protected void setLegend(Legend legend) { if (this.legend != null) { legendContainer.remove(this.legend); this.legend.clear(); this.legend.setBaseFont(null); } this.legend = legend; if (this.legend != null) { this.legend.setBaseFont(font); Location constraints = getLegendLocation(); legendContainer.add(legend, constraints); for (DataSource source : getVisibleData()) { legend.add(source); } } } /** * Refreshes the positioning and spacing of the legend. */ protected void refreshLegendLayout() { double absoluteLegendDistance = 0.0; if (MathUtils.isCalculatable(legendDistance)) { absoluteLegendDistance = legendDistance*font.getSize2D(); } OuterEdgeLayout layout = new OuterEdgeLayout(absoluteLegendDistance); legendContainer.setLayout(layout); } @Override public Paint getBackground() { return background; } @Override public void setBackground(Paint background) { this.background = background; } @Override public Stroke getBorderStroke() { return borderStroke; } @Override public void setBorderStroke(Stroke border) { this.borderStroke = border; } @Override public Paint getBorderColor() { return borderColor; } @Override public void setBorderColor(Paint color) { this.borderColor = color; } @Override public Font getFont() { return font; } @Override public void setFont(Font font) { this.font = font; updateBaseFont(); } private void updateBaseFont() { // Update layout float gap = DEFAULT_LAYOUT_GAP*font.getSize2D(); getLayout().setGapX(gap); getLayout().setGapY(gap); // Update plot area if (plotArea != null) { plotArea.setBaseFont(font); } // Update legend if (legend != null) { legend.setBaseFont(font); } } @Override public boolean isLegendVisible() { return legendVisible; } @Override public void setLegendVisible(boolean legendVisible) { this.legendVisible = legendVisible; } @Override public Location getLegendLocation() { return legendLocation; } @Override public void setLegendLocation(Location location) { legendLocation = location; if (legend != null) { legendContainer.remove(legend); legendContainer.add(legend, legendLocation); } } @Override public double getLegendDistance() { return legendDistance; } @Override public void setLegendDistance(double distance) { legendDistance = distance; refreshLegendLayout(); } /** * Adds a new data series to the plot which is visible by default. * @param source Data series. */ public void add(DataSource source) { add(source, true); } /** * Adds a new data series to the plot. * @param source Data series. * @param visible {@code true} if the series should be displayed, * {@code false} otherwise. */ public void add(DataSource source, boolean visible) { add(data.size(), source, visible); } /** * Inserts the specified data series to the plot at a specified position. * @param index Position. * @param source Data series. * @param visible {@code true} if the series should be displayed, * {@code false} otherwise. */ public void add(int index, DataSource source, boolean visible) { data.add(index, source); if (visible) { dataVisible.add(source); } autoscaleAxes(); if (getLegend() != null) { getLegend().add(source); } source.addDataListener(this); invalidateAxisExtrema(); } /** * Returns whether the plot contains the specified data series. * @param source Data series. * @return {@code true} if the specified element is stored in the * plot, otherwise {@code false} */ public boolean contains(DataSource source) { return data.contains(source); } /** * Returns the data series at a specified index. * @param index Position of the data series. * @return Instance of the data series. */ public DataSource get(int index) { return data.get(index); } /** * Deletes the specified data series from the plot. * @param source Data series. * @return {@code true} if the series existed, * otherwise {@code false}. */ public boolean remove(DataSource source) { source.removeDataListener(this); dataVisible.remove(source); if (getLegend() != null) { getLegend().remove(source); } boolean existed = data.remove(source); invalidateAxisExtrema(); return existed; } /** * Removes all data series from this plot. */ public void clear() { for (DataSource source : data) { source.removeDataListener(this); } dataVisible.clear(); if (getLegend() != null) { getLegend().clear(); } data.clear(); invalidateAxisExtrema(); } /** * Returns the mapping of a data source column to an axis name. If no * mapping exists {@code null} will be returned. * @param source Data source. * @param col Column index. * @return Axis name or {@code null} if no mapping exists. */ private String getMapping(DataSource source, int col) { if (!contains(source)) { return null; } Column column = source.getColumn(col); String axisName = mapping.get(column); return axisName; } /** * Returns the mapping of data source columns to axis names. The elements * of returned array equal the column indexes, i.e. the first element (axis * name) matches the first column of {@code source}. If no mapping exists * {@code null} will be stored in the array. * @param source Data source. * @return Array containing axis names in the order of the columns, * or {@code null} if no mapping exists for the column. */ public String[] getMapping(DataSource source) { String[] mapping = new String[source.getColumnCount()]; for (int col = 0; col < mapping.length; col++) { mapping[col] = getMapping(source, col); } return mapping; } /** * Sets the mapping of data source columns to axis names. The column index * is taken from the order of the axis names, i.e. the first column of * {@code source} will be mapped to first element of {@code axisNames}. * Axis names with value {@code null} will be ignored. * @param source Data source. * @param axisNames Sequence of axis names in the order of the columns. */ public void setMapping(DataSource source, String... axisNames) { if (!contains(source)) { throw new IllegalArgumentException( "Data source does not exist in plot."); //$NON-NLS-1$ } if (axisNames.length > source.getColumnCount()) { throw new IllegalArgumentException(MessageFormat.format( "Data source only has {0,number,integer} column, {1,number,integer} values given.", //$NON-NLS-1$ source.getColumnCount(), axisNames.length)); } for (int col = 0; col < axisNames.length; col++) { String axisName = axisNames[col]; if (axisName != null) { Column column = source.getColumn(col); mapping.put(column, axisName); } } invalidateAxisExtrema(); } /** * Returns the minimum value of the axis specified by {@code axisName}. * @param axisName Name of the axis. * @return Minimum value for the specified axis, or {@code 0.0} if no * minimum value can be determined. */ protected Double getAxisMin(String axisName) { Double min = axisMin.get(axisName); if (min == null) { revalidateAxisExtrema(); min = axisMin.get(axisName); } if (min == null) { min = 0.0; } return min; } /** * Returns the maximum value of the axis specified by {@code axisName}. * @param axisName Name of the axis. * @return Maximum value for the specified axis, or {@code 0.0} if no * maximum value can be determined. */ protected Double getAxisMax(String axisName) { Double max = axisMax.get(axisName); if (max == null) { revalidateAxisExtrema(); max = axisMax.get(axisName); } if (max == null) { return 0.0; } return max; } /** * Returns a list of all data series stored in the plot. * @return List of all data series. */ public List getData() { return Collections.unmodifiableList(data); } /** * Returns a list of all visible data series stored in the plot. * @return List of all visible data series. */ public List getVisibleData() { List visible = new LinkedList(); for (DataSource s : data) { if (dataVisible.contains(s)) { visible.add(s); } } return visible; } /** * Returns whether the specified data series is drawn. * @param source Data series. * @return {@code true} if visible, {@code false} otherwise. */ public boolean isVisible(DataSource source) { return dataVisible.contains(source); } /** * Changes the visibility of the specified data series. * @param source Data series. * @param visible {@code true} if the series should be visible, * {@code false} otherwise. */ public void setVisible(DataSource source, boolean visible) { if (visible) { if (dataVisible.add(source)) { invalidateAxisExtrema(); } } else { if (dataVisible.remove(source)) { invalidateAxisExtrema(); } } } /** * Method that is invoked when data has been added. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been added. */ public void dataAdded(DataSource source, DataChangeEvent... events) { dataChanged(source, events); } /** * Method that is invoked when data has been updated. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been updated. */ public void dataUpdated(DataSource source, DataChangeEvent... events) { dataChanged(source, events); } /** * Method that is invoked when data has been removed. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been removed. */ public void dataRemoved(DataSource source, DataChangeEvent... events) { dataChanged(source, events); } /** * Method that is invoked when data has been added, updated, or removed. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been changed. */ protected void dataChanged(DataSource source, DataChangeEvent... events) { invalidateAxisExtrema(); if (getLegend() != null) { getLegend().refresh(); } autoscaleAxes(); layout(); } /** * Causes cached plot data to be be updated. */ private void invalidateAxisExtrema() { axisMin.clear(); axisMax.clear(); } /** * Rebuilds cached plot data. */ private void revalidateAxisExtrema() { synchronized (this) { for (Entry entry : mapping.entrySet()) { Column col = entry.getKey(); if (col.size() == 0) { continue; } String axisName = entry.getValue(); Double min = axisMin.get(axisName); Double max = axisMax.get(axisName); if (min == null || max == null) { min = col.getStatistics(Statistics.MIN); max = col.getStatistics(Statistics.MAX); } else { min = Math.min(min, col.getStatistics(Statistics.MIN)); max = Math.max(max, col.getStatistics(Statistics.MAX)); } axisMin.put(axisName, min); axisMax.put(axisName, max); } } } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Default deserialization in.defaultReadObject(); // Custom deserialization borderStroke = (Stroke) SerializationUtils.unwrap( (Serializable) in.readObject()); // Restore listeners for (DataSource source : getData()) { source.addDataListener(this); } } /** * Custom serialization method. * @param out Output stream. * @throws ClassNotFoundException if a serialized class doesn't exist. * @throws IOException if there is an error while writing data to the * output stream. */ private void writeObject(ObjectOutputStream out) throws ClassNotFoundException, IOException { // Default serialization out.defaultWriteObject(); // Custom serialization out.writeObject(SerializationUtils.wrap(borderStroke)); // Restore listeners for (DataSource source : getData()) { source.addDataListener(this); } } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/BarPlot.java000066400000000000000000000425571267060725100262520ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Arrays; import java.util.List; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DummyData; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.areas.AreaRenderer; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.axes.LinearRenderer2D; import de.erichseifert.gral.plots.colors.ColorMapper; import de.erichseifert.gral.plots.legends.ValueLegend; import de.erichseifert.gral.plots.lines.LineRenderer; import de.erichseifert.gral.plots.points.DefaultPointRenderer2D; import de.erichseifert.gral.plots.points.PointData; import de.erichseifert.gral.plots.points.PointRenderer; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.graphics.Location; import de.erichseifert.gral.util.MathUtils; import de.erichseifert.gral.util.PointND; import de.erichseifert.gral.util.SerializationUtils; /** *

Class that displays data in a bar plot.

*

To create a new {@code BarPlot} simply create a new instance * using one or more data sources. Example:

*
 * DataTable data = new DataTable(Integer.class, Double.class);
 * data.add(2010, -5.00);
 * data.add(2011,  3.25);
 * data.add(2012, -0.50);
 * data.add(2012,  4.00);
 *
 * BarPlot plot = new BarPlot(data);
 * 
*/ public class BarPlot extends XYPlot { /** Version id for serialization. */ private static final long serialVersionUID = 3177733647455649147L; /** Relative width of the bars. 1.0 means the bars touch each other * without gap. */ private double barWidth; /** Minimal height of the bars in pixels. */ private double barHeightMin; /** Decides whether the bars should be filled as a whole, or each bar on * its own. This can e.g. be important for gradients. */ private boolean paintAllBars; /** * Class that renders a bar in a bar plot. */ public static class BarRenderer extends DefaultPointRenderer2D { /** Version id for serialization. */ private static final long serialVersionUID = 2183638342305398522L; /** Plot that contains settings and renderers. */ private final BarPlot plot; /** Stroke to draw the border of the bar. */ // Custom serialization will be done with a wrapper object private transient Stroke borderStroke; /** Color to fill the border of the bar. */ private Paint borderColor; /** * Constructor that creates a new instance and initializes it with a * plot as data provider. * @param plot The associated plot. */ public BarRenderer(BarPlot plot) { this.plot = plot; setValueLocation(Location.NORTH); borderStroke = null; borderColor = Color.BLACK; } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Default deserialization in.defaultReadObject(); // Custom deserialization borderStroke = (Stroke) SerializationUtils.unwrap( (Serializable) in.readObject()); } /** * Custom serialization method. * @param out Output stream. * @throws ClassNotFoundException if a serialized class doesn't exist. * @throws IOException if there is an error while writing data to the * output stream. */ private void writeObject(ObjectOutputStream out) throws ClassNotFoundException, IOException { // Default serialization out.defaultWriteObject(); // Custom serialization out.writeObject(SerializationUtils.wrap(borderStroke)); } /** * Returns the stroke used to paint the outline of the point shape. * @return Stroke used to paint the outline of the point shape. */ public Stroke getBorderStroke() { return borderStroke; } /** * Sets the stroke used to paint the outline of the point shape. * @param stroke Stroke used to paint the outline of the point shape. */ public void setBorderStroke(Stroke stroke) { this.borderStroke = stroke; } /** * Returns the paint which is used to fill the point shape. * @return Paint which is used to fill the point shape. */ public Paint getBorderColor() { return borderColor; } /** * Sets the paint which will be used to fill the point shape. * @param color Paint which will be used to fill the point shape. */ public void setBorderColor(Paint color) { this.borderColor = color; } /** * Returns the graphical representation to be drawn for the specified data * value. * @param data Information on axes, renderers, and values. * @param shape Outline that describes the point's shape. * @return Component that can be used to draw the point */ @Override public Drawable getPoint(final PointData data, final Shape shape) { return new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = -3145112034673683520L; public void draw(DrawingContext context) { BarRenderer renderer = BarRenderer.this; Row row = data.row; Rectangle2D paintBoundaries = null; Graphics2D graphics = context.getGraphics(); ColorMapper colors = renderer.getColor(); Paint paint = colors.get(row.getIndex()); if (plot.isPaintAllBars()) { AffineTransform txOld = graphics.getTransform(); Rectangle2D shapeBounds = shape.getBounds2D(); paintBoundaries = new Rectangle2D.Double();//plot.getPlotArea().getBounds(); paintBoundaries = new Rectangle2D.Double( shapeBounds.getX(), paintBoundaries.getY() - txOld.getTranslateY(), shapeBounds.getWidth(), paintBoundaries.getHeight() ); } GraphicsUtils.fillPaintedShape( graphics, shape, paint, paintBoundaries); Stroke stroke = renderer.getBorderStroke(); Paint strokePaint = renderer.getBorderColor(); if (stroke != null && strokePaint != null) { GraphicsUtils.drawPaintedShape( graphics, shape, strokePaint, null, stroke); } } }; } /** * Returns a {@code Shape} instance that can be used for further * calculations. * @param data Information on axes, renderers, and values. * @return Outline that describes the point's shape. */ @Override public Shape getPointShape(PointData data) { int colX = 0; int colY = 1; Axis axisX = data.axes.get(0); Axis axisY = data.axes.get(1); AxisRenderer axisXRenderer = data.axisRenderers.get(0); AxisRenderer axisYRenderer = data.axisRenderers.get(1); Row row = data.row; if (!row.isColumnNumeric(colX) || !row.isColumnNumeric(colY)) { return null; } double valueX = ((Number) row.get(colX)).doubleValue(); double valueY = ((Number) row.get(colY)).doubleValue(); double axisYOrigin = 0.0; double barWidthRel = plot.getBarWidth(); barWidthRel = Math.max(barWidthRel, 0.0); double barAlign = 0.5; double barXMin = axisXRenderer .getPosition(axisX, valueX - barWidthRel*barAlign, true, false) .get(PointND.X); double barXMax = axisXRenderer .getPosition(axisX, valueX + barWidthRel*barAlign, true, false) .get(PointND.X); double barYVal = axisYRenderer.getPosition( axisY, valueY, true, false).get(PointND.Y); double barYOrigin = axisYRenderer.getPosition( axisY, axisYOrigin, true, false).get(PointND.Y); double barYMin = Math.min(barYVal, barYOrigin); double barYMax = Math.max(barYVal, barYOrigin); double barWidth = Math.abs(barXMax - barXMin); double barHeight = Math.abs(barYMax - barYMin); // position of the bar's left edge in screen coordinates double barX = axisXRenderer.getPosition( axisX, valueX, true, false).get(PointND.X); // position of the bar's upper edge in screen coordinates // (the origin of the screen y axis is at the top) boolean barAboveAxis = barYMax == barYOrigin; double barY = barAboveAxis ? 0.0 : -barHeight; double barHeightMin = plot.getBarHeightMin(); if (MathUtils.isCalculatable(barHeightMin) && barHeightMin > 0.0 && barHeight < barHeightMin) { if (barAboveAxis) { barY += -barHeightMin + barHeight; } barHeight = barHeightMin; } Shape shape = getBarShape( barXMin - barX, barY, barWidth, barHeight); return shape; } /** * Returns the shape for a bar. The default shape is defined in the * settings, but more complex shapes may be implemented by overriding * this method. * @param x Distance from the left in view units (e.g. pixels). * @param y Distance from the top in view units (e.g. pixels). * @param width Width of the shape in view units (e.g. pixels). * @param height Height of the shape in view units (e.g. pixels). * @return A geometric shape for displaying a bar in bar plot. */ protected Shape getBarShape(double x, double y, double width, double height) { Shape shape = getShape(); Rectangle2D shapeBounds = shape.getBounds2D(); AffineTransform tx = new AffineTransform(); tx.translate(x, y); tx.scale(width/shapeBounds.getWidth(), height/shapeBounds.getHeight()); tx.translate(-shapeBounds.getMinX(), -shapeBounds.getMinY()); Shape shapeTransformed = tx.createTransformedShape(shape); return shapeTransformed; } /** * Returns a graphical representation of the value label to be drawn for * the specified data value. * @param data Information on axes, renderers, and values. * @param shape Outline that describes the bounds for the value label. * @return Component that can be used to draw the value label. */ @Override public Drawable getValue(final PointData data, final Shape shape) { Drawable drawable = new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = -1133369168849171793L; public void draw(DrawingContext context) { PointRenderer renderer = BarRenderer.this; Row row = data.row; if (renderer.isValueVisible()) { int colValue = renderer.getValueColumn(); drawValueLabel(context, shape, row, colValue); } } }; return drawable; } } /** * A legend implementation for bar plots that displays all values of the * data source as items. */ public static class BarPlotLegend extends ValueLegend { /** Version id for serialization. */ private static final long serialVersionUID = 4752278896167602641L; /** Source for dummy data. */ private static final DataSource DUMMY_DATA = new DummyData(2, 1, 0.5); /** Plot that contains settings and renderers. */ private final BarPlot plot; /** * Constructor that initializes the instance with a plot acting as a * provider for settings and renderers. * @param plot Plot. */ public BarPlotLegend(BarPlot plot) { this.plot = plot; } /** * Returns a symbol for rendering a legend item. * @param row Data row. * @return A drawable object that can be used to display the symbol. */ public Drawable getSymbol(final Row row) { return new AbstractSymbol(this) { /** Version id for serialization. */ private static final long serialVersionUID = 5744026898590787285L; public void draw(DrawingContext context) { DataSource data = row.getSource(); Row symbolRow = new Row(DUMMY_DATA, row.getIndex()); Rectangle2D bounds = getBounds(); double barWidthRel = plot.getBarWidth(); Axis axisX = new Axis(0.5 - barWidthRel/2.0, 0.5 + barWidthRel/2.0); AxisRenderer axisRendererX = new LinearRenderer2D(); axisRendererX.setShape(new Line2D.Double( bounds.getMinX(), bounds.getMaxY(), bounds.getMaxX(), bounds.getMaxY())); Axis axisY = new Axis(0.0, 0.5); AxisRenderer axisRendererY = new LinearRenderer2D(); axisRendererY.setShape(new Line2D.Double( bounds.getMinX(), bounds.getMaxY(), bounds.getMinX(), bounds.getMinY())); PointData pointData = new PointData( Arrays.asList(axisX, axisY), Arrays.asList(axisRendererX, axisRendererY), symbolRow, 0); // TODO: Provide a means to set the PointRenderer used for the Legend PointRenderer pointRenderer = null; List pointRenderers = plot.getPointRenderers(data); if (!pointRenderers.isEmpty()) { pointRenderer = pointRenderers.get(0); } Drawable drawable = null; if (pointRenderer != null) { Shape shape = pointRenderer.getPointShape(pointData); drawable = pointRenderer.getPoint(pointData, shape); } DataPoint point = new DataPoint(pointData, new PointND(bounds.getCenterX(), bounds.getMinY())); if (drawable != null) { Graphics2D graphics = context.getGraphics(); Point2D pos = point.position.getPoint2D(); AffineTransform txOrig = graphics.getTransform(); graphics.translate(pos.getX(), pos.getY()); drawable.draw(context); graphics.setTransform(txOrig); } } }; } } /** * Creates a new instance and initializes it with the specified * data sources. * @param data Data to be displayed. */ public BarPlot(DataSource... data) { super(data); ((XYPlotArea2D) getPlotArea()).setMajorGridX(false); barWidth = 1.0; barHeightMin = 0.0; paintAllBars = false; setLegend(new BarPlotLegend(this)); autoscaleAxes(); } @Override public void autoscaleAxis(String axisName) { if (!AXIS_X.equals(axisName) && !AXIS_Y.equals(axisName)) { super.autoscaleAxis(axisName); } Axis axis = getAxis(axisName); if (axis == null || !axis.isAutoscaled()) { return; } List sources = getData(); if (sources.isEmpty()) { return; } int rowCount = 0; for (DataSource data : sources) { rowCount = Math.max(rowCount, data.getRowCount()); } if (rowCount == 0) { return; } double min = getAxisMin(axisName); double max = getAxisMax(axisName); double spacing = 0.0; if (AXIS_X.equals(axisName)) { // Add margin double barWidth = getBarWidth(); double margin = barWidth*(max - min)/rowCount; spacing = margin/2.0; } else { // Make sure 0 is always visible for y axis min = Math.min(min, 0.0); max = Math.max(max, 0.0); } axis.setRange(min - spacing, max + spacing); } @Override public void add(int index, DataSource source, boolean visible) { super.add(index, source, visible); // Assign default renderers PointRenderer pointRendererDefault = new BarRenderer(this); LineRenderer lineRendererDefault = null; AreaRenderer areaRendererDefault = null; // FIXME: Overwrites possible present point and line renderers setPointRenderers(source, pointRendererDefault); setLineRenderers(source, lineRendererDefault); setAreaRenderers(source, areaRendererDefault); } /** * Returns the width of the bars in axis coordinates. * @return Width of the bars in axis coordinates. */ public double getBarWidth() { return barWidth; } /** * Sets the width of the bars in axis coordinates. * @param barWidth Width of the bars in axis coordinates. */ public void setBarWidth(double barWidth) { this.barWidth = barWidth; } /** * Returns the minimum height of the bars in view units * (e.g. pixels on screen). * @return Minimum height of the bars in view units. */ public double getBarHeightMin() { return barHeightMin; } /** * Sets the minimum height of the bars in view units * (e.g. pixels on screen). * @param barHeightMin Minimum height of the bars in view units. */ public void setBarHeightMin(double barHeightMin) { this.barHeightMin = barHeightMin; } /** * Returns whether all bars are filled as a whole, or if each bar is filled * independently. * @return {@code true} if all bars are filled as a whole, or * {@code false} if each bar is filled independently. */ public boolean isPaintAllBars() { return paintAllBars; } /** * Sets whether all bars will be filled as a whole, or if each bar will be * filled independently. * @param paintAllBars {@code true} to fill all bars as a whole, or * {@code false} to fill each bar independently. */ public void setPaintAllBars(boolean paintAllBars) { this.paintAllBars = paintAllBars; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/BoxPlot.java000066400000000000000000000715271267060725100262750ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Arrays; import java.util.List; import de.erichseifert.gral.data.AbstractDataSource; import de.erichseifert.gral.data.Column; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.data.statistics.Statistics; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.axes.LinearRenderer2D; import de.erichseifert.gral.plots.colors.ColorMapper; import de.erichseifert.gral.plots.colors.ContinuousColorMapper; import de.erichseifert.gral.plots.colors.SingleColor; import de.erichseifert.gral.plots.legends.ValueLegend; import de.erichseifert.gral.plots.points.AbstractPointRenderer; import de.erichseifert.gral.plots.points.PointData; import de.erichseifert.gral.plots.points.PointRenderer; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.util.PointND; import de.erichseifert.gral.util.SerializationUtils; /** *

Class that displays data as a box-and-whisker plot showing summaries of * important statistical values. The data source must provide six columns to * the {@code BoxPlot}:

*
    *
  • Box position (for multiple boxes)
  • *
  • Position of the center bar (e.g. median)
  • *
  • Length of the lower whisker and position of the bottom bar * (e.g. minimum)
  • *
  • Position of the bottom edge of the box (e.g. first quartile)
  • *
  • Position of the top edge of the box (e.g. third quartile)
  • *
  • Length of the upper whisker and position of the top bar * (e.g. maximum)
  • *
*

The utility method {@link #createBoxData(DataSource)} can be used to * obtain common statistics for these properties from the each column of an * existing data source.

* *

To create a new {@code BoxPlot} simply create a new instance using * a data source. Example:

*
 * DataTable data = new DataTable(Double.class, Double.class);
 * data.add(10.98, -12.34);
 * data.add( 7.65,  45.67);
 * data.add(43.21,  89.01);
 * DataSource boxData = BoxPlot.createBoxData(data);
 * BoxPlot plot = new BoxPlot(boxData);
 * 
*/ public class BoxPlot extends XYPlot { /** Version id for serialization. */ private static final long serialVersionUID = -3069831535208696337L; /** * Class that renders a box and its whiskers in a box-and-whisker plot. */ public static class BoxWhiskerRenderer extends AbstractPointRenderer { /** Version id for serialization. */ private static final long serialVersionUID = 2944482729753981341L; /** Index of the column for the horizontal position of a box. */ private int positionColumn; /** Index of the column for the vertical center bar. */ private int centerBarColumn; /** Index of the column for the lower vertical bar. */ private int bottomBarColumn; /** Index of the column for the lower end of the box. */ private int boxBottomColumn; /** Index of the column for the upper end of the box. */ private int boxTopColumn; /** Index of the column for the upper vertical bar. */ private int topBarColumn; /** Relative width of each box. 1.0 means boxes touch each other. */ private double boxWidth; /** Color mapping to fill the background of the boxes. */ private ColorMapper boxBackground; /** Paint to fill the border of the boxes. */ private Paint boxBorderColor; /** Stroke to draw the border of the boxes. */ private transient Stroke boxBorderStroke; /** Paint to fill the border of the whiskers. */ private Paint whiskerColor; /** Stroke to draw the border of the whiskers. */ private transient Stroke whiskerStroke; /** Relative width of the vertical bars. */ private double barWidth; /** Paint to fill the center bar. */ private Paint centerBarColor; /** Stroke to draw the center bar. */ private transient Stroke centerBarStroke; /** * Constructor that creates a new instance and initializes it with a * plot as data provider. */ public BoxWhiskerRenderer() { positionColumn = 0; centerBarColumn = 1; bottomBarColumn = 2; boxBottomColumn = 3; boxTopColumn = 4; topBarColumn = 5; boxWidth = 0.75; boxBackground = new SingleColor(Color.WHITE); boxBorderColor = Color.BLACK; boxBorderStroke = new BasicStroke(1f); whiskerColor = Color.BLACK; whiskerStroke = new BasicStroke(1f); barWidth = 0.75; centerBarColor = Color.BLACK; centerBarStroke = new BasicStroke( 2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Default deserialization in.defaultReadObject(); // Custom deserialization boxBorderStroke = (Stroke) SerializationUtils.unwrap( (Serializable) in.readObject()); whiskerStroke = (Stroke) SerializationUtils.unwrap( (Serializable) in.readObject()); centerBarStroke = (Stroke) SerializationUtils.unwrap( (Serializable) in.readObject()); } /** * Custom serialization method. * @param out Output stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while writing data to the * output stream. */ private void writeObject(ObjectOutputStream out) throws ClassNotFoundException, IOException { // Default serialization out.defaultWriteObject(); // Custom serialization out.writeObject(SerializationUtils.wrap(boxBorderStroke)); out.writeObject(SerializationUtils.wrap(whiskerStroke)); out.writeObject(SerializationUtils.wrap(centerBarStroke)); } /** * Returns the index of the column which is used for the horizontal * position of a box. * @return Index of the column that is used for the horizontal position * of a box. */ public int getPositionColumn() { return positionColumn; } /** * Sets the index of the column which will be used for the horizontal * position of a box. * @param columnIndex Index of the column that is used for the * horizontal position of a box. */ public void setPositionColumn(int columnIndex) { this.positionColumn = columnIndex; } /** * Returns the index of the column which is used for the center bar. * @return Index of the column which is used for the center bar. */ public int getCenterBarColumn() { return centerBarColumn; } /** * Sets the index of the column which will be used for the center bar. * @param columnIndex Index of the column which will be used for * the center bar. */ public void setCenterBarColumn(int columnIndex) { this.centerBarColumn = columnIndex; } /** * Returns the index of the column which is used for the bottom bar. * @return Index of the column which is used for the bottom bar. */ public int getBottomBarColumn() { return bottomBarColumn; } /** * Sets the index of the column which will be used for the bottom bar. * @param columnIndex Index of the column which will be used for * the bottom bar. */ public void setBottomBarColumn(int columnIndex) { this.bottomBarColumn = columnIndex; } /** * Returns the index of the column which is used for the bottom edge of * the box. * @return Index of the column which is used for the bottom edge of the * box. */ public int getBoxBottomColumn() { return boxBottomColumn; } /** * Sets the index of the column which will be used for the bottom edge * of the box. * @param columnIndex Index of the column which will be used for * the bottom edge of the box. */ public void setColumnBoxBottom(int columnIndex) { this.boxBottomColumn = columnIndex; } /** * Returns the index of the column which is used for the top edge of * the box. * @return Index of the column which is used for the top edge of the * box. */ public int getBoxTopColumn() { return boxTopColumn; } /** * Sets the index of the column which will be used for the top edge of * the box. * @param columnIndex Index of the column which will be used for the * top edge of the box. */ public void setBoxTopColumn(int columnIndex) { this.boxTopColumn = columnIndex; } /** * Returns the index of the column which is used for the top bar. * @return Index of the column which is used for the top bar. */ public int getTopBarColumn() { return topBarColumn; } /** * Sets the index of the column which will be used for the top bar. * @param columnIndex Index of the column which will be used for the * top bar. */ public void setTopBarColumn(int columnIndex) { this.topBarColumn = columnIndex; } /** * Returns the relative width of the box. * @return Relative width of the box. */ public double getBoxWidth() { return boxWidth; } /** * Sets the relative width of the box. * @param boxWidth Relative width of the box. */ public void setBoxWidth(double boxWidth) { this.boxWidth = boxWidth; } /** * Returns the mapping which is used to fill the background of a box. * @return {@code ColorMapper} instance which is used to fill the * background of a box. */ public ColorMapper getBoxBackground() { return boxBackground; } /** * Sets the mapping which will be used to fill the background of a box. * @param color {@code ColorMapper} instance which will be used to fill * the background of a box. */ public void setBoxBackground(ColorMapper color) { this.boxBackground = color; } /** * Sets the paint which will be used to fill the background of a box. * @param color {@code Paint} instance which will be used to fill the * background of a box. */ public void setBoxBackground(Paint color) { setBoxBackground(new SingleColor(color)); } /** * Returns the paint which is used to fill the border of a box and the * lines of bars. * @return Paint which is used to fill the border of a box and the * lines of bars. */ public Paint getBoxBorderColor() { return boxBorderColor; } /** * Sets the paint which will be used to fill the border of a box and * the lines of bars. * @param color Paint which will be used to fill the border of a box * and the lines of bars. */ public void setBoxBorderColor(Paint color) { this.boxBorderColor = color; } /** * Returns the stroke which is used to paint the border of a box and * the lines of the bars. * @return {@code Stroke} instance which is used to paint the border of * a box and the lines of the bars. */ public Stroke getBoxBorderStroke() { return boxBorderStroke; } /** * Sets the stroke which will be used to paint the border of a box and * the lines of the bars. * @param stroke {@code Stroke} instance which will be used to paint * the border of a box and the lines of the bars. */ public void setBoxBorderStroke(Stroke stroke) { this.boxBorderStroke = stroke; } /** * Returns the paint which is used to fill the lines of the whiskers. * @return Paint which is used to fill the lines of the whiskers. */ public Paint getWhiskerColor() { return whiskerColor; } /** * Sets the paint which will be used to fill the lines of the whiskers. * @param color Paint which will be used to fill the lines of the * whiskers. */ public void setWhiskerColor(Paint color) { this.whiskerColor = color; } /** * Returns the stroke which is used to paint the lines of the whiskers. * @return {@code Stroke} instance which is used to paint the lines of * the whiskers. */ public Stroke getWhiskerStroke() { return whiskerStroke; } /** * Sets the stroke which will be used to paint the lines of the * whiskers. * @param stroke {@code Stroke} instance which will be used to paint * the lines of the whiskers. */ public void setWhiskerStroke(Stroke stroke) { this.whiskerStroke = stroke; } /** * Returns the relative width of the bottom and top bars. * @return Relative width of the bottom and top bars. */ public double getBarWidth() { return barWidth; } /** * Sets the relative width of the bottom and top bars. * @param width Relative width of the bottom and top bars. */ public void setBarWidth(double width) { this.barWidth = width; } /** * Returns the paint which is used to fill the lines of the center bar. * @return Paint which is used to fill the lines of the center bar. */ public Paint getCenterBarColor() { return centerBarColor; } /** * Sets the paint which will be used to fill the lines of the center * bar. * @param color Paint which will be used to fill the lines of the * center bar. */ public void setCenterBarColor(Paint color) { this.centerBarColor = color; } /** * Returns the stroke which is used to paint the lines of the center * bar. * @return {@code Stroke} instance which is used to paint the lines of * the center bar. */ public Stroke getCenterBarStroke() { return centerBarStroke; } /** * Sets the stroke which will be used to paint the lines of the * center bar. * @param stroke {@code Stroke} instance which will be used to paint * the lines of the center bar. */ public void setCenterBarStroke(Stroke stroke) { this.centerBarStroke = stroke; } /** * Returns the graphical representation to be drawn for the specified * data value. * @param data Information on axes, renderers, and values. * @param shape Outline that describes the point's shape. * @return Component that can be used to draw the point */ public Drawable getPoint(final PointData data, final Shape shape) { return new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = 2765031432328349977L; public void draw(DrawingContext context) { Axis axisX = data.axes.get(0); Axis axisY = data.axes.get(1); AxisRenderer axisXRenderer = data.axisRenderers.get(0); AxisRenderer axisYRenderer = data.axisRenderers.get(1); Row row = data.row; // Get the values from data columns BoxWhiskerRenderer renderer = BoxWhiskerRenderer.this; int colPos = renderer.getPositionColumn(); int colBarCenter = renderer.getCenterBarColumn(); int colBarBottom = renderer.getBottomBarColumn(); int colBoxBottom = renderer.getBoxBottomColumn(); int colBoxTop = renderer.getBoxTopColumn(); int colBarTop = renderer.getTopBarColumn(); if (!row.isColumnNumeric(colPos) || !row.isColumnNumeric(colBarCenter) || !row.isColumnNumeric(colBarBottom) || !row.isColumnNumeric(colBoxBottom) || !row.isColumnNumeric(colBoxTop) || !row.isColumnNumeric(colBarTop)) { return; } double valueX = ((Number) row.get(colPos)).doubleValue(); double valueYBarBottom = ((Number) row.get(colBarBottom)).doubleValue(); double valueYBoxBottom = ((Number) row.get(colBoxBottom)).doubleValue(); double valueYBarCenter = ((Number) row.get(colBarCenter)).doubleValue(); double valueYBoxTop = ((Number) row.get(colBoxTop)).doubleValue(); double valueYBarTop = ((Number) row.get(colBarTop)).doubleValue(); // Calculate positions in screen units double boxWidthRel = getBoxWidth(); double boxAlign = 0.5; // Box X double boxXMin = axisXRenderer .getPosition(axisX, valueX - boxWidthRel*boxAlign, true, false) .get(PointND.X); double boxX = axisXRenderer.getPosition( axisX, valueX, true, false).get(PointND.X); double boxXMax = axisXRenderer .getPosition(axisX, valueX + boxWidthRel*boxAlign, true, false) .get(PointND.X); // Box Y double barYbottom = axisYRenderer.getPosition( axisY, valueYBarBottom, true, false).get(PointND.Y); double boxYBottom = axisYRenderer.getPosition( axisY, valueYBoxBottom, true, false).get(PointND.Y); double barYCenter = axisYRenderer.getPosition( axisY, valueYBarCenter, true, false).get(PointND.Y); double boxYTop = axisYRenderer.getPosition( axisY, valueYBoxTop, true, false).get(PointND.Y); double barYTop = axisYRenderer.getPosition( axisY, valueYBarTop, true, false).get(PointND.Y); double boxWidth = Math.abs(boxXMax - boxXMin); // Bars double barWidthRel = getBarWidth(); double barXMin = boxXMin + (1.0 - barWidthRel)*boxWidth/2.0; double barXMax = boxXMax - (1.0 - barWidthRel)*boxWidth/2.0; // Create shapes // The origin of all shapes is (boxX, boxY) Rectangle2D boxBounds = new Rectangle2D.Double( boxXMin - boxX, boxYTop - barYCenter, boxWidth, Math.abs(boxYTop - boxYBottom)); Rectangle2D shapeBounds = shape.getBounds2D(); AffineTransform tx = new AffineTransform(); tx.translate(boxBounds.getX(), boxBounds.getY()); tx.scale(boxBounds.getWidth()/shapeBounds.getWidth(), boxBounds.getHeight()/shapeBounds.getHeight()); tx.translate(-shapeBounds.getMinX(), -shapeBounds.getMinY()); Shape box = tx.createTransformedShape(shape); Line2D whiskerMax = new Line2D.Double( 0.0, boxYTop - barYCenter, 0.0, barYTop - barYCenter ); Line2D whiskerMin = new Line2D.Double( 0.0, boxYBottom - barYCenter, 0.0, barYbottom - barYCenter ); Line2D barMax = new Line2D.Double( barXMin - boxX, barYTop - barYCenter, barXMax - boxX, barYTop - barYCenter ); Line2D barMin = new Line2D.Double( barXMin - boxX, barYbottom - barYCenter, barXMax - boxX, barYbottom - barYCenter ); Line2D barCenter = new Line2D.Double( boxXMin - boxX, 0.0, boxXMax - boxX, 0.0 ); // Paint shapes Graphics2D graphics = context.getGraphics(); ColorMapper paintBoxMapper = getBoxBackground(); Paint paintBox; if (paintBoxMapper instanceof ContinuousColorMapper) { paintBox = ((ContinuousColorMapper) paintBoxMapper) .get(valueX); } else { int index = row.getIndex(); paintBox = paintBoxMapper.get(index); } Paint paintStrokeBox = getBoxBorderColor(); Stroke strokeBox = getBoxBorderStroke(); Paint paintWhisker = getWhiskerColor(); Stroke strokeWhisker = getWhiskerStroke(); Paint paintBarCenter = getCenterBarColor(); Stroke strokeBarCenter = getCenterBarStroke(); // Fill box GraphicsUtils.fillPaintedShape( graphics, box, paintBox, box.getBounds2D()); // Save current graphics state Paint paintOld = graphics.getPaint(); Stroke strokeOld = graphics.getStroke(); // Draw whiskers graphics.setPaint(paintWhisker); graphics.setStroke(strokeWhisker); graphics.draw(whiskerMax); graphics.draw(whiskerMin); // Draw box and bars graphics.setPaint(paintStrokeBox); graphics.setStroke(strokeBox); graphics.draw(box); graphics.draw(barMax); graphics.draw(barMin); graphics.setPaint(paintBarCenter); graphics.setStroke(strokeBarCenter); graphics.draw(barCenter); // Restore previous graphics state graphics.setStroke(strokeOld); graphics.setPaint(paintOld); } }; } /** * Returns a {@code Shape} instance that can be used for further * calculations. * @param data Information on axes, renderers, and values. * @return Outline that describes the point's shape. */ public Shape getPointShape(PointData data) { return getShape(); } /** * Returns a graphical representation of the value label to be drawn for * the specified data value. * @param data Information on axes, renderers, and values. * @param shape Outline that describes the bounds for the value label. * @return Component that can be used to draw the value label. */ public Drawable getValue(final PointData data, final Shape shape) { Drawable drawable = new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = 6788431763837737592L; public void draw(DrawingContext context) { // TODO Implement rendering of value label } }; return drawable; } } /** * A legend implementation for box-and-whisker plots that displays all * values of the data source as items. */ public static class BoxPlotLegend extends ValueLegend { /** Version id for serialization. */ private static final long serialVersionUID = 1517792984459627757L; /** Source for dummy data. */ @SuppressWarnings("unchecked") private static final DataSource DUMMY_DATA = new AbstractDataSource( Double.class, Double.class, Double.class, Double.class, Double.class, Double.class) { /** Version id for serialization. */ private static final long serialVersionUID = -8233716728143117368L; /** Positions of x position, center bar, bottom bar, box bottom, box top, and top bar. */ private final Double[] values = { 0.5, 0.0, 0.0, 1.0, 1.0 }; /** * Returns the number of rows of the data source. * @return number of rows in the data source. */ public int getRowCount() { return 1; } /** * Returns the value with the specified row and column index. * @param col index of the column to return * @param row index of the row to return * @return the specified value of the data cell */ public Comparable get(int col, int row) { if (col == 0) { return (double) (row + 1); } return values[col - 1]; } }; /** Associated plot. */ private final BoxPlot plot; /** * Initializes a new instance with the specified plot. * @param plot Associated plot. */ public BoxPlotLegend(BoxPlot plot) { this.plot = plot; } /** * Returns a symbol for rendering a legend item. * @param row Data row. * @return A drawable object that can be used to display the symbol. */ public Drawable getSymbol(final Row row) { return new AbstractSymbol(this) { /** Version id for serialization. */ private static final long serialVersionUID = 1906894939358065143L; /** * Draws the {@code Drawable} with the specified drawing context. * @param context Environment used for drawing */ public void draw(DrawingContext context) { DataSource data = row.getSource(); // TODO: Provide a means to set the PointRenderer used for the Legend BoxWhiskerRenderer pointRenderer = null; List pointRenderers = plot.getPointRenderers(data); for (PointRenderer p : pointRenderers) { if (pointRenderer instanceof BoxWhiskerRenderer) { pointRenderer = (BoxWhiskerRenderer) p; break; } } if (pointRenderer == null) { return; } Row symbolRow = new Row(DUMMY_DATA, row.getIndex()); Rectangle2D bounds = getBounds(); double boxWidthRel = pointRenderer.getBoxWidth(); double posX = ((Number) row.get(0)).doubleValue(); Axis axisX = new Axis(posX - boxWidthRel/2.0, posX + boxWidthRel/2.0); AxisRenderer axisRendererX = new LinearRenderer2D(); axisRendererX.setShape(new Line2D.Double( bounds.getMinX(), bounds.getMaxY(), bounds.getMaxX(), bounds.getMaxY())); Axis axisY = new Axis(1.0, 2.0); AxisRenderer axisRendererY = new LinearRenderer2D(); axisRendererY.setShape(new Line2D.Double( bounds.getMinX(), bounds.getMaxY(), bounds.getMinX(), bounds.getMinY())); PointData pointData = new PointData( Arrays.asList(axisX, axisY), Arrays.asList(axisRendererX, axisRendererY), symbolRow, 0); Shape shape = pointRenderer.getPointShape(pointData); DataPoint point = new DataPoint(pointData, new PointND(bounds.getCenterX(), bounds.getCenterY())); Graphics2D graphics = context.getGraphics(); graphics.draw(bounds); Point2D pos = point.position.getPoint2D(); AffineTransform txOrig = graphics.getTransform(); graphics.translate(pos.getX(), pos.getY()); Drawable drawable = pointRenderer.getPoint(pointData, shape); drawable.draw(context); graphics.setTransform(txOrig); } }; } } /** * Initializes a new box-and-whisker plot with the specified data source. * @param data Data to be displayed. */ public BoxPlot(DataSource data) { setLegend(new BoxPlotLegend(this)); ((XYPlotArea2D) getPlotArea()).setMajorGridX(false); getAxisRenderer(AXIS_X).setTickSpacing(1.0); getAxisRenderer(AXIS_X).setMinorTicksVisible(false); getAxisRenderer(AXIS_X).setIntersection(-Double.MAX_VALUE); getAxisRenderer(AXIS_Y).setIntersection(-Double.MAX_VALUE); add(data); autoscaleAxes(); } /** * Extracts statistics from the columns of an data source that are commonly * used for box-and-whisker plots. The result is a new data source * containing column index, median, mininum, first * quartile, third quartile, and maximum for each column. * @param data Original data source * @return New data source with (columnIndex, median, min, quartile1, * quartile3, max) */ @SuppressWarnings("unchecked") public static DataSource createBoxData(DataSource data) { if (data == null) { throw new NullPointerException( "Cannot extract statistics from null data source."); } DataTable stats = new DataTable(Integer.class, Double.class, Double.class, Double.class, Double.class, Double.class); // Generate statistical values for each column for (int c = 0; c < data.getColumnCount(); c++) { Column col = data.getColumn(c); if (!col.isNumeric()) { continue; } stats.add( c + 1, col.getStatistics(Statistics.MEDIAN), col.getStatistics(Statistics.MIN), col.getStatistics(Statistics.QUARTILE_1), col.getStatistics(Statistics.QUARTILE_3), col.getStatistics(Statistics.MAX) ); } return stats; } @Override public void add(int index, DataSource source, boolean visible) { if (getData().size() > 0) { throw new IllegalArgumentException( "This plot type only supports a single data source."); //$NON-NLS-1$ } super.add(index, source, visible); // FIXME: Overwrites possible present point and line renderers setLineRenderers(source, null); setPointRenderers(source, new BoxWhiskerRenderer()); } @Override public void autoscaleAxis(String axisName) { if (!AXIS_X.equals(axisName) && !AXIS_Y.equals(axisName)) { super.autoscaleAxis(axisName); } Axis axis = getAxis(axisName); if (axis == null || !axis.isAutoscaled()) { return; } List sources = getData(); if (sources.isEmpty()) { return; } boolean isXAxis = AXIS_X.equals(axisName); double min = Double.MAX_VALUE; double max = Double.MIN_VALUE; for (DataSource data : sources) { BoxWhiskerRenderer pointRenderer = null; for (PointRenderer p : getPointRenderers(data)) { if (p instanceof BoxWhiskerRenderer) { pointRenderer = (BoxWhiskerRenderer) p; break; } } if (pointRenderer == null) { continue; } int minColumnIndex, maxColumnIndex; if (isXAxis) { minColumnIndex = pointRenderer.getPositionColumn(); maxColumnIndex = pointRenderer.getPositionColumn(); } else { minColumnIndex = pointRenderer.getBottomBarColumn(); maxColumnIndex = pointRenderer.getTopBarColumn(); } min = Math.min(min, data.getColumn(minColumnIndex) .getStatistics(Statistics.MIN)); max = Math.max(max, data.getColumn(maxColumnIndex) .getStatistics(Statistics.MAX)); } double spacing = (isXAxis) ? 0.5 : 0.05*(max - min); axis.setRange(min - spacing, max + spacing); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/DataPoint.java000066400000000000000000000030561267060725100265610ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import de.erichseifert.gral.plots.points.PointData; import de.erichseifert.gral.util.PointND; /** * Class for storing points of a plot. */ public class DataPoint { /** Axes and data values that were used to create the data point. */ public final PointData data; /** Position of the data point (n-dimensional). */ public final PointND position; /** * Creates a new {@code DataPoint} object with the specified position, * {@code Drawable}, and shape. * @param data Data that this point was created from. * @param position Coordinates in view/screen units. */ public DataPoint(PointData data, PointND position) { this.data = data; this.position = position; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/PiePlot.java000066400000000000000000001013561267060725100262540ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import java.awt.BasicStroke; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.Arc2D; import java.awt.geom.Area; import java.awt.geom.Dimension2D; import java.awt.geom.Ellipse2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.io.ObjectInputStream; import java.text.Format; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import de.erichseifert.gral.data.Column; import de.erichseifert.gral.data.DataChangeEvent; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.graphics.Label; import de.erichseifert.gral.navigation.AbstractNavigator; import de.erichseifert.gral.navigation.Navigable; import de.erichseifert.gral.navigation.Navigator; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.axes.LinearRenderer2D; import de.erichseifert.gral.plots.colors.ColorMapper; import de.erichseifert.gral.plots.colors.ContinuousColorMapper; import de.erichseifert.gral.plots.colors.QuasiRandomColors; import de.erichseifert.gral.plots.legends.ValueLegend; import de.erichseifert.gral.plots.points.AbstractPointRenderer; import de.erichseifert.gral.plots.points.PointData; import de.erichseifert.gral.plots.points.PointRenderer; import de.erichseifert.gral.util.GeometryUtils; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.graphics.Insets2D; import de.erichseifert.gral.graphics.Location; import de.erichseifert.gral.util.MathUtils; import de.erichseifert.gral.util.PointND; /** *

Class that displays data as segments of a pie plot. Empty segments are * displayed for negative values.

*

To create a new {@code PiePlot} simply create a new instance using * a data source. Example:

*
 * DataTable data = new DataTable(Integer.class, Double.class);
 * data.add(-23.50);
 * data.add(100.00);
 * data.add( 60.25);
 *
 * PiePlot plot = new PiePlot(data);
 * 
*/ public class PiePlot extends AbstractPlot implements Navigable { /** Version id for serialization. */ private static final long serialVersionUID = 5486418164040578150L; /** Key for specifying the tangential axis of a pie plot. */ public static final String AXIS_TANGENTIAL = "tangential"; //$NON-NLS-1$ /** Mapping from data source to point renderer. */ private final Map pointRenderers; /** Slice objects with start and end position for each visible data source. */ private transient Map> slices; /** Cache for the {@code Navigator} implementation. */ private transient PiePlotNavigator navigator; /** Position of the pie center. */ private final Point2D center; /** Radius of the the pie. */ private double radius; /** Starting angle in degrees. */ private double start; /** Decides whether pie slices are drawn in clockwise direction. */ private boolean clockwise; /** * Navigator implementation for pie plots. Zooming changes the * {@code RADIUS} setting and panning the {@code CENTER} setting. */ public static class PiePlotNavigator extends AbstractNavigator { /** Pie plot that will be navigated. */ private final PiePlot plot; /** Location of center in default state. */ private PointND centerOriginal; /** Zoom level in default state. */ private double zoomOriginal; /** Current zoom level. */ private double zoom; /** * Initializes a new instance with a pie plot to be navigated. * @param plot Pie plot. */ public PiePlotNavigator(PiePlot plot) { this.plot = plot; this.zoom = 1.0; setDefaultState(); } /** * Returns the current zoom level of the associated object. * @return Current zoom level. */ public double getZoom() { return zoom; } /** * Sets the zoom level of the associated object to the specified value. * @param zoomNew New zoom level. */ public void setZoom(double zoomNew) { if (!isZoomable() || (zoomNew <= 0.0) || !MathUtils.isCalculatable(zoomNew)) { return; } double zoomOld = getZoom(); zoomNew = MathUtils.limit(zoomNew, getZoomMin(), getZoomMax()); if (zoomOld == zoomNew) { return; } zoom = zoomNew; plot.setRadius(zoomOriginal*getZoom()); } /** * Returns the current center point. The returned point contains value in * world units. * @return Center point in world units. */ public PointND getCenter() { Point2D center = plot.getCenter(); return new PointND(center.getX(), center.getY()); } /** * Sets a new center point. The values of the point are in world units. * @param center New center point in world units. */ public void setCenter(PointND center) { if (center == null || !isPannable()) { return; } Point2D center2d = center.getPoint2D(); plot.setCenter(center2d); } /** * Moves the center by the relative values of the specified point. * The values of the point are in screen units. * @param deltas Relative values to use for panning. */ @SuppressWarnings("unchecked") public void pan(PointND deltas) { PlotArea plotArea = plot.getPlotArea(); PointND center = (PointND) getCenter(); double x = center.get(0).doubleValue(); x += deltas.get(0).doubleValue()/plotArea.getWidth(); double y = center.get(1).doubleValue(); y += deltas.get(1).doubleValue()/plotArea.getHeight(); center.set(0, x); center.set(1, y); setCenter(center); } /** * Sets the object's position and zoom level to the default state. */ public void reset() { setCenter(centerOriginal); setZoom(1.0); } /** * Sets the current state as the default state of the object. * Resetting the navigator will then return to the default state. */ public void setDefaultState() { centerOriginal = getCenter(); zoomOriginal = plot.getRadius(); } } /** * Class that represents the drawing area of a {@code PiePlot}. */ public static class PiePlotArea2D extends PlotArea { /** Version id for serialization. */ private static final long serialVersionUID = 5646816099037852271L; /** Pie plot that this renderer is associated to. */ private final PiePlot plot; /** * Constructor that creates a new instance and initializes it with a * plot acting as data provider. * @param plot Data provider. */ public PiePlotArea2D(PiePlot plot) { this.plot = plot; } /** * Draws the {@code Drawable} with the specified drawing context. * @param context Environment used for drawing */ public void draw(DrawingContext context) { drawBackground(context); drawBorder(context); drawPlot(context); plot.drawLegend(context); } @Override protected void drawPlot(DrawingContext context) { Graphics2D graphics = context.getGraphics(); Shape clipBoundsOld = graphics.getClip(); Insets2D clipOffset = getClippingOffset(); if (clipOffset != null) { final double fontSize = getBaseFont().getSize2D(); // Perform clipping Shape clipBounds = new Rectangle2D.Double( getX() + clipOffset.getLeft()*fontSize, getY() + clipOffset.getTop()*fontSize, getWidth() - clipOffset.getHorizontal()*fontSize, getHeight() - clipOffset.getVertical()*fontSize ); // Take care of old clipping region. This is used when getting // scrolled in a JScrollPane for example. if (clipBoundsOld != null) { Area clipBoundsNew = new Area(clipBoundsOld); clipBoundsNew.intersect(new Area(clipBounds)); clipBounds = clipBoundsNew; } graphics.setClip(clipBounds); } AffineTransform txOrig = graphics.getTransform(); graphics.translate(getX(), getY()); // Get width and height of the plot area for relative sizes Rectangle2D bounds = getBounds(); // Move to center, so origin for point renderers will be (0, 0) Point2D center = plot.getCenter(); if (center == null) { center = new Point2D.Double(0.5, 0.5); } graphics.translate( center.getX()*bounds.getWidth(), center.getY()*bounds.getHeight() ); // Paint points and lines for (DataSource s : plot.getVisibleData()) { // Skip empty data source if (s.getColumnCount() == 0) { continue; } // TODO Use property for column index int colIndex = 0; if (colIndex < 0 || colIndex >= s.getColumnCount() || !s.isColumnNumeric(colIndex)) { continue; } PointRenderer pointRenderer = plot.getPointRenderer(s); String[] axisNames = plot.getMapping(s); // TODO Use loop to get all axes instead of direct access Axis axis = plot.getAxis(axisNames[0]); if (!axis.isValid()) { continue; } AxisRenderer axisRenderer = plot.getAxisRenderer(axisNames[0]); List axes = Arrays.asList(axis); List axisRenderers = Arrays.asList(axisRenderer); // Draw graphics for (int rowIndex = 0; rowIndex < s.getRowCount(); rowIndex++) { Row row = s.getRow(rowIndex); PointData pointData = new PointData( axes, axisRenderers, row, 0); Shape shape = pointRenderer.getPointShape(pointData); Drawable point = pointRenderer.getPoint(pointData, shape); point.setBounds(bounds); point.draw(context); } // Draw labels for (int rowIndex = 0; rowIndex < s.getRowCount(); rowIndex++) { Row row = s.getRow(rowIndex); PointData pointData = new PointData( axes, axisRenderers, row, 0); Shape shape = pointRenderer.getPointShape(pointData); Drawable point = pointRenderer.getValue(pointData, shape); point.setBounds(bounds); point.draw(context); } } graphics.setTransform(txOrig); if (clipOffset != null) { // Reset clipping graphics.setClip(clipBoundsOld); } } } /** * Data class for storing slice information in world units. */ protected static final class Slice { /** Value where the slice starts. */ public final double start; /** Value where the slice ends. */ public final double end; /** * Initializes a new slice with start and end value. * @param start Value where the slice starts. * @param end Value where the slice ends. */ public Slice(double start, double end) { this.start = start; this.end = end; } } /** * A point renderer for a single slice in a pie plot. */ public static class PieSliceRenderer extends AbstractPointRenderer { /** Version id for serialization. */ private static final long serialVersionUID = 1135636437801090607L; /** Pie plot this renderer is attached to. */ private final PiePlot plot; /** Relative outer radius of the current pie slice, * in percentage of the total radius. */ private double outerRadius; /** Relative inner radius of the current pie slice, * in percentage of the total radius. */ private double innerRadius; /** Gap of the current pie slice, in pixels. */ private double gap; /** * Initializes a new instance with a pie plot object. * @param plot Pie plot. */ public PieSliceRenderer(PiePlot plot) { this.plot = plot; setValueColumn(0); setErrorColumnTop(1); setErrorColumnBottom(2); setColor(new QuasiRandomColors()); outerRadius = 1.0; innerRadius = 0.0; gap = 0.0; } /** * Returns the value for the outer radius of a pie relative to the * radius set in the plot. * @return Outer radius of a pie relative to the radius of the plot. */ public double getOuterRadius() { return outerRadius; } /** * Sets the value for the outer radius of a pie relative to the radius * set in the plot. * @param radius Outer radius of a pie relative to the radius of the * plot. */ public void setOuterRadius(double radius) { this.outerRadius = radius; } /** * Returns the value for the inner radius of a pie relative to the * radius set in the plot. * @return Inner radius of a pie relative to the radius of the plot. */ public double getInnerRadius() { return innerRadius; } /** * Sets the value for the inner radius of a pie relative to the radius * set in the plot. * @param radius Inner radius of a pie relative to the radius of the * plot. */ public void setInnerRadius(double radius) { this.innerRadius = radius; } /** * Returns the width of gaps between the segments relative to the font * size. * @return Width of gaps between the segments relative to the font * size. */ public double getGap() { return gap; } /** * Sets the width of gaps between the segments relative to the font * size. * @param gap Width of gaps between the segments relative to the font * size. */ public void setGap(double gap) { this.gap = gap; } /** * Returns the graphical representation to be drawn for the specified data * value. * @param data Information on axes, renderers, and values. * @param shape Outline that describes the point's shape. * @return Component that can be used to draw the point. */ public Drawable getPoint(final PointData data, final Shape shape) { return new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = -1783451355453643712L; public void draw(DrawingContext context) { PointRenderer renderer = PieSliceRenderer.this; Row row = data.row; if (shape == null) { return; } Slice slice = plot.getSlice( row.getSource(), row.getIndex()); if (slice == null) { return; } // Paint slice ColorMapper colorMapper = renderer.getColor(); Paint paint; if (colorMapper instanceof ContinuousColorMapper) { double sum = plot.getSum(row.getSource()); if (sum == 0.0) { return; } double sliceStartRel = slice.start/sum; double sliceEndRel = slice.end/sum; double coloringRel = 0.0; int rows = row.getSource().getRowCount(); if (rows > 1) { double posRel = row.getIndex() / (double)(rows - 1); double posRelInv = 1.0 - posRel; coloringRel = posRelInv*sliceStartRel + posRel*sliceEndRel; } paint = ((ContinuousColorMapper) colorMapper).get(coloringRel); } else { paint = colorMapper.get(row.getIndex()); } GraphicsUtils.fillPaintedShape( context.getGraphics(), shape, paint, null); } }; } /** * Returns a {@code Shape} instance that can be used for further * calculations. * @param data Information on axes, renderers, and values. * @return Outline that describes the point's shape. */ public Shape getPointShape(PointData data) { Row row = data.row; int col = data.col; Number valueObj = (Number) row.get(col); if (!MathUtils.isCalculatable(valueObj) || valueObj.doubleValue() <= 0.0) { return null; } Font font = getValueFont(); double fontSize = font.getSize2D(); PlotArea plotArea = plot.getPlotArea(); double plotAreaSize = Math.min( plotArea.getWidth(), plotArea.getHeight())/2.0; double radiusRel = plot.getRadius(); double radius = plotAreaSize*radiusRel; double radiusRelOuter = getOuterRadius(); double radiusOuter = radius*radiusRelOuter; // Construct slice double sum = plot.getSum(row.getSource()); if (sum == 0.0) { return null; } Slice slice = plot.getSlice( row.getSource(), row.getIndex()); if (slice == null) { return null; } double sliceStartRel = slice.start/sum; double sliceEndRel = slice.end/sum; double start = plot.getStart(); double sliceSpan = (sliceEndRel - sliceStartRel)*360.0; double sliceStart; if (plot.isClockwise()) { sliceStart = start - sliceEndRel*360.0; } else { sliceStart = start + sliceStartRel*360.0; } start = MathUtils.normalizeDegrees(start); Arc2D pieSlice = new Arc2D.Double( -radiusOuter, -radiusOuter, 2.0*radiusOuter, 2.0*radiusOuter, sliceStart, sliceSpan, Arc2D.PIE ); Area doughnutSlice = new Area(pieSlice); double gap = getGap(); if (gap > 0.0) { Stroke sliceStroke = new BasicStroke((float) (gap*fontSize)); Area sliceContour = new Area(sliceStroke.createStrokedShape(pieSlice)); doughnutSlice.subtract(sliceContour); } double radiusRelInner = getInnerRadius(); if (radiusRelInner > 0.0 && radiusRelInner < radiusRelOuter) { double radiusInner = radius*radiusRelInner; Ellipse2D inner = new Ellipse2D.Double( -radiusInner, -radiusInner, 2.0*radiusInner, 2.0*radiusInner ); Area hole = new Area(inner); doughnutSlice.subtract(hole); } return doughnutSlice; } /** * Draws the specified value label for the specified shape. * @param context Environment used for drawing. * @param slice Pie slice to draw. * @param radius Radius of pie slice in view units (e.g. pixels). * @param row Data row containing the point. * @param col Index of the column that will be projected on the axis. */ protected void drawValueLabel(DrawingContext context, Slice slice, double radius, Row row, int col) { Comparable value = row.get(col); // Formatting Format format = getValueFormat(); if ((format == null) && (value instanceof Number)) { format = NumberFormat.getInstance(); } // Text to display String text = (format != null) ? format.format(value) : value.toString(); // Visual settings ColorMapper colors = getValueColor(); Paint paint = colors.get(row.getIndex()); Font font = getValueFont(); double fontSize = font.getSize2D(); // Layout settings Location location = getValueLocation(); double alignX = getValueAlignmentX(); double alignY = getValueAlignmentY(); double rotation = getValueRotation(); double distance = getValueDistance(); if (MathUtils.isCalculatable(distance)) { distance *= fontSize; } else { distance = 0.0; } // Vertical layout double radiusRelOuter = getOuterRadius(); double radiusRelInner = getInnerRadius(); double radiusOuter = radius*radiusRelOuter; double radiusInner = radius*radiusRelInner; double distanceV = distance; double labelPosV; if (location == Location.NORTH) { labelPosV = radiusOuter + distanceV; } else if (location == Location.SOUTH) { labelPosV = Math.max(radiusInner - distanceV, 0); } else { double sliceHeight = radiusOuter - radiusInner; if (2.0*distance >= sliceHeight) { alignY = 0.5; distanceV = 0.0; } labelPosV = radiusInner + distanceV + alignY*(sliceHeight - 2.0*distanceV); } // Horizontal layout double sum = plot.getSum(row.getSource()); if (sum == 0.0) { return; } double sliceStartRel = slice.start/sum; double sliceEndRel = slice.end/sum; double circumference = 2.0*labelPosV*Math.PI; double distanceRelH = distance/circumference; double sliceWidthRel = sliceEndRel - sliceStartRel; if (2.0*distanceRelH >= sliceWidthRel) { alignX = 0.5; distanceRelH = 0.0; } double labelPosRelH = sliceStartRel + distanceRelH + alignX*(sliceWidthRel - 2.0*distanceRelH); double start = plot.getStart(); double angleStart = Math.toRadians(-start); double direction = 1.0; if (!plot.isClockwise()) { direction = -1.0; } double angle = angleStart + direction*labelPosRelH*2.0*Math.PI; double dirX = Math.cos(angle); double dirY = Math.sin(angle); // Create a label with the settings Label label = new Label(text); label.setAlignmentX(1.0 - 0.5*dirX - 0.5); label.setAlignmentY(0.5*dirY + 0.5); label.setRotation(rotation); label.setColor(paint); label.setFont(font); // Calculate label position Dimension2D sizeLabel = label.getPreferredSize(); double anchorX = 0.5; double anchorY = 0.5; if (location == Location.NORTH || location == Location.SOUTH) { anchorX = dirX*sizeLabel.getWidth()/2.0; anchorY = dirY*sizeLabel.getHeight()/2.0; if (location == Location.SOUTH) { anchorX = -anchorX; anchorY = -anchorY; } } // Resize label component double x = labelPosV*dirX + anchorX - sizeLabel.getWidth()/2.0; double y = labelPosV*dirY + anchorY - sizeLabel.getHeight()/2.0; double w = sizeLabel.getWidth(); double h = sizeLabel.getHeight(); label.setBounds(x, y, w, h); label.draw(context); } @Override public Drawable getValue(final PointData data, final Shape shape) { Drawable drawable = new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = 8389872806138135038L; public void draw(DrawingContext context) { PointRenderer renderer = PieSliceRenderer.this; Row row = data.row; if (shape == null) { return; } Slice slice = plot.getSlice( row.getSource(), row.getIndex()); if (slice == null) { return; } PlotArea plotArea = plot.getPlotArea(); double plotAreaSize = Math.min( plotArea.getWidth(), plotArea.getHeight())/2.0; double radiusRel = plot.getRadius(); double radius = plotAreaSize*radiusRel; if (renderer.isValueVisible()) { int colValue = renderer.getValueColumn(); drawValueLabel(context, slice, radius, row, colValue); } } }; return drawable; } } /** * A legend implementation for pie plots that displays items for each data * value of a data source. */ public static class PiePlotLegend extends ValueLegend { /** Version id for serialization. */ private static final long serialVersionUID = 309673490751330686L; /** Plot that contains settings and renderers. */ private final PiePlot plot; /** * Initializes a new instance with a specified plot. * @param plot Plot. */ public PiePlotLegend(PiePlot plot) { this.plot = plot; } @Override protected Iterable getEntries(DataSource source) { Iterable slicesAndGaps = super.getEntries(source); List slices = new LinkedList(); for (Row row : slicesAndGaps) { if (!row.isColumnNumeric(0)) { continue; } Number value = (Number) row.get(0); boolean isGap = value.doubleValue() < 0.0; if (!isGap) { slices.add(row); } } return slices; } /** * Returns a symbol for rendering a legend item. * @param row Data row. * @return A drawable object that can be used to display the symbol. */ public Drawable getSymbol(final Row row) { return new AbstractSymbol(this) { /** Version id for serialization. */ private static final long serialVersionUID = -5460249256507481057L; /** * Draws the {@code Drawable} with the specified drawing context. * @param context Environment used for drawing */ public void draw(DrawingContext context) { DataSource data = row.getSource(); Rectangle2D bounds = getBounds(); PointRenderer pointRenderer = plot.getPointRenderer(data); Shape shape = new Rectangle2D.Double( 0.0, 0.0, bounds.getWidth(), bounds.getHeight()); if (pointRenderer == null) { return; } PointData pointData = new PointData( Arrays.asList((Axis) null), Arrays.asList((AxisRenderer) null), row, 0); Drawable drawable = pointRenderer.getPoint(pointData, shape); Graphics2D graphics = context.getGraphics(); AffineTransform txOrig = graphics.getTransform(); graphics.translate(bounds.getX(), bounds.getY()); drawable.draw(context); graphics.setTransform(txOrig); } }; } } /** * Initializes a new pie plot with the specified data source. * @param data Data to be displayed. */ public PiePlot(DataSource data) { super(); center = new Point2D.Double(0.5, 0.5); radius = 1.0; start = 0.0; clockwise = true; pointRenderers = new HashMap(); slices = new HashMap>(); setPlotArea(new PiePlotArea2D(this)); setLegend(new PiePlotLegend(this)); add(data); createDefaultAxes(); createDefaultAxisRenderers(); dataUpdated(data); } @Override protected void createDefaultAxes() { // Create x axis and y axis by default Axis axisPie = new Axis(); setAxis(AXIS_TANGENTIAL, axisPie); } @Override public void autoscaleAxis(String axisName) { if (!AXIS_TANGENTIAL.equals(axisName)) { super.autoscaleAxis(axisName); return; } List sources = getVisibleData(); if (sources.isEmpty()) { return; } DataSource data = sources.get(0); if (data.getRowCount() == 0) { return; } double sum = getSum(data); if (sum == 0.0) { return; } Axis axis = getAxis(axisName); if (axis == null || !axis.isAutoscaled()) { return; } axis.setRange(0.0, sum); } @Override protected void createDefaultAxisRenderers() { // Create a linear renderer for the pie slices by default AxisRenderer renderer = new LinearRenderer2D(); // Create a circle with radius 1.0 as shape for the axis Shape shape = new Ellipse2D.Double(-1.0, -1.0, 2.0, 2.0); renderer.setShape(shape); // Don't show axis renderer.setShapeVisible(false); setAxisRenderer(AXIS_TANGENTIAL, renderer); } @Override public void add(int index, DataSource source, boolean visible) { if (getData().size() != 0) { throw new IllegalArgumentException( "This plot type only supports a single data source."); //$NON-NLS-1$ } super.add(index, source, visible); PointRenderer pointRendererDefault = new PieSliceRenderer(this); setPointRenderer(source, pointRendererDefault); setMapping(source, AXIS_TANGENTIAL); } /** * Returns the {@code PointRenderer} for the specified data source. * @param s Data source. * @return PointRenderer. */ public PointRenderer getPointRenderer(DataSource s) { return pointRenderers.get(s); } /** * Sets the {@code PointRenderer} for a certain data source to the * specified value. * @param s Data source. * @param pointRenderer PointRenderer to be set. */ public void setPointRenderer(DataSource s, PointRenderer pointRenderer) { this.pointRenderers.put(s, pointRenderer); } /** * Returns a navigator instance that can control the current object. * @return A navigator instance. */ public Navigator getNavigator() { if (navigator == null) { navigator = new PiePlotNavigator(this); } return navigator; } /** * Returns the sum of all absolute values from the specified data source up * to the row with the specified index. This is used to determine the * position of pie slices. * @param source Data source. * @param index Index of the row. * @return Sum of all absolute values from the specified data source up * to the row with the specified index */ protected Slice getSlice(DataSource source, int index) { if (index < 0) { return null; } List dataSlices; synchronized (slices) { if (!slices.containsKey(source)) { createSlices(source); } dataSlices = slices.get(source); } if (dataSlices == null || index >= dataSlices.size()) { return null; } return dataSlices.get(index); } /** * Returns the sum of all absolute values in the data column of a specified * data source. * @param source Data source. * @return Sum of all absolute values for the specified data source. */ protected double getSum(DataSource source) { double sum = 0.0; synchronized (source) { Slice lastSlice = getSlice(source, source.getRowCount() - 1); if (lastSlice != null) { sum = lastSlice.end; } } return sum; } /** * Creates the slice objects with start and end information for a specified * data source. * @param source Data source. */ private void createSlices(DataSource source) { if (!isVisible(source)) { return; } final int colIndex = 0; Column col = source.getColumn(colIndex); List dataSlices = new ArrayList(col.size()); slices.put(source, dataSlices); double start = 0.0; for (Comparable cell : col) { Number numericCell = (Number) cell; double value = 0.0; if (MathUtils.isCalculatable(numericCell)) { value = numericCell.doubleValue(); } // abs() is required because negative values cause // "empty" slices double span = Math.abs(value); Slice slice = new Slice(start, start + span); dataSlices.add(slice); start += span; } } /** * Rebuilds cached information for a specified data source. * @param source Data source. */ protected void revalidate(DataSource source) { slices.remove(source); autoscaleAxes(); } @Override protected void dataChanged(DataSource source, DataChangeEvent... events) { super.dataChanged(source, events); revalidate(source); } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Default deserialization in.defaultReadObject(); // Handle transient fields slices = new HashMap>(); // Update caches for (DataSource source : getData()) { dataUpdated(source); } } /** * Returns a point which defines the center of the pie. The coordinates * are relative to the plot area dimensions, i.e. 0.0 means left/top, * 0.5 means the center, and 1.0 means right/bottom. * @return Point which defines the center of the pie. */ public Point2D getCenter() { return center; } /** * Sets the center of the pie. The coordinates must be relative to the plot * area dimensions, i.e. 0.0 means left/top, 0.5 means the center, and 1.0 * means right/bottom. * @param center Point which defines the center of the pie. */ public void setCenter(Point2D center) { this.center.setLocation(center); } /** * Returns the radius of the pie relative to the plot area size. * @return Radius of the pie relative to the plot area size. */ public double getRadius() { return radius; } /** * Sets the radius of the pie relative to the plot area size. * @param radius Radius of the pie relative to the plot area size. */ public void setRadius(double radius) { this.radius = radius; } /** * Returns the starting angle of the first segment. The angle is * counterclockwise. * @return Starting angle of the first segment in degrees. */ public double getStart() { return start; } /** * Sets the starting angle of the first segment. The angle is always * applied counterclockwise. * @param start Starting angle of the first segment in degrees. */ public void setStart(double start) { double startOld = this.start; this.start = start; AxisRenderer axisRenderer = getAxisRenderer(PiePlot.AXIS_TANGENTIAL); if (axisRenderer != null) { Shape shape = axisRenderer.getShape(); if (shape != null) { double delta = Math.toRadians(startOld - start); AffineTransform tx = AffineTransform.getRotateInstance(delta); shape = tx.createTransformedShape(shape); axisRenderer.setShape(shape); } } } /** * Returns whether the segments are in clockwise or counterclockwise order. * @return {@code true} if segments are in clockwise order, * otherwise {@code false}. */ public boolean isClockwise() { return clockwise; } /** * Sets whether the segments will be in clockwise or counterclockwise order. * @param clockwise {@code true} if segments should be in clockwise order, * otherwise {@code false}. */ public void setClockwise(boolean clockwise) { this.clockwise = clockwise; AxisRenderer axisRenderer = getAxisRenderer(PiePlot.AXIS_TANGENTIAL); if (axisRenderer != null) { Shape shape = axisRenderer.getShape(); if (shape != null) { shape = GeometryUtils.reverse(shape); axisRenderer.setShape(shape); } } } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/Plot.java000066400000000000000000000214421267060725100256130ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import java.awt.Font; import java.awt.Paint; import java.awt.Stroke; import java.util.Collection; import java.util.List; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.graphics.Container; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.Label; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.legends.Legend; import de.erichseifert.gral.graphics.Location; /** *

Interface for classes that display data in a plot.

*

Functionality includes:

*
    *
  • Adding axes to the plot
  • *
  • Adding a title to the plot
  • *
  • Adding a legend to the plot
  • *
  • Administration of settings
  • *
*/ public interface Plot extends Drawable, Container { /** * Returns the axis with the specified name. * @param name Name of the axis. * @return Axis. */ Axis getAxis(String name); /** * Sets the axis with the specified name and the associated * {@code AxisRenderer}. * @param name Name of the axis. * @param axis Axis. */ void setAxis(String name, Axis axis); /** * Removes the axis with the specified name. * @param name Name of the axis to be removed. */ void removeAxis(String name); /** * Returns a collection of all names of the axes stored in this plot. * @return The names of all axes stored in this plot. */ Collection getAxesNames(); /** * Tries to automatically set the ranges of the axes specified by the name * if it is set to auto-scale. * @param axisName Name of the axis that should be scaled. * @see Axis#setAutoscaled(boolean) */ void autoscaleAxis(String axisName); /** * Returns the renderer for the axis with the specified name. * @param axisName Axis name. * @return Instance that renders the axis. */ AxisRenderer getAxisRenderer(String axisName); /** * Sets the renderer for the axis with the specified name. * @param axisName Name of the axis to be rendered. * @param renderer Instance to render the axis. */ void setAxisRenderer(String axisName, AxisRenderer renderer); /** * Returns the drawing area of this plot. * @return {@code PlotArea2D}. */ PlotArea getPlotArea(); /** * Returns the title component of this plot. * @return Label representing the title. */ Label getTitle(); /** * Returns the legend component. * @return Legend. */ Legend getLegend(); /** * Adds a new data series to the plot which is visible by default. * @param source Data series. */ void add(DataSource source); /** * Adds a new data series to the plot. * @param source Data series. * @param visible {@code true} if the series should be displayed, * {@code false} otherwise. */ void add(DataSource source, boolean visible); /** * Inserts the specified data series to the plot at a specified position. * @param index Position. * @param source Data series. * @param visible {@code true} if the series should be displayed, * {@code false} otherwise. */ void add(int index, DataSource source, boolean visible); /** * Returns whether the plot contains the specified data series. * @param source Data series. * @return {@code true} if the specified element is stored in the * plot, otherwise {@code false} */ boolean contains(DataSource source); /** * Returns the data series at a specified index. * @param index Position of the data series. * @return Instance of the data series. */ DataSource get(int index); /** * Deletes the specified data series from the plot. * @param source Data series. * @return {@code true} if the series existed, * otherwise {@code false}. */ boolean remove(DataSource source); /** * Removes all data series from this plot. */ void clear(); /** * Returns the mapping of data source columns to axis names. The elements * of returned array equal the column indexes, i.e. the first element (axis * name) matches the first column of {@code source}. If no mapping exists * {@code null} will be stored in the array. * @param source Data source. * @return Array containing axis names in the order of the columns, * or {@code null} if no mapping exists for the column. */ String[] getMapping(DataSource source); /** * Sets the mapping of data source columns to axis names. The column index * is taken from the order of the axis names, i.e. the first column of * {@code source} will be mapped to first element of {@code axisNames}. * Axis names with value {@code null} will be ignored. * @param source Data source. * @param axisNames Sequence of axis names in the order of the columns. */ void setMapping(DataSource source, String... axisNames); /** * Returns a list of all data series stored in the plot. * @return List of all data series. */ List getData(); /** * Returns a list of all visible data series stored in the plot. * @return List of all visible data series. */ List getVisibleData(); /** * Returns whether the specified data series is drawn. * @param source Data series. * @return {@code true} if visible, {@code false} otherwise. */ boolean isVisible(DataSource source); /** * Changes the visibility of the specified data series. * @param source Data series. * @param visible {@code true} if the series should be visible, * {@code false} otherwise. */ void setVisible(DataSource source, boolean visible); /** * Returns the paint which is used to fill the background of the plot. * @return Paint which is used to fill the background of the plot. */ Paint getBackground(); /** * Sets the paint which will be used to fill the background of the plot. * @param background Paint which will be used to fill the background of the * plot. */ void setBackground(Paint background); /** * Returns the stroke which is used to paint the border of the plot. * @return Stroke which is used to paint the border of the plot. */ Stroke getBorderStroke(); /** * Sets the stroke which will be used to paint the border of the plot. * @param border Stroke which will be used to paint the border of the plot. */ void setBorderStroke(Stroke border); /** * Returns the paint which is used to fill the border of the plot. * @return Paint which is used to fill the border of the plot. */ Paint getBorderColor(); /** * Sets the paint which will be used to fill the border of the plot. * @param color Paint which will be used to fill the border of the plot. */ void setBorderColor(Paint color); /** * Returns the base font used by the plot. * @return Font used by the plot. */ Font getFont(); /** * Sets the base font that will be used by the plot. * @param font Font that will used by the plot. */ void setFont(Font font); /** * Returns whether the legend is shown. * @return {@code true} if the legend is shown, * {@code false} if the legend is hidden. */ boolean isLegendVisible(); /** * Sets whether the legend will be shown. * @param legendVisible {@code true} if the legend should be shown, * {@code false} if the legend should be hidden. */ void setLegendVisible(boolean legendVisible); /** * Returns the current positioning of the legend inside the plot. * @return Current positioning of the legend inside the plot. */ Location getLegendLocation(); /** * Sets the positioning of the legend inside the plot. * @param location Positioning of the legend inside the plot. */ void setLegendLocation(Location location); /** * Returns the spacing between the plot area and the legend. * @return Spacing between the plot area and the legend relative to font * height. */ double getLegendDistance(); /** * Sets the spacing between the plot area and the legend. * The distance is defined in font height. * @param distance Spacing between the plot area and the legend relative to font * height. */ void setLegendDistance(double distance); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/PlotArea.java000066400000000000000000000160141267060725100264030ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Paint; import java.awt.Stroke; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.graphics.Insets2D; import de.erichseifert.gral.util.SerializationUtils; /** * Abstract class that represents a canvas on which plot data will be drawn. * It serves as base for specialized implementations for different plot types. * Derived classes have to implement how the actual drawing is done. */ public abstract class PlotArea extends AbstractDrawable { /** Version id for serialization. */ private static final long serialVersionUID = 2745982325709470005L; /** Default font used for sub-components and the calculation of relative sizes. */ private Font baseFont; /** Paint to fill the background. */ private Paint background; /** Stroke to draw the border. Property will be serialized using a wrapper. */ private transient Stroke borderStroke; /** Paint to fill the border. */ private Paint borderColor; /** Offset to clip plot graphics in pixels, specified relative to the outline of the plot area. */ private Insets2D clippingOffset; /** * Initializes a new instance with default background color and border. */ public PlotArea() { baseFont = null; background = Color.WHITE; borderStroke = new BasicStroke(1f); borderColor = Color.BLACK; clippingOffset = new Insets2D.Double(0.0); } /** * Draws the background of this legend with the specified drawing context. * @param context Environment used for drawing. */ protected void drawBackground(DrawingContext context) { // FIXME duplicate code! See de.erichseifert.gral.Legend Paint paint = getBackground(); if (paint != null) { GraphicsUtils.fillPaintedShape(context.getGraphics(), getBounds(), paint, null); } } /** * Draws the border of this Legend with the specified drawing context. * @param context Environment used for drawing. */ protected void drawBorder(DrawingContext context) { // FIXME duplicate code! See de.erichseifert.gral.Legend Stroke stroke = getBorderStroke(); if (stroke != null) { Paint borderColor = getBorderColor(); GraphicsUtils.drawPaintedShape(context.getGraphics(), getBounds(), borderColor, null, stroke); } } /** * Draws the data using the specified drawing context. * @param context Environment used for drawing. */ protected abstract void drawPlot(DrawingContext context); /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { in.defaultReadObject(); borderStroke = (Stroke) SerializationUtils.unwrap((Serializable) in.readObject()); } /** * Custom serialization method. * @param out Output stream. * @throws ClassNotFoundException if a deserialized class does not exist. * @throws IOException if there is an error while writing data to the * output stream. */ private void writeObject(ObjectOutputStream out) throws ClassNotFoundException, IOException { out.defaultWriteObject(); out.writeObject(SerializationUtils.wrap(borderStroke)); } /** * Returns the current font used as a default for sub-components ans for * calculation of relative sizes. * @return Current base font. */ public Font getBaseFont() { return baseFont; } /** * Sets the new font that will be used as a default for sub-components and * for calculation of relative sizes. This method is only used internally * to propagate the base font and shouldn't be used manually. * @param baseFont New base font. */ public void setBaseFont(Font baseFont) { this.baseFont = baseFont; } /** * Returns the paint which is used to draw the background of the plot area. * @return Paint which is used to fill the background. */ public Paint getBackground() { return background; } /** * Sets the paint which will be used to fill the background of the plot * area. * @param background Paint which should be used to fill the background. */ public void setBackground(Paint background) { this.background = background; } /** * Returns the stroke which is used to draw the border of the plot area. * @return Stroke which is used to draw the border. */ public Stroke getBorderStroke() { return borderStroke; } /** * Sets the stroke which will be used to draw the border of the plot area. * @param stroke Stroke which should be used to draw the border. */ public void setBorderStroke(Stroke stroke) { this.borderStroke = stroke; } /** * Returns the paint which is used to fill the border of the plot area. * @return Paint which is used to fill the border. */ public Paint getBorderColor() { return borderColor; } /** * Sets the paint which will be used to fill the border of the plot area. * @param color Paint which should be used to fill the border. */ public void setBorderColor(Paint color) { this.borderColor = color; } /** * Returns the clipping offset of the plotted data relative to the plot * area. Positive inset values result in clipping inside the plot area, * negative values result in clipping outside the plot area. * Specifying a {@code null} values will turn off clipping. * @return Clipping offset in pixels relative to the outline of the plot * area. */ public Insets2D getClippingOffset() { return clippingOffset; } /** * Sets the clipping offset of the plotted data relative to the plot area. * Positive inset values result in clipping inside the plot area, * negative values result in clipping outside the plot area. * Specifying a {@code null} values will turn off clipping. * @param offset Clipping offset in pixels relative to the outline of the * plot area. */ public void setClippingArea(Insets2D offset) { this.clippingOffset = offset; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/PlotNavigator.java000066400000000000000000000330311267060725100274630ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import de.erichseifert.gral.navigation.AbstractNavigator; import de.erichseifert.gral.navigation.NavigationEvent; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.util.MathUtils; import de.erichseifert.gral.util.PointND; /** *

Abstract base class that can be used to control the zoom and panning of a * plot. The navigator translates the interaction to operations on a defined * set of axes: Zooming is translated as scaling, panning is done by uniformly * changing the minimum and maximum values of the axes.

* *

Additionally, the actions can also be bound to a certain direction by * defining a more restricted set of axes. The methods {@link #getDirection()} * and {@link #setDirection(de.erichseifert.gral.navigation.NavigationDirection)} * provide a convenient way for setting predefined sets of axes.

*/ public abstract class PlotNavigator extends AbstractNavigator { /** AbstractPlot that will be navigated. */ private final Plot plot; /** Mapping of axis name to informations on center and zoom. */ private final Map infos; /** Axes affected by navigation. */ private final List axes; /** * Data class for storing navigational information for an axis. */ protected static final class NavigationInfo { /** Minimum value of the original axis. */ private final Number minOriginal; /** Maximum value of the original axis. */ private final Number maxOriginal; /** Center value of the original axis. */ private final double centerOriginal; /** Current center value. */ private double center; /** Current zoom level. */ private double zoom; /** * Initializes a new {@code NavigationInfo} instance. * @param min Minimum value in axis units. * @param max Maximum value in axis units. * @param center Center in axis units. */ public NavigationInfo(Number min, Number max, double center) { this.minOriginal = min; this.maxOriginal = max; this.centerOriginal = center; this.center = centerOriginal; this.zoom = 1.0; } /** * Returns the original minimum value. * @return Original minimum value. */ public Number getMinOriginal() { return minOriginal; } /** * Returns the original maximum value. * @return Original maximum value. */ public Number getMaxOriginal() { return maxOriginal; } /** * Returns the original center value. * @return Original center value. */ public double getCenterOriginal() { return centerOriginal; } /** * Returns the current center value. * @return Current center value. */ public double getCenter() { return center; } /** * Sets the current center value. * @param center New center value. */ public void setCenter(double center) { this.center = center; } /** * Returns the current zoom factor. * @return Current zoom factor. */ public double getZoom() { return zoom; } /** * Sets the current zoom factor. * @param zoom New zoom factor. */ public void setZoom(double zoom) { this.zoom = zoom; } } /** * Initializes a new instance that is responsible for zooming and panning * the axes with the specified names of the specified plot. * @param plot AbstractPlot to be zoomed and panned. * @param axesNames Names of the axes that should be controlled by this * navigator. */ public PlotNavigator(Plot plot, List axesNames) { axes = new LinkedList(); infos = new HashMap(); this.plot = plot; setAxes(axesNames); } /** * Initializes a new instance that is responsible for zooming and panning * the axes with the specified names of the specified plot. * @param plot AbstractPlot to be zoomed and panned. * @param axesNames Names of the axes that should be controlled by this * navigator. */ public PlotNavigator(Plot plot, String... axesNames) { this(plot, Arrays.asList(axesNames)); } /** * Refreshes the values of all axis to reflect navigation actions. */ private void refresh() { for (String axisName : getAxes()) { NavigationInfo info = getInfo(axisName); if (info == null) { continue; } AxisRenderer renderer = getPlot().getAxisRenderer(axisName); if (renderer == null) { continue; } Axis axis = getPlot().getAxis(axisName); // Original range in screen units // Most up-to-date view coordinates (axis's layout) must be used double minOrig = renderer.worldToView( axis, info.getMinOriginal(), true); double maxOrig = renderer.worldToView( axis, info.getMaxOriginal(), true); double rangeOrig = maxOrig - minOrig; // New axis scale double zoom = info.getZoom(); double range = rangeOrig/zoom; double center = renderer.worldToView(axis, info.getCenter(), true); Number min = renderer.viewToWorld(axis, center - 0.5*range, true); Number max = renderer.viewToWorld(axis, center + 0.5*range, true); // Change axis axis.setRange(min, max); } } /** * Returns the plot stored in this instance. * @return Stored plot object. */ protected Plot getPlot() { return plot; } /** * Returns the current zoom level of the associated object. * @return Current zoom level. */ public double getZoom() { double zoom = 0.0; int count = 0; for (String axisName : getAxes()) { NavigationInfo info = getInfo(axisName); if (info == null) { continue; } if (!MathUtils.isCalculatable(info.getZoom())) { continue; } zoom += info.getZoom(); count++; } return zoom / count; } /** * Sets the zoom level of the associated object to the specified value. * @param zoomNew New zoom level. */ public void setZoom(double zoomNew) { if (!isZoomable() || (zoomNew <= 0.0) || !MathUtils.isCalculatable(zoomNew)) { return; } double zoomOld = getZoom(); zoomNew = MathUtils.limit(zoomNew, getZoomMin(), getZoomMax()); if (zoomOld == zoomNew) { return; } for (String axisName : getAxes()) { NavigationInfo info = getInfo(axisName); if (info == null) { continue; } info.setZoom(zoomNew); } NavigationEvent event = new NavigationEvent(this, zoomOld, zoomNew); fireZoomChanged(event); refresh(); } /** * Returns the current center point. The returned point contains value in * world units. * @return Center point in world units. */ public PointND getCenter() { List axesNames = getAxes(); Double[] centerCoords = new Double[axesNames.size()]; int axisIndex = 0; for (String axisName : axesNames) { NavigationInfo info = getInfo(axisName); if (info != null) { double axisCenter = info.getCenter(); centerCoords[axisIndex] = axisCenter; } axisIndex++; } return new PointND(centerCoords); } /** * Sets a new center point. The values of the point are in world units. * @param center New center point in world units. */ public void setCenter(PointND center) { if (!isPannable()) { return; } PointND centerOld = getCenter(); if (centerOld.equals(center)) { return; } List axesNames = getAxes(); int axisIndex = 0; for (String axisName : axesNames) { NavigationInfo info = getInfo(axisName); if (info != null) { Number centerCoordNew = center.get(axisIndex); info.setCenter(centerCoordNew.doubleValue()); } axisIndex++; } NavigationEvent> event = new NavigationEvent>(this, centerOld, center); fireCenterChanged(event); refresh(); } /** * Moves the center by the relative values of the specified point. * The values of the point are in screen units. * @param deltas Relative values to use for panning. */ public void pan(PointND deltas) { if (!isPannable()) { return; } PointND centerOld = getCenter(); Double[] centerCoords = new Double[centerOld.getDimensions()]; int axisIndex = 0; for (String axisName : getAxes()) { NavigationInfo info = getInfo(axisName); if (info != null) { double delta = getDimensionValue(axisName, deltas).doubleValue(); AxisRenderer renderer = getPlot().getAxisRenderer(axisName); if (renderer != null) { boolean swapped = renderer.isShapeDirectionSwapped(); if (swapped) { delta = -delta; } Axis axis = getPlot().getAxis(axisName); // Fetch current center on screen double center = renderer.worldToView( axis, info.getCenter(), true); // Move center and convert it to axis coordinates Number centerNew = renderer.viewToWorld( axis, center - delta, true); // Change axis (world units) info.setCenter(centerNew.doubleValue()); centerCoords[axisIndex] = centerNew.doubleValue(); } } axisIndex++; } PointND centerNew = new PointND(centerCoords); NavigationEvent> event = new NavigationEvent>(this, centerOld, centerNew); fireCenterChanged(event); refresh(); } /** * Sets the current state as the default state of the object. * Resetting the navigator will then return to the default state. */ public void setDefaultState() { infos.clear(); for (String axisName : getAxes()) { Axis axis = getPlot().getAxis(axisName); if (axis == null) { continue; } double min; double max; Number center = 0.0; AxisRenderer renderer = getPlot().getAxisRenderer(axisName); if (renderer != null && axis.isValid()) { min = renderer.worldToView(axis, axis.getMin(), false); max = renderer.worldToView(axis, axis.getMax(), false); if (MathUtils.isCalculatable(min) && MathUtils.isCalculatable(max)) { center = renderer.viewToWorld(axis, (min + max)/2.0, false); } } NavigationInfo info = new NavigationInfo( axis.getMin(), axis.getMax(), center.doubleValue()); infos.put(axisName, info); } } /** * Sets the object's position and zoom level to the default state. */ public void reset() { double zoomOld = getZoom(); double zoomNew = 1.0; PointND centerOld = getCenter(); List axesNames = getAxes(); Double[] centerCoordsOriginal = new Double[centerOld.getDimensions()]; int axisIndex = 0; for (String axisName : axesNames) { NavigationInfo info = getInfo(axisName); if (info != null) { double centerCoordOriginal = info.getCenterOriginal(); centerCoordsOriginal[axisIndex] = centerCoordOriginal; info.setCenter(centerCoordOriginal); info.setZoom(zoomNew); } axisIndex++; } PointND centerNew = new PointND(centerCoordsOriginal); NavigationEvent> panEvent = new NavigationEvent>(this, centerOld, centerNew); fireCenterChanged(panEvent); NavigationEvent zoomEvent = new NavigationEvent(this, zoomOld, 1.0); fireZoomChanged(zoomEvent); refresh(); } /** * Returns navigational information for the axis with specified name. * @param axisName Axis name. * @return Navigational information. */ protected NavigationInfo getInfo(String axisName) { return infos.get(axisName); } /** * Returns the names of all axes handled by this object. * @return Names of all axes handled by this object. */ protected List getAxes() { return Collections.unmodifiableList(axes); } /** * Sets the names of the axes that should be handled by this object. * @param axesNames Names of the axes that should be handled. */ protected void setAxes(List axesNames) { axes.clear(); axes.addAll(axesNames); setDefaultState(); } /** * Sets the names of the axes that should be handled by this object. * @param axesNames Names of the axes that should be handled. */ protected void setAxes(String... axesNames) { setAxes(Arrays.asList(axesNames)); } /** * Returns the number dimensions the associated plot can handle. For a * one-dimensional plot like {@link PiePlot} this is 1, for a * two-dimensional plot like {@link XYPlot} this is 2, and so on. * @return Number of dimensions the associated plot can handle. */ protected abstract int getDimensions(); /** * Return the index that can be used to access data for the axis with the * specified name. The returned index must be larger than or equal to 0 and * smaller than the result of {@link #getDimensions()}. * @param axisName Name of the axis. * @param values Data values. * @return Dimension index. */ protected abstract Number getDimensionValue( String axisName, PointND values); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/RasterPlot.java000066400000000000000000000326571267060725100270060ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Dimension2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.data.statistics.Statistics; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.colors.ColorMapper; import de.erichseifert.gral.plots.colors.ContinuousColorMapper; import de.erichseifert.gral.plots.colors.Grayscale; import de.erichseifert.gral.plots.points.AbstractPointRenderer; import de.erichseifert.gral.plots.points.PointData; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.util.PointND; /** *

Class that displays two coordinate values and a value as a raster of * boxes. The data source must provide at least three columns:

*
    *
  • x coordinate
  • *
  • y coordinate
  • *
  • value
  • *
*

The method {@link #createRasterData(DataSource)} can be used to convert * a matrix of values to the (coordinates, value) format.

* *

To create a new {@code RasterPlot} simply create a new instance using * a suitable data source. Example:

*
 * DataTable data = new DataTable(Double.class, Double.class);
 * data.add(10.98, -12.34);
 * data.add( 7.65,  45.67);
 * data.add(43.21,  89.01);
 * DataSource rasterData = RasterPlot.createRasterData(data);
 * RasterPlot plot = new RasterPlot(rasterData);
 * 
*/ public class RasterPlot extends XYPlot { /** Version id for serialization. */ private static final long serialVersionUID = 5844862286358250831L; /** Offset of the raster pixels to the origin. */ private final Point2D offset; /** Size of the raster pixels. */ private final Dimension2D distance; /** Color mapping to fill the raster pixels. */ private ColorMapper colors; /** * Class that renders the grid points of a {@code RasterPlot}. */ protected static class RasterRenderer extends AbstractPointRenderer { /** Version id for serialization. */ private static final long serialVersionUID = 1266585364126459761L; /** Plot specific settings. */ private final RasterPlot plot; /** Horizontal position of the current raster pixel. */ private int xColumn; /** Vertical position of the current raster pixel. */ private int yColumn; /** Value of the current raster pixel. */ private int valueColumn; /** * Constructor that creates a new instance and initializes it with a * plot as data provider. The default columns for (x, y, value) are set * to (0, 1, 2) * @param plot Plot storing global settings. */ public RasterRenderer(RasterPlot plot) { this.plot = plot; xColumn = 0; yColumn = 1; valueColumn = 2; } /** * Returns the index of the column which is used for the x coordinate * of a point. * @return Index of the column for the x coordinate of a point. */ public int getXColumn() { return xColumn; } /** * Sets the index of the column which will be used for the x coordinate * of a point. * @param columnIndex Index of the column for the x coordinate of a point. */ public void setXColumn(int columnIndex) { this.xColumn = columnIndex; } /** * Returns the index of the column which is used for the y coordinate * of a point. * @return Index of the column for the y coordinate of a point. */ public int getYColumn() { return yColumn; } /** * Sets the index of the column which will be used for the y coordinate * of a point. * @param columnIndex Index of the column for the y coordinate of a point. */ public void setYColumn(int columnIndex) { this.yColumn = columnIndex; } /** * Returns the index of the column which is used for the value of a * point. * @return Index of the column for the value of a point. */ @Override public int getValueColumn() { return valueColumn; } /** * Sets the index of the column which will be used for the value of a * point. * @param columnIndex Index of the column for the value of a point. */ @Override public void setValueColumn(int columnIndex) { this.valueColumn = columnIndex; } /** * Returns the graphical representation to be drawn for the specified data * value. * @param data Information on axes, renderers, and values. * @param shape Outline that describes the point's shape. * @return Component that can be used to draw the point */ public Drawable getPoint(final PointData data, final Shape shape) { return new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = -1136689797647794969L; public void draw(DrawingContext context) { RasterRenderer renderer = RasterRenderer.this; Axis axisX = data.axes.get(0); Axis axisY = data.axes.get(1); AxisRenderer axisXRenderer = data.axisRenderers.get(0); AxisRenderer axisYRenderer = data.axisRenderers.get(1); Row row = data.row; int colX = renderer.getXColumn(); if (colX < 0 || colX >= row.size() || !row.isColumnNumeric(colX)) { return; } int colY = renderer.getYColumn(); if (colY < 0 || colY >= row.size() || !row.isColumnNumeric(colY)) { return; } int colValue = renderer.getValueColumn(); if (colValue < 0 || colValue >= row.size() || !row.isColumnNumeric(colValue)) { return; } double valueX = ((Number) row.get(colX)).doubleValue(); double valueY = ((Number) row.get(colY)).doubleValue(); Number value = (Number) row.get(colValue); // Pixel dimensions double xMin = axisXRenderer .getPosition(axisX, valueX - 0.5, true, false) .get(PointND.X); double xMax = axisXRenderer .getPosition(axisX, valueX + 0.5, true, false) .get(PointND.X); double width = Math.abs(xMax - xMin) + 1.0; double yMin = axisYRenderer .getPosition(axisY, valueY - 0.5, true, false) .get(PointND.Y); double yMax = axisYRenderer .getPosition(axisY, valueY + 0.5, true, false) .get(PointND.Y); double height = Math.abs(yMax - yMin) + 1.0; // Create shape for pixel // The origin of all shapes is (boxX, boxY) Rectangle2D shapeBounds = shape.getBounds2D(); AffineTransform tx = new AffineTransform(); tx.scale(width/shapeBounds.getWidth(), height/shapeBounds.getHeight()); tx.translate(-shapeBounds.getMinX(), -shapeBounds.getMinY()); Shape pixel = tx.createTransformedShape(shape); // Paint pixel Graphics2D graphics = context.getGraphics(); ColorMapper colorMapper = plot.getColors(); Paint paint; if (colorMapper instanceof ContinuousColorMapper) { paint = ((ContinuousColorMapper) colorMapper) .get(value.doubleValue()); } else if (colorMapper != null) { Integer index = value.intValue(); paint = colorMapper.get(index); } else { paint = Color.BLACK; } GraphicsUtils.fillPaintedShape( graphics, pixel, paint, pixel.getBounds2D()); } }; } /** * Returns a {@code Shape} instance that can be used for further * calculations. * @param data Information on axes, renderers, and values. * @return Outline that describes the point's shape. */ public Shape getPointShape(PointData data) { return getShape(); } /** * Returns a graphical representation of the value label to be drawn for * the specified data value. * @param data Information on axes, renderers, and values. * @param shape Outline that describes the bounds for the value label. * @return Component that can be used to draw the value label. */ public Drawable getValue(final PointData data, final Shape shape) { Drawable drawable = new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = -8402945980942955359L; public void draw(DrawingContext context) { // TODO Implement rendering of value label } }; return drawable; } } /** * Initializes a new box-and-whisker plot with the specified data source. * @param data Data to be displayed. */ public RasterPlot(DataSource data) { offset = new Point2D.Double(); distance = new de.erichseifert.gral.graphics.Dimension2D.Double(1.0, 1.0); colors = new Grayscale(); ((XYPlotArea2D) getPlotArea()).setMajorGridX(false); ((XYPlotArea2D) getPlotArea()).setMajorGridY(false); //getAxisRenderer(AXIS_X).setSetting(AxisRenderer.TICKS, false); //getAxisRenderer(AXIS_Y).setSetting(AxisRenderer.TICKS, false); getAxisRenderer(AXIS_X).setIntersection(-Double.MAX_VALUE); getAxisRenderer(AXIS_Y).setIntersection(-Double.MAX_VALUE); // Store data add(data); // Adjust axes to the data series autoscaleAxes(); } @Override public void autoscaleAxis(String axisName) { if (AXIS_X.equals(axisName) || AXIS_Y.equals(axisName)) { Dimension2D dist = getDistance(); // In case we get called before settings defaults have been set, // just set distance to a sane default if (dist == null) { dist = new de.erichseifert.gral.graphics.Dimension2D.Double(1.0, 1.0); } Axis axis = getAxis(axisName); if (axis == null || !axis.isAutoscaled()) { return; } double min = getAxisMin(axisName); double max = getAxisMax(axisName); if (AXIS_X.equals(axisName)) { axis.setRange(min, max + dist.getWidth()); } else if (AXIS_Y.equals(axisName)) { axis.setRange(min - dist.getHeight(), max); } } else { super.autoscaleAxis(axisName); } } /** * Takes a matrix of values and creates a new data source that stores the * values in (x, y, value) format. * @param data Original data source with values in each cell. * @return New data source with (x, y, value) columns */ @SuppressWarnings("unchecked") public static DataSource createRasterData(DataSource data) { if (data == null) { throw new NullPointerException("Cannot convert null data source."); } DataTable coordsValueData = new DataTable(Double.class, Double.class, Double.class); // Generate pixel data with (x, y, value) Statistics stats = data.getStatistics(); double min = stats.get(Statistics.MIN); double max = stats.get(Statistics.MAX); double range = max - min; int i = 0; for (Comparable cell : data) { int x = i%data.getColumnCount(); int y = -i/data.getColumnCount(); double v = Double.NaN; if (cell instanceof Number) { Number numericCell = (Number) cell; v = (numericCell.doubleValue() - min) / range; } coordsValueData.add((double) x, (double) y, v); i++; } return coordsValueData; } @Override public void add(int index, DataSource source, boolean visible) { if (getData().size() > 0) { throw new IllegalArgumentException( "This plot type only supports a single data source."); //$NON-NLS-1$ } // Add data source super.add(index, source, visible); // Adjust rendering // FIXME: Overwrites possible present point and line renderers setLineRenderers(source, null); setPointRenderers(source, new RasterRenderer(this)); } /** * Returns the horizontal and vertical offset of the raster from the * origin. * @return Horizontal and vertical offset of the raster from the origin. */ public Point2D getOffset() { return offset; } /** * Sets the horizontal and vertical offset of the raster from the * origin. * @param offset Horizontal and vertical offset of the raster from the * origin. */ public void setOffset(Point2D offset) { this.offset.setLocation(offset); } /** * Returns the horizontal and vertical distance of the raster elements. * @return Horizontal and vertical distance of the raster elements. */ public Dimension2D getDistance() { return distance; } /** * Returns the horizontal and vertical distance of the raster elements. * @param distance Horizontal and vertical distance of the raster elements. */ public void setDistance(Dimension2D distance) { this.distance.setSize(distance); } /** * Returns the object which is used to map pixel values to colors. * @return Object which is used to map pixel values to colors. */ public ColorMapper getColors() { return colors; } /** * Sets the object which will be used to map pixel values to colors. * @param colors Object which will be used to map pixel values to colors. */ public void setColors(ColorMapper colors) { this.colors = colors; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/XYPlot.java000066400000000000000000001107711267060725100261000ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.geom.Dimension2D; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DummyData; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.graphics.Insets2D; import de.erichseifert.gral.graphics.Orientation; import de.erichseifert.gral.navigation.Navigable; import de.erichseifert.gral.navigation.NavigationDirection; import de.erichseifert.gral.navigation.Navigator; import de.erichseifert.gral.plots.areas.AreaRenderer; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisListener; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.axes.LinearRenderer2D; import de.erichseifert.gral.plots.axes.Tick; import de.erichseifert.gral.plots.axes.Tick.TickType; import de.erichseifert.gral.plots.legends.SeriesLegend; import de.erichseifert.gral.plots.lines.LineRenderer; import de.erichseifert.gral.plots.points.DefaultPointRenderer2D; import de.erichseifert.gral.plots.points.PointData; import de.erichseifert.gral.plots.points.PointRenderer; import de.erichseifert.gral.util.GeometryUtils; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.util.MathUtils; import de.erichseifert.gral.util.PointND; /** *

Class that displays data in an two dimensional coordinate system * (x-y plot). It also serves as a base class for many other plot types.

*

To create a new {@code XYPlot} simply create a new instance * using one or more data sources. Example:

*
 * DataTable data = new DataTable(Integer.class, Integer.class);
 * data.add( 1, 2);
 * data.add(-5, 0);
 *
 * XYPlot plot = new XYPlot(data);
 * 
*/ public class XYPlot extends AbstractPlot implements Navigable, AxisListener { /** Version id for serialization. */ private static final long serialVersionUID = 4501074701747572783L; /** Key for specifying the x-axis of an xy-plot. */ public static final String AXIS_X = "x"; //$NON-NLS-1$ /** Key for specifying the secondary x-axis of an xy-plot. */ public static final String AXIS_X2 = "x2"; //$NON-NLS-1$ /** Key for specifying the y-axis of an xy-plot. */ public static final String AXIS_Y = "y"; //$NON-NLS-1$ /** Key for specifying the secondary y-axis of an xy-plot. */ public static final String AXIS_Y2 = "y2"; //$NON-NLS-1$ /** Mapping from data source to point renderers. */ private final Map> pointRenderersByDataSource; /** Mapping from data source to line renderers. */ private final Map> lineRenderersByDataSource; /** Mapping from data source to area renderers. */ private final Map> areaRenderersByDataSource; /** Cache for the {@code Navigator} implementation. */ private transient XYPlotNavigator navigator; /** A flag that shows whether the navigator has been properly initialized. */ private transient boolean navigatorInitialized; /** * Constants which determine the direction of zoom and pan actions. */ public static enum XYNavigationDirection implements NavigationDirection { /** Value for zooming and panning horizontally. */ HORIZONTAL(XYPlot.AXIS_X, XYPlot.AXIS_X2), /** Value for zooming and panning vertically. */ VERTICAL(XYPlot.AXIS_Y, XYPlot.AXIS_Y2), /** Value for zooming and panning in all direction. */ ARBITRARY(XYPlot.AXIS_X, XYPlot.AXIS_Y, XYPlot.AXIS_X2, XYPlot.AXIS_Y2); /** Names of the axes that have the same direction. */ private final String[] axesNames; /** * Initializes a new instance with the names of the axes that have the * same direction. * @param axesNames Names of the axes that have the same direction. */ private XYNavigationDirection(String... axesNames) { this.axesNames = axesNames; } /** * Returns the names of the axes that have the direction described by * this object. * @return Names of the axes that have the same direction. */ public String[] getAxesNames() { return axesNames; } } /** * Navigator implementation for two-dimensional plots. */ public static class XYPlotNavigator extends PlotNavigator { /** * Initializes a new Navigator for two-dimensional plots with the * default axes. * @param plot Two-dimensional plot that should be controlled. */ public XYPlotNavigator(XYPlot plot) { super(plot, XYNavigationDirection.ARBITRARY.getAxesNames()); } @Override public void setDirection(NavigationDirection direction) { if (direction == getDirection()) { return; } if (!(direction instanceof XYNavigationDirection)) { throw new IllegalArgumentException("Unknown direction."); } String[] axesNames = ((XYNavigationDirection)direction).getAxesNames(); setAxes(axesNames); super.setDirection(direction); } @Override protected Number getDimensionValue(String axisName, PointND values) { if (XYPlot.AXIS_Y.equals(axisName) || XYPlot.AXIS_Y2.equals(axisName)) { return -values.get(1).doubleValue(); } return values.get(0); } @Override protected int getDimensions() { return 2; } } /** * Class that represents the drawing area of an {@code XYPlot}. */ public static class XYPlotArea2D extends PlotArea { /** Version id for serialization. */ private static final long serialVersionUID = -3673157774425536428L; /** x-y plot this plot area is associated to. */ private final XYPlot plot; /** Decides whether the horizontal grid lines at major ticks are drawn. */ private boolean majorGridX; /** Decides whether the vertical grid lines at major ticks are drawn. */ private boolean majorGridY; /** Paint to fill the grid lines at major ticks. */ private Paint majorGridColor; /** Decides whether the horizontal grid lines at minor ticks are drawn. */ private boolean minorGridX; /** Decides whether the vertical grid lines at minor ticks are drawn. */ private boolean minorGridY; /** Paint to fill the grid lines at minor ticks. */ private Paint minorGridColor; /** * Creates a new instance with default settings and initializes it with * a plot serving as data provider. * @param plot Data provider. */ public XYPlotArea2D(XYPlot plot) { this.plot = plot; majorGridX = true; majorGridY = true; majorGridColor = new Color(0.0f, 0.0f, 0.0f, 0.1f); minorGridX = false; minorGridY = false; minorGridColor = new Color(0.0f, 0.0f, 0.0f, 0.05f); } /** * Draws the {@code Drawable} with the specified {@code Graphics2D} * object. * @param context Environment used for drawing */ public void draw(DrawingContext context) { drawBackground(context); drawGrid(context); drawBorder(context); drawPlot(context); plot.drawAxes(context); plot.drawLegend(context); } /** * Draws the grid using the specified drawing context. * @param context Environment used for drawing. */ protected void drawGrid(DrawingContext context) { Graphics2D graphics = context.getGraphics(); AffineTransform txOrig = graphics.getTransform(); graphics.translate(getX(), getY()); AffineTransform txOffset = graphics.getTransform(); Rectangle2D bounds = getBounds(); // Draw gridX if (isMajorGridX() || isMinorGridX()) { AxisRenderer axisXRenderer = plot.getAxisRenderer(AXIS_X); Axis axisX = plot.getAxis(AXIS_X); if (axisXRenderer != null && axisX != null && axisX.isValid()) { Shape shapeX = axisXRenderer.getShape(); Rectangle2D shapeBoundsX = shapeX.getBounds2D(); List ticksX = axisXRenderer.getTicks(axisX); Line2D gridLineVert = new Line2D.Double( -shapeBoundsX.getMinX(), -shapeBoundsX.getMinY(), -shapeBoundsX.getMinX(), bounds.getHeight() - shapeBoundsX.getMinY() ); for (Tick tick : ticksX) { if ((tick.type == TickType.MAJOR && !isMajorGridX()) || (tick.type == TickType.MINOR && !isMinorGridX())) { continue; } Point2D tickPoint = tick.position.getPoint2D(); if (tickPoint == null) { continue; } Paint paint = majorGridColor; if (tick.type == TickType.MINOR) { paint = getMinorGridColor(); } graphics.translate(tickPoint.getX(), tickPoint.getY()); GraphicsUtils.drawPaintedShape( graphics, gridLineVert, paint, null, null); graphics.setTransform(txOffset); } } } // Draw gridY if (isMajorGridY() || isMinorGridY()) { Axis axisY = plot.getAxis(AXIS_Y); AxisRenderer axisYRenderer = plot.getAxisRenderer(AXIS_Y); if (axisY != null && axisY.isValid() && axisYRenderer != null) { Shape shapeY = axisYRenderer.getShape(); Rectangle2D shapeBoundsY = shapeY.getBounds2D(); List ticksY = axisYRenderer.getTicks(axisY); Line2D gridLineHoriz = new Line2D.Double( -shapeBoundsY.getMinX(), -shapeBoundsY.getMinY(), bounds.getWidth() - shapeBoundsY.getMinX(), -shapeBoundsY.getMinY() ); for (Tick tick : ticksY) { boolean isMajorTick = tick.type == TickType.MAJOR; boolean isMinorTick = tick.type == TickType.MINOR; if ((isMajorTick && !isMajorGridY()) || (isMinorTick && !isMinorGridY())) { continue; } Point2D tickPoint = tick.position.getPoint2D(); if (tickPoint == null) { continue; } Paint paint = majorGridColor; if (isMinorTick) { paint = getMinorGridColor(); } graphics.translate(tickPoint.getX(), tickPoint.getY()); GraphicsUtils.drawPaintedShape( graphics, gridLineHoriz, paint, null, null); graphics.setTransform(txOffset); } } } graphics.setTransform(txOrig); } @Override protected void drawPlot(DrawingContext context) { Graphics2D graphics = context.getGraphics(); Shape clipBoundsOld = graphics.getClip(); Insets2D clipOffset = getClippingOffset(); if (clipOffset != null) { final double fontSize = getBaseFont().getSize2D(); // Perform clipping Shape clipBounds = new Rectangle2D.Double( getX() + clipOffset.getLeft()*fontSize, getY() + clipOffset.getTop()*fontSize, getWidth() - clipOffset.getHorizontal()*fontSize, getHeight() - clipOffset.getVertical()*fontSize ); // Take care of old clipping region. This is used when getting // scrolled in a JScrollPane for example. if (clipBoundsOld != null) { Area clipBoundsNew = new Area(clipBoundsOld); clipBoundsNew.intersect(new Area(clipBounds)); clipBounds = clipBoundsNew; } graphics.setClip(clipBounds); } AffineTransform txOrig = graphics.getTransform(); graphics.translate(getX(), getY()); AffineTransform txOffset = graphics.getTransform(); // Paint points and lines for (DataSource s : plot.getVisibleData()) { // Skip empty data source if (s.getColumnCount() == 0) { continue; } int colX = 0; if (colX < 0 || colX >= s.getColumnCount() || !s.isColumnNumeric(colX)) { continue; } int colY = 1; if (colY < 0 || colY >= s.getColumnCount() || !s.isColumnNumeric(colY)) { continue; } String[] axisNames = plot.getMapping(s); Axis axisX = plot.getAxis(axisNames[0]); Axis axisY = plot.getAxis(axisNames[1]); if (!axisX.isValid() || !axisY.isValid()) { continue; } AxisRenderer axisXRenderer = plot.getAxisRenderer(axisNames[0]); AxisRenderer axisYRenderer = plot.getAxisRenderer(axisNames[1]); List points = new LinkedList(); for (int i = 0; i < s.getRowCount(); i++) { Row row = new Row(s, i); Number valueX = (Number) row.get(colX); Number valueY = (Number) row.get(colY); PointND axisPosX = (axisXRenderer != null) ? axisXRenderer.getPosition(axisX, valueX, true, false) : new PointND(0.0, 0.0); PointND axisPosY = (axisYRenderer != null) ? axisYRenderer.getPosition(axisY, valueY, true, false) : new PointND(0.0, 0.0); if (axisPosX == null || axisPosY == null) { continue; } PointND pos = new PointND( axisPosX.get(PointND.X), axisPosY.get(PointND.Y)); PointData pointData = new PointData( Arrays.asList(axisX, axisY), Arrays.asList(axisXRenderer, axisYRenderer), row, colY); DataPoint dataPoint = new DataPoint(pointData, pos); points.add(dataPoint); } List pointRenderers = new ArrayList(plot.getPointRenderers(s)); Collections.reverse(pointRenderers); List areaRenderers = new ArrayList(plot.getAreaRenderers(s)); Collections.reverse(areaRenderers); for (AreaRenderer areaRenderer : areaRenderers) { Shape area = areaRenderer.getAreaShape(points); Shape punchedArea = area; for (PointRenderer pointRenderer : pointRenderers) { List punchShapes = new ArrayList(points.size()); for (DataPoint point : points) { Shape punchShape = pointRenderer.getPointShape(point.data); punchShapes.add(punchShape); } punchedArea = punch(punchedArea, points, punchShapes, areaRenderer.getGap(), areaRenderer.isGapRounded()); } Drawable drawable = areaRenderer.getArea(points, punchedArea); drawable.draw(context); } List lineRenderers = new ArrayList(plot.getLineRenderers(s)); Collections.reverse(lineRenderers); for (LineRenderer lineRenderer : lineRenderers) { Shape line = lineRenderer.getLineShape(points); Shape punchedLine = line; for (PointRenderer pointRenderer : pointRenderers) { List punchShapes = new ArrayList(points.size()); for (DataPoint point : points) { Shape punchShape = pointRenderer.getPointShape(point.data); punchShapes.add(punchShape); } punchedLine = punch(punchedLine, points, punchShapes, lineRenderer.getGap(), lineRenderer.isGapRounded()); } Drawable drawable = lineRenderer.getLine(points, punchedLine); drawable.draw(context); } if (!plot.getPointRenderers(s).isEmpty()) { // Draw graphics for (DataPoint point : points) { PointND pos = point.position; double pointX = pos.get(PointND.X); double pointY = pos.get(PointND.Y); graphics.translate(pointX, pointY); for (PointRenderer pointRenderer : plot.getPointRenderers(s)) { Shape pointShape = pointRenderer.getPointShape(point.data); Drawable pointDrawable = pointRenderer.getPoint(point.data, pointShape); pointDrawable.draw(context); } graphics.setTransform(txOffset); } // Draw labels for (DataPoint point : points) { PointND pos = point.position; double pointX = pos.get(PointND.X); double pointY = pos.get(PointND.Y); graphics.translate(pointX, pointY); for (PointRenderer pointRenderer : plot.getPointRenderers(s)) { Shape pointShape = pointRenderer.getPointShape(point.data); Drawable labelDrawable = pointRenderer.getValue(point.data, pointShape); labelDrawable.draw(context); } graphics.setTransform(txOffset); } } } // Reset transformation (offset) graphics.setTransform(txOrig); if (clipOffset != null) { // Reset clipping graphics.setClip(clipBoundsOld); } } /** * Returns the shape from which the shapes of the specified points are subtracted. * @param shape Shape to be modified. * @param dataPoints Data points on the line. * @param punchShapes Shape used for punching. * @param gap Gap between shape and point shapes. * @param roundedGaps {@code true} if the shape gaps are rounded. * @return Punched shape. */ protected static Shape punch(Shape shape, List dataPoints, List punchShapes, double gap, boolean roundedGaps) { if (!MathUtils.isCalculatable(gap) || gap == 0.0) { return shape; } // Subtract shapes of data points from the line to yield gaps. Area punched = new Area(shape); for (int pointIndex = 0; pointIndex < dataPoints.size(); pointIndex++) { DataPoint p = dataPoints.get(pointIndex); punched = GeometryUtils.punch(punched, gap, roundedGaps, p.position.getPoint2D(), punchShapes.get(pointIndex)); } return punched; } /** * Returns whether horizontal grid lines at major ticks along the * x-axis are drawn. * @return {@code true} if horizontal grid lines at major ticks along * the x-axis are drawn, otherwise {@code false}. */ public boolean isMajorGridX() { return majorGridX; } /** * Sets whether horizontal grid lines at major ticks along the x-axis * will be drawn. * @param gridMajorX {@code true} if horizontal grid lines at major * ticks along the x-axis should be drawn, otherwise {@code false}. */ public void setMajorGridX(boolean gridMajorX) { this.majorGridX = gridMajorX; } /** * Returns whether vertical grid lines at major ticks along the y-axis * are drawn. * @return {@code true} if vertical grid lines at major ticks along the * y-axis are drawn, otherwise {@code false}. */ public boolean isMajorGridY() { return majorGridY; } /** * Sets whether vertical grid lines at major ticks along the y-axis * will be drawn. * @param gridMajorY {@code true} if vertical grid lines at major ticks * along the y-axis should be drawn, otherwise {@code false}. */ public void setMajorGridY(boolean gridMajorY) { this.majorGridY = gridMajorY; } /** * Returns the paint which is used to paint the grid lines at major * ticks. * @return Paint which is used to paint the grid lines at major ticks. */ public Paint getMajorGridColor() { return majorGridColor; } /** * Sets the paint which will be used to paint the grid lines at major * ticks. * @param color Paint which should be used to paint the grid lines at * major ticks. */ public void setMajorGridColor(Color color) { this.majorGridColor = color; } /** * Returns whether horizontal grid lines at minor ticks along the * x-axis are drawn. * @return {@code true} if horizontal grid lines at minor ticks along * the x-axis are drawn, otherwise {@code false}. */ public boolean isMinorGridX() { return minorGridX; } /** * Sets whether horizontal grid lines at minor ticks along the x-axis * will be drawn. * @param gridMinorX {@code true} if horizontal grid lines at minor * ticks along the x-axis should be drawn, otherwise {@code false}. */ public void setMinorGridX(boolean gridMinorX) { this.minorGridX = gridMinorX; } /** * Returns whether vertical grid lines at minor ticks along the y-axis * are drawn. * @return {@code true} if vertical grid lines at minor ticks along the * y-axis are drawn, otherwise {@code false}. */ public boolean isMinorGridY() { return minorGridY; } /** * Sets whether vertical grid lines at minor ticks along the y-axis * will be drawn. * @param gridMinorY {@code true} if vertical grid lines at minor ticks * along the y-axis should be drawn, otherwise {@code false}. */ public void setMinorGridY(boolean gridMinorY) { this.minorGridY = gridMinorY; } /** * Returns the paint which is used to paint the grid lines at minor * ticks. * @return Paint which is used to paint the grid lines at minor ticks. */ public Paint getMinorGridColor() { return minorGridColor; } /** * Sets the paint which will be used to paint the grid lines at minor * ticks. * @param color Paint which should be used to paint the grid lines at * minor ticks. */ public void setMinorGridColor(Color color) { this.minorGridColor = color; } } /** * Class that displays a legend in an {@code XYPlot}. */ public static class XYLegend extends SeriesLegend { /** Version id for serialization. */ private static final long serialVersionUID = -4629928754001372002L; /** Source for dummy data. */ private static final DataSource DUMMY_DATA = new DummyData(2, Integer.MAX_VALUE, 0.5); /** Plot that contains settings and renderers. */ private final XYPlot plot; /** * Constructor that initializes the instance with a plot acting as a * provider for settings and renderers. * @param plot Plot. */ public XYLegend(XYPlot plot) { this.plot = plot; } /** * Returns a symbol for rendering a legend item. * @param row Data row. * @return A drawable object that can be used to display the symbol. */ public Drawable getSymbol(final Row row) { return new AbstractSymbol(this) { /** Version id for serialization. */ private static final long serialVersionUID = 5744026898590787285L; public void draw(DrawingContext context) { DataSource data = row.getSource(); Row symbolRow = new Row(DUMMY_DATA, row.getIndex()); Rectangle2D bounds = getBounds(); Axis axisX = new Axis(0.0, 1.0); AxisRenderer axisRendererX = new LinearRenderer2D(); axisRendererX.setShape(new Line2D.Double( bounds.getMinX(), bounds.getCenterY(), bounds.getMaxX(), bounds.getCenterY())); Axis axisY = new Axis(0.0, 1.0); AxisRenderer axisRendererY = new LinearRenderer2D(); axisRendererY.setShape(new Line2D.Double( bounds.getCenterX(), bounds.getMaxY(), bounds.getCenterX(), bounds.getMinY())); PointData pointData = new PointData( Arrays.asList(axisX, axisY), Arrays.asList(axisRendererX, axisRendererY), symbolRow, 0); DataPoint p1 = new DataPoint( pointData, new PointND(bounds.getMinX(), bounds.getCenterY()) ); DataPoint p2 = new DataPoint( pointData, new PointND(bounds.getCenterX(), bounds.getCenterY()) ); DataPoint p3 = new DataPoint( pointData, new PointND(bounds.getMaxX(), bounds.getCenterY()) ); List points = Arrays.asList(p1, p2, p3); // TODO: Provide a means to set the AreaRenderer used for the Legend AreaRenderer areaRenderer = null; List areaRenderers = plot.getAreaRenderers(data); if (!areaRenderers.isEmpty()) { areaRenderer = areaRenderers.get(0); } if (areaRenderer != null) { Shape area = areaRenderer.getAreaShape(points); Drawable drawable = areaRenderer.getArea(points, area); drawable.draw(context); } // TODO: Provide a means to set the LineRenderer used for the Legend LineRenderer lineRenderer = null; List lineRenderers = plot.getLineRenderers(data); if (!lineRenderers.isEmpty()) { lineRenderer = lineRenderers.get(0); } if (lineRenderer != null) { Shape line = lineRenderer.getLineShape(points); Drawable drawable = lineRenderer.getLine(points, line); drawable.draw(context); } // TODO: Provide a means to set the PointRenderer used for the Legend PointRenderer pointRenderer = null; List pointRenderers = plot.getPointRenderers(data); if (!pointRenderers.isEmpty()) { pointRenderer = pointRenderers.get(0); } if (pointRenderer != null) { Graphics2D graphics = context.getGraphics(); Point2D pos = p2.position.getPoint2D(); AffineTransform txOrig = graphics.getTransform(); graphics.translate(pos.getX(), pos.getY()); Shape shape = pointRenderer.getPointShape(pointData); Drawable drawable = pointRenderer.getPoint(pointData, shape); drawable.draw(context); graphics.setTransform(txOrig); } } }; } } /** * Initializes a new instance object with the specified data sources and * reasonable default settings. * @param data Data to be displayed. */ public XYPlot(DataSource... data) { super(); pointRenderersByDataSource = new HashMap>(data.length); lineRenderersByDataSource = new HashMap>(data.length); areaRenderersByDataSource = new HashMap>(data.length); setPlotArea(new XYPlotArea2D(this)); setLegend(new XYLegend(this)); // Handle data sources after the renderer lists are initialized for (DataSource source : data) { add(source); } createDefaultAxes(); autoscaleAxes(); createDefaultAxisRenderers(); // Listen for changes of the axis range for (String axisName : getAxesNames()) { getAxis(axisName).addAxisListener(this); } } @Override protected void createDefaultAxes() { // Create x axis and y axis by default Axis axisX = new Axis(); Axis axisY = new Axis(); setAxis(AXIS_X, axisX); setAxis(AXIS_Y, axisY); } @Override protected void createDefaultAxisRenderers() { // Create renderers for x and y axes by default AxisRenderer axisXRenderer = new LinearRenderer2D(); AxisRenderer axisYRenderer = new LinearRenderer2D(); setAxisRenderer(AXIS_X, axisXRenderer); setAxisRenderer(AXIS_Y, axisYRenderer); } @Override protected void layoutAxes() { if (getPlotArea() == null) { return; } // Set the new shapes first to allow for correct positioning layoutAxisShape(AXIS_X, Orientation.HORIZONTAL); layoutAxisShape(AXIS_X2, Orientation.HORIZONTAL); layoutAxisShape(AXIS_Y, Orientation.VERTICAL); layoutAxisShape(AXIS_Y2, Orientation.VERTICAL); // Set bounds with new axis shapes layoutAxisComponent(AXIS_X, Orientation.HORIZONTAL); layoutAxisComponent(AXIS_X2, Orientation.HORIZONTAL); layoutAxisComponent(AXIS_Y, Orientation.VERTICAL); layoutAxisComponent(AXIS_Y2, Orientation.VERTICAL); } private void layoutAxisShape(String axisName, Orientation orientation) { Rectangle2D plotBounds = getPlotArea().getBounds(); Drawable comp = getAxisComponent(axisName); AxisRenderer renderer = getAxisRenderer(axisName); if (comp == null || renderer == null) { return; } Dimension2D size = comp.getPreferredSize(); Shape shape; if (orientation == Orientation.HORIZONTAL) { shape = new Line2D.Double( 0.0, 0.0, plotBounds.getWidth(), 0.0 ); } else { shape = new Line2D.Double( size.getWidth(), plotBounds.getHeight(), size.getWidth(), 0.0 ); } renderer.setShape(shape); } private void layoutAxisComponent(String axisName, Orientation orientation) { Drawable comp = getAxisComponent(axisName); AxisRenderer renderer = getAxisRenderer(axisName); if (comp == null || renderer == null) { return; } String nameSecondary; if (orientation == Orientation.HORIZONTAL) { nameSecondary = AXIS_Y; } else { nameSecondary = AXIS_X; } Axis axisSecondary = getAxis(nameSecondary); AxisRenderer rendererSecondary = getAxisRenderer(nameSecondary); if (axisSecondary == null || !axisSecondary.isValid() || rendererSecondary == null) { return; } Number intersection = renderer.getIntersection(); PointND pos = rendererSecondary.getPosition( axisSecondary, intersection, false, false); if (pos == null) { pos = new PointND(0.0, 0.0); } Rectangle2D plotBounds = getPlotArea().getBounds(); Dimension2D size = comp.getPreferredSize(); if (orientation == Orientation.HORIZONTAL) { comp.setBounds( plotBounds.getMinX(), pos.get(1) + plotBounds.getMinY(), plotBounds.getWidth(), size.getHeight() ); } else { comp.setBounds( plotBounds.getMinX() - size.getWidth() + pos.get(0), plotBounds.getMinY(), size.getWidth(), plotBounds.getHeight() ); } } /** * Returns all {@code PointRenderer}s that display the data of the specified data source. * @param s Data source in question. * @return Renderers being applied on the specified data source. */ public List getPointRenderers(DataSource s) { List pointRenderers = pointRenderersByDataSource.get(s); if (pointRenderers != null) { return Collections.unmodifiableList(pointRenderers); } return Collections.emptyList(); } /** * Adds a {@code PointRenderer} for the specified data source. * @param s Data to be rendered. * @param pointRenderer PointRenderer to be used. */ public void addPointRenderer(DataSource s, PointRenderer pointRenderer) { List pointRenderers = pointRenderersByDataSource.get(s); if (pointRenderers == null) { pointRenderers = new ArrayList(); pointRenderersByDataSource.put(s, pointRenderers); } pointRenderers.add(pointRenderer); } /** * Decouples the specified {@code PointRenderer} from the rendering of the specified data source. * @param s Data to be rendered no longer. * @param pointRenderer PointRenderer to be removed. */ public void removePointRenderer(DataSource s, PointRenderer pointRenderer) { List pointRenderers = pointRenderersByDataSource.get(s); if (pointRenderers != null) { pointRenderers.remove(pointRenderer); } } /** * Sets the {@code PointRenderer}s for a certain data source to the specified value. * @param s Data source. * @param pointRenderers PointRenderers to be set. */ public void setPointRenderers(DataSource s, List pointRenderers) { this.pointRenderersByDataSource.put(s, pointRenderers); } /** * Sets the {@code PointRenderer}s for a certain data source to the specified value. * @param s Data source. * @param pointRendererFirst First PointRenderer. * @param pointRenderers Remaining PointRenderers to be set. */ public void setPointRenderers(DataSource s, PointRenderer pointRendererFirst, PointRenderer... pointRenderers) { List pointRendererList = null; if (pointRendererFirst == null) { setPointRenderers(s, pointRendererList); return; } pointRendererList = new ArrayList(pointRenderers.length + 1); pointRendererList.add(pointRendererFirst); for (PointRenderer pointRenderer : pointRenderers) { if (pointRenderer == null) { throw new IllegalArgumentException("A PointRenderer for a DataSource cannot be null."); } pointRendererList.add(pointRenderer); } setPointRenderers(s, pointRendererList); } /** * Returns all {@code LineRenderer}s that display the data of the specified data source. * @param s Data source in question. * @return Renderers being applied on the specified data source. */ public List getLineRenderers(DataSource s) { List lineRenderers = lineRenderersByDataSource.get(s); if (lineRenderers != null) { return Collections.unmodifiableList(lineRenderers); } return Collections.emptyList(); } /** * Sets the {@code LineRenderer}s for a certain data source to the specified * value. * @param s Data source. * @param lineRenderers {@code LineRenderer}s to be set. */ public void setLineRenderers(DataSource s, List lineRenderers) { lineRenderersByDataSource.put(s, lineRenderers); } /** * Sets the {@code LineRenderer}s for a certain data source to the specified * value. * @param s Data source. * @param lineRendererFirst First {@code LineRenderer} to be set. * @param lineRenderers Remaining {@code LineRenderer}s to be set. */ public void setLineRenderers(DataSource s, LineRenderer lineRendererFirst, LineRenderer... lineRenderers) { List lineRendererList = null; if (lineRendererFirst == null) { setLineRenderers(s, lineRendererList); return; } lineRendererList = new ArrayList(lineRenderers.length + 1); lineRendererList.add(lineRendererFirst); for (LineRenderer lineRenderer : lineRenderers) { if (lineRenderer == null) { throw new IllegalArgumentException("A LineRenderer for a DataSource cannot be null."); } lineRendererList.add(lineRenderer); } setLineRenderers(s, lineRendererList); } /** * Returns all {@code AreaRenderer}s for the specified data source. * @param s Data source. * @return {@code AreaRenderer}s used to render the {@code DataSource}. */ public List getAreaRenderers(DataSource s) { List areaRenderers = areaRenderersByDataSource.get(s); if (areaRenderers != null) { return Collections.unmodifiableList(areaRenderers); } return Collections.emptyList(); } /** * Sets the {@code AreaRenderer}s for a certain data source to the specified * value. * @param s Data source. * @param areaRenderers {@code AreaRenderer}s to be set. */ public void setAreaRenderers(DataSource s, List areaRenderers) { areaRenderersByDataSource.put(s, areaRenderers); } /** * Sets the {@code AreaRenderer}s for a certain data source to the specified * value. * @param s Data source. * @param areaRendererFirst First {@code AreaRenderer} to be set. * @param areaRenderers Remaining {@code AreaRenderer}s to be set. */ public void setAreaRenderers(DataSource s, AreaRenderer areaRendererFirst, AreaRenderer... areaRenderers) { List areaRendererList = null; if (areaRendererFirst == null) { setAreaRenderers(s, areaRendererList); return; } areaRendererList = new ArrayList(areaRenderers.length + 1); areaRendererList.add(areaRendererFirst); for (AreaRenderer areaRenderer : areaRenderers) { if (areaRenderer == null) { throw new IllegalArgumentException("An AreaRenderer for a DataSource cannot be null."); } areaRendererList.add(areaRenderer); } setAreaRenderers(s, areaRendererList); } @Override public void setAxisRenderer(String axisName, AxisRenderer renderer) { if (renderer != null) { if (AXIS_X2.equals(axisName) || AXIS_Y.equals(axisName)) { renderer.setShapeNormalOrientationClockwise(true); } if (AXIS_Y.equals(axisName)) { renderer.getLabel().setRotation(90.0); } } super.setAxisRenderer(axisName, renderer); } @Override public void add(int index, DataSource source, boolean visible) { super.add(index, source, visible); // Set axis mapping setMapping(source, AXIS_X, AXIS_Y); // The mapping from columns to axes has changed, so scaling has to be // refreshed autoscaleAxes(); // Assign default renderers PointRenderer pointRendererDefault = new DefaultPointRenderer2D(); LineRenderer lineRendererDefault = null; AreaRenderer areaRendererDefault = null; // FIXME: Overwrites possible present point and line renderers setPointRenderers(source, pointRendererDefault); setLineRenderers(source, lineRendererDefault); setAreaRenderers(source, areaRendererDefault); } /** * Returns a navigator instance that can control the current object. * @return A navigator instance. */ public Navigator getNavigator() { if (navigator == null) { navigator = new XYPlotNavigator(this); } return navigator; } @Override public void draw(DrawingContext context) { super.draw(context); if (!navigatorInitialized) { getNavigator().setDefaultState(); navigatorInitialized = true; } } /** * Notified if the range of an axis has changed. * @param axis Axis instance that has changed. * @param min New minimum value. * @param max New maximum value. */ public void rangeChanged(Axis axis, Number min, Number max) { layoutAxes(); } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Normal deserialization in.defaultReadObject(); // Restore listeners for (String axisName : getAxesNames()) { getAxis(axisName).addAxisListener(this); } } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/areas/000077500000000000000000000000001267060725100251225ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/areas/AbstractAreaRenderer.java000066400000000000000000000042271267060725100320150ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.areas; import java.awt.Color; import java.awt.Paint; import java.io.Serializable; /** *

Abstract class that renders an area in two-dimensional space.

*

Functionality includes:

*
    *
  • Punching data points out of the area's shape
  • *
  • Administration of settings
  • *
*/ public abstract class AbstractAreaRenderer implements AreaRenderer, Serializable { /** Version id for serialization. */ private static final long serialVersionUID = -9064749128190128428L; /** Gap between points and the area. */ private double gap; /** Decides whether the shape of the gap between points and the area is * rounded. */ private boolean gapRounded; /** Paint to fill the area. */ private Paint color; /** * Initializes a new instance with default settings. */ public AbstractAreaRenderer() { gap = 0.0; gapRounded = false; color = Color.GRAY; } @Override public double getGap() { return gap; } @Override public void setGap(double gap) { this.gap = gap; } @Override public boolean isGapRounded() { return gapRounded; } @Override public void setGapRounded(boolean gapRounded) { this.gapRounded = gapRounded; } @Override public Paint getColor() { return color; } @Override public void setColor(Paint color) { this.color = color; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/areas/AreaRenderer.java000066400000000000000000000051261267060725100303300ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.areas; import java.awt.Paint; import java.awt.Shape; import java.util.List; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.plots.DataPoint; /** * Interface for renderers that display areas in plots. */ public interface AreaRenderer { /** * Returns the shape used for rendering the area of a data points. * @param points Data points. * @return Geometric shape for the area of the specified data points. */ Shape getAreaShape(List points); /** * Returns the graphical representation to be drawn for the specified data * points. * @param points Points that define the shape of the area. * @param shape Geometric shape of the area. * @return Representation of the area. */ Drawable getArea(List points, Shape shape); // TODO: Mention which unit the Gap property has (pixels?) /** * Returns the value for the gap between the area and a data point. * @return Gap between area and data point. */ double getGap(); /** * Sets the value for the gap between the area and a data point. * @param gap Gap between area and data point. */ void setGap(double gap); /** * Returns whether the gaps should have rounded corners. * @return {@code true}, if the gaps should have rounded corners. */ boolean isGapRounded(); /** * Sets a value which decides whether the gaps should have rounded corners. * @param gapRounded {@code true}, if the gaps should have rounded corners. */ void setGapRounded(boolean gapRounded); /** * Returns the paint used to fill the area shape. * @return Paint for the area shape. */ Paint getColor(); /** * Sets the paint used to fill the area shape. * @param color Paint for the area shape. */ void setColor(Paint color); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/areas/DefaultAreaRenderer2D.java000066400000000000000000000072711267060725100320260ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.areas; import java.awt.Paint; import java.awt.Shape; import java.awt.geom.Path2D; import java.awt.geom.Point2D; import java.util.List; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.DataPoint; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.util.MathUtils; import de.erichseifert.gral.util.PointND; /** * Default two-dimensional implementation of the {@code AreaRenderer} * interface. */ public class DefaultAreaRenderer2D extends AbstractAreaRenderer { /** Version id for serialization. */ private static final long serialVersionUID = -202003022764142849L; /** * Returns the graphical representation to be drawn for the specified * data points. * @param points Points to be used for creating the area. * @param shape Geometric shape of the area. * @return Representation of the area. */ public Drawable getArea(final List points, final Shape shape) { return new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = -3659798228877496727L; /** * Draws the {@code Drawable} with the specified drawing context. * @param context Environment used for drawing */ public void draw(DrawingContext context) { Paint paint = DefaultAreaRenderer2D.this.getColor(); GraphicsUtils.fillPaintedShape(context.getGraphics(), shape, paint, null); } }; } /** * Returns the shape used for rendering the area of a data points. * @param points Data points. * @return Geometric shape for the area of the specified data points. */ public Shape getAreaShape(List points) { if (points.isEmpty() || points.get(0) == null) { return null; } Axis axisY = points.get(0).data.axes.get(1); AxisRenderer axisRendererY = points.get(0).data.axisRenderers.get(1); double axisYMin = axisY.getMin().doubleValue(); double axisYMax = axisY.getMax().doubleValue(); double axisYOrigin = MathUtils.limit(0.0, axisYMin, axisYMax); PointND posOrigin = null; if (axisRendererY != null) { posOrigin = axisRendererY.getPosition( axisY, axisYOrigin, true, false); } Path2D shape = new Path2D.Double(); if (posOrigin == null) { return shape; } double posYOrigin = posOrigin.get(PointND.Y); double x = 0.0; double y = 0.0; for (DataPoint p: points) { Point2D pos = p.position.getPoint2D(); x = pos.getX(); y = pos.getY(); if (shape.getCurrentPoint() == null) { shape.moveTo(x, posYOrigin); } shape.lineTo(x, y); } if (shape.getCurrentPoint() != null) { shape.lineTo(x, posYOrigin); shape.closePath(); } return shape; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/areas/LineAreaRenderer2D.java000066400000000000000000000103501267060725100313210ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.areas; import java.awt.BasicStroke; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.Path2D; import java.awt.geom.Point2D; import java.util.List; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.DataPoint; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.util.MathUtils; import de.erichseifert.gral.util.PointND; /** * Default two-dimensional implementation of the {@code AreaRenderer} interface * that draws lines from data points to the main axis. */ public class LineAreaRenderer2D extends AbstractAreaRenderer { /** Version id for serialization. */ private static final long serialVersionUID = -8396097579938931392L; /** Stroke that is used to draw the lines from the data points to the * axis. */ private Stroke stroke; /** * Standard constructor that initializes a new instance. */ public LineAreaRenderer2D() { stroke = new BasicStroke(1f); } /** * Returns the graphical representation to be drawn for the specified data * points. * @param points Points that define the shape of the area. * @param shape Geometric shape of the area. * @return Representation of the area. */ public Drawable getArea(final List points, final Shape shape) { return new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = 5492321759151727458L; /** * Draws the {@code Drawable} with the specified drawing context. * @param context Environment used for drawing */ public void draw(DrawingContext context) { Paint paint = LineAreaRenderer2D.this.getColor(); GraphicsUtils.fillPaintedShape(context.getGraphics(), shape, paint, null); } }; } /** * Returns the shape used for rendering the area of a data points. * @param points Data points. * @return Geometric shape for the area of the specified data points. */ public Shape getAreaShape(List points) { if (points.isEmpty() || points.get(0) == null) { return null; } Axis axisY = points.get(0).data.axes.get(1); AxisRenderer axisRendererY = points.get(0).data.axisRenderers.get(1); double axisYMin = axisY.getMin().doubleValue(); double axisYMax = axisY.getMax().doubleValue(); double axisYOrigin = MathUtils.limit(0.0, axisYMin, axisYMax); double posYOrigin = 0.0; if (axisRendererY != null) { posYOrigin = axisRendererY.getPosition( axisY, axisYOrigin, true, false).get(PointND.Y); } Path2D shape = new Path2D.Double(); double x = 0.0; double y = 0.0; for (DataPoint p : points) { Point2D pos = p.position.getPoint2D(); x = pos.getX(); y = pos.getY(); shape.moveTo(x, y); shape.lineTo(x, posYOrigin); } Stroke stroke = getStroke(); return stroke.createStrokedShape(shape); } /** * Returns the stroke that is used to draw the lines from the * data points to the axis. * @return Stroke for line drawing. */ public Stroke getStroke() { return stroke; } /** * Set the stroke that is used to draw the lines from the * data points to the axis. * @param stroke Stroke for line drawing. */ public void setStroke(Stroke stroke) { this.stroke = stroke; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/areas/package-info.java000077500000000000000000000016771267060725100303270ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Classes for drawing areas in plots. */ package de.erichseifert.gral.plots.areas; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/axes/000077500000000000000000000000001267060725100247675ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/axes/AbstractAxisRenderer2D.java000066400000000000000000000724141267060725100321070ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.axes; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.Dimension2D; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.text.Format; import java.text.NumberFormat; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.graphics.Label; import de.erichseifert.gral.plots.axes.Tick.TickType; import de.erichseifert.gral.util.GeometryUtils; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.util.MathUtils; import de.erichseifert.gral.util.PointND; import de.erichseifert.gral.util.SerializationUtils; /** *

Abstract class that provides function for rendering axes in * two-dimensional space.

*

Functionality includes:

*
    *
  • Calculating tick positions of an axis
  • *
  • Calculating tick normals
  • *
  • Administration of settings
  • *
*/ public abstract class AbstractAxisRenderer2D implements AxisRenderer, Serializable { /** Version id for serialization. */ private static final long serialVersionUID = 5623525683845512624L; /** Line segments approximating the shape of the axis. */ private Line2D[] shapeLines; /** Normals of the line segments approximating the axis. */ private Point2D[] shapeLineNormals; /** Lengths of the line segments approximating the axis. */ private double[] shapeSegmentLengths; /** Length of the axis up to a certain approximating line segment. */ private double[] shapeSegmentLengthsAccumulated; /** Intersection point of the axis. */ private Number intersection; /** Shape used for drawing. */ private Shape shape; /** Decides whether the shape is drawn. */ private boolean shapeVisible; /** Decides whether the shape normals are orientated clockwise. */ private boolean shapeNormalOrientationClockwise; /** Paint used to draw axis shape, ticks, and labels. */ private Paint shapeColor; /** Stroke used for drawing the axis shape. */ // Property will be serialized using a wrapper private transient Stroke shapeStroke; /** Decides whether the axis direction will be changed. */ private boolean shapeDirectionSwapped; /** Decides whether major ticks are drawn. */ private boolean ticksVisible; /** Distance on axis in which major ticks are drawn. */ private Number tickSpacing; /** Decides whether automatic tick spacing is enabled. */ private boolean ticksAutoSpaced; /** Tick length relative to the font */ private double tickLength; /** Stroke which is used to draw all major ticks. */ // Property will be serialized using a wrapper private transient Stroke tickStroke; /** Alignment of major ticks relative to the axis. */ private double tickAlignment; /** Font used to display the text of major ticks. */ private Font tickFont; /** Paint used to draw the shapes of major ticks. */ private Paint tickColor; /** Decides whether tick labels will be shown. */ private boolean tickLabelsVisible; /** Format which converts the tick values to labels. */ private Format tickLabelFormat; /** Distance between labels and ticks relative to the font height. */ private double tickLabelDistance; /** Decides whether the tick labels are drawn outside of the plot. */ private boolean tickLabelsOutside; /** Tick label rotation in degrees. */ private double tickLabelRotation; /** Decides whether minor ticks are drawn. */ private boolean minorTickVisible; /** Number of minor ticks between two major ticks. */ private int minorTicksCount; /** Tick length relative to font height.*/ private double minorTickLength; /** Stroke used to draw all minor ticks. */ // Property will be serialized using a wrapper private transient Stroke minorTickStroke; /** Minor tick alignment relative to the axis. */ private double minorTickAlignment; /** Paint used to draw the shapes of minor ticks. */ private Paint minorTickColor; /** Custom labels containing their respective position and text. */ private final Map customTicks; /** Label text of the axis. */ private Label label; /** Distance relative to font height. */ private double labelDistance; /** * Initializes a new instance with default settings. */ public AbstractAxisRenderer2D() { intersection = 0.0; // The direction must defined as swapped before the shape is evaluated. shapeDirectionSwapped = false; shape = new Line2D.Double(0.0, 0.0, 1.0, 0.0); evaluateShape(shape); shapeVisible = true; shapeNormalOrientationClockwise = false; shapeStroke = new BasicStroke(); shapeColor = Color.BLACK; ticksVisible = true; tickSpacing = 0.0; ticksAutoSpaced = false; tickLength = 1.0; tickStroke = new BasicStroke(); tickAlignment = 0.5; tickFont = Font.decode(null); tickColor = Color.BLACK; tickLabelsVisible = true; tickLabelFormat = NumberFormat.getInstance(); tickLabelDistance = 1.0; tickLabelsOutside = true; tickLabelRotation = 0.0; customTicks = new HashMap(); minorTickVisible = true; minorTicksCount = 1; minorTickLength = 0.5; minorTickStroke = new BasicStroke(); minorTickAlignment = 0.5; minorTickColor = Color.BLACK; label = new Label(); labelDistance = 1.0; } /** * Returns a component that displays the specified axis. * @param axis axis to be displayed * @return component displaying the axis * @see Axis */ public Drawable getRendererComponent(final Axis axis) { final Drawable component = new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = 3605211198378801694L; /** * Draws the {@code Drawable} with the specified drawing context. * @param context Environment used for drawing */ public void draw(DrawingContext context) { if (shapeLines == null || shapeLines.length == 0) { return; } AbstractAxisRenderer2D renderer = AbstractAxisRenderer2D.this; Graphics2D graphics = context.getGraphics(); // Remember old state of Graphics2D instance AffineTransform txOrig = graphics.getTransform(); graphics.translate(getX(), getY()); Stroke strokeOld = graphics.getStroke(); Paint paintOld = graphics.getPaint(); // Draw axis shape Paint axisPaint = renderer.getShapeColor(); Stroke axisStroke = renderer.getShapeStroke(); boolean isShapeVisible = renderer.isShapeVisible(); if (isShapeVisible) { Shape shape = renderer.getShape(); GraphicsUtils.drawPaintedShape( graphics, shape, axisPaint, null, axisStroke); } double fontSize = renderer.getTickFont().getSize2D(); // Draw ticks boolean drawTicksMajor = renderer.isTicksVisible(); boolean drawTicksMinor = renderer.isMinorTicksVisible(); if (drawTicksMajor || (drawTicksMajor && drawTicksMinor)) { // Calculate tick positions (in pixel coordinates) List ticks = getTicks(axis); boolean isTickLabelVisible = renderer.isTickLabelsVisible(); boolean isTickLabelOutside = renderer.isTickLabelsOutside(); double tickLabelRotation = renderer.getTickLabelRotation(); double tickLabelDist = renderer.getTickLabelDistanceAbsolute(); Line2D tickShape = new Line2D.Double(); for (Tick tick : ticks) { // Draw tick if ((tick.position == null) || (tick.normal == null)) { continue; } Point2D tickPoint = tick.position.getPoint2D(); Point2D tickNormal = tick.normal.getPoint2D(); double tickLength; double tickAlignment; Paint tickPaint; Stroke tickStroke; if (TickType.MINOR.equals(tick.type)) { tickLength = renderer.getTickMinorLengthAbsolute(); tickAlignment = renderer.getMinorTickAlignment(); tickPaint = renderer.getMinorTickColor(); tickStroke = renderer.getMinorTickStroke(); } else { tickLength = getTickLengthAbsolute(); tickAlignment = renderer.getTickAlignment(); tickPaint = renderer.getTickColor(); tickStroke = renderer.getTickStroke(); } double tickLengthInner = tickLength*tickAlignment; double tickLengthOuter = tickLength*(1.0 - tickAlignment); if ((drawTicksMajor && (tick.type == TickType.MAJOR) || tick.type == TickType.CUSTOM) || (drawTicksMinor && tick.type == TickType.MINOR)) { tickShape.setLine( tickPoint.getX() - tickNormal.getX()*tickLengthInner, tickPoint.getY() - tickNormal.getY()*tickLengthInner, tickPoint.getX() + tickNormal.getX()*tickLengthOuter, tickPoint.getY() + tickNormal.getY()*tickLengthOuter ); GraphicsUtils.drawPaintedShape( graphics, tickShape, tickPaint, null, tickStroke); } // Draw label if (isTickLabelVisible && (tick.type == TickType.MAJOR || tick.type == TickType.CUSTOM)) { String tickLabelText = tick.label; if (tickLabelText != null && !tickLabelText.trim().isEmpty()) { Label tickLabel = new Label(tickLabelText); tickLabel.setFont(renderer.getTickFont()); // TODO Allow separate colors for ticks and tick labels? tickLabel.setColor(tickPaint); double labelDist = tickLengthOuter + tickLabelDist; layoutLabel(tickLabel, tickPoint, tickNormal, labelDist, isTickLabelOutside, tickLabelRotation); tickLabel.draw(context); } } } } // Draw axis label Label axisLabel = renderer.getLabel(); if (axisLabel != null && !axisLabel.getText().trim().isEmpty()) { double tickLength = getTickLengthAbsolute(); double tickAlignment = renderer.getTickAlignment(); double tickLengthOuter = tickLength*(1.0 - tickAlignment); double tickLabelDistance = renderer.getTickLabelDistanceAbsolute(); double labelDistance = renderer.getLabelDistance()*fontSize; double labelDist = tickLengthOuter + tickLabelDistance + fontSize + labelDistance; double axisLabelPos = (axis.getMin().doubleValue() + axis.getMax().doubleValue()) * 0.5; boolean isTickLabelOutside = renderer.isTickLabelsOutside(); PointND labelPos = getPosition(axis, axisLabelPos, false, true); PointND labelNormal = getNormal(axis, axisLabelPos, false, true); if (labelPos != null && labelNormal != null) { layoutLabel(axisLabel, labelPos.getPoint2D(), labelNormal.getPoint2D(), labelDist, isTickLabelOutside, axisLabel.getRotation()); axisLabel.draw(context); } } graphics.setPaint(paintOld); graphics.setStroke(strokeOld); graphics.setTransform(txOrig); } private void layoutLabel(Label label, Point2D labelPos, Point2D labelNormal, double labelDist, boolean isLabelOutside, double rotation) { Rectangle2D labelSize = label.getTextRectangle(); Shape marginShape = new Rectangle2D.Double( 0, 0, labelSize.getWidth() + 2.0*labelDist, labelSize.getHeight() + 2.0*labelDist ); Rectangle2D marginBounds = marginShape.getBounds2D(); label.setRotation(rotation); if ((rotation%360.0) != 0.0) { marginShape = AffineTransform.getRotateInstance( Math.toRadians(-rotation), marginBounds.getCenterX(), marginBounds.getCenterY() ).createTransformedShape(marginShape); } marginBounds = marginShape.getBounds2D(); double intersRayLength = marginBounds.getHeight()*marginBounds.getHeight() + marginBounds.getWidth()*marginBounds.getWidth(); double intersRayDir = (isLabelOutside?-1.0:1.0)*intersRayLength; List descriptionBoundsIntersections = GeometryUtils.intersection( marginBounds, new Line2D.Double( marginBounds.getCenterX(), marginBounds.getCenterY(), marginBounds.getCenterX() + intersRayDir*labelNormal.getX(), marginBounds.getCenterY() + intersRayDir*labelNormal.getY() ) ); if (!descriptionBoundsIntersections.isEmpty()) { Point2D inters = descriptionBoundsIntersections.get(0); double intersX = inters.getX() - marginBounds.getCenterX(); double intersY = inters.getY() - marginBounds.getCenterY(); double posX = labelPos.getX() - intersX - labelSize.getWidth()/2.0; double posY = labelPos.getY() - intersY - labelSize.getHeight()/2.0; label.setBounds(posX, posY, labelSize.getWidth(), labelSize.getHeight()); } } @Override public Dimension2D getPreferredSize() { AbstractAxisRenderer2D renderer = AbstractAxisRenderer2D.this; double fontSize = renderer.getTickFont().getSize2D(); double tickLength = getTickLengthAbsolute(); double tickAlignment = renderer.getTickAlignment(); double tickLengthOuter = tickLength*(1.0 - tickAlignment); double labelDistance = renderer.getTickLabelDistanceAbsolute() + tickLengthOuter; double minSize = fontSize + labelDistance + tickLengthOuter; return new de.erichseifert.gral.graphics.Dimension2D.Double(minSize, minSize); } }; return component; } /** * Returns a list of all tick element on the axis. * @param axis Axis * @return A list of {@code Tick} instances */ public List getTicks(Axis axis) { List ticks = new LinkedList(); if (!axis.isValid()) { return ticks; } double min = axis.getMin().doubleValue(); double max = axis.getMax().doubleValue(); Set tickPositions = new HashSet(); createTicksCustom(ticks, axis, min, max, tickPositions); boolean isAutoSpacing = isTicksAutoSpaced(); // If the spacing is invalid, use auto spacing if (!isAutoSpacing) { Number tickSpacing = getTickSpacing(); if (tickSpacing == null) { isAutoSpacing = true; } else { double tickSpacingValue = tickSpacing.doubleValue(); if (tickSpacingValue <= 0.0 || !MathUtils.isCalculatable(tickSpacingValue)) { isAutoSpacing = true; } } } createTicks(ticks, axis, min, max, tickPositions, isAutoSpacing); return ticks; } /** * Returns the absolute length of a major tick. * @return Major tick length in pixels. */ protected double getTickLengthAbsolute() { double fontSize = getTickFont().getSize2D(); return getTickLength()*fontSize; } /** * Returns the absolute length of a minor tick. * @return Minor tick length in pixels. */ protected double getTickMinorLengthAbsolute() { double fontSize = getTickFont().getSize2D(); return getMinorTickLength()*fontSize; } /** * Returns the absolute distance between ticks and labels. * @return Distance in pixels. */ protected double getTickLabelDistanceAbsolute() { double fontSize = getTickFont().getSize2D(); return getTickLabelDistance()*fontSize; } /** * Adds minor and major ticks to a list of ticks. * @param ticks List of ticks * @param axis Axis * @param min Minimum value of axis * @param max Maximum value of axis * @param tickPositions Set of tick positions * @param isAutoSpacing Use automatic scaling */ protected abstract void createTicks(List ticks, Axis axis, double min, double max, Set tickPositions, boolean isAutoSpacing); /** * Adds custom ticks to a list of ticks. * @param ticks List of ticks * @param axis Axis * @param min Minimum value of axis * @param max Maximum value of axis * @param tickPositions Set of tick positions */ protected void createTicksCustom(List ticks, Axis axis, double min, double max, Set tickPositions) { Map labelsCustom = getCustomTicks(); if (labelsCustom != null) { for (Number tickPositionWorldObj : labelsCustom.keySet()) { double tickPositionWorld = tickPositionWorldObj.doubleValue(); if (tickPositionWorld < min || tickPositionWorld > max) { continue; } Tick tick = getTick( TickType.CUSTOM, axis, tickPositionWorld); ticks.add(tick); tickPositions.add(tickPositionWorld); } } } /** * Returns the point of the tick mark (in pixel coordinates) on the * specified axis with the specified value. * @param type Type of tick mark. * @param axis Axis containing the tick mark. * @param tickPositionWorld Displayed value on the axis. * @return Object describing the desired tick mark. */ protected Tick getTick(TickType type, Axis axis, double tickPositionWorld) { // Calculate position of tick on axis shape PointND tickPoint = getPosition(axis, tickPositionWorld, false, false); // Calculate tick normal PointND tickNormal = getNormal(axis, tickPositionWorld, false, false); // Retrieve tick label String tickLabel; Map labelsCustom = getCustomTicks(); if (labelsCustom != null && labelsCustom.containsKey(tickPositionWorld)) { tickLabel = labelsCustom.get(tickPositionWorld); } else { Format labelFormat = getTickLabelFormat(); if (labelFormat != null) { tickLabel = labelFormat.format(tickPositionWorld); } else { tickLabel = String.valueOf(tickPositionWorld); } } Tick tick = new Tick(type, tickPoint, tickNormal, null, null, tickLabel); return tick; } /** * Returns the normal vector at the position of the specified value. * The vector is normalized. * @param axis Axis * @param value World coordinate value to convert * @param extrapolate Option to activate extrapolation value that are not * on the axis * @param forceLinear Force linear interpolation. * @return N-dimensional normal vector at the position */ public PointND getNormal(Axis axis, Number value, boolean extrapolate, boolean forceLinear) { double valueView; if (forceLinear) { valueView = (value.doubleValue() - axis.getMin().doubleValue()) / axis.getRange()*getShapeLength(); } else { valueView = worldToView(axis, value, extrapolate); } int segmentIndex = MathUtils.binarySearchFloor(shapeSegmentLengthsAccumulated, valueView); if (segmentIndex < 0 || segmentIndex >= shapeLines.length) { return null; } segmentIndex = MathUtils.limit( segmentIndex, 0, shapeLineNormals.length - 1); boolean normalOrientationClockwise = AbstractAxisRenderer2D.this .isShapeNormalOrientationClockwise(); double normalOrientation = normalOrientationClockwise ? 1.0 : -1.0; PointND tickNormal = new PointND( normalOrientation * shapeLineNormals[segmentIndex].getX(), normalOrientation * shapeLineNormals[segmentIndex].getY() ); return tickNormal; } /** * Returns the length of the shape path which is used to render axes. * @return Shape length. */ protected double getShapeLength() { if (shapeSegmentLengthsAccumulated == null || shapeSegmentLengthsAccumulated.length == 0) { return 0.0; } return shapeSegmentLengthsAccumulated[shapeSegmentLengthsAccumulated.length - 1]; } /** * Returns the position of the specified value on the axis. * The value is returned in view coordinates. * @param axis Axis * @param value World coordinate value to convert * @param extrapolate Option to activate extrapolation value that are not * on the axis * @param forceLinear Force linear interpolation. * @return N-dimensional point of the value */ public PointND getPosition(Axis axis, Number value, boolean extrapolate, boolean forceLinear) { if (shapeLines == null || shapeLines.length == 0 || value == null) { return null; } // Determine relative position of the value double relativePositionOnShapePath = axis.getPosition(value).doubleValue(); if (!extrapolate) { relativePositionOnShapePath = MathUtils.limit(relativePositionOnShapePath, 0.0, 1.0); } // Determine absolute position of the value double positionOnShapePath; if (forceLinear) { positionOnShapePath = relativePositionOnShapePath*getShapeLength(); } else { positionOnShapePath = worldToView(axis, value, extrapolate); } if (Double.isNaN(positionOnShapePath)) { return null; } // TODO Check if this is a valid way to allow infinite values if (positionOnShapePath == Double.NEGATIVE_INFINITY) { positionOnShapePath = 0.0; } else if (positionOnShapePath == Double.POSITIVE_INFINITY) { positionOnShapePath = 1.0; } // Determine shape segment int segmentIndex; if (relativePositionOnShapePath <= 0.0) { segmentIndex = 0; } else if (relativePositionOnShapePath >= 1.0) { segmentIndex = shapeLines.length - 1; } else { // Determine to which segment the value belongs using a binary search segmentIndex = MathUtils.binarySearchFloor(shapeSegmentLengthsAccumulated, positionOnShapePath); } if (segmentIndex < 0 || segmentIndex >= shapeLines.length) { return null; } // Compute actual position of the value in view coordinates Line2D segment = shapeLines[segmentIndex]; double segmentLen = shapeSegmentLengths[segmentIndex]; double segmentLenAcc = shapeSegmentLengthsAccumulated[segmentIndex]; double relLen = (positionOnShapePath - segmentLenAcc)/segmentLen; double x = segment.getX1() + (segment.getX2() - segment.getX1())*relLen; double y = segment.getY1() + (segment.getY2() - segment.getY1())*relLen; return new PointND(x, y); } /** * Calculates important aspects of the specified shape. * @param shape Shape to be evaluated. */ protected final void evaluateShape(Shape shape) { boolean directionSwapped = isShapeDirectionSwapped(); shapeLines = GeometryUtils.shapeToLines(shape, directionSwapped); shapeSegmentLengths = new double[shapeLines.length]; // First length is always 0.0, last length is the total length shapeSegmentLengthsAccumulated = new double[shapeLines.length + 1]; shapeLineNormals = new Point2D[shapeLines.length]; if (shapeLines.length == 0) { return; } for (int i = 0; i < shapeLines.length; i++) { Line2D line = shapeLines[i]; // Calculate length of axis shape at each shape segment double segmentLength = line.getP1().distance(line.getP2()); shapeSegmentLengths[i] = segmentLength; shapeSegmentLengthsAccumulated[i + 1] = shapeSegmentLengthsAccumulated[i] + segmentLength; // Calculate a normalized vector perpendicular to the current // axis shape segment shapeLineNormals[i] = new Point2D.Double( (line.getY2() - line.getY1()) / segmentLength, -(line.getX2() - line.getX1()) / segmentLength ); } } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Default deserialization in.defaultReadObject(); // Custom deserialization shapeStroke = (Stroke) SerializationUtils.unwrap((Serializable) in.readObject()); tickStroke = (Stroke) SerializationUtils.unwrap((Serializable) in.readObject()); minorTickStroke = (Stroke) SerializationUtils.unwrap((Serializable) in.readObject()); } private void writeObject(ObjectOutputStream out) throws IOException { // Default deserialization out.defaultWriteObject(); // Custom serialization out.writeObject(SerializationUtils.wrap(shapeStroke)); out.writeObject(SerializationUtils.wrap(tickStroke)); out.writeObject(SerializationUtils.wrap(minorTickStroke)); } @Override public Number getIntersection() { return intersection; } @Override public void setIntersection(Number intersection) { this.intersection = intersection; } @Override public Shape getShape() { return shape; } @Override public void setShape(Shape shape) { this.shape = shape; evaluateShape(shape); } @Override public boolean isShapeVisible() { return shapeVisible; } @Override public void setShapeVisible(boolean shapeVisible) { this.shapeVisible = shapeVisible; } @Override public boolean isShapeNormalOrientationClockwise() { return shapeNormalOrientationClockwise; } @Override public void setShapeNormalOrientationClockwise(boolean clockwise) { this.shapeNormalOrientationClockwise = clockwise; } @Override public Paint getShapeColor() { return shapeColor; } @Override public void setShapeColor(Paint color) { this.shapeColor = color; } @Override public Stroke getShapeStroke() { return shapeStroke; } @Override public void setShapeStroke(Stroke stroke) { this.shapeStroke = stroke; } @Override public boolean isShapeDirectionSwapped() { return shapeDirectionSwapped; } @Override public void setShapeDirectionSwapped(boolean directionSwapped) { this.shapeDirectionSwapped = directionSwapped; } @Override public boolean isTicksVisible() { return ticksVisible; } @Override public void setTicksVisible(boolean ticksVisible) { this.ticksVisible = ticksVisible; } @Override public Number getTickSpacing() { return tickSpacing; } @Override public void setTickSpacing(Number spacing) { this.tickSpacing = spacing; } @Override public boolean isTicksAutoSpaced() { return ticksAutoSpaced; } @Override public void setTicksAutoSpaced(boolean autoSpaced) { this.ticksAutoSpaced = autoSpaced; } @Override public double getTickLength() { return tickLength; } @Override public void setTickLength(double length) { this.tickLength = length; } @Override public Stroke getTickStroke() { return tickStroke; } @Override public void setTickStroke(Stroke stroke) { this.tickStroke = stroke; } @Override public double getTickAlignment() { return tickAlignment; } @Override public void setTickAlignment(double alignment) { this.tickAlignment = alignment; } @Override public Font getTickFont() { return tickFont; } @Override public void setTickFont(Font font) { this.tickFont = font; } @Override public Paint getTickColor() { return tickColor; } @Override public void setTickColor(Paint color) { this.tickColor = color; } @Override public boolean isTickLabelsVisible() { return tickLabelsVisible; } @Override public void setTickLabelsVisible(boolean tickLabelsVisible) { this.tickLabelsVisible = tickLabelsVisible; } @Override public Format getTickLabelFormat() { return tickLabelFormat; } @Override public void setTickLabelFormat(Format format) { this.tickLabelFormat = format; } @Override public double getTickLabelDistance() { return tickLabelDistance; } @Override public void setTickLabelDistance(double distance) { this.tickLabelDistance = distance; } @Override public boolean isTickLabelsOutside() { return tickLabelsOutside; } @Override public void setTickLabelsOutside(boolean labelsOutside) { this.tickLabelsOutside = labelsOutside; } @Override public double getTickLabelRotation() { return tickLabelRotation; } @Override public void setTickLabelRotation(double angle) { this.tickLabelRotation = angle; } @Override public boolean isMinorTicksVisible() { return minorTickVisible; } @Override public void setMinorTicksVisible(boolean minorTicksVisible) { this.minorTickVisible = minorTicksVisible; } @Override public int getMinorTicksCount() { return minorTicksCount; } @Override public void setMinorTicksCount(int count) { this.minorTicksCount = count; } @Override public double getMinorTickLength() { return minorTickLength; } @Override public void setMinorTickLength(double length) { this.minorTickLength = length; } @Override public Stroke getMinorTickStroke() { return minorTickStroke; } @Override public void setMinorTickStroke(Stroke stroke) { this.minorTickStroke = stroke; } @Override public double getMinorTickAlignment() { return minorTickAlignment; } @Override public void setMinorTickAlignment(double alignment) { this.minorTickAlignment = alignment; } @Override public Paint getMinorTickColor() { return minorTickColor; } @Override public void setMinorTickColor(Paint color) { this.minorTickColor = color; } @Override public Map getCustomTicks() { return Collections.unmodifiableMap(customTicks); } @Override public void setCustomTicks(Map positionsAndLabels) { customTicks.clear(); customTicks.putAll(positionsAndLabels); } @Override public Label getLabel() { return label; } @Override public void setLabel(Label label) { this.label = label; } @Override public double getLabelDistance() { return labelDistance; } @Override public void setLabelDistance(double distance) { this.labelDistance = distance; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/axes/Axis.java000066400000000000000000000143161267060725100265430ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.axes; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import java.util.HashSet; import java.util.Set; import de.erichseifert.gral.util.MathUtils; /** *

Class that represents an arbitrary axis.

*

Functionality includes:

*
    *
  • Different ways of setting and getting the range of this axis
  • *
  • Administration of {@link AxisListener AxisListeners}
  • *
*/ public class Axis implements Serializable { /** Version id for serialization. */ private static final long serialVersionUID = 5355772833362614591L; /** Objects that will be notified when axis settings are changing. */ private transient Set axisListeners; /** Minimal value on axis. */ private Number min; /** Maximal value on axis. */ private Number max; /** Has the axis a valid range. Used for auto-scaling. */ private boolean autoscaled; /** * Initializes a new instance with a specified automatic scaling mode, but * without minimum and maximum values. * @param autoscaled {@code true} to turn automatic scaling on */ private Axis(boolean autoscaled) { axisListeners = new HashSet(); this.autoscaled = autoscaled; } /** * Initializes a new instance without minimum and maximum values. */ public Axis() { this(true); } /** * Initializes a new instance with the specified minimum and maximum values. * @param min minimum value * @param max maximum value */ public Axis(Number min, Number max) { this(false); this.min = min; this.max = max; } /** * Adds the specified {@code AxisListener} to this Axis. * The Listeners will be notified if changes to the Axis occur, * for Example if the minimum or maximum value changes. * @param listener Listener to be added * @see AxisListener */ public void addAxisListener(AxisListener listener) { axisListeners.add(listener); } /** * Removes the specified {@code AxisListener} from this Axis. * @param listener Listener to be removed * @see AxisListener */ public void removeAxisListener(AxisListener listener) { axisListeners.remove(listener); } /** * Notifies all registered {@code AxisListener}s that the value * range has changed. * @param min new minimum value * @param max new maximum value */ private void fireRangeChanged(Number min, Number max) { for (AxisListener listener : axisListeners) { listener.rangeChanged(this, min, max); } } /** * Returns the minimum value to be displayed. * @return Minimum value. */ public Number getMin() { return min; } /** * Sets the minimum value to be displayed. * @param min Minimum value. */ public void setMin(Number min) { setRange(min, getMax()); } /** * Returns the maximum value to be displayed. * @return Maximum value. */ public Number getMax() { return max; } /** * Sets the maximum value to be displayed. * @param max Maximum value. */ public void setMax(Number max) { setRange(getMin(), max); } /** * Returns the range of values to be displayed. * @return Distance between maximum and minimum value. */ public double getRange() { return getMax().doubleValue() - getMin().doubleValue(); } /** * Sets the range of values to be displayed. * @param min Minimum value. * @param max Maximum value. */ public void setRange(Number min, Number max) { if ((getMin() != null) && getMin().equals(min) && (getMax() != null) && getMax().equals(max)) { return; } this.min = min; this.max = max; fireRangeChanged(min, max); } /** * Returns the relative position of the specified value on the axis. * The value is returned in view coordinates. * @param value Value whose positition is to be determined * @return Position relative to axis range */ public Number getPosition(Number value) { if (value == null) { return null; } double relativePosition = (value.doubleValue() - getMin().doubleValue()) / getRange(); return relativePosition; } /** * Returns whether the axis range should be determined automatically rather * than using the axis's minimum and a maximum values. * @return whether the axis is scaled automatically to fit the current data */ public boolean isAutoscaled() { return autoscaled; } /** * Sets whether the axis range should be determined automatically rather * than using the axis's minimum and a maximum values. * @param autoscaled Defines whether the axis should be automatically * scaled to fit the current data. */ public void setAutoscaled(boolean autoscaled) { if (this.autoscaled != autoscaled) { this.autoscaled = autoscaled; } } /** * Returns whether the currently set minimum and maximum values are valid. * @return {@code true} when minimum and maximum values are correct, * otherwise {@code false} */ public boolean isValid() { return MathUtils.isCalculatable(min) && MathUtils.isCalculatable(max); } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Normal deserialization in.defaultReadObject(); // Handle transient fields axisListeners = new HashSet(); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/axes/AxisListener.java000066400000000000000000000023161267060725100302460ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.axes; /** * Interface that provides a function to listen for changes in axes. */ public interface AxisListener { /** * Notified if the range of the axis has changed. * @param axis Axis instance that has changed. * @param min New minimum value. * @param max New maximum value. */ void rangeChanged(Axis axis, Number min, Number max); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/axes/AxisRenderer.java000066400000000000000000000327721267060725100302400ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.axes; import java.awt.Font; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.text.Format; import java.util.List; import java.util.Map; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.Label; import de.erichseifert.gral.util.PointND; /** * Interface for generic renderers of axes. */ public interface AxisRenderer { /** * Returns a component that displays the specified axis. * @param axis axis to be displayed * @return component displaying the axis * @see Axis */ public abstract Drawable getRendererComponent(Axis axis); /* * TODO: Enforce minimum and maximum values when extrapolation is turned off * by using MathUtils.limit(double, double, double) on the result */ /** * Converts a world (axis) coordinate value to a view (screen) coordinate * value. If @code{extrapolate == false}, this method should return 0.0 when * value is smaller than @code{axis.getMin()} and {@code getShapeLength()} when * value is larger than @code{axis.getMax(}). * @param axis Axis * @param value World coordinate value to convert * @param extrapolate Option to activate extrapolation value that are not * on the axis * @return Screen coordinate value */ public abstract double worldToView(Axis axis, Number value, boolean extrapolate); /** * Converts a view (screen) coordinate value to a world (axis) coordinate * value. * @param axis Axis * @param value View coordinate value to convert * @param extrapolate Option to activate extrapolation value that are not * on the axis * @return World coordinate value */ public abstract Number viewToWorld(Axis axis, double value, boolean extrapolate); /** * Returns a list of all tick element on the axis. * @param axis Axis * @return A list of {@code Tick} instances */ public abstract List getTicks(Axis axis); /** * Returns the position of the specified value on the axis. * The value is returned in view coordinates. * @param axis Axis * @param value World coordinate value to convert * @param extrapolate Option to activate extrapolation value that are not * on the axis * @param forceLinear Force linear interpolation. * @return N-dimensional point of the value */ PointND getPosition(Axis axis, Number value, boolean extrapolate, boolean forceLinear); /** * Returns the normal vector at the position of the specified value. * The vector is normalized. * @param axis Axis * @param value World coordinate value to convert * @param extrapolate Option to activate extrapolation value that are not * on the axis * @param forceLinear Force linear interpolation. * @return N-dimensional normal vector at the position */ PointND getNormal(Axis axis, Number value, boolean extrapolate, boolean forceLinear); /** * Returns the intersection point of the axis. * @return Point at which this axis intersects other axes. */ Number getIntersection(); /** * Sets the intersection point of the axis. * @param intersection Point at which this axis intersects other axes. */ void setIntersection(Number intersection); /** * Returns the shape of the axis. * @return Shape used for drawing. */ Shape getShape(); /** * Sets the shape of the axis. * @param shape Shape used for drawing. */ void setShape(Shape shape); /** * Returns whether the shape of the axis will be drawn. * This doesn't influence ticks or labels. * @return {@code true} if the shape should be drawn, false otherwise. */ boolean isShapeVisible(); /** * Sets whether the shape of the axis will be drawn. * This doesn't influence ticks or labels. * @param shapeVisible {@code true} if the shape should be drawn, false otherwise. */ void setShapeVisible(boolean shapeVisible); /** * Returns whether the normal vector of the shape is calculated using * clockwise or counterclockwise rotation. * @return {@code true} if the orientation is clockwise, {@code false} if it is * counterclockwise. */ boolean isShapeNormalOrientationClockwise(); /** * Sets whether the normal vector of the shape is calculated using * clockwise or counterclockwise rotation. * @param clockwise {@code true} if the orientation is clockwise, * {@code false} if it is counterclockwise. */ void setShapeNormalOrientationClockwise(boolean clockwise); /** * Returns the paint used to draw the axis, its ticks and its labels. * @return Paint used for drawing. */ Paint getShapeColor(); /** * Sets the paint used to draw the axis, its ticks and its labels. * @param color Paint used for drawing. */ void setShapeColor(Paint color); /** * Returns the stroke which defines the shape of the axis. * @return Stroke used for drawing the shape. */ Stroke getShapeStroke(); /** * Sets the stroke which defines the shape of the axis. * @param stroke Stroke used for drawing the shape. */ void setShapeStroke(Stroke stroke); /** * Returns whether the axis direction is changed. * @return {@code true} if the shape of the axis is inverted, * {@code false} otherwise. */ boolean isShapeDirectionSwapped(); /** * Sets whether the axis direction will be changed. * @param directionSwapped {@code true} if the shape of the axis * should be inverted, {@code false} otherwise. */ void setShapeDirectionSwapped(boolean directionSwapped); /** * Returns whether major ticks are drawn. * @return {@code true} if major ticks are drawn, {@code false} otherwise. */ boolean isTicksVisible(); /** * Sets whether major ticks will be drawn. * @param ticksVisible {@code true} if major ticks should be drawn, * {@code false} otherwise. */ void setTicksVisible(boolean ticksVisible); /** * Returns the interval for major ticks. * @return Distance on axis in which major ticks are drawn. */ Number getTickSpacing(); /** * Sets the interval for major ticks. * @param spacing Distance on axis in which major ticks are drawn. */ void setTickSpacing(Number spacing); /** * Returns whether the interval for major and minor ticks is chosen automatically. * @return {@code true} if auto-spacing is enabled, {@code false} otherwise. */ boolean isTicksAutoSpaced(); /** * Sets whether the interval for major and minor ticks is chosen automatically. * @param autoSpaced {@code true} if auto-spacing is enabled, {@code false} otherwise. */ void setTicksAutoSpaced(boolean autoSpaced); /** * Returns the length of major tick strokes. * @return Tick length relative to the font height. */ double getTickLength(); /** * Sets the length of major tick strokes. * @param length Tick length relative to the font height. */ void setTickLength(double length); /** * Returns the stroke which is used to draw all major ticks. * @return Stroke used for major tick drawing. */ Stroke getTickStroke(); /** * Sets the stroke which is used to draw all major ticks. * @param stroke Stroke used for major tick drawing. */ void setTickStroke(Stroke stroke); /** * Returns the alignment of major ticks relative to the axis. * 0.0 means outside the plotting area, 0.5 means centered on the axis, * 1.0 means inside the plotting area. * @return Major tick alignment relative to the axis. */ double getTickAlignment(); /** * Sets the alignment of major ticks relative to the axis. * 0.0 means outside the plotting area, 0.5 means centered on the axis, * 1.0 means inside the plotting area. * @param alignment Major tick alignment relative to the axis. */ void setTickAlignment(double alignment); /** * Returns the font used to display the text of major ticks. * @return Font used for tick labels. */ Font getTickFont(); /** * Sets the font used to display the text of major ticks. * @param font Font used for tick labels. */ void setTickFont(Font font); /** * Returns the paint used to draw the shapes of major ticks. * @return Paint used for major tick drawing. */ Paint getTickColor(); /** * Sets the paint used to draw the shapes of major ticks. * @param color Paint used for major tick drawing. */ void setTickColor(Paint color); /** * Returns whether tick labels will be shown. * @return {@code true} if tick labels will be drawn, {@code false} otherwise. */ boolean isTickLabelsVisible(); /** * Sets whether tick labels will be shown. * @param tickLabelsVisible {@code true} if tick labels will be drawn, {@code false} otherwise. */ void setTickLabelsVisible(boolean tickLabelsVisible); /** * Returns the format which converts the tick values to labels. * @return Format used for tick labels. */ Format getTickLabelFormat(); /** * Sets the format which converts the tick values to labels. * @param format Format used for tick labels. */ void setTickLabelFormat(Format format); /** * Returns the distance of labels to their ticks. * @return Label distance relative to the font height. */ double getTickLabelDistance(); /** * Sets the distance of labels to their ticks. * @param distance Label distance relative to the font height. */ void setTickLabelDistance(double distance); /** * Returns whether the tick labels are drawn outside of the plot. * @return {@code true} if the labels are drawn outside of the plot, {@code false} otherwise. */ boolean isTickLabelsOutside(); /** * Sets whether the tick labels are drawn outside of the plot. * @param tickLabelsOutside {@code true} if the labels are drawn outside of the plot, * {@code false} otherwise. */ void setTickLabelsOutside(boolean tickLabelsOutside); /** * Returns the rotation of the tick labels. * @return Tick label rotation in degrees. */ double getTickLabelRotation(); /** * Sets the rotation of the tick labels. * @param angle Tick label rotation in degrees. */ void setTickLabelRotation(double angle); /** * Returns whether minor ticks are drawn. * @return {@code true} if minor ticks are drawn, {@code false} otherwise. */ boolean isMinorTicksVisible(); /** * Sets whether minor ticks are drawn. * @param minorTicksVisible {@code true} if minor ticks are drawn, {@code false} otherwise. */ void setMinorTicksVisible(boolean minorTicksVisible); /** * Returns the count of minor ticks. * @return Number of minor ticks between two major ticks. */ int getMinorTicksCount(); /** * Sets the count of minor ticks. * @param count Number of minor ticks between two major ticks. */ void setMinorTicksCount(int count); /** * Returns the length of minor tick strokes. * @return Tick length relative to font height. */ double getMinorTickLength(); /** * Sets the length of minor tick strokes. * @param length Tick length relative to font height. */ void setMinorTickLength(double length); /** * Returns the stroke used to draw all minor ticks. * @return Stroke used for minor tick drawing. */ Stroke getMinorTickStroke(); /** * Sets the stroke used to draw all minor ticks. * @param stroke Stroke used for minor tick drawing. */ void setMinorTickStroke(Stroke stroke); /** * Returns the alignment of minor ticks. * 0.0 means outside the plotting area, 0.5 means centered on the axis, * 1.0 means inside the plotting area. * @return Minor tick alignment relative to the axis. */ double getMinorTickAlignment(); /** * Sets the alignment of minor ticks. * 0.0 means outside the plotting area, 0.5 means centered on the axis, * 1.0 means inside the plotting area. * @param alignment Minor tick alignment relative to the axis. */ void setMinorTickAlignment(double alignment); /** * Returns the paint used to draw the shapes of minor ticks. * @return Paint used for minor tick drawing. */ Paint getMinorTickColor(); /** * Sets the paint used to draw the shapes of minor ticks. * @param ticksMinorColor Paint used for minor tick drawing. */ void setMinorTickColor(Paint ticksMinorColor); /** * Returns custom ticks with their respective position and label. * @return A map of custom tick positions and labels. */ Map getCustomTicks(); /** * Sets custom ticks with their respective position and label. * @param positionsAndLabels A map of custom tick positions and labels. */ void setCustomTicks(Map positionsAndLabels); /** * Returns the label of the axis. * @return Axis label. */ Label getLabel(); /** * Sets the label of the axis. * @param label Axis label. */ void setLabel(Label label); /** * Returns the distance from the axis to the label. * @return Distance relative to font height. */ double getLabelDistance(); /** * Sets the distance from the axis to the label. * @param distance Distance relative to font height. */ void setLabelDistance(double distance); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/axes/LinearRenderer2D.java000066400000000000000000000105511267060725100307230ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.axes; import java.util.List; import java.util.Set; import de.erichseifert.gral.plots.axes.Tick.TickType; import de.erichseifert.gral.util.MathUtils; /** * Class that renders axes with a linear scale in two dimensional space. */ public class LinearRenderer2D extends AbstractAxisRenderer2D { /** Version id for serialization. */ private static final long serialVersionUID = -1257582880797196423L; /** * Creates a new renderer for linear axes in two-dimensional space. */ public LinearRenderer2D() { } /** * Converts a world (axis) coordinate value to a view (screen) coordinate * value. * @param axis Axis * @param value World coordinate value to convert * @param extrapolate Option to activate extrapolation value that are not * on the axis * @return Screen coordinate value */ public double worldToView(Axis axis, Number value, boolean extrapolate) { double min = axis.getMin().doubleValue(); double max = axis.getMax().doubleValue(); double val = value.doubleValue(); if (!extrapolate) { if (val <= min) { return 0.0; } if (val >= max) { return getShapeLength(); } } return (val - min)/(max - min)*getShapeLength(); } /** * Converts a view (screen) coordinate value to a world (axis) coordinate * value. * @param axis Axis * @param value View coordinate value to convert * @param extrapolate Option to activate extrapolation value that are not * on the axis * @return World coordinate value */ public Number viewToWorld(Axis axis, double value, boolean extrapolate) { double min = axis.getMin().doubleValue(); double max = axis.getMax().doubleValue(); if (!extrapolate) { if (value <= 0.0) { return min; } if (value >= getShapeLength()) { return max; } } return value/getShapeLength()*(max - min) + min; } @Override protected void createTicks(List ticks, Axis axis, double min, double max, Set tickPositions, boolean isAutoSpacing) { double tickSpacing = 1.0; int ticksMinorCount = 3; if (isAutoSpacing) { // TODO Use number of screen units to decide whether to subdivide double range = max - min; // 1-steppings (0.1, 1, 10) tickSpacing = MathUtils.magnitude(10.0, range/4.0); // 2-steppings (0.2, 2, 20) if (range/tickSpacing > 8.0) { tickSpacing *= 2.0; ticksMinorCount = 1; } // 5-steppings (0.5, 5, 50) if (range/tickSpacing > 8.0) { tickSpacing *= 2.5; ticksMinorCount = 4; } } else { tickSpacing = getTickSpacing().doubleValue(); ticksMinorCount = getMinorTicksCount(); } double tickSpacingMinor = tickSpacing; if (ticksMinorCount > 0) { tickSpacingMinor = tickSpacing/(ticksMinorCount + 1); } double minTickMajor = MathUtils.ceil(min, tickSpacing); double minTickMinor = MathUtils.ceil(min, tickSpacingMinor); int ticksTotal = (int) Math.ceil((max - min)/tickSpacingMinor); int initialTicksMinor = (int) ((minTickMajor - min)/tickSpacingMinor); // Add major and minor ticks // (Use integer to avoid rounding errors) for (int tickCur = 0; tickCur < ticksTotal; tickCur++) { double tickPositionWorld = minTickMinor + tickCur*tickSpacingMinor; if (tickPositions.contains(tickPositionWorld)) { continue; } TickType tickType = TickType.MINOR; if ((tickCur - initialTicksMinor) % (ticksMinorCount + 1) == 0) { tickType = TickType.MAJOR; } Tick tick = getTick(tickType, axis, tickPositionWorld); if (tick.position != null) { ticks.add(tick); tickPositions.add(tickPositionWorld); } } } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/axes/LogarithmicRenderer2D.java000066400000000000000000000124271267060725100317570ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.axes; import java.util.List; import de.erichseifert.gral.plots.axes.Tick.TickType; import de.erichseifert.gral.util.MathUtils; /** * Class that renders axes with a logarithmic scale in two dimensional space. */ public class LogarithmicRenderer2D extends AbstractAxisRenderer2D { /** Version id for serialization. */ private static final long serialVersionUID = 6360029510782348529L; /** * Creates a new renderer for logarithmic scaled axes in two-dimensional * space. */ public LogarithmicRenderer2D() { } /** * Converts a world (axis) coordinate value to a view (screen) coordinate * value. * @param axis Axis * @param value World coordinate value to convert * @param extrapolate Option to activate extrapolation value that are not * on the axis * @return Screen coordinate value */ public double worldToView(Axis axis, Number value, boolean extrapolate) { checkAxisBounds(axis); double min = axis.getMin().doubleValue(); double max = axis.getMax().doubleValue(); double val = value.doubleValue(); if (!extrapolate) { if (val <= min) { return 0.0; } if (val >= max) { return getShapeLength(); } } double minLog = (min > 0.0) ? Math.log10(min) : 0.0; double maxLog = (max > 0.0) ? Math.log10(max) : 1.0; return (Math.log10(val) - minLog)*getShapeLength() / (maxLog - minLog); } /** * Converts a view (screen) coordinate value to a world (axis) coordinate * value. * @param axis Axis * @param value View coordinate value to convert * @param extrapolate Option to activate extrapolation value that are not * on the axis * @return World coordinate value */ public Number viewToWorld(Axis axis, double value, boolean extrapolate) { checkAxisBounds(axis); double min = axis.getMin().doubleValue(); double max = axis.getMax().doubleValue(); if (!extrapolate) { if (value <= 0.0) { return min; } if (value >= getShapeLength()) { return max; } } double minLog = (min > 0.0) ? Math.log10(min) : 0.0; double maxLog = (max > 0.0) ? Math.log10(max) : 1.0; return Math.pow(10.0, value*(maxLog - minLog)/getShapeLength() + minLog); } @Override public List getTicks(Axis axis) { checkAxisBounds(axis); return super.getTicks(axis); } @Override protected void createTicks(java.util.List ticks, Axis axis, double min, double max, java.util.Set tickPositions, boolean isAutoSpacing) { double tickSpacing = 1.0; if (isAutoSpacing) { // TODO Automatic scaling for logarithmic axes tickSpacing = 1.0; } else { tickSpacing = getTickSpacing().doubleValue(); } int ticksMinorCount = getMinorTicksCount(); double tickSpacingMinor = (ticksMinorCount > 0) ? tickSpacing/(ticksMinorCount + 1) : tickSpacing; // TODO Check if this is a valid solution to allow zeroes if (min == 0.0) { min = 1.0; } final double BASE = 10.0; double powerMin = MathUtils.magnitude(BASE, min); double powerMax = MathUtils.magnitude(BASE, max); double minTickMajor = MathUtils.ceil(min, powerMin*tickSpacing); int ticksPerPower = (int) Math.floor(BASE/tickSpacingMinor); int initialTicksMinor = (int) Math.floor((minTickMajor - min) / (powerMin*tickSpacingMinor)); // Add major ticks int i = 0; for (double power = powerMin; power <= powerMax; power *= BASE) { double multipliedTickSpacingMinor = power*tickSpacingMinor; double minTick = MathUtils.ceil(power, multipliedTickSpacingMinor); for (int pi = 0; pi < ticksPerPower; pi++) { double tickPositionWorld = minTick + pi*multipliedTickSpacingMinor; if (tickPositionWorld < min) { continue; } else if (tickPositionWorld > max) { break; } TickType tickType = TickType.MINOR; if ((i++ - initialTicksMinor) % (ticksMinorCount + 1) == 0) { tickType = TickType.MAJOR; } Tick tick = getTick(tickType, axis, tickPositionWorld); if (tick.position != null && !tickPositions.contains(tickPositionWorld)) { ticks.add(tick); tickPositions.add(tickPositionWorld); } } } } /** * Utility method that makes sure that axis bounds comply to rules of * logarithmic axes. * @param axis Axis to be checked */ private static void checkAxisBounds(Axis axis) { if ((axis.getMin().doubleValue() < 0.0) || (axis.getMax().doubleValue() < 0.0)) { throw new IllegalStateException( "Axis bounds must be greater than or equal to zero for logarithmic axes."); //$NON-NLS-1$ } } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/axes/Tick.java000066400000000000000000000043441267060725100265310ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.axes; import java.awt.Shape; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.plots.DataPoint; import de.erichseifert.gral.util.PointND; /** * Class for storing the tick mark of an axis. */ public class Tick extends DataPoint { /** Type of tick mark. */ public static enum TickType { /** Major tick mark. */ MAJOR, /** Minor tick mark. */ MINOR, /** User-defined tick mark. */ CUSTOM } /** The type of tick mark (major/minor/custom). */ public final TickType type; /** The normal of the tick mark. */ public final PointND normal; /** Drawable that will be used to render the tick. */ public final Drawable drawable; /** Shape describing the tick. */ public final Shape shape; /** Label text associated with this tick mark. */ public final String label; /** * Creates a new instance with the specified position, normal, * {@code Drawable}, point and label. * @param type Type of the tick mark. * @param position Coordinates. * @param normal Normal. * @param drawable Representation. * @param point Point. * @param label Description. */ public Tick(TickType type, PointND position, PointND normal, Drawable drawable, Shape point, String label) { super(null, position); this.type = type; this.normal = normal; this.drawable = drawable; this.shape = point; this.label = label; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/axes/package-info.java000077500000000000000000000017121267060725100301620ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Classes for managing and drawing axes in plots. */ package de.erichseifert.gral.plots.axes; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/colors/000077500000000000000000000000001267060725100253305ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/colors/AbstractColorMapper.java000066400000000000000000000043541267060725100321100ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import java.io.Serializable; /** * Interface that maps numbers to Paint objects. This can be used to generate * colors or gradients for various elements in a plot, e.g. lines, areas, etc. * * @param Data type of input values. */ public abstract class AbstractColorMapper implements ColorMapper, Serializable { /** Version id for serialization. */ private static final long serialVersionUID = 8456831369409589441L; /** Handling of values that are outside the mapping range. */ private Mode mode; /** * Initializes a new instance with default values. */ public AbstractColorMapper() { mode = Mode.REPEAT; } /** * Returns how values outside of the mapping range will be handled. * @return Handling of values outside of the mapping range. */ public Mode getMode() { return mode; } /** * Sets how values outside of the mapping range will be handled. * @param mode Handling of values outside of the mapping range. */ protected void setMode(Mode mode) { this.mode = mode; } /** * Transforms a value outside of the mapping range. If the value is inside * the range, no transformation will be applied. * @param value Value to be handled. * @param rangeMin Lower bounds of range * @param rangeMax Upper bounds of range * @return Transformed value. */ protected abstract T applyMode(T value, T rangeMin, T rangeMax); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/colors/ColorMapper.java000066400000000000000000000033771267060725100304300ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import java.awt.Paint; /** * Basic interface for classes that map numbers to Paint objects. This can be * used to generate colors or gradients for various elements in a plot, e.g. * points, lines, areas, etc. * * {@link ContinuousColorMapper} or {@link IndexedColorMapper} should be used * as base classes in most cases. */ public interface ColorMapper { /** Data type to define how values outside of the mapping range will be handled. */ enum Mode { /** Ignore missing values. */ OMIT, /** Repeat the last value. */ REPEAT, /** Repeat the data. */ CIRCULAR } /** * Returns the Paint object according to the specified value. * @param value Numeric value. * @return Paint object. */ Paint get(Number value); /** * Returns how values outside of the mapping range will be handled. * @return Handling of values outside of the mapping range. */ Mode getMode(); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/colors/ContinuousColorMapper.java000066400000000000000000000042651267060725100325140ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import java.awt.Paint; import de.erichseifert.gral.util.MathUtils; /** * Class that maps floating point numbers to Paint objects. This can be used to * generate colors or gradients for various elements in a plot, e.g. lines, * areas, etc. */ public abstract class ContinuousColorMapper extends AbstractColorMapper { /** Version id for serialization. */ private static final long serialVersionUID = 4616781244057993699L; /** * Returns the Paint object according to the specified value. * @param value Numeric value. * @return Paint object. */ public abstract Paint get(double value); /** * Returns the Paint object according to the specified value. The specified * value will be handled like a double value. * @param value Numeric value object. * @return Paint object. */ public Paint get(Number value) { return get(value.doubleValue()); } @Override protected Double applyMode(Double value, Double rangeMin, Double rangeMax) { if (value >= rangeMin && value <= rangeMax) { return value; } Mode mode = getMode(); if (mode == Mode.REPEAT) { return MathUtils.limit(value, rangeMin, rangeMax); } else if (mode == Mode.CIRCULAR) { double range = rangeMax - rangeMin; double i = value%range; if (i < 0.0) { i += range; } return i + rangeMin; } return null; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/colors/Grayscale.java000066400000000000000000000036001267060725100301040ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import java.awt.Color; import java.awt.Paint; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.util.MathUtils; /** * Class that generates shades of gray for values between 0.0 and 1.0. */ public class Grayscale extends ScaledContinuousColorMapper { /** Version id for serialization. */ private static final long serialVersionUID = -1005712209663359529L; /** * Returns the Paint object according to the specified value. * @param value Value of color. * @return Paint object. */ @Override public Paint get(double value) { Double v = scale(value); v = applyMode(v, 0.0, 1.0); if (!MathUtils.isCalculatable(v)) { return null; } double lightness = 100.0*v; double[] rgb = GraphicsUtils.luv2rgb(new double[] {lightness, 0.0, 0.0}, null); return new Color( (float) MathUtils.limit(rgb[0], 0.0, 1.0), (float) MathUtils.limit(rgb[1], 0.0, 1.0), (float) MathUtils.limit(rgb[2], 0.0, 1.0) ); } @Override public void setMode(Mode mode) { super.setMode(mode); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/colors/HeatMap.java000066400000000000000000000047031267060725100275160ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import java.awt.Color; import java.awt.Paint; import de.erichseifert.gral.util.MathUtils; /** * Class that generates different color shades for values between 0.0 and 1.0. */ public class HeatMap extends ScaledContinuousColorMapper { /** Version id for serialization. */ private static final long serialVersionUID = -5398973874608239179L; private static final Color[] COLORS = { new Color(0.0f, 0.0f, 0.0f), new Color(0.0f, 0.0f, 1.0f), new Color(1.0f, 0.0f, 0.0f), new Color(1.0f, 1.0f, 0.0f), new Color(1.0f, 1.0f, 1.0f) }; /** * Returns the Paint according to the specified value. * @param value Value of color. * @return Paint. */ @Override public Paint get(double value) { Double v = scale(value); v = applyMode(v, 0.0, 1.0); if (!MathUtils.isCalculatable(v)) { return null; } double x = v; double xInv = 1.0 - x; double xInv2 = xInv*xInv; double x2 = x*x; // Bernstein coefficients double[] coeffs = { xInv2*xInv2, 4.0*x*xInv2*xInv, 6.0*x2*xInv2, 4.0*x*x2*xInv, x2*x2 }; double r = 0.0, g = 0.0, b = 0.0, a = 0.0; for (int i = 0; i < COLORS.length; i++) { r += coeffs[i]*COLORS[i].getRed(); g += coeffs[i]*COLORS[i].getGreen(); b += coeffs[i]*COLORS[i].getBlue(); a += coeffs[i]*COLORS[i].getAlpha(); } return new Color( (float) MathUtils.limit(r, 0.0, 255.0)/255f, (float) MathUtils.limit(g, 0.0, 255.0)/255f, (float) MathUtils.limit(b, 0.0, 255.0)/255f, (float) MathUtils.limit(a, 0.0, 255.0)/255f ); } @Override public void setMode(Mode mode) { super.setMode(mode); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/colors/IndexedColorMapper.java000066400000000000000000000042511267060725100317210ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import java.awt.Paint; import de.erichseifert.gral.util.MathUtils; /** * Class that maps integer numbers to Paint objects. This can be used to * generate colors or gradients for various elements in a plot, e.g. lines, * areas, etc. */ public abstract class IndexedColorMapper extends AbstractColorMapper { /** Version id for serialization. */ private static final long serialVersionUID = 553890535328678411L; /** * Returns the Paint object according to the specified index. * @param value Numeric index. * @return Paint object. */ public abstract Paint get(int value); /** * Returns the Paint object according to the specified index. The specified * value will be handled like an integer index. * @param index Numeric index object. * @return Paint object. */ public Paint get(Number index) { return get(index.intValue()); } @Override protected Integer applyMode(Integer index, Integer rangeMin, Integer rangeMax) { if (index >= rangeMin && index <= rangeMax) { return index; } Mode mode = getMode(); if (mode == Mode.REPEAT) { return MathUtils.limit(index, rangeMin, rangeMax); } else if (mode == Mode.CIRCULAR) { int range = rangeMax - rangeMin + 1; int i = index%range; if (i < 0) { i += range; } return i + rangeMin; } return null; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/colors/IndexedColors.java000066400000000000000000000044771267060725100307510ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import java.awt.Color; import java.awt.Paint; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import de.erichseifert.gral.util.MathUtils; /** * Maps index values to a specified color palette. */ public class IndexedColors extends IndexedColorMapper { /** Version id for serialization. */ private static final long serialVersionUID = -8072979842165455075L; /** Color palette that will be used for mapping. **/ private final List colors; /** * Creates a new instance with at least one color. * @param color1 First color. * @param colors Additional colors. */ public IndexedColors(Color color1, Color... colors) { this.colors = new ArrayList(); this.colors.add(color1); this.colors.addAll(Arrays.asList(colors)); } /** * Returns the Paint object associated to the specified index value. * @param index Numeric index. * @return Paint object. */ @Override public Paint get(int index) { Integer i = applyMode(index, 0, colors.size() - 1); if (!MathUtils.isCalculatable(i)) { return null; } return colors.get(i); } /** * Returns the colors that are used for mapping. * @return A list of colors in the order they are used as the color palette. */ public List getColors() { return Collections.unmodifiableList(colors); } @Override public void setMode( de.erichseifert.gral.plots.colors.ColorMapper.Mode mode) { super.setMode(mode); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/colors/LinearGradient.java000066400000000000000000000060411267060725100310640ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import java.awt.Color; import java.awt.Paint; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import de.erichseifert.gral.util.MathUtils; /** * Linearly blends different colors for values between 0.0 and 1.0. */ public class LinearGradient extends ScaledContinuousColorMapper { /** Version id for serialization. */ private static final long serialVersionUID = 4256873420364549677L; /** Colors that will be used for blending. **/ private final List colors; /** * Creates a new instance with at least one color. * @param color1 First color. * @param colors Additional colors. */ public LinearGradient(Color color1, Color... colors) { this.colors = new ArrayList(); this.colors.add(color1); this.colors.addAll(Arrays.asList(colors)); } /** * Returns the Paint according to the specified value. * @param value Value of color. * @return Paint. */ @Override public Paint get(double value) { Double v = scale(value); v = applyMode(v, 0.0, 1.0); if (!MathUtils.isCalculatable(v)) { return null; } double x = v; int colorMax = colors.size() - 1; double pos = MathUtils.limit(x*colorMax, 0.0, colorMax); if (pos == 0.0) { return colors.get(0); } if (pos == colorMax) { return colors.get(colorMax); } double fract = pos - (int) pos; Color color1 = colors.get((int) pos); if (fract == 0.0) { return color1; } double fractInv = 1.0 - fract; Color color2 = colors.get((int) pos + 1); double r = fractInv*color1.getRed() + fract*color2.getRed(); double g = fractInv*color1.getGreen() + fract*color2.getGreen(); double b = fractInv*color1.getBlue() + fract*color2.getBlue(); double a = fractInv*color1.getAlpha() + fract*color2.getAlpha(); return new Color( (int) Math.round(r), (int) Math.round(g), (int) Math.round(b), (int) Math.round(a) ); } @Override public void setMode(Mode mode) { super.setMode(mode); } /** * Returns the colors that are used for blending. * @return A list of colors in the order they will be used for blending. */ public List getColors() { return Collections.unmodifiableList(colors); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/colors/QuasiRandomColors.java000066400000000000000000000064731267060725100316120ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import java.awt.Color; import java.awt.Paint; import java.util.HashMap; import java.util.Map; import de.erichseifert.gral.util.HaltonSequence; import de.erichseifert.gral.util.MathUtils; /** * Class that generates seemingly random colors for specified index values. */ public class QuasiRandomColors extends IndexedColorMapper { /** Version id for serialization. */ private static final long serialVersionUID = 3320256963368776894L; /** Object for mapping a plot value to a hue. */ private final HaltonSequence seqHue = new HaltonSequence(3); /** Object for mapping a plot value to a saturation. */ private final HaltonSequence seqSat = new HaltonSequence(5); /** Object for mapping a plot value to a brightness. */ private final HaltonSequence seqBrightness = new HaltonSequence(2); /** Cache for colors that have already been generated. */ private final Map colorCache; /** Variance settings for hue, saturation and brightness. */ //FIXME duplicate code! See RandomColors private float[] colorVariance; /** * Creates a new QuasiRandomColors object with default color variance. */ public QuasiRandomColors() { colorCache = new HashMap(); colorVariance = new float[] { 0.00f, 1.00f, // Hue 0.75f, 0.25f, // Saturation 0.25f, 0.75f // Brightness }; } /** * Returns the Paint associated to the specified index value. * @param index Numeric index. * @return Paint object. */ @Override public Paint get(int index) { Integer key = index; if (colorCache.containsKey(key)) { return colorCache.get(key); } float[] colorVariance = getColorVariance(); float hue = colorVariance[0] + colorVariance[1]*seqHue.next().floatValue(); float saturation = colorVariance[2] + colorVariance[3]*seqSat.next().floatValue(); float brightness = colorVariance[4] + colorVariance[5]*seqBrightness.next().floatValue(); Color color = Color.getHSBColor( hue, MathUtils.limit(saturation, 0f, 1f), MathUtils.limit(brightness, 0f, 1f) ); colorCache.put(key, color); return color; } /** * Returns the current color variance. * @return Range of hue, saturation and brightness a color can have. */ public float[] getColorVariance() { return colorVariance; } /** * Sets the current color variance. * @param colorVariance Range of hue, saturation and brightness a color * can have. */ public void setColorVariance(float[] colorVariance) { this.colorVariance = colorVariance; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/colors/RainbowColors.java000066400000000000000000000031451267060725100307610ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import java.awt.Color; import java.awt.Paint; import de.erichseifert.gral.util.MathUtils; /** * Class that generates the colors of a rainbow. */ public class RainbowColors extends ScaledContinuousColorMapper { /** Version id for serialization. */ private static final long serialVersionUID = 6096507341747323265L; /** * Returns the Paint according to the specified value. * @param value Value of color. * @return Paint. */ @Override public Paint get(double value) { Double v = scale(value); v = applyMode(v, 0.0, 1.0); if (!MathUtils.isCalculatable(v)) { return null; } float hue = v.floatValue(); return Color.getHSBColor(hue, 1f, 1f); } @Override public void setMode(Mode mode) { super.setMode(mode); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/colors/RandomColors.java000066400000000000000000000113251267060725100305770ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import java.awt.Color; import java.awt.Paint; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Random; import de.erichseifert.gral.util.MathUtils; /** * Class that generates pseudo-random colors for specified index values. */ public class RandomColors extends IndexedColorMapper { /** Version id for serialization. */ private static final long serialVersionUID = -4518470000665474457L; /** Number of comparisons that will be done before accepting two similar random values. */ private static final int NUM_COMPARISONS = 4; /** Minimal distance the causes a random values to be to re-generated. */ private static final double MIN_DIST = 0.3; /** Cache for colors that have already been generated. */ private final Map colorCache; /** Object for generating random values. */ private final Random random; /** Variance settings for hue, saturation and brightness. */ //FIXME duplicate code! See QuasiRandomColors private final float[] colorVariance; /** * Creates a new RandomColors object with default seed. */ public RandomColors() { random = new Random(); colorCache = new LinkedHashMap(); colorVariance = new float[] { 0.00f, 1.00f, // Hue 0.75f, 0.25f, // Saturation 0.25f, 0.75f // Brightness }; } /** * Creates a new instances with the specified seed. * @param seed Random number seed. */ public RandomColors(long seed) { this(); random.setSeed(seed); } /** * Returns the Paint associated to the specified index value. * @param index Numeric index. * @return Paint. */ @Override public Paint get(int index) { Integer key = index; if (colorCache.containsKey(key)) { return colorCache.get(key); } // Use the same random numbers for the same input value //long seed = Double.doubleToRawLongBits(value); //random.setSeed(seed); // Generate a new color that is distant enough from previous colors boolean match; Color r; do { r = getRandomColor(); match = true; Iterator colors = colorCache.values().iterator(); for (int i=0; i, * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; /** * An abstract base class for implementations of {@code ContinuousColorMapper} * that allow to apply a a scaling factor to the values passed to * {@link #get(double)}. */ public abstract class ScaledContinuousColorMapper extends ContinuousColorMapper { /** Version id for serialization. */ private static final long serialVersionUID = 323911118647457851L; /** Offset. **/ private double offset; /** Scaling factor. **/ private double scale; /** * Default constructor that initializes a new instance with a default * offset of 0.0 and a scale of 1.0. */ public ScaledContinuousColorMapper() { this(0.0, 1.0); } /** * Constructor that initializes a new instance with a specified offset and * scaling factor. * @param offset Offset. * @param scale Scaling factor. */ public ScaledContinuousColorMapper(double offset, double scale) { this.offset = offset; this.scale = scale; } /** * Returns the current offset value. * @return Offset value. */ public double getOffset() { return offset; } /** * Sets a new offset value. * @param offset Offset value. */ public void setOffset(double offset) { this.offset = offset; } /** * Returns the current scaling factor. * @return Scaling factor. */ public double getScale() { return scale; } /** * Sets a new scaling factor for passed values. * @param scale Scaling factor. */ public void setScale(double scale) { this.scale = scale; } /** * Sets offset and scale based on start and end values. * @param start Start value. * @param end End value. */ public void setRange(double start, double end) { setOffset(start); setScale(end - start); } /** * Linearly transforms a value using offset and scale. * @param value Original value. * @return Transformed value. */ protected Double scale(double value) { return (value - getOffset())/getScale(); } @Override public boolean equals(Object obj) { if (!(obj instanceof ScaledContinuousColorMapper)) { return false; } ScaledContinuousColorMapper cm = (ScaledContinuousColorMapper) obj; return getOffset() == cm.getOffset() && getScale() == cm.getScale() && getMode() == cm.getMode(); } @Override public int hashCode() { long bits = Double.doubleToLongBits(getOffset()); bits ^= Double.doubleToLongBits(getScale()) * 31; return ((int) bits) ^ ((int) (bits >> 32)); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/colors/SingleColor.java000066400000000000000000000042251267060725100304160ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import java.awt.Paint; /** * Class that represents a ColorMapper with a single color. */ public class SingleColor extends IndexedColorMapper { /** Version id for serialization. */ private static final long serialVersionUID = -3377452532555792998L; /** The color that will be returned in any case. */ private Paint color; /** * Creates a new instance with the specified color. * @param color Color to use. */ public SingleColor(Paint color) { this.color = color; } /** * Returns the Paint according to the specified value. * @param value Numeric index. * @return Paint. */ @Override public Paint get(int value) { return getColor(); } /** * Returns the color of this ColorMapper. * @return Color. */ public Paint getColor() { return color; } /** * Sets the color of this ColorMapper. * @param color Color to be set. */ public void setColor(Paint color) { this.color = color; } @Override public boolean equals(Object obj) { if (!(obj instanceof SingleColor)) { return false; } SingleColor cm = (SingleColor) obj; return color.equals(cm.color) && getMode() == cm.getMode(); } @Override public int hashCode() { long bits = getColor().hashCode(); bits ^= getMode().hashCode() * 31; return ((int) bits) ^ ((int) (bits >> 32)); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/colors/package-info.java000077500000000000000000000017321267060725100305250ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Classes that provide color schemes for plots and data series. */ package de.erichseifert.gral.plots.colors; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/legends/000077500000000000000000000000001267060725100254505ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/legends/AbstractLegend.java000066400000000000000000000343331267060725100312030ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.legends; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Paint; import java.awt.Stroke; import java.awt.geom.Dimension2D; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawableContainer; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.graphics.layout.EdgeLayout; import de.erichseifert.gral.graphics.layout.Layout; import de.erichseifert.gral.graphics.layout.OrientedLayout; import de.erichseifert.gral.graphics.layout.StackedLayout; import de.erichseifert.gral.graphics.Label; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.graphics.Insets2D; import de.erichseifert.gral.graphics.Location; import de.erichseifert.gral.graphics.Orientation; import de.erichseifert.gral.util.SerializationUtils; /** *

Abstract class that serves as a base for legends in plots. * It stores a list of of items that are used to display a symbol and label for * each (visible) data source.

*

Like other elements legends can be styled using various settings. The * settings are used to control to control how the legend, and its items * are displayed. The actual rendering of symbols has to be implemented by * derived classes.

*/ public abstract class AbstractLegend extends DrawableContainer implements Legend, LegendSymbolRenderer { /** Version id for serialization. */ private static final long serialVersionUID = -1561976879958765700L; /** List of data sources displayed in this legend. */ private final Set sources; /** Mapping of data rows to drawable components. */ private final Map components; /** Flag that tells whether the data in the legend is up-to-date. */ private transient boolean valid; /** Default font used for sub-components and the calculation of relative sizes. */ private Font baseFont; /** Paint used to draw the background. */ private Paint background; /** Stroke used to draw the border of the legend. */ // Property will be serialized using a wrapper private transient Stroke borderStroke; /** Font used to display the labels. */ private Font font; /** Paint used to fill the border of the legend. */ private Paint borderColor; /** Direction of the legend's items. */ private Orientation orientation; /** Horizontal alignment of the legend relative to the plot area. */ private double alignmentX; /** Vertical alignment of the legend relative to the plot area. */ private double alignmentY; /** Gap size relative to the font height. */ private Dimension2D gap; /** Symbol size relative to the font height. */ private Dimension2D symbolSize; /** * An abstract base class for drawable symbols. */ protected static abstract class AbstractSymbol extends AbstractDrawable { /** Version id for serialization. */ private static final long serialVersionUID = 7475404103140652668L; /** Settings for determining the visual of the symbol. */ private final Legend legend; /** * Initializes a new instances. * @param legend Legend that determines the appearance of the symbol. */ public AbstractSymbol(Legend legend) { this.legend = legend; } @Override public Dimension2D getPreferredSize() { double fontSize = legend.getFont().getSize2D(); Dimension2D symbolSize = legend.getSymbolSize(); Dimension2D size = super.getPreferredSize(); size.setSize(symbolSize.getWidth()*fontSize, symbolSize.getHeight()*fontSize); return size; } } /** * Class that displays a specific data source as an item of a legend. */ public static class Item extends DrawableContainer { /** Version id for serialization. */ private static final long serialVersionUID = 3401141040936913098L; /** Default font used for sub-components and the calculation of relative sizes. */ private Font baseFont; /** Data source that is related to this item. */ private final Row row; /** Symbol that should be drawn. */ private final Drawable symbol; /** Label string that should be drawn. */ private final Label label; /** * Creates a new Item object with the specified data source and text. * @param row Data row to be displayed. * @param symbolRenderer Renderer for the symbol. * @param labelText Description text. * @param font Font for the description text. */ public Item(Row row, LegendSymbolRenderer symbolRenderer, String labelText, Font font) { double fontSize = font.getSize2D(); setLayout(new EdgeLayout(fontSize, 0.0)); this.row = row; symbol = symbolRenderer.getSymbol(row); add(symbol, Location.WEST); label = new Label(labelText); label.setFont(font); label.setAlignmentX(0.0); label.setAlignmentY(0.5); add(label, Location.CENTER); } /** * Returns the row that is displayed by this item. * @return Displayed data row. */ public Row getRow() { return row; } public Label getLabel() { return label; } public Drawable getSymbol() { return symbol; } } /** * Initializes a new instance with a default background color, a border, * vertical orientation and a gap between the items. The default alignment * is set to top-left. */ public AbstractLegend() { setInsets(new Insets2D.Double(10.0)); sources = new LinkedHashSet(); components = new HashMap(); background = Color.WHITE; borderStroke = new BasicStroke(1f); font = Font.decode(null); setDrawableFonts(font); borderColor = Color.BLACK; orientation = Orientation.VERTICAL; alignmentX = 0.0; alignmentY = 0.0; // TODO: Replace setter call in constructor setGap(new de.erichseifert.gral.graphics.Dimension2D.Double(2.0, 0.5)); symbolSize = new de.erichseifert.gral.graphics.Dimension2D.Double(2.0, 2.0); setLayout(new StackedLayout(orientation, gap.getWidth(), gap.getHeight())); refreshLayout(); } /** * Draws the {@code Drawable} with the specified drawing context. * @param context Environment used for drawing. */ @Override public void draw(DrawingContext context) { if (components.isEmpty()) { return; } drawBackground(context); drawBorder(context); drawComponents(context); } /** * Draws the background of this legend with the specified drawing context. * @param context Environment used for drawing. */ protected void drawBackground(DrawingContext context) { Paint background = getBackground(); if (background != null) { GraphicsUtils.fillPaintedShape( context.getGraphics(), getBounds(), background, null); } } /** * Draws the border of this legend with the specified drawing context. * @param context Environment used for drawing. */ protected void drawBorder(DrawingContext context) { Stroke stroke = getBorderStroke(); if (stroke != null) { Paint borderColor = getBorderColor(); GraphicsUtils.drawPaintedShape( context.getGraphics(), getBounds(), borderColor, null, stroke); } } /** * Returns a sequence of items for the specified data source that should be * added to the legend. * @param source Data source. * @return A sequence of items for the specified data source. */ protected abstract Iterable getEntries(DataSource source); /** * Returns the label text for the specified row. * @param row Data row. * @return Label text. */ protected abstract String getLabel(Row row); /** * Adds the specified data source in order to display it. * @param source data source to be added. */ public void add(DataSource source) { sources.add(source); for (Row row : getEntries(source)) { String label = getLabel(row); Font font = getFont(); Item item = new Item(row, this, label, font); add(item); components.put(row, item); } invalidate(); } /** * Returns whether the specified data source was added to the legend. * @param source Data source. * @return {@code true} if legend contains the data source, * otherwise {@code false}. */ public boolean contains(DataSource source) { return sources.contains(source); } /** * Removes the specified data source. * @param source Data source to be removed. */ public void remove(DataSource source) { sources.remove(source); Set rows = new HashSet(components.keySet()); for (Row row : rows) { if (row.getSource() != source) { continue; } Drawable item = components.remove(row); if (item != null) { remove(item); } } invalidate(); } /** * Removes all data sources from the legend. */ public void clear() { Set sources = new HashSet(this.sources); for (DataSource source : sources) { remove(source); } } /** * Updates the items for all data sources stored in this legend. The update * is only performed if the legend is invalid. * @see #invalidate() */ public void refresh() { if (isValid()) { return; } Set sources = new LinkedHashSet(this.sources); clear(); for (DataSource source : sources) { add(source); } valid = true; } /** * Refreshes the layout of the legend. It's currently used to handle new * gap values. */ protected final void refreshLayout() { Dimension2D gap = getGap(); Layout layout = getLayout(); layout.setGapX(gap.getWidth()); layout.setGapY(gap.getHeight()); if (layout instanceof OrientedLayout) { OrientedLayout orientedLayout = (OrientedLayout) layout; orientedLayout.setOrientation(getOrientation()); } } @Override public void setBounds(double x, double y, double width, double height) { Dimension2D size = getPreferredSize(); double alignX = getAlignmentX(); double alignY = getAlignmentY(); super.setBounds( x + alignX*(width - size.getWidth()), y + alignY*(height - size.getHeight()), size.getWidth(), size.getHeight() ); } /** * Returns whether this legend's values and layout are valid. * @return {@code true} if the values and the layout are valid, * otherwise {@code false}. * @see #invalidate() */ protected boolean isValid() { return valid; } /** * Marks this legend's values and layout as invalid. The legend will only * be refreshed if it's invalid. * @see #refresh() */ protected void invalidate() { valid = false; } /** * Sets the font of the contained drawables. * @param font Font to be set. */ protected final void setDrawableFonts(Font font) { for (Drawable drawable : components.values()) { if (drawable instanceof Item) { Item item = (Item) drawable; item.label.setFont(font); } } } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { in.defaultReadObject(); borderStroke = (Stroke) SerializationUtils.unwrap((Serializable) in.readObject()); } /** * Custom serialization method. * @param out Output stream. * @throws ClassNotFoundException if a deserialized class does not exist. * @throws IOException if there is an error while writing data to the * output stream. */ private void writeObject(ObjectOutputStream out) throws ClassNotFoundException, IOException { out.defaultWriteObject(); out.writeObject(SerializationUtils.wrap(borderStroke)); } @Override public Font getBaseFont() { return baseFont; } @Override public void setBaseFont(Font baseFont) { this.baseFont = baseFont; } @Override public Paint getBackground() { return background; } @Override public void setBackground(Paint background) { this.background = background; } @Override public Stroke getBorderStroke() { return borderStroke; } @Override public void setBorderStroke(Stroke borderStroke) { this.borderStroke = borderStroke; } @Override public Font getFont() { return font; } @Override public void setFont(Font font) { this.font = font; setDrawableFonts(font); } @Override public Paint getBorderColor() { return borderColor; } @Override public void setBorderColor(Paint borderColor) { this.borderColor = borderColor; } @Override public Orientation getOrientation() { return orientation; } @Override public void setOrientation(Orientation orientation) { this.orientation = orientation; refreshLayout(); } @Override public double getAlignmentX() { return alignmentX; } @Override public void setAlignmentX(double alignmentX) { this.alignmentX = alignmentX; } @Override public double getAlignmentY() { return alignmentY; } @Override public void setAlignmentY(double alignmentY) { this.alignmentY = alignmentY; } @Override public Dimension2D getGap() { return gap; } @Override public void setGap(Dimension2D gap) { this.gap = gap; if (this.gap != null) { double fontSize = getFont().getSize2D(); this.gap.setSize(this.gap.getWidth()*fontSize, this.gap.getHeight()*fontSize); } } @Override public Dimension2D getSymbolSize() { return symbolSize; } @Override public void setSymbolSize(Dimension2D symbolSize) { this.symbolSize = symbolSize; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/legends/Legend.java000066400000000000000000000125511267060725100275150ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.legends; import java.awt.Font; import java.awt.Paint; import java.awt.Stroke; import java.awt.geom.Dimension2D; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.graphics.Container; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.Orientation; /** * Interface for a legend that display visual examples of the variables used in * a plot. */ public interface Legend extends Container, Drawable { /** * Adds the specified data source in order to display it. * @param source data source to be added. */ void add(DataSource source); /** * Returns whether the specified data source was added to the legend. * @param source Data source * @return {@code true} if legend contains the data source, otherwise {@code false} */ boolean contains(DataSource source); /** * Removes the specified data source. * @param source Data source to be removed. */ void remove(DataSource source); /** * Removes all data sources from the legend. */ void clear(); /** * Updates the items for all data sources stored in this legend. */ void refresh(); /** * Returns the current font used as a default for sub-components ans for * calculation of relative sizes. * @return Current base font. */ Font getBaseFont(); /** * Sets the new font that will be used as a default for sub-components and * for calculation of relative sizes. This method is only used internally * to propagate the base font and shouldn't be used manually. * @param baseFont New base font. */ void setBaseFont(Font baseFont); /** * Returns the paint used to draw the background. * @return Paint used for background drawing. */ Paint getBackground(); /** * Sets the paint used to draw the background. * @param background Paint used for background drawing. */ void setBackground(Paint background); /** * Returns the stroke used to draw the border of the legend. * @return Stroke used for border drawing. */ Stroke getBorderStroke(); /** * Sets the stroke used to draw the border of the legend. * @param borderStroke Stroke used for border drawing. */ void setBorderStroke(Stroke borderStroke); /** * Returns the font used to display the labels. * @return Font used for labels. */ Font getFont(); /** * Sets the font used to display the labels. * @param font Font used for labels. */ void setFont(Font font); /** * Returns the paint used to fill the border of the legend. * @return Paint used for border drawing. */ Paint getBorderColor(); /** * Sets the paint used to fill the border of the legend. * @param borderColor Paint used for border drawing. */ void setBorderColor(Paint borderColor); /** * Returns the direction of the legend's items. * @return Item orientation. */ Orientation getOrientation(); /** * Sets the direction of the legend's items. * @param orientation Item orientation. */ void setOrientation(Orientation orientation); /** * Returns the size of the legend's symbols. * @return Symbol size relative to the font height. */ Dimension2D getSymbolSize(); /** * Sets the size of the legend's symbols. * @param symbolSize Symbol size relative to the font height. */ void setSymbolSize(Dimension2D symbolSize); /** * Returns the horizontal alignment of the legend relative to the plot area. * {@code 0.0} means left, {@code 0.5} means centered, and {@code 1.0} means right. * @return Relative horizontal alignment. */ double getAlignmentX(); /** * Sets the horizontal alignment of the legend relative to the plot area. * {@code 0.0} means left, {@code 0.5} means centered, and {@code 1.0} means right. * @param alignmentX Relative horizontal alignment. */ void setAlignmentX(double alignmentX); /** * Returns the vertical alignment of the legend relative to the plot area. * {@code 0.0} means top, {@code 0.5} means centered, and {@code 1.0} means bottom. * @return Relative vertical alignment. */ double getAlignmentY(); /** * Sets the vertical alignment of the legend relative to the plot area. * {@code 0.0} means top, {@code 0.5} means centered, and {@code 1.0} means bottom. * @param alignmentY Relative vertical alignment. */ void setAlignmentY(double alignmentY); /** * Returns the horizontal and vertical gap between items. * @return Gap size relative to the font height. */ Dimension2D getGap(); /** * Sets the horizontal and vertical gap between items. * @param gap Gap size relative to the font height. */ void setGap(Dimension2D gap); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/legends/LegendSymbolRenderer.java000066400000000000000000000023641267060725100323730ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.legends; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.graphics.Drawable; /** * A renderer for symbols that are used in legend items. */ public interface LegendSymbolRenderer { /** * Returns a symbol for rendering a legend item. * @param row Data row. * @return A drawable object that can be used to display the symbol. */ Drawable getSymbol(Row row); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/legends/SeriesLegend.java000066400000000000000000000030511267060725100306630ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.legends; import java.util.LinkedList; import java.util.List; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.Row; /** * A legend implementation that displays an item for each data series that are * added to the legend. */ public abstract class SeriesLegend extends AbstractLegend { /** Version id for serialization. */ private static final long serialVersionUID = 1092110896986707546L; @Override protected Iterable getEntries(DataSource source) { List items = new LinkedList(); Row row = new Row(source, 0); items.add(row); return items; } @Override protected String getLabel(Row row) { return row.getSource().toString(); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/legends/ValueLegend.java000066400000000000000000000123421267060725100305100ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.legends; import java.text.Format; import java.text.NumberFormat; import java.util.LinkedList; import java.util.List; import de.erichseifert.gral.data.DataChangeEvent; import de.erichseifert.gral.data.DataListener; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.Row; /** * A legend implementation that displays items for all data values of all data * series that are added to the legend. */ public abstract class ValueLegend extends AbstractLegend implements DataListener { /** Version id for serialization. */ private static final long serialVersionUID = -4274009997506638823L; /** Column index containing the labels. */ private int labelColumn; /** Format for data to label text conversion. */ private Format labelFormat; /** * Initializes a new instance with default values. */ public ValueLegend() { labelColumn = 0; } @Override protected Iterable getEntries(DataSource source) { List items = new LinkedList(); for (int rowIndex = 0; rowIndex < source.getRowCount(); rowIndex++) { Row row = new Row(source, rowIndex); items.add(row); } return items; } @Override protected String getLabel(Row row) { int col = getLabelColumn(); Comparable value = row.get(col); if (value == null) { return ""; } // Formatting Format format = getLabelFormat(); if ((format == null) && row.isColumnNumeric(col)) { format = NumberFormat.getInstance(); } // Text to display String text = (format != null) ? format.format(value) : value.toString(); return text; } @Override public void add(DataSource source) { super.add(source); source.addDataListener(this); } @Override public void remove(DataSource source) { super.remove(source); source.removeDataListener(this); } /** * Method that is invoked when data has been added. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been added. */ public void dataAdded(DataSource source, DataChangeEvent... events) { dataChanged(source, events); } /** * Method that is invoked when data has been updated. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been updated. */ public void dataUpdated(DataSource source, DataChangeEvent... events) { dataChanged(source, events); } /** * Method that is invoked when data has been removed. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been removed. */ public void dataRemoved(DataSource source, DataChangeEvent... events) { dataChanged(source, events); } /** * Method that is invoked when data has been added, updated, or removed. * This method is invoked by objects that provide support for * {@code DataListener}s and should not be called manually. * @param source Data source that has been changed. * @param events Optional event object describing the data values that * have been changed. */ private void dataChanged(DataSource source, DataChangeEvent... events) { invalidate(); } /** * Returns the index of the column that contains the labels for the values. * @return Column index containing the labels. */ public int getLabelColumn() { return labelColumn; } /** * Sets the index of the column that contains the labels for the values. * @param labelColumn Column index containing the labels. */ public void setLabelColumn(int labelColumn) { this.labelColumn = labelColumn; invalidate(); refresh(); } /** * Returns the format used to display data values. * @return Format for data to label text conversion. */ public Format getLabelFormat() { return labelFormat; } /** * Sets the format used to display data values. * @param labelFormat Format for data to label text conversion. */ public void setLabelFormat(Format labelFormat) { this.labelFormat = labelFormat; invalidate(); refresh(); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/legends/package-info.java000077500000000000000000000016651267060725100306520ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Classes for rendering different kind of legends. */ package de.erichseifert.gral.plots.legends; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/lines/000077500000000000000000000000001267060725100251415ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/lines/AbstractLineRenderer2D.java000066400000000000000000000076601267060725100322450ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.lines; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import de.erichseifert.gral.util.SerializationUtils; /** *

Abstract class that renders a line in two-dimensional space.

*

Functionality includes:

*
    *
  • Punching data points out of the line's shape
  • *
  • Administration of settings
  • *
*/ public abstract class AbstractLineRenderer2D implements LineRenderer, Serializable { /** Version id for serialization. */ private static final long serialVersionUID = -4172505541305453796L; /** Stroke to draw the line. */ private transient Stroke stroke; /** Gap between points and the line. */ private double gap; /** Decides whether the shape of the gap between points and the line is * rounded. */ private boolean gapRounded; /** Paint to fill the line. */ private Paint color; /** * Initializes a new {@code AbstractLineRenderer2D} instance with * default settings. */ public AbstractLineRenderer2D() { stroke = new BasicStroke(1.5f); gap = 0.0; gapRounded = false; color = Color.BLACK; } /** * Returns the stroked shape of the specified line. * @param line Shape of the line. * @return Stroked shape. */ protected Shape stroke(Shape line) { if (line == null) { return null; } Stroke stroke = getStroke(); Shape lineShape = stroke.createStrokedShape(line); return lineShape; } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Default deserialization in.defaultReadObject(); // Custom deserialization stroke = (Stroke) SerializationUtils.unwrap( (Serializable) in.readObject()); } /** * Custom serialization method. * @param out Output stream. * @throws ClassNotFoundException if a serialized class doesn't exist. * @throws IOException if there is an error while writing data to the * output stream. */ private void writeObject(ObjectOutputStream out) throws ClassNotFoundException, IOException { // Default serialization out.defaultWriteObject(); // Custom serialization out.writeObject(SerializationUtils.wrap(stroke)); } @Override public Stroke getStroke() { return stroke; } @Override public void setStroke(Stroke stroke) { this.stroke = stroke; } @Override public double getGap() { return gap; } @Override public void setGap(double gap) { this.gap = gap; } @Override public boolean isGapRounded() { return gapRounded; } @Override public void setGapRounded(boolean gapRounded) { this.gapRounded = gapRounded; } @Override public Paint getColor() { return color; } @Override public void setColor(Paint color) { this.color = color; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/lines/DefaultLineRenderer2D.java000066400000000000000000000061631267060725100320630ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.lines; import java.awt.Paint; import java.awt.Shape; import java.awt.geom.Path2D; import java.awt.geom.Point2D; import java.util.List; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.DataPoint; import de.erichseifert.gral.util.GraphicsUtils; /** * Class that connects two dimensional data points with a straight line. */ public class DefaultLineRenderer2D extends AbstractLineRenderer2D { /** Version id for serialization. */ private static final long serialVersionUID = -1728830281555843667L; /** Number of line segments which will be reserved to avoid unnecessary copying of array data. */ private static final int INITIAL_LINE_CAPACITY = 10000; /** * Initializes a new {@code DefaultLineRenderer2D} instance. */ public DefaultLineRenderer2D() { } /** * Returns a graphical representation for the line defined by * {@code e points}. * @param points Points used for creating the line. * @param shape Geometric shape for this line. * @return Representation of the line. */ public Drawable getLine(final List points, final Shape shape) { Drawable d = new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = 7995515716470892483L; /** * Draws the {@code Drawable} with the specified drawing context. * @param context Environment used for drawing */ public void draw(DrawingContext context) { // Draw line Paint paint = DefaultLineRenderer2D.this.getColor(); GraphicsUtils.fillPaintedShape( context.getGraphics(), shape, paint, null); } }; return d; } /** * Returns the geometric shape for this line. * @param points Points used for creating the line. * @return Geometric shape for this line. */ public Shape getLineShape(List points) { // Construct shape Path2D shape = new Path2D.Double( Path2D.WIND_NON_ZERO, INITIAL_LINE_CAPACITY); for (DataPoint point : points) { Point2D pos = point.position.getPoint2D(); if (shape.getCurrentPoint() == null) { shape.moveTo(pos.getX(), pos.getY()); } else { shape.lineTo(pos.getX(), pos.getY()); } } return stroke(shape); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/lines/DiscreteLineRenderer2D.java000066400000000000000000000112171267060725100322350ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.lines; import java.awt.Paint; import java.awt.Shape; import java.awt.geom.Path2D; import java.awt.geom.Point2D; import java.util.List; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.DataPoint; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.graphics.Orientation; /** * Class that connects {@code DataPoint}s with a stair-like line. */ public class DiscreteLineRenderer2D extends AbstractLineRenderer2D { /** Version id for serialization. */ private static final long serialVersionUID = 4648286099838467355L; /** Primary direction of the "steps". */ private Orientation ascentDirection; /** Relative distance between points, where the orientation changes. */ private Number ascendingPoint; /** * Initializes a new {@code DiscreteLineRenderer2D} instance with default * settings. */ public DiscreteLineRenderer2D() { ascentDirection = Orientation.HORIZONTAL; ascendingPoint = 0.5; } /** * Returns a graphical representation for the line defined by * {@code points}. * @param points Points to be used for creating the line. * @param shape Geometric shape for this line. * @return Representation of the line. */ public Drawable getLine(final List points, final Shape shape) { Drawable d = new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = -1686744943386843195L; /** * Draws the {@code Drawable} with the specified drawing context. * @param context Environment used for drawing */ public void draw(DrawingContext context) { // Draw path Paint paint = DiscreteLineRenderer2D.this.getColor(); GraphicsUtils.fillPaintedShape( context.getGraphics(), shape, paint, null); } }; return d; } /** * Returns the geometric shape for this line. * @param points Points used for creating the line. * @return Geometric shape for this line. */ public Shape getLineShape(List points) { Orientation dir = getAscentDirection(); double ascendingPoint = getAscendingPoint().doubleValue(); // Construct shape Path2D shape = new Path2D.Double(); for (DataPoint point : points) { Point2D pos = point.position.getPoint2D(); if (shape.getCurrentPoint() == null) { shape.moveTo(pos.getX(), pos.getY()); } else { Point2D posPrev = shape.getCurrentPoint(); if (dir == Orientation.HORIZONTAL) { double ascendingX = posPrev.getX() + (pos.getX() - posPrev.getX()) * ascendingPoint; shape.lineTo(ascendingX, posPrev.getY()); shape.lineTo(ascendingX, pos.getY()); } else { double ascendingY = posPrev.getY() + (pos.getY() - posPrev.getY()) * ascendingPoint; shape.lineTo(posPrev.getX(), ascendingY); shape.lineTo(pos.getX(), ascendingY); } shape.lineTo(pos.getX(), pos.getY()); } } return stroke(shape); } /** * Returns the primary direction of the "steps". * @return Orientation of the "steps". */ public Orientation getAscentDirection() { return ascentDirection; } /** * Sets the primary direction of the "steps". * @param ascentDirection Orientation of the "steps". */ public void setAscentDirection(Orientation ascentDirection) { this.ascentDirection = ascentDirection; } /** * Returns the relative distance between two points, {@literal i.e.} the "step" of a stair. * @return Relative point distance. */ public Number getAscendingPoint() { return ascendingPoint; } /** * Sets the relative distance between two points, {@literal i.e.} the "step" of a stair. * @param ascendingPoint Relative point distance. */ public void setAscendingPoint(Number ascendingPoint) { this.ascendingPoint = ascendingPoint; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/lines/LineRenderer.java000066400000000000000000000062111267060725100303620ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.lines; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.util.List; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.plots.DataPoint; /** *

Interface that provides functions for rendering a line in two dimensional * space.

*

Functionality includes:

*
    *
  • Punching data points out of the line's shape
  • *
  • Administration of settings
  • *
*/ public interface LineRenderer { /** * Returns the geometric shape for this line. * @param points Points used for creating the line. * @return Geometric shape for this line. */ Shape getLineShape(List points); /** * Returns a graphical representation for the line defined by * {@code points}. * @param points Points to be used for creating the line. * @param shape Geometric shape for this line. * @return Representation of the line. */ Drawable getLine(List points, Shape shape); /** * Returns the stroke to be used to define the line shape. * @return Stroke used for drawing. */ Stroke getStroke(); /** * Sets the stroke to be used to define the line shape. * @param stroke Stroke used for drawing. */ void setStroke(Stroke stroke); /** * Returns the value for the gap between the line and a point. * If the gap value is equal to or smaller than 0 no gap will be used. * @return Gap size between drawn line and connected points in pixels. */ double getGap(); /** * Sets the value for the gap between the line and a point. * If the gap value is equal to or smaller than 0 no gap will be used. * @param gap Gap size between drawn line and connected points in pixels. */ void setGap(double gap); /** * Returns whether the gaps should have rounded corners. * @return {@code true} if the gap corners should be rounded. */ boolean isGapRounded(); /** * Sets whether the gaps should have rounded corners. * @param gapRounded {@code true} if the gap corners should be rounded. */ void setGapRounded(boolean gapRounded); /** * Returns the paint to be used to paint the line shape. * @return Paint for line drawing. */ Paint getColor(); /** * Sets the paint to be used to paint the line shape. * @param color Paint for line drawing. */ void setColor(Paint color); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/lines/SmoothLineRenderer2D.java000066400000000000000000000150651267060725100317510ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.lines; import java.awt.Paint; import java.awt.Shape; import java.awt.geom.Path2D; import java.awt.geom.Point2D; import java.util.List; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.DataPoint; import de.erichseifert.gral.util.GraphicsUtils; /** *

Class that connects {@code DataPoint}s with a smooth line.

*

See Interpolation * with Bezier Curves for more information.

*/ public class SmoothLineRenderer2D extends AbstractLineRenderer2D { /** Version id for serialization. */ private static final long serialVersionUID = -6390029474886495264L; /** Degree of "smoothness", where 0.0 means no smoothing, and 1.0 means * maximal smoothing. */ private Number smoothness; /** * Initializes a new {@code SmoothLineRenderer2D} instance with * default settings. */ public SmoothLineRenderer2D() { smoothness = 1.0; } /** * Returns a graphical representation for the line defined by * {@code points}. * @param points Points to be used for creating the line. * @param shape Geometric shape for this line. * @return Representation of the line. */ public Drawable getLine(final List points, final Shape shape) { Drawable d = new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = 3641589240264518755L; /** * Draws the {@code Drawable} with the specified drawing context. * @param context Environment used for drawing */ public void draw(DrawingContext context) { // Draw path Paint paint = SmoothLineRenderer2D.this.getColor(); GraphicsUtils.fillPaintedShape( context.getGraphics(), shape, paint, null); } }; return d; } /** * Returns the geometric shape for this line. * @param points Points used for creating the line. * @return Geometric shape for this line. */ public Shape getLineShape(List points) { double smoothness = getSmoothness().doubleValue(); // Construct shape Path2D shape = new Path2D.Double(); Point2D p0 = null, p1 = null, p2 = null, p3 = null; Point2D ctrl1 = new Point2D.Double(); Point2D ctrl2 = new Point2D.Double(); for (DataPoint point : points) { if (point == null) { continue; } p3 = point.position.getPoint2D(); addCurve(shape, p0, p1, p2, p3, ctrl1, ctrl2, smoothness); p0 = p1; p1 = p2; p2 = p3; } addCurve(shape, p0, p1, p2, p3, ctrl1, ctrl2, smoothness); return stroke(shape); } /** * Utility method to add a smooth curve segment to a specified line path. * @param line Line path. * @param p0 Previous neighbor. * @param p1 First point. * @param p2 Second point. * @param p3 Next neighbor. * @param ctrl1 First control point. * @param ctrl2 Second control point. * @param smoothness Smoothness factor */ private static void addCurve(Path2D line, Point2D p0, Point2D p1, Point2D p2, Point2D p3, Point2D ctrl1, Point2D ctrl2, double smoothness) { if (p1 == null ) { return; } if (line.getCurrentPoint() == null) { line.moveTo(p1.getX(), p1.getY()); } if (p2 == null) { return; } getControlsPoints(p0, p1, p2, p3, ctrl1, ctrl2, smoothness); line.curveTo( ctrl1.getX(), ctrl1.getY(), ctrl2.getX(), ctrl2.getY(), p2.getX(), p2.getY()); } /** * Set the coordinates of two control points ctrl1 and ctrl2 * which can be used to draw a smooth Bézier curve through two points * p1 and p2. To get a smooth curve the two neighboring * points p0 and p3 are required. However, p0 and * p3 may also be set to {@code null} in case of end points. * @param p0 Previous neighbor. * @param p1 First point. * @param p2 Second point. * @param p3 Next neighbor. * @param ctrl1 First control point. * @param ctrl2 Second control point. * @param smoothness Smoothness factor */ private static void getControlsPoints(Point2D p0, Point2D p1, Point2D p2, Point2D p3, Point2D ctrl1, Point2D ctrl2, double smoothness) { if (p0 == null) { p0 = p1; } if (p3 == null) { p3 = p2; } Point2D c1 = new Point2D.Double( (p0.getX() + p1.getX()) / 2.0, (p0.getY() + p1.getY()) / 2.0); Point2D c2 = new Point2D.Double( (p1.getX() + p2.getX()) / 2.0, (p1.getY() + p2.getY()) / 2.0); Point2D c3 = new Point2D.Double( (p2.getX() + p3.getX()) / 2.0, (p2.getY() + p3.getY()) / 2.0); double len1 = p1.distance(p0); double len2 = p2.distance(p1); double len3 = p3.distance(p2); double k1 = len1 / (len1 + len2); double k2 = len2 / (len2 + len3); Point2D m1 = new Point2D.Double( c1.getX() + (c2.getX() - c1.getX()) * k1, c1.getY() + (c2.getY() - c1.getY()) * k1); Point2D m2 = new Point2D.Double( c2.getX() + (c3.getX() - c2.getX()) * k2, c2.getY() + (c3.getY() - c2.getY()) * k2); ctrl1.setLocation( m1.getX() + (c2.getX() - m1.getX()) * smoothness + p1.getX() - m1.getX(), m1.getY() + (c2.getY() - m1.getY()) * smoothness + p1.getY() - m1.getY() ); ctrl2.setLocation( m2.getX() + (c2.getX() - m2.getX()) * smoothness + p2.getX() - m2.getX(), m2.getY() + (c2.getY() - m2.getY()) * smoothness + p2.getY() - m2.getY() ); } /** * Returns the smoothness of the line. * The value must be in range 0 (sharpest) to 1 (smoothest). * @return Line smoothness. */ public Number getSmoothness() { return smoothness; } /** * Returns the smoothness of the line. * The value must be in range 0 (sharpest) to 1 (smoothest). * @param smoothness Line smoothness. */ public void setSmoothness(Number smoothness) { this.smoothness = smoothness; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/lines/package-info.java000077500000000000000000000017211267060725100303340ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Classes for rendering data series connected by lines. */ package de.erichseifert.gral.plots.lines; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/package-info.java000077500000000000000000000017161267060725100272260ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Plot related classes like axis and plot area management. */ package de.erichseifert.gral.plots; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/points/000077500000000000000000000000001267060725100253435ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/points/AbstractPointRenderer.java000066400000000000000000000202161267060725100324530ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.points; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.text.Format; import de.erichseifert.gral.plots.colors.ColorMapper; import de.erichseifert.gral.plots.colors.SingleColor; import de.erichseifert.gral.graphics.Location; import de.erichseifert.gral.util.SerializationUtils; /** * Abstract class implementing functions for the administration of settings. */ public abstract class AbstractPointRenderer implements PointRenderer, Serializable { /** Version id for serialization. */ private static final long serialVersionUID = -408976260196287753L; /** Shape to draw for the points. */ private Shape shape; /** Color mapping used to fill the points. */ private ColorMapper color; /** Decides whether a value label are drawn at the point. */ private boolean valueVisible; /** Index of the column for the value label content. */ private int valueColumn; /** Format of the value label content. */ private Format valueFormat; /** Position of the value label relative to the point position. */ private Location valueLocation; /** Horizontal alignment of the value label. */ private double valueAlignmentX; /** Vertical alignment of the value label. */ private double valueAlignmentY; /** Rotation angle of the value label in degrees. */ private double valueRotation; /** Distance of the value label to the shape of the point. */ private double valueDistance; /** Color mapping to fill the value label. */ private ColorMapper valueColor; /** Font to draw the value label contents. */ private Font valueFont; /** Decides whether error indicators are drawn for the point. */ private boolean errorVisible; /** Index of the column for the upper error bounds. */ private int errorColumnTop; /** Index of the column for the lower error bounds. */ private int errorColumnBottom; /** Color mapping to fill the error indicators. */ private ColorMapper errorColor; /** Shape to draw the error indicators. */ private Shape errorShape; /** Stroke to the shapes of the error indicators. */ private transient Stroke errorStroke; /** * Creates a new AbstractPointRenderer object with default shape and * color. */ public AbstractPointRenderer() { shape = new Rectangle2D.Double(-2.5, -2.5, 5.0, 5.0); color = new SingleColor(Color.BLACK); valueVisible = false; valueColumn = 1; valueLocation = Location.CENTER; valueAlignmentX = 0.5; valueAlignmentY = 0.5; valueRotation = 0.0; valueDistance = 1.0; valueColor = new SingleColor(Color.BLACK); valueFont = Font.decode(null); errorVisible = false; errorColumnTop = 2; errorColumnBottom = 3; errorColor = new SingleColor(Color.BLACK); errorShape = new Line2D.Double(-2.0, 0.0, 2.0, 0.0); errorStroke = new BasicStroke(1f); } /** * Custom deserialization method. * @param in Input stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while reading data from the * input stream. */ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { // Default deserialization in.defaultReadObject(); // Custom deserialization errorStroke = (Stroke) SerializationUtils.unwrap( (Serializable) in.readObject()); } /** * Custom serialization method. * @param out Output stream. * @throws ClassNotFoundException if a serialized class doesn't exist anymore. * @throws IOException if there is an error while writing data to the * output stream. */ private void writeObject(ObjectOutputStream out) throws ClassNotFoundException, IOException { // Default serialization out.defaultWriteObject(); // Custom serialization out.writeObject(SerializationUtils.wrap(errorStroke)); } @Override public Shape getShape() { return shape; } @Override public void setShape(Shape shape) { // TODO Store clone of shape to prevent external modification this.shape = shape; } @Override public ColorMapper getColor() { return color; } @Override public void setColor(ColorMapper color) { this.color = color; } @Override public void setColor(Paint color) { setColor(new SingleColor(color)); } @Override public boolean isValueVisible() { return valueVisible; } @Override public void setValueVisible(boolean valueVisible) { this.valueVisible = valueVisible; } @Override public int getValueColumn() { return valueColumn; } @Override public void setValueColumn(int columnIndex) { this.valueColumn = columnIndex; } @Override public Format getValueFormat() { return valueFormat; } @Override public void setValueFormat(Format format) { this.valueFormat = format; } @Override public Location getValueLocation() { return valueLocation; } @Override public void setValueLocation(Location location) { this.valueLocation = location; } @Override public double getValueAlignmentX() { return valueAlignmentX; } @Override public void setValueAlignmentX(double alignmentX) { this.valueAlignmentX = alignmentX; } @Override public double getValueAlignmentY() { return valueAlignmentY; } @Override public void setValueAlignmentY(double alignmentY) { this.valueAlignmentY = alignmentY; } @Override public double getValueRotation() { return valueRotation; } @Override public void setValueRotation(double angle) { this.valueRotation = angle; } @Override public double getValueDistance() { return valueDistance; } @Override public void setValueDistance(double distance) { this.valueDistance = distance; } @Override public ColorMapper getValueColor() { return valueColor; } @Override public void setValueColor(ColorMapper color) { this.valueColor = color; } @Override public void setValueColor(Paint color) { setValueColor(new SingleColor(color)); } @Override public Font getValueFont() { return valueFont; } @Override public void setValueFont(Font font) { this.valueFont = font; } @Override public boolean isErrorVisible() { return errorVisible; } @Override public void setErrorVisible(boolean errorVisible) { this.errorVisible = errorVisible; } @Override public int getErrorColumnTop() { return errorColumnTop; } @Override public void setErrorColumnTop(int columnIndex) { this.errorColumnTop = columnIndex; } @Override public int getErrorColumnBottom() { return errorColumnBottom; } @Override public void setErrorColumnBottom(int columnIndex) { this.errorColumnBottom = columnIndex; } @Override public ColorMapper getErrorColor() { return errorColor; } @Override public void setErrorColor(ColorMapper color) { this.errorColor = color; } @Override public void setErrorColor(Paint color) { setErrorColor(new SingleColor(color)); } @Override public Shape getErrorShape() { return errorShape; } @Override public void setErrorShape(Shape shape) { // TODO Store clone of shape to prevent external modification this.errorShape = shape; } @Override public Stroke getErrorStroke() { return errorStroke; } @Override public void setErrorStroke(Stroke stroke) { this.errorStroke = stroke; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/points/DefaultPointRenderer2D.java000066400000000000000000000211011267060725100324540ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.points; import java.awt.BasicStroke; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; import java.text.Format; import java.text.NumberFormat; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawableContainer; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.graphics.layout.OuterEdgeLayout; import de.erichseifert.gral.graphics.Label; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.colors.ColorMapper; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.graphics.Location; import de.erichseifert.gral.util.MathUtils; import de.erichseifert.gral.util.PointND; /** * Class that creates {@code Drawable}s for a row of data. */ public class DefaultPointRenderer2D extends AbstractPointRenderer { /** Version id for serialization. */ private static final long serialVersionUID = -895832597380598383L; /** * Returns the graphical representation to be drawn for the specified data * value. * @param data Information on axes, renderers, and values. * @param shape Outline that describes the point's shape. * @return Component that can be used to draw the point */ public Drawable getPoint(final PointData data, final Shape shape) { Drawable drawable = new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = 1915778739867091906L; public void draw(DrawingContext context) { PointRenderer renderer = DefaultPointRenderer2D.this; Axis axisY = data.axes.get(1); AxisRenderer axisRendererY = data.axisRenderers.get(1); Row row = data.row; int col = data.col; ColorMapper colors = getColor(); Paint paint = colors.get(row.getIndex()); GraphicsUtils.fillPaintedShape( context.getGraphics(), shape, paint, null); if (renderer.isErrorVisible()) { int colErrorTop = renderer.getErrorColumnTop(); int colErrorBottom = renderer.getErrorColumnBottom(); drawErrorBars(context, shape, row, col, colErrorTop, colErrorBottom, axisY, axisRendererY); } } }; return drawable; } /** * Draws the specified value label for the specified shape. * @param context Environment used for drawing. * @param point Point shape used to layout the label. * @param row Data row containing the point. * @param col Index of the column that will be projected on the axis. */ protected void drawValueLabel(DrawingContext context, Shape point, Row row, int col) { Comparable value = row.get(col); // Formatting Format format = getValueFormat(); if ((format == null) && row.isColumnNumeric(col)) { format = NumberFormat.getInstance(); } // Text to display String text = (format != null) ? format.format(value) : value.toString(); // Visual settings ColorMapper colors = getValueColor(); Paint paint = colors.get(row.getIndex()); Font font = getValueFont(); double fontSize = font.getSize2D(); // Layout settings Location location = getValueLocation(); double alignX = getValueAlignmentX(); double alignY = getValueAlignmentY(); double rotation = getValueRotation(); double distance = getValueDistance(); if (MathUtils.isCalculatable(distance)) { distance *= fontSize; } else { distance = 0.0; } // Create a label with the settings Label label = new Label(text); label.setAlignmentX(alignX); label.setAlignmentY(alignY); label.setRotation(rotation); label.setColor(paint); label.setFont(font); Rectangle2D boundsPoint = point.getBounds2D(); DrawableContainer labelContainer = new DrawableContainer(new OuterEdgeLayout(distance)); labelContainer.add(label, location); labelContainer.setBounds(boundsPoint); labelContainer.draw(context); } /** * Draws error bars. * @param context Environment used for drawing. * @param point Shape of the point. * @param row Data row containing the point. * @param col Index of the column that will be projected on the axis. * @param colErrorTop Index of the column that contains the upper error value. * @param colErrorBottom Index of the column that contains the lower error value. * @param axis Axis. * @param axisRenderer Axis renderer. */ protected void drawErrorBars(DrawingContext context, Shape point, Row row, int col, int colErrorTop, int colErrorBottom, Axis axis, AxisRenderer axisRenderer) { if (axisRenderer == null) { return; } if (colErrorTop < 0 || colErrorTop >= row.size() || !row.isColumnNumeric(colErrorTop) || colErrorBottom < 0 || colErrorBottom >= row.size() || !row.isColumnNumeric(colErrorBottom)) { return; } Number value = (Number) row.get(col); Number errorTop = (Number) row.get(colErrorTop); Number errorBottom = (Number) row.get(colErrorBottom); if (!MathUtils.isCalculatable(value) || !MathUtils.isCalculatable(errorTop) || !MathUtils.isCalculatable(errorBottom)) { return; } Graphics2D graphics = context.getGraphics(); AffineTransform txOld = graphics.getTransform(); // Calculate positions PointND pointValue = axisRenderer.getPosition(axis, value, true, false); PointND pointTop = axisRenderer.getPosition(axis, value.doubleValue() + errorTop.doubleValue(), true, false); PointND pointBottom = axisRenderer.getPosition(axis, value.doubleValue() - errorBottom.doubleValue(), true, false); if (pointValue == null || pointTop == null || pointBottom == null) { return; } double posY = pointValue.get(PointND.Y); double posYTop = pointTop.get(PointND.Y) - posY; double posYBottom = pointBottom.get(PointND.Y) - posY; // Draw the error bar Line2D errorBar = new Line2D.Double(0.0, posYTop, 0.0, posYBottom); ColorMapper colors = getErrorColor(); Paint errorPaint = colors.get(row.getIndex()); Stroke errorStroke = getErrorStroke(); GraphicsUtils.drawPaintedShape( graphics, errorBar, errorPaint, null, errorStroke); // Draw the shapes at the end of the error bars Shape endShape = getErrorShape(); graphics.translate(0.0, posYTop); Stroke endShapeStroke = new BasicStroke(1f); GraphicsUtils.drawPaintedShape( graphics, endShape, errorPaint, null, endShapeStroke); graphics.setTransform(txOld); graphics.translate(0.0, posYBottom); GraphicsUtils.drawPaintedShape( graphics, endShape, errorPaint, null, endShapeStroke); graphics.setTransform(txOld); } /** * Returns a {@code Shape} instance that can be used for further * calculations. * @param data Information on axes, renderers, and values. * @return Outline that describes the point's shape. */ public Shape getPointShape(PointData data) { return getShape(); } /** * Returns a graphical representation of the value label to be drawn for * the specified data value. * @param data Information on axes, renderers, and values. * @param shape Outline that describes the bounds for the value label. * @return Component that can be used to draw the value label. */ public Drawable getValue(final PointData data, final Shape shape) { Drawable drawable = new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = -2568531344817590175L; public void draw(DrawingContext context) { PointRenderer renderer = DefaultPointRenderer2D.this; Row row = data.row; if (renderer.isValueVisible()) { int colValue = renderer.getValueColumn(); drawValueLabel(context, shape, row, colValue); } } }; return drawable; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/points/LabelPointRenderer.java000066400000000000000000000113121267060725100317240ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.points; import java.awt.Font; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.text.Format; import java.text.NumberFormat; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.util.GraphicsUtils; /** * Class that provides {@code Drawable}s, which display specified data * values as labels. */ public class LabelPointRenderer extends DefaultPointRenderer2D { /** Version id for serialization. */ private static final long serialVersionUID = -2612520977245369774L; /** Index of the column for the label content. */ private int column; /** Format for the label content. */ private Format format; /** Font for the label content. */ private Font font; /** Horizontal alignment of the label content. */ private double alignmentX; /** Vertical alignment of the label content. */ private double alignmentY; /** * Initializes a new renderer. */ public LabelPointRenderer() { column = 1; format = NumberFormat.getInstance(); font = Font.decode(null); alignmentX = 0.5; alignmentY = 0.5; } /** * Returns the index of the column which is used for the label. * @return Index of the column which is used for the label. */ public int getColumn() { return column; } /** * Sets the index of the column which will be used for the label. * @param column Index of the column which will be used for the label. */ public void setColumn(int column) { this.column = column; } /** * Returns the format which specifies how the labels are displayed. * @return {@code Format} instance which specifies how the labels are * displayed. */ public Format getFormat() { return format; } /** * Sets the format which specifies how the labels will be displayed. * @param format {@code Format} instance which specifies how the labels will * be displayed. */ public void setFormat(Format format) { this.format = format; } /** * Returns the font of this label. * @return Font of this label. */ public Font getFont() { return font; } /** * Sets font of this label. * @param font Font of this label. */ public void setFont(Font font) { this.font = font; } /** * Returns the horizontal alignment relative to the data point. * 0 means left, 1 means right. * @return Horizontal alignment relative to the data point. */ public double getAlignmentX() { return alignmentX; } /** * Sets the horizontal alignment relative to the data point. * 0 means left, 1 means right. * @param alignmentX Horizontal alignment relative to the data point. */ public void setAlignmentX(double alignmentX) { this.alignmentX = alignmentX; } /** * Returns the vertical alignment relative to the data point. * 0 means top, 1 means bottom. * @return Vertical alignment relative to the data point. */ public double getAlignmentY() { return alignmentY; } /** * Sets the vertical alignment relative to the data point. * 0 means top, 1 means bottom. * @param alignmentY Vertical alignment relative to the data point. */ public void setAlignmentY(double alignmentY) { this.alignmentY = alignmentY; } @Override public Shape getPointShape(PointData data) { Row row = data.row; int colLabel = getColumn(); if (colLabel >= row.size()) { return null; } Comparable labelValue = row.get(colLabel); if (labelValue == null) { return null; } Format format = getFormat(); Font font = getFont(); String text = format.format(labelValue); double alignment = getAlignmentX(); Shape shape = GraphicsUtils.getOutline(text, font, 0f, alignment); double alignX = getAlignmentX(); double alignY = getAlignmentY(); Rectangle2D bounds = shape.getBounds2D(); AffineTransform tx = AffineTransform.getTranslateInstance( -alignX*bounds.getWidth(), alignY*bounds.getHeight()); shape = tx.createTransformedShape(shape); return shape; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/points/PointData.java000066400000000000000000000041471267060725100300770ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.points; import java.util.Collections; import java.util.List; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; /** * Class for storing data that will be used to create a data point in a plot. */ public class PointData { /** Axes that will be used to project the point. */ public final List axes; /** Renderers for the axes that will be used to project the point. */ public final List axisRenderers; /** The data row that will get projected. */ public final Row row; /** The index of the column in the row that contains the data value. */ public final int col; /** * Initializes a new instance with the specified data. * @param axes Axes that are used to project the point. * @param axisRenderers Renderers for the axes. * @param row Data row containing that will be projected on the axes. * @param col Index of the column in the row that contains the data value. */ public PointData(List axes, List axisRenderers, Row row, int col) { this.axes = Collections.unmodifiableList(axes); this.axisRenderers = Collections.unmodifiableList(axisRenderers); this.row = row; this.col = col; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/points/PointRenderer.java000066400000000000000000000227241267060725100307750ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.points; import java.awt.Font; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.text.Format; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.plots.colors.ColorMapper; import de.erichseifert.gral.graphics.Location; /** *

An interface providing functions for rendering points in a plot. * It defines methods for:

*
    *
  • Retrieving the point of a certain row in a DataTable
  • *
  • Getting and setting the points color
  • *
  • Getting and setting the bounds of the points
  • *
*/ public interface PointRenderer { /** * Returns the shape which is used to draw the point. * @return {@code Shape} instance for the point. */ Shape getShape(); /** * Sets the shape which will be used to draw the point. * @param shape {@code Shape} instance for the point. */ void setShape(Shape shape); /** * Returns a mapping that is used to fill the point shapes. * @return {@code ColorMapper} that is used to fill the point shapes. */ ColorMapper getColor(); /** * Sets the mapping that will be used to fill the point shapes. * @param color {@code ColorMapper} instance to fill the point shapes. */ void setColor(ColorMapper color); /** * Sets the paint that will be used to fill the point shapes. * @param color {@code Paint} instance to fill the point shapes. */ void setColor(Paint color); /** * Returns whether the data value of a point is displayed or not. * @return {@code true} when the value is displayed, otherwise * {@code false}. */ boolean isValueVisible(); /** * Returns whether the data value of a point will be displayed or not. * @param valueVisible {@code true} if the value should be displayed, * otherwise {@code false}. */ void setValueVisible(boolean valueVisible); /** * Returns the index of the column that contains the displayed values. * @return Index of the column that contains the displayed values. */ int getValueColumn(); /** * Sets the index of the column that contains the displayed values. * @param columnIndex Index of the column that contains the displayed * values. */ void setValueColumn(int columnIndex); /** * Returns the format that is used to render the displayed data values. * @return {@code Format} instance that is used to render the displayed * data values. */ Format getValueFormat(); /** * Sets the format that will be used to render the displayed data values. * @param format {@code Format} instance that will be used to render the * displayed data values. */ void setValueFormat(Format format); /** * Returns the current positioning of the data value relative to the data * point. * @return Current positioning of the data value relative to the data * point. */ Location getValueLocation(); /** * Sets the positioning of the data value relative to the data point. * @param location Positioning of the data value relative to the data point. */ void setValueLocation(Location location); /** * Returns the relative horizontal position of the value. The position will * be between 0 and 1. * @return Relative horizontal position of the value. */ double getValueAlignmentX(); /** * Sets the relative horizontal position of the value. The position can be * specified between 0 and 1. * @param alignmentX Relative horizontal position of the value. */ void setValueAlignmentX(double alignmentX); /** * Returns the relative vertical position of the value. The position will * be between 0 and 1. * @return Relative vertical position of the value. */ double getValueAlignmentY(); /** * Sets the relative vertical position of the value. The position can be * specified between 0 and 1. * @param alignmentX Relative vertical position of the value. */ void setValueAlignmentY(double alignmentX); /** * Returns the current rotation angle of the value. * @return Rotation angle in degrees. */ double getValueRotation(); /** * Sets the rotation angle of the value. * @param angle Rotation angle in degrees. */ void setValueRotation(double angle); /** * Returns the current distance of values to the point. The distance is * specified relative to the font height. * @return Distance relative to the font height. */ double getValueDistance(); /** * Sets the distance of values to the point. The distance is specified * relative to the font height. * @param distance Distance relative to the font height. */ void setValueDistance(double distance); /** * Returns the mapping that is used to fill the value. * @return {@code ColorMapper} instance that is used to fill the value. */ ColorMapper getValueColor(); /** * Sets the mapping that will be used to fill the value. * @param color {@code ColorMapper} instance that will be used to fill * the value. */ void setValueColor(ColorMapper color); /** * Sets the paint that will be used to fill the value. * @param color {@code Paint} instance that will be used to fill the * value. */ void setValueColor(Paint color); /** * Returns the font that is used to render the value. * @return Font that is used to render the value. */ Font getValueFont(); /** * Sets the font that will be used to render the value. * @param font Font that will be used to render the value. */ void setValueFont(Font font); /** * Returns whether the error value is displayed. * @return {@code true} if the error value is displayed, otherwise * {@code false}. */ boolean isErrorVisible(); /** * Sets whether the error value will be displayed. * @param errorVisible {@code true} if the error value should be displayed, * otherwise {@code false}. */ void setErrorVisible(boolean errorVisible); /** * Returns the index of the column that contains the upper error value. * @return Index of the column that contains the upper error value. */ int getErrorColumnTop(); /** * Sets the index of the column that contains the upper error value. * @param columnIndex Index of the column that contains the upper error * value. */ void setErrorColumnTop(int columnIndex); /** * Returns the index of the column that contains the lower error value. * @return Index of the column that contains the lower error value. */ int getErrorColumnBottom(); /** * Sets the index of the column that contains the lower error value. * @param columnIndex Index of the column that contains the lower error * value. */ void setErrorColumnBottom(int columnIndex); /** * Returns the mapping that is used to fill the error indicators. * @return {@code ColorMapper} instance that is used to fill the error * indicators. */ ColorMapper getErrorColor(); /** * Sets the mapping that will be used to fill the error indicators. * @param color {@code ColorMapper} instance that will be used to fill * the error indicators. */ void setErrorColor(ColorMapper color); /** * Sets the paint that will be used to fill the error indicators. * @param color {@code Paint} instance that will be used to fill the * error indicators. */ void setErrorColor(Paint color); /** * Returns the shape which is used to draw the error indicators. * @return {@code Shape} instance of the error indicators. */ Shape getErrorShape(); /** * Sets the shape which will be used to draw the error indicators. * @param shape {@code Shape} instance for the error indicators. */ void setErrorShape(Shape shape); /** * Returns the stroke which is used to draw the error indicators. * @return Current stroke of the error indicators. */ Stroke getErrorStroke(); /** * Sets the stroke which will be used to draw the error indicators. * @param stroke Stroke of the error indicators. */ void setErrorStroke(Stroke stroke); /** * Returns a {@code Shape} instance that can be used for further * calculations. * @param data Information on axes, renderers, and values. * @return Outline that describes the point's shape. */ Shape getPointShape(PointData data); /** * Returns the graphical representation to be drawn for the specified data * value. * @param data Information on axes, renderers, and values. * @param shape Outline that describes the point's shape. * @return Component that can be used to draw the point. */ Drawable getPoint(PointData data, Shape shape); /** * Returns a graphical representation of the value label to be drawn for * the specified data value. * @param data Information on axes, renderers, and values. * @param shape Outline that describes the bounds for the value label. * @return Component that can be used to draw the value label. */ Drawable getValue(PointData data, Shape shape); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/points/SizeablePointRenderer.java000066400000000000000000000047031267060725100324510ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.points; import java.awt.Shape; import java.awt.geom.AffineTransform; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.util.DataUtils; import de.erichseifert.gral.util.MathUtils; /** * Class that provides {@code Drawable}s, which are sized accordingly to * the data. */ public class SizeablePointRenderer extends DefaultPointRenderer2D { /** Version id for serialization. */ private static final long serialVersionUID = 3276439387457161307L; /** Index of the column for the point size. */ private int column; /** * Initializes a new object. */ public SizeablePointRenderer() { column = 2; } /** * Returns the index of the column which is used for point sizes. * @return index of the column which is used for point sizes. */ public int getColumn() { return column; } /** * Sets the index of the column which will be used for point sizes. * @param column Index of the column which will be used for point sizes. */ public void setColumn(int column) { this.column = column; } @Override public Shape getPointShape(PointData data) { Shape shape = getShape(); Row row = data.row; int colSize = getColumn(); if (colSize >= row.size() || colSize < 0 || !row.isColumnNumeric(colSize)) { return shape; } Number value = (Number) row.get(colSize); double size = DataUtils.getValueOrDefault(value, Double.NaN); if (!MathUtils.isCalculatable(size) || size <= 0.0) { return null; } if (size != 1.0) { AffineTransform tx = AffineTransform.getScaleInstance(size, size); shape = tx.createTransformedShape(shape); } return shape; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/plots/points/package-info.java000077500000000000000000000017121267060725100305360ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Classes for rendering point shapes in a plot. */ package de.erichseifert.gral.plots.points; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/ui/000077500000000000000000000000001267060725100233035ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/ui/DrawablePanel.java000066400000000000000000000066331267060725100266570ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.ui; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.geom.Dimension2D; import javax.swing.JPanel; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; /** * A class that represents an adapter between the components of this library * and Swing. It displays a single {@code Drawable} in a {@code JPanel}. */ public class DrawablePanel extends JPanel { /** Version id for serialization. */ private static final long serialVersionUID = 1036506991203257170L; /** Drawable that should be displayed. */ private final Drawable drawable; /** Defines whether this panel uses antialiasing. */ private boolean antialiased; /** * Initializes a new instance with the specified {@code Drawable}. * Antialiasing is enabled by default. * @param drawable {@code Drawable} to be displayed */ public DrawablePanel(Drawable drawable) { this.drawable = drawable; setOpaque(false); antialiased = true; } /** * Returns the {@code Drawable} instance that is displayed by this * panel. * @return {@code Drawable} instance */ public Drawable getDrawable() { return drawable; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); if (isVisible()) { Graphics2D graphics = (Graphics2D) g; if (isAntialiased()) { graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } getDrawable().draw(new DrawingContext(graphics)); } } @Override public void setBounds(Rectangle bounds) { super.setBounds(bounds); getDrawable().setBounds(bounds); } @Override public void setBounds(int x, int y, int width, int height) { super.setBounds(x, y, width, height); getDrawable().setBounds(0.0, 0.0, width, height); } @Override public Dimension getPreferredSize() { Dimension dims = super.getPreferredSize(); Dimension2D dimsPlot = getDrawable().getPreferredSize(); dims.setSize(dimsPlot); return dims; } @Override public Dimension getMinimumSize() { return super.getPreferredSize(); } /** * Returns whether antialiasing is applied. * @return {@code true} if the panel uses antialiasing, {@code false} otherwise. */ public boolean isAntialiased() { return antialiased; } /** * Sets whether antialiasing should be applied. * @param antialiased {@code true} if the panel should use antialiasing, {@code false} otherwise. */ public void setAntialiased(boolean antialiased) { this.antialiased = antialiased; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/ui/DrawableWriterFilter.java000066400000000000000000000050311267060725100302310ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.ui; import java.io.File; import java.text.MessageFormat; import javax.swing.filechooser.FileFilter; import de.erichseifert.gral.io.IOCapabilities; import de.erichseifert.gral.util.Messages; /** * File filter that extracts files that can be read with a certain set of * {@link de.erichseifert.gral.io.IOCapabilities}. */ public class DrawableWriterFilter extends FileFilter { /** Capabilities that describe the data formats that can be processed by this filter. */ private final IOCapabilities capabilities; /** * Creates a new instance and initializes it with an * {@link de.erichseifert.gral.io.IOCapabilities} object. * @param capabilities writer capabilities. */ public DrawableWriterFilter(IOCapabilities capabilities) { this.capabilities = capabilities; } @Override public boolean accept(File f) { if (f == null) { return false; } if (f.isDirectory()) { return true; } String ext = getExtension(f).toLowerCase(); for (String extension : capabilities.getExtensions()) { if (extension.equals(ext)) { return true; } } return false; } @Override public String getDescription() { return MessageFormat.format(Messages.getString("IO.formatDescription"), //$NON-NLS-1$ capabilities.getFormat(), capabilities.getName()); } /** * Returns the capabilities filtered by this instance. * @return writer capabilities. */ public IOCapabilities getWriterCapabilities() { return capabilities; } private static String getExtension(File f) { String name = f.getName(); int lastDot = name.lastIndexOf('.'); if ((lastDot <= 0) || (lastDot == name.length() - 1)) { return ""; //$NON-NLS-1$ } return name.substring(lastDot + 1); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/ui/ExportChooser.java000066400000000000000000000034361267060725100267600ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.ui; import java.util.List; import javax.swing.JFileChooser; import de.erichseifert.gral.io.IOCapabilities; /** * A file chooser implementation that can be for export purposes. */ public class ExportChooser extends JFileChooser { /** Version id for serialization. */ private static final long serialVersionUID = -7885235526259131711L; /** * Creates a new instance and initializes it with an array of * {@link de.erichseifert.gral.io.IOCapabilities}. * @param strict Determines whether this dialog allows only the file formats * specified in {@code capabilities}. * @param capabilities List of objects describing the file formats that * are supported by this dialog. */ public ExportChooser(boolean strict, List capabilities) { setAcceptAllFileFilterUsed(!strict); for (IOCapabilities c : capabilities) { addChoosableFileFilter(new DrawableWriterFilter(c)); } } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/ui/ExportDialog.java000066400000000000000000000162161267060725100265550ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.ui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.Rectangle2D; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.text.DecimalFormat; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFormattedTextField; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.util.Messages; /** * A dialog implementation for exporting plots. It allows the user to * specify the document dimensions. */ public class ExportDialog extends JDialog { /** Version id for serialization. */ private static final long serialVersionUID = -1344719157074981540L; /** Type of user feedback. */ public static enum UserAction { /** User confirmed dialog. */ APPROVE, /** User canceled or closed dialog. */ CANCEL } /** Bounding rectangle for document. */ private final Rectangle2D documentBounds; /** Action that was used to close this dialog. */ private UserAction userAction; /** Input component for horizontal document offset. */ private final JFormattedTextField inputX; /** Input component for vertical document offset. */ private final JFormattedTextField inputY; /** Input component for document width. */ private final JFormattedTextField inputW; /** Input component for document height. */ private final JFormattedTextField inputH; /** * Creates a new instance and initializes it with a parent and a * drawable component. * @param parent Parent component. * @param drawable Drawable component. */ public ExportDialog(Component parent, Drawable drawable) { super(JOptionPane.getFrameForComponent(parent), true); setTitle(Messages.getString("ExportDialog.exportOptionsTitle")); //$NON-NLS-1$ documentBounds = new Rectangle2D.Double(); documentBounds.setFrame(drawable.getBounds()); setUserAction(UserAction.CANCEL); JPanel cp = new JPanel(new BorderLayout()); cp.setBorder(new EmptyBorder(10, 10, 10, 10)); setContentPane(cp); DecimalFormat formatMm = new DecimalFormat(); formatMm.setMinimumFractionDigits(2); JPanel options = new JPanel(new GridLayout(4, 2, 10, 2)); getContentPane().add(options, BorderLayout.NORTH); PropertyChangeListener docBoundsListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { setDocumentBounds( ((Number) inputX.getValue()).doubleValue(), ((Number) inputY.getValue()).doubleValue(), ((Number) inputW.getValue()).doubleValue(), ((Number) inputH.getValue()).doubleValue()); } }; inputX = new JFormattedTextField(formatMm); addInputField(inputX, Messages.getString("ExportDialog.left"), //$NON-NLS-1$ options, documentBounds.getX(), docBoundsListener); inputY = new JFormattedTextField(formatMm); addInputField(inputY, Messages.getString("ExportDialog.top"), //$NON-NLS-1$ options, documentBounds.getY(), docBoundsListener); inputW = new JFormattedTextField(formatMm); addInputField(inputW, Messages.getString("ExportDialog.width"), //$NON-NLS-1$ options, documentBounds.getWidth(), docBoundsListener); inputH = new JFormattedTextField(formatMm); addInputField(inputH, Messages.getString("ExportDialog.height"), //$NON-NLS-1$ options, documentBounds.getHeight(), docBoundsListener); JPanel controls = new JPanel(new FlowLayout()); cp.add(controls, BorderLayout.SOUTH); JButton buttonConfirm = new JButton( Messages.getString("ExportDialog.confirm")); //$NON-NLS-1$ buttonConfirm.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { setUserAction(UserAction.APPROVE); dispose(); } }); controls.add(buttonConfirm); JButton buttonCancel = new JButton( Messages.getString("ExportDialog.abort")); //$NON-NLS-1$ buttonCancel.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { setUserAction(UserAction.CANCEL); dispose(); } }); controls.add(buttonCancel); pack(); setLocationRelativeTo(parent); } /** * Utility method that adds a new label and a new input field to the * dialog. * @param input Input field. * @param labelText Text for label. * @param cont Container. * @param initialValue Initial value for the input field. * @param pcl Property change listener that should be associated with the * input field. */ private static void addInputField(JFormattedTextField input, String labelText, java.awt.Container cont, Object initialValue, PropertyChangeListener pcl) { JLabel label = new JLabel(labelText); label.setHorizontalAlignment(JLabel.RIGHT); cont.add(label); input.setValue(initialValue); input.setHorizontalAlignment(JFormattedTextField.RIGHT); input.addPropertyChangeListener("value", pcl); //$NON-NLS-1$ cont.add(input); label.setLabelFor(input); } /** * Returns the bounds entered by the user. * @return Document bounds that should be used to export the plot */ public Rectangle2D getDocumentBounds() { Rectangle2D bounds = new Rectangle2D.Double(); bounds.setFrame(documentBounds); return bounds; } /** * Sets new bounds for the document. * @param x Top-left corner * @param y Bottom-right corner * @param w Width. * @param h Height. */ protected void setDocumentBounds(double x, double y, double w, double h) { if ((documentBounds.getX() == x) && (documentBounds.getY() == y) && (documentBounds.getWidth() == w) && (documentBounds.getHeight() == h)) { return; } documentBounds.setFrame(x, y, w, h); inputX.setValue(x); inputY.setValue(y); inputW.setValue(w); inputH.setValue(h); } /** * Returns the last action by the user. The return value can be used to * determine whether the user approved or canceled the dialog. * @return Type of user action. */ public UserAction getUserAction() { return userAction; } /** * Sets the type of action the user executed. The value can later be used * to determine whether the user approved or canceled the dialog. * @param userAction Type of user action. */ private void setUserAction(UserAction userAction) { this.userAction = userAction; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/ui/InteractivePanel.java000066400000000000000000000431271267060725100274120ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.ui; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.swing.AbstractAction; import javax.swing.ActionMap; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import de.erichseifert.gral.graphics.Container; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.io.IOCapabilities; import de.erichseifert.gral.io.plots.DrawableWriter; import de.erichseifert.gral.io.plots.DrawableWriterFactory; import de.erichseifert.gral.navigation.Navigable; import de.erichseifert.gral.navigation.Navigator; import de.erichseifert.gral.util.Messages; import de.erichseifert.gral.util.PointND; /** * A panel implementation that displays a {@code Drawable} instance as a * rich Swing component. */ public class InteractivePanel extends DrawablePanel implements Printable { /** Version id for serialization. */ private static final long serialVersionUID = 9084883142053148090L; // FIXME Find better method to adjust resolution /** Constant that can be used to convert from millimeters to points (1/72 inch). */ private static final double MM_TO_PT = 72.0/25.4; /** Constant that defines how many millimeters a pixel will be. */ private static final double MM_PER_PX = 0.2*MM_TO_PT; /** Job for printing the current panel. */ private final PrinterJob printerJob; /** Value that is necessary before panning is triggered. */ private static final int MIN_DRAG = 0; /** Defines whether the panel can be zoomed. */ private boolean zoomable; /** Defines whether the panel can be panned. */ private boolean pannable; /** Map that stored actions by names like "zoomIn", "zoomOut", "resetView", "exportImage", or "print". */ protected final ActionMap actions; /** Cache for the popup menu. */ private JPopupMenu popupMenu; private boolean popupMenuEnabled; private Point2D popupMenuPos; /** Chooser for image export. */ private final JFileChooser exportImageChooser; /** Object to be used as listener for zooming actions. */ private MouseZoomListener zoomListener; /** Object to be used as listener for panning actions. */ private NavigationMoveListener panListener; /** * Listener class for zooming actions. */ private final static class MouseZoomListener extends MouseAdapter implements MouseWheelListener, Serializable { /** Version id for serialization. */ private static final long serialVersionUID = -7323541053291673122L; private final InteractivePanel panel; public MouseZoomListener(InteractivePanel panel) { this.panel = panel; } @Override public void mouseWheelMoved(MouseWheelEvent e) { Point2D point = e.getPoint(); panel.zoom(point, -e.getWheelRotation()); } @Override public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e) && (e.getClickCount() == 2)) { Point2D point = e.getPoint(); panel.zoom(point, 1); } } } /** * Creates a new panel instance and initializes it with a * drawable component. * @param drawable Drawable component. */ @SuppressWarnings("serial") public InteractivePanel(Drawable drawable) { super(drawable); printerJob = PrinterJob.getPrinterJob(); printerJob.setPrintable(this); List exportFormats = DrawableWriterFactory.getInstance() .getCapabilities(); exportImageChooser = new ExportChooser(true, exportFormats); exportImageChooser.setDialogTitle(Messages.getString( "InteractivePanel.exportImageTitle")); //$NON-NLS-1$ actions = new ActionMap(); actions.put("zoomIn", new AbstractAction(Messages.getString( //$NON-NLS-1$ "InteractivePanel.zoomIn")) { //$NON-NLS-1$ public void actionPerformed(ActionEvent e) { zoom(popupMenuPos, 1); } }); actions.put("zoomOut", new AbstractAction(Messages.getString( //$NON-NLS-1$ "InteractivePanel.zoomOut")) { //$NON-NLS-1$ public void actionPerformed(ActionEvent e) { zoom(popupMenuPos, -1); } }); actions.put("resetView", new AbstractAction(Messages.getString( //$NON-NLS-1$ "InteractivePanel.resetView")) { //$NON-NLS-1$ public void actionPerformed(ActionEvent e) { resetZoom(popupMenuPos); } }); actions.put("exportImage", new AbstractAction(Messages.getString( //$NON-NLS-1$ "InteractivePanel.exportImage")) { //$NON-NLS-1$ public void actionPerformed(ActionEvent e) { int ret = exportImageChooser.showSaveDialog( InteractivePanel.this); // Clear artifacts of the file chooser repaint(); // If the user aborted we can stop if (ret != JFileChooser.APPROVE_OPTION) { return; } // If the user didn't select a file we can stop File file = exportImageChooser.getSelectedFile(); if (file == null) { return; } // If the selected an existing file we ask for permission // to overwrite it else if (file.exists()) { int retOverwrite = JOptionPane.showConfirmDialog( InteractivePanel.this, Messages.getString("InteractivePanel.exportExistsWarning"), //$NON-NLS-1$ Messages.getString("InteractivePanel.warning"), //$NON-NLS-1$ JOptionPane.YES_NO_OPTION ); // Clear artifacts of the confirm dialog repaint(); if (retOverwrite == JOptionPane.NO_OPTION) { return; } } // Export current view to the selected file Drawable d = getDrawable(); ExportDialog ed = new ExportDialog(InteractivePanel.this, d); ed.setVisible(true); if (!ed.getUserAction().equals( ExportDialog.UserAction.APPROVE)) { return; } DrawableWriterFilter filter = (DrawableWriterFilter) exportImageChooser.getFileFilter(); export(d, filter.getWriterCapabilities().getMimeType(), file, ed.getDocumentBounds()); } }); actions.put("print", new AbstractAction(Messages.getString( //$NON-NLS-1$ "InteractivePanel.print")) { //$NON-NLS-1$ public void actionPerformed(ActionEvent e) { if (printerJob.printDialog()) { try { printerJob.print(); } catch (PrinterException ex) { // TODO Show error dialog ex.printStackTrace(); } } } }); popupMenuEnabled = true; addMouseListener(new PopupListener()); setZoomable(true); setPannable(true); } /** * Method that returns the popup menu for a given mouse event. It will be * called on each popup event if the menu is enabled. If the menu is static * caching can be used to prevent unnecessary generation of menu objects. * @param e Mouse event that triggered the popup menu. * @return A popup menu instance, or {@code null} if no popup menu should be shown. * @see #isPopupMenuEnabled() * @see #setPopupMenuEnabled(boolean) */ protected JPopupMenu getPopupMenu(MouseEvent e) { if (popupMenu == null) { popupMenu = new JPopupMenu(); popupMenu.add(actions.get("zoomIn")); //$NON-NLS-1$ popupMenu.add(actions.get("zoomOut")); //$NON-NLS-1$ popupMenu.add(actions.get("resetView")); //$NON-NLS-1$ popupMenu.addSeparator(); popupMenu.add(actions.get("exportImage")); //$NON-NLS-1$ popupMenu.add(actions.get("print")); //$NON-NLS-1$ } return popupMenu; } /** * Returns whether a popup menu will be shown by this panel when the user * takes the appropriate action. The necessary action depends on the * operating system of the user. * @return {@code true} when a popup menu will be shown, * otherwise {@code false}. */ public boolean isPopupMenuEnabled() { return popupMenuEnabled; } /** * Sets whether a popup menu will be shown by this panel when the user * takes the appropriate action. The necessary action depends on the * operating system of the user. * @param popupMenuEnabled {@code true} when a popup menu should be * shown, otherwise {@code false}. */ public void setPopupMenuEnabled(boolean popupMenuEnabled) { this.popupMenuEnabled = popupMenuEnabled; } /** * Zooms a navigable object in (positive values) or out (negative values). * @param point The location where the zoom was triggered. * @param times Number of times the navigable object will be zoomed. * Positive values zoom in, negative values zoom out. */ private void zoom(Point2D point, int times) { if (!isZoomable()) { return; } Navigable navigable = InteractivePanel.getNavigableAt(getDrawable(), point); if (navigable == null) { return; } Navigator navigator = navigable.getNavigator(); if (times >= 0) { for (int i = 0; i < times; i++) { navigator.zoomIn(); } } else { for (int i = 0; i < -times; i++) { navigator.zoomOut(); } } repaint(); } private void resetZoom(Point2D point) { if (!isZoomable()) { return; } Navigable navigable = InteractivePanel.getNavigableAt(getDrawable(), point); if (navigable == null) { return; } Navigator navigator = navigable.getNavigator(); navigator.reset(); repaint(); } /** * Method that exports the current view to a file using a specified file type. * @param component Drawable that will be exported. * @param mimeType File format as MIME type string. * @param file File to export to. * @param documentBounds Document boundary rectangle */ private void export(Drawable component, String mimeType, File file, Rectangle2D documentBounds) { FileOutputStream destination; try { destination = new FileOutputStream(file); } catch (FileNotFoundException ex) { // TODO Auto-generated catch block ex.printStackTrace(); return; } DrawableWriter writer = DrawableWriterFactory.getInstance().get(mimeType); try { writer.write(component, destination, documentBounds.getX(), documentBounds.getY(), documentBounds.getWidth(), documentBounds.getHeight()); } catch (IOException ex) { // TODO Auto-generated catch block ex.printStackTrace(); } finally { try { destination.close(); } catch (IOException ex2) { // TODO Auto-generated catch block ex2.printStackTrace(); } } } /** * Class that is responsible for showing the popup menu. */ private class PopupListener extends MouseAdapter { @Override public void mousePressed(MouseEvent e) { showPopup(e); } @Override public void mouseReleased(MouseEvent e) { showPopup(e); } private void showPopup(MouseEvent e) { if (!isPopupMenuEnabled() || !e.isPopupTrigger()) { return; } JPopupMenu menu = getPopupMenu(e); if (menu == null) { return; } popupMenuPos = e.getPoint(); menu.show(e.getComponent(), e.getX(), e.getY()); } } /** * Class that handles mouse moves for navigation. */ private static class NavigationMoveListener extends MouseAdapter { /** A reference to the panel for refreshing. */ private final InteractivePanel panel; /** AbstractPlot that will be changed by this class. */ private Navigable navigable; /** Previously clicked point or {@code null}. */ private Point posPrev; /** * Creates a new listener and initializes it with a panel. * @param panel InteractivePanel that should be refreshed. */ public NavigationMoveListener(InteractivePanel panel) { this.panel = panel; } @Override public void mousePressed(MouseEvent e) { Point point = e.getPoint(); navigable = InteractivePanel.getNavigableAt(panel.getDrawable(), point); posPrev = point; } @Override public void mouseDragged(MouseEvent e) { if (navigable == null) { return; } // Calculate distance that the current view was dragged // (screen units) Point pos = e.getPoint(); Navigator navigator = navigable.getNavigator(); int dx = pos.x - posPrev.x; int dy = pos.y - posPrev.y; posPrev = pos; if (Math.abs(dx) > MIN_DRAG || Math.abs(dy) > MIN_DRAG) { PointND deltas = new PointND(dx, dy); navigator.pan(deltas); panel.repaint(); } } } /** * Prints the page at the specified index into the specified * {@link Graphics} context in the specified format. * @param g the context into which the page is drawn * @param pageFormat the size and orientation of the page being drawn * @param pageIndex the zero based index of the page to be drawn * @return PAGE_EXISTS if the page is rendered successfully * or NO_SUCH_PAGE if {@code pageIndex} specifies a * non-existent page. * @exception java.awt.print.PrinterException * thrown when the print job is terminated. */ public int print(Graphics g, PageFormat pageFormat, int pageIndex) throws PrinterException { if (pageIndex > 0) { return Printable.NO_SUCH_PAGE; } Graphics2D graphics = (Graphics2D) g; AffineTransform txOld = graphics.getTransform(); graphics.scale(MM_PER_PX, MM_PER_PX); Rectangle2D boundsOld = getDrawable().getBounds(); Rectangle2D pageBounds = new Rectangle2D.Double( pageFormat.getImageableX()/MM_PER_PX, pageFormat.getImageableY()/MM_PER_PX, pageFormat.getImageableWidth()/MM_PER_PX, pageFormat.getImageableHeight()/MM_PER_PX ); // Set size // TODO Keep Drawable's aspect ratio when scaling getDrawable().setBounds(pageBounds); // TODO Assure to temporarily turn off anti-aliasing before printing try { getDrawable().draw(new DrawingContext(graphics)); } finally { getDrawable().setBounds(boundsOld); } graphics.setTransform(txOld); return Printable.PAGE_EXISTS; } /** * Returns whether the plot area in the panel can be zoomed. * @return {@code true} if the plot can be zoomed, * {@code false} otherwise. */ public boolean isZoomable() { return zoomable; } /** * Sets whether the plot area in the panel can be zoomed. * @param zoomable {@code true} if the plot should be zoomable, * {@code false} otherwise. */ public void setZoomable(boolean zoomable) { if (this.zoomable == zoomable) { return; } this.zoomable = zoomable; if (zoomListener != null) { removeMouseWheelListener(zoomListener); removeMouseListener(zoomListener); zoomListener = null; } if (zoomable) { zoomListener = new MouseZoomListener(this); addMouseListener(zoomListener); addMouseWheelListener(zoomListener); } actions.get("zoomIn").setEnabled(isZoomable()); //$NON-NLS-1$ actions.get("zoomOut").setEnabled(isZoomable()); //$NON-NLS-1$ actions.get("resetView").setEnabled(isZoomable() && isPannable()); //$NON-NLS-1$ } /** * Returns whether the plot area in the panel can be panned. * @return {@code true} if the plot can be panned, * {@code false} otherwise. */ public boolean isPannable() { return pannable; } /** * Sets whether the plot area in the panel can be panned. * @param pannable {@code true} if the plot should be pannable, * {@code false} otherwise. */ public void setPannable(boolean pannable) { if (this.pannable == pannable) { return; } this.pannable = pannable; if (panListener != null) { removeMouseMotionListener(panListener); removeMouseListener(panListener); panListener = null; } if (pannable) { // Register a new handler to move the map by dragging // This requires that an x- and a y-axis do exist in the plot panListener = new NavigationMoveListener(this); addMouseListener(panListener); addMouseMotionListener(panListener); } actions.get("resetView").setEnabled(isZoomable() && isPannable()); //$NON-NLS-1$ } /** * Returns a navigable area at the specified point, {@code null} if no * object could be found. If the specified container isn't navigable, its * children are recursively checked. * @param drawable The drawable container to check for navigable children. * @param point Position that should hit the navigable object. * @return A navigable object. */ private static Navigable getNavigableAt(Drawable drawable, Point2D point) { List componentsToCheck; if (drawable instanceof Container) { componentsToCheck = ((Container) drawable).getDrawablesAt(point); } else { componentsToCheck = new ArrayList(1); componentsToCheck.add(drawable); } for (Drawable component : componentsToCheck) { if ((component instanceof Navigable) && component.getBounds().contains(point)) { return (Navigable) component; } } return null; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/ui/package-info.java000077500000000000000000000020371267060725100264770ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * User interface classes. The classes implement ready-to-use user interface * components, e.g. for settings and file chooser dialogs, that be used by * applications. */ package de.erichseifert.gral.ui; gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/000077500000000000000000000000001267060725100236435ustar00rootroot00000000000000gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/DataUtils.java000066400000000000000000000046601267060725100264060ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.util.HashMap; import java.util.Map; /** * Abstract class that contains utility functions for creating data structures * and for working with data sources and values. */ public abstract class DataUtils { /** * Default constructor that prevents creation of class. */ private DataUtils() { throw new UnsupportedOperationException(); } /** * Creates a mapping from two arrays, one with keys, one with values. * @param Data type of the keys. * @param Data type of the values. * @param keys Array containing the keys. * @param values Array containing the values. * @return Map with keys and values from the specified arrays. */ public static Map map(K[] keys, V[] values) { // Check for valid parameters if (keys.length != values.length) { throw new IllegalArgumentException( "Could not create the map because the number of keys and values differs."); } // Fill map with keys and values Map map = new HashMap(); for (int i = 0; i < keys.length; i++) { K key = keys[i]; V value = values[i]; map.put(key, value); } return map; } /** * Returns the double value of the {@code Number} object or the specified * default value if the object is {@code null}. * @param n Number object. * @param defaultValue Default value. * @return Double value of the {@code Number} object or the default value * if the object is {@code null} */ public static double getValueOrDefault(Number n, double defaultValue) { if (n == null) { return defaultValue; } return n.doubleValue(); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/GeometryUtils.java000066400000000000000000000330751267060725100273320ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.awt.BasicStroke; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.geom.FlatteningPathIterator; import java.awt.geom.Line2D; import java.awt.geom.Path2D; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.io.Serializable; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; /** * Abstract class that represents a collection of utility functions * concerning geometry. */ public abstract class GeometryUtils { /** Precision. */ public static final double EPSILON = 1e-5; /** Precision squared. */ public static final double EPSILON_SQ = EPSILON*EPSILON; /** * Default constructor that prevents creation of class. */ private GeometryUtils() { throw new UnsupportedOperationException(); } /** * Returns the line fragments of the specified Shape. * @param path Shape to be divided. * @param swapped Invert segment direction. * @return Array of lines. */ public static Line2D[] shapeToLines(Shape path, boolean swapped) { Deque lines = new ArrayDeque(); PathIterator i = new FlatteningPathIterator(path.getPathIterator(null), 0.5); double[] coords = new double[6]; double[] coordsPrev = new double[6]; while (!i.isDone()) { int segment = i.currentSegment(coords); if (segment == PathIterator.SEG_LINETO || segment == PathIterator.SEG_CLOSE) { Line2D line; if (!swapped) { line = new Line2D.Double( coordsPrev[0], coordsPrev[1], coords[0], coords[1]); lines.addLast(line); } else { line = new Line2D.Double( coords[0], coords[1], coordsPrev[0], coordsPrev[1]); lines.addFirst(line); } } if (segment == PathIterator.SEG_CLOSE && !lines.isEmpty()) { Point2D firstPoint = lines.getFirst().getP1(); Point2D lastPoint = lines.getLast().getP2(); if (!firstPoint.equals(lastPoint)) { Line2D line; if (!swapped) { line = new Line2D.Double( coords[0], coords[1], firstPoint.getX(), firstPoint.getY()); lines.addLast(line); } else { line = new Line2D.Double( firstPoint.getX(), firstPoint.getY(), coords[0], coords[1]); lines.addFirst(line); } } } System.arraycopy(coords, 0, coordsPrev, 0, 6); i.next(); } Line2D[] linesArray = new Line2D[lines.size()]; lines.toArray(linesArray); return linesArray; } /** * Returns all intersection points of two shapes. * @param s1 First shape * @param s2 Second shape * @return Intersection points, or empty array if * no intersections were found */ public static List intersection(final Shape s1, final Shape s2) { List intersections = new ArrayList(2); Line2D[] lines1 = shapeToLines(s1, false); Line2D[] lines2 = shapeToLines(s2, false); for (Line2D l1 : lines1) { for (Line2D l2 : lines2) { Point2D intersection = intersection(l1, l2); if (intersection != null) { intersections.add(intersection); } } } return intersections; } /** * Returns the intersection point of two lines. * @param l1 First line * @param l2 Second line * @return Intersection point, or {@code null} if * no intersection was found */ public static Point2D intersection(final Line2D l1, final Line2D l2) { Point2D p0 = l1.getP1(); Point2D d0 = new Point2D.Double(l1.getX2() - p0.getX(), l1.getY2() - p0.getY()); Point2D p1 = l2.getP1(); Point2D d1 = new Point2D.Double(l2.getX2() - p1.getX(), l2.getY2() - p1.getY()); Point2D e = new Point2D.Double(p1.getX() - p0.getX(), p1.getY() - p0.getY()); double kross = d0.getX()*d1.getY() - d0.getY()*d1.getX(); double sqrKross = kross*kross; double sqrLen0 = d0.distanceSq(0.0, 0.0); double sqrLen1 = d1.distanceSq(0.0, 0.0); if (sqrKross > EPSILON_SQ * sqrLen0 * sqrLen1) { double s = (e.getX()*d1.getY() - e.getY()*d1.getX())/kross; if (s < 0d || s > 1d) { return null; } double t = (e.getX()*d0.getY() - e.getY()*d0.getX())/kross; if (t < 0d || t > 1d) { return null; } return new Point2D.Double( p0.getX() + s*d0.getX(), p0.getY() + s*d0.getY() ); } /* double sqrLenE = e.lengthSq(); kross = e.cross(d0); sqrKross = kross*kross; if (sqrKross > EPSILON_SQ*sqrLen0*sqrLenE) { return null; } */ return null; } /** * Expand or shrink a shape in all directions by a defined offset. * @param s Shape * @param offset Offset * @return New shape that was expanded or shrunk by the specified amount */ public static Area grow(final Shape s, final double offset) { return grow(s, offset, BasicStroke.JOIN_MITER, 10f); } /** * Expand or shrink a shape in all directions by a defined offset. * @param s Shape * @param offset Offset to expand/shrink * @param join Method for handling edges (see BasicStroke) * @param miterlimit Limit for miter joining method * @return New shape that is expanded or shrunk by the specified amount */ public static Area grow(final Shape s, final double offset, int join, float miterlimit) { Area shape = new Area(s); if (MathUtils.almostEqual(offset, 0.0, EPSILON)) { return shape; } Stroke stroke = new BasicStroke((float)Math.abs(2.0*offset), BasicStroke.CAP_SQUARE, join, miterlimit); Area strokeShape = new Area(stroke.createStrokedShape(s)); if (offset > 0.0) { shape.add(strokeShape); } else { shape.subtract(strokeShape); } return shape; } /** * Subtract a specified geometric area of data points from another shape to yield gaps. * @param shapeArea Shape from which to subtract. * @param gap Size of the gap. * @param rounded Gap corners will be rounded if {@code true}. * @param pointPos Position of the data point * @param pointShape Shape of the data point * @return Shape with punched holes */ public static Area punch(Area shapeArea, double gap, boolean rounded, Point2D pointPos, Shape pointShape) { if (gap <= 1e-10 || pointPos == null || pointShape == null) { return shapeArea; } AffineTransform tx = AffineTransform.getTranslateInstance( pointPos.getX(), pointPos.getY()); int gapJoin = rounded ? BasicStroke.JOIN_ROUND : BasicStroke.JOIN_MITER; Area gapArea = GeometryUtils.grow( tx.createTransformedShape(pointShape), gap, gapJoin, 10f); shapeArea.subtract(gapArea); return shapeArea; } /** * Utility data class for the values of the segments in a geometric shape. */ public static final class PathSegment implements Serializable { /** Version id for serialization. */ private static final long serialVersionUID = 526444553637955799L; /** Segment type id as defined in {@link PathIterator}. */ public final int type; /** Starting point. */ public final Point2D start; /** End point. */ public final Point2D end; /** Coordinates necessary to draw the segment. */ public final double[] coords; /** * Initializes a new instance with type, starting and end point, and * all other coordinates that are necessary to draw the segment. * @param type Segment type id as defined in {@link PathIterator}. * @param start Starting point. * @param end End point. * @param coords Array of coordinates necessary to draw the segment. */ public PathSegment(int type, Point2D start, Point2D end, double[] coords) { this.type = type; this.start = start; this.end = end; this.coords = new double[6]; System.arraycopy(coords, 0, this.coords, 0, 6); } } /** * Returns a list of a shape's segments as they are returned by its path * iterator. * @param shape Shape to be iterated. * @return A list of path segment objects. */ public static List getSegments(Shape shape) { PathIterator path = shape.getPathIterator(null); Point2D pointStart = null, pointEnd = null; double[] coords = new double[6]; List segments = new LinkedList(); while (!path.isDone()) { int type = path.currentSegment(coords); if (type == PathIterator.SEG_MOVETO || type == PathIterator.SEG_LINETO) { pointEnd = new Point2D.Double(coords[0], coords[1]); } else if (type == PathIterator.SEG_QUADTO) { pointEnd = new Point2D.Double(coords[2], coords[3]); } else if (type == PathIterator.SEG_CUBICTO) { pointEnd = new Point2D.Double(coords[4], coords[5]); } PathSegment segment = new PathSegment(type, pointStart, pointEnd, coords); segments.add(segment); pointStart = pointEnd; path.next(); } return segments; } /** * Constructs a geometric shape from a list of path segments. * @param segments List of path segments. * @param isDouble {@code true} if the shape contents should be stored with * double values, {@code false} if they should be stored as float. * @return A geometric shape. */ public static Shape getShape(List segments, boolean isDouble) { if (isDouble) { return getShapeDouble(segments); } else { return getShapeFloat(segments); } } /** * Constructs a geometric shape with double precision from a list of path * segments. * @param segments List of path segments. * @return A geometric shape. */ private static Shape getShapeDouble(List segments) { Path2D.Double path = new Path2D.Double(Path2D.WIND_NON_ZERO, segments.size()); for (PathSegment segment : segments) { double[] coords = segment.coords; if (segment.type == PathIterator.SEG_MOVETO) { path.moveTo(coords[0], coords[1]); } else if (segment.type == PathIterator.SEG_LINETO) { path.lineTo(coords[0], coords[1]); } else if (segment.type == PathIterator.SEG_QUADTO) { path.quadTo(coords[0], coords[1], coords[2], coords[3]); } else if (segment.type == PathIterator.SEG_CUBICTO) { path.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); } else if (segment.type == PathIterator.SEG_CLOSE) { path.closePath(); } } return path; } /** * Constructs a geometric shape with single precision from a list of path * segments. * @param segments List of path segments. * @return A geometric shape. */ private static Shape getShapeFloat(List segments) { Path2D.Float path = new Path2D.Float(Path2D.WIND_NON_ZERO, segments.size()); for (PathSegment segment : segments) { float[] coords = new float[segment.coords.length]; for (int i = 0; i < coords.length; i++) { coords[i] = (float) segment.coords[i]; } if (segment.type == PathIterator.SEG_MOVETO) { path.moveTo(coords[0], coords[1]); } else if (segment.type == PathIterator.SEG_LINETO) { path.lineTo(coords[0], coords[1]); } else if (segment.type == PathIterator.SEG_QUADTO) { path.quadTo(coords[0], coords[1], coords[2], coords[3]); } else if (segment.type == PathIterator.SEG_CUBICTO) { path.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); } else if (segment.type == PathIterator.SEG_CLOSE) { path.closePath(); } } return path; } /** * Returns a clone of a specified shape which has a reversed order of the * points, lines and curves. * @param shape Original shape. * @return Shape with reversed direction. */ public static Shape reverse(Shape shape) { List segments = getSegments(shape); boolean closed = false; Path2D reversed = new Path2D.Double(Path2D.WIND_NON_ZERO, segments.size()); ListIterator i = segments.listIterator(segments.size()); while (i.hasPrevious()) { PathSegment segment = i.previous(); if (segment.type == PathIterator.SEG_CLOSE) { closed = true; continue; } if (reversed.getCurrentPoint() == null) { reversed.moveTo( segment.end.getX(), segment.end.getY()); } if (segment.type == PathIterator.SEG_LINETO) { reversed.lineTo( segment.start.getX(), segment.start.getY()); } else if (segment.type == PathIterator.SEG_QUADTO) { reversed.quadTo( segment.coords[0], segment.coords[1], segment.start.getX(), segment.start.getY()); } else if (segment.type == PathIterator.SEG_CUBICTO) { reversed.curveTo( segment.coords[2], segment.coords[3], segment.coords[0], segment.coords[1], segment.start.getX(), segment.start.getY()); } else if (segment.type == PathIterator.SEG_MOVETO) { if (closed) { reversed.closePath(); closed = false; } } } return reversed; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/GraphicsUtils.java000066400000000000000000000354651267060725100273040ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.awt.font.FontRenderContext; import java.awt.font.LineBreakMeasurer; import java.awt.font.TextAttribute; import java.awt.font.TextLayout; import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.geom.Rectangle2D; import java.text.AttributedCharacterIterator; import java.text.AttributedString; import java.util.LinkedList; import java.util.List; /** * Abstract class that contains utility functions for working with graphics. * For example, this includes font handling or color space conversion. */ public abstract class GraphicsUtils { /** Default font render context. */ private static final FontRenderContext frc = new FontRenderContext(null, true, true); /** Constant for the CIE XYZ and CIE L*u*v* color spaces: (6/29)^3 **/ private static final double CIE_EPSILON = 216.0/24389.0; /** Constant for the CIE XYZ and CIE L*u*v* color spaces: (29/3)^3 **/ private static final double CIE_KAPPA = 24389.0/27.0; /** Xr, Yr, Zr constants with D50 white point used for CIE XYZ to CIE L*u*v* conversion **/ private static final double[] XYZ_R_D50 = { 0.964221, 1.000000, 0.825211 }; /** Precalculated u0 constant for CIE L*u*v* to CIE XYZ conversion. **/ private static final double XYZ_R_D50_U0 = 4.0*XYZ_R_D50[0]/(XYZ_R_D50[0] + 15.0*XYZ_R_D50[1] + 3.0*XYZ_R_D50[2]); /** Precalculated v0 constant for CIE L*u*v* to CIE XYZ conversion. **/ private static final double XYZ_R_D50_V0 = 9.0*XYZ_R_D50[1]/(XYZ_R_D50[0] + 15.0*XYZ_R_D50[1] + 3.0*XYZ_R_D50[2]); /** sRGB to CIE XYZ conversion matrix. See http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html#Specifications **/ private static final double[] MATRIX_SRGB2XYZ_D50 = { 0.436052025, 0.385081593, 0.143087414, 0.222491598, 0.716886060, 0.060621486, 0.013929122, 0.097097002, 0.714185470 }; /** CIE XYZ to sRGB conversion matrix. See http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html#Specifications **/ private static final double[] MATRIX_XYZ2SRGB_D50 = { 3.1338561, -1.6168667, -0.4906146, -0.9787684, 1.9161415, 0.0334540, 0.0719453, -0.2289914, 1.4052427 }; /** * Default constructor that prevents creation of class. */ protected GraphicsUtils() { throw new UnsupportedOperationException(); } /** * Returns the outline for the specified text using the specified font and * line width. The text may also contain line breaks ({@literal '\n'}). * @param text Text to be displayed. * @param font Font of the Text. * @param wrappingWidth Maximum width of lines * @param alignment Alignment of the text when it spans multiple lines. * @return Shape of the text outline in the specified font. */ public static Shape getOutline(String text, Font font, float wrappingWidth, double alignment) { boolean wordWrap = true; if (wrappingWidth <= 0f) { wordWrap = false; wrappingWidth = Float.MAX_VALUE; } AttributedString string = new AttributedString(text); string.addAttribute(TextAttribute.FONT, font); AttributedCharacterIterator iterator = string.getIterator(); LineBreakMeasurer measurer = new LineBreakMeasurer(iterator, frc); List lines = new LinkedList(); while (measurer.getPosition() < text.length()) { // Find out which character will be wrapped next int nextBreakPos = measurer.nextOffset(wrappingWidth); int lineBreakPos = text.indexOf('\n', measurer.getPosition()) + 1; int breakPos = nextBreakPos; if (lineBreakPos > 0 && lineBreakPos < nextBreakPos) { breakPos = lineBreakPos; } TextLayout line = measurer.nextLayout(wrappingWidth, breakPos, false); lines.add(line); } if (!wordWrap) { // Determine the maximal line length float advanceMax = 0f; for (TextLayout line : lines) { advanceMax = Math.max(line.getAdvance(), advanceMax); } wrappingWidth = advanceMax; } AffineTransform txLinePos = new AffineTransform(); Area outlineAllLines = null; for (TextLayout line : lines) { // Distribute the space that's left double dx = alignment*(wrappingWidth - line.getAdvance()); // Move to baseline txLinePos.translate(dx, line.getAscent()); // Get the shape of the current line Area outlineLine = new Area(line.getOutline(txLinePos)); // Add the shape of the line to the shape if (outlineAllLines == null) { outlineAllLines = outlineLine; } else { outlineAllLines.add(outlineLine); } // Move to next line txLinePos.translate(-dx, line.getDescent() + line.getLeading()); } return outlineAllLines; } /** * Fills a Shape with the specified Paint object. * @param graphics Graphics to be painted into. * @param shape Shape to be filled. * @param paint Paint to be used. * @param paintBounds Optional bounds describing the painted area. */ public static void fillPaintedShape(Graphics2D graphics, Shape shape, Paint paint, Rectangle2D paintBounds) { if (shape == null) { return; } if (paintBounds == null) { paintBounds = shape.getBounds2D(); } AffineTransform txOrig = graphics.getTransform(); graphics.translate(paintBounds.getX(), paintBounds.getY()); graphics.scale(paintBounds.getWidth(), paintBounds.getHeight()); Paint paintOld = null; if (paint != null) { paintOld = graphics.getPaint(); graphics.setPaint(paint); } AffineTransform tx = AffineTransform.getScaleInstance( 1.0/paintBounds.getWidth(), 1.0/paintBounds.getHeight()); tx.translate(-paintBounds.getX(), -paintBounds.getY()); graphics.fill(tx.createTransformedShape(shape)); if (paintOld != null) { graphics.setPaint(paintOld); } graphics.setTransform(txOrig); } /** * Draws a filled Shape with the specified Paint object. * @param graphics Graphics to be painted into. * @param shape Shape to be filled. * @param paint Paint to be used. * @param paintBounds Optional bounds describing the painted area. * @param stroke Stroke to be used for outlines. */ public static void drawPaintedShape(Graphics2D graphics, Shape shape, Paint paint, Rectangle2D paintBounds, Stroke stroke) { if (shape == null) { return; } if (stroke == null) { stroke = graphics.getStroke(); } shape = stroke.createStrokedShape(shape); fillPaintedShape(graphics, shape, paint, paintBounds); } /** * Converts color components from the sRGB to the CIE XYZ color space. * A D50 white point is assumed for the sRGB conversion. If the xyz * array is {@code null}, a new one will be created with the same * size as the rgb array. * * See http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html * * @param rgb Color components in the sRGB color space. * @param xyz Optional array to store color components in the CIE XYZ color space. * @return Color components in the CIE XYZ color space. */ public static double[] rgb2xyz(double[] rgb, double[] xyz) { if (xyz == null) { xyz = new double[rgb.length]; } // Remove sRGB companding to make RGB components linear double[] rgbLin = new double[rgb.length]; for (int i = 0; i < rgb.length; i++) { if (rgb[i] <= 0.04045) { rgbLin[i] = rgb[i]/12.92; } else { rgbLin[i] = Math.pow((rgb[i] + 0.055)/1.055, 2.4); } } // Convert linear sRGB with D50 white point to CIE XYZ for (int i = 0; i < xyz.length; i++) { xyz[i] = MATRIX_SRGB2XYZ_D50[i*3 + 0]*rgbLin[0] + MATRIX_SRGB2XYZ_D50[i*3 + 1]*rgbLin[1] + MATRIX_SRGB2XYZ_D50[i*3 + 2]*rgbLin[2]; } return xyz; } /** * Convert color components from the CIE L*u*v* to the CIE XYZ color space. * If the xyz array is {@code null}, a new one will be created * with the same size as the luv array. * * See http://www.brucelindbloom.com/index.html?Eqn_Luv_to_XYZ.html * * @param luv Color components in the CIE L*u*v* color space * @param xyz Optional array to store color components in the CIE XYZ color * space. * @return Color components in the CIE XYZ color space. */ public static double[] luv2xyz(double[] luv, double[] xyz) { if (xyz == null) { xyz = new double[luv.length]; } if (luv[0] > CIE_KAPPA*CIE_EPSILON) { xyz[1] = (luv[0] + 16.0)/116.0; xyz[1] = xyz[1]*xyz[1]*xyz[1]; } else { xyz[1] = luv[0]/CIE_KAPPA; } double a = (luv[0] != 0.0 || luv[1] != 0.0) ? ((52.0*luv[0])/(luv[1] + 13.0*luv[0]*XYZ_R_D50_U0) - 1.0)/3.0 : 0.0; double b = -5*xyz[1]; double c = -1.0/3.0; double d = (luv[0] != 0.0 || luv[2] != 0.0) ? xyz[1]*((39.0*luv[0])/(luv[2] + 13.0*luv[0]*XYZ_R_D50_V0) - 5.0) : 0.0; xyz[0] = !MathUtils.almostEqual(a, c, 1e-15) ? (d - b)/(a - c) : 0.0; xyz[2] = xyz[0]*a + b; return xyz; } /** * Converts color components from the sRGB to the CIE XYZ color space. * A D50 white point is assumed for the sRGB conversion. If the rgb * array is {@code null}, a new one will be created with the same * size as the xyz array. * * See http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html * * @param xyz Color components in the CIE XYZ color space. * @param rgb Optional array for storing color components in the sRGB color * space. * @return Color components in the sRGB color space. */ public static double[] xyz2rgb(double[] xyz, double[] rgb) { if (rgb == null) { rgb = new double[xyz.length]; } // XYZ to linear sRGB with D50 white point for (int i = 0; i < xyz.length; i++) { rgb[i] = MATRIX_XYZ2SRGB_D50[i*3 + 0]*xyz[0] + MATRIX_XYZ2SRGB_D50[i*3 + 1]*xyz[1] + MATRIX_XYZ2SRGB_D50[i*3 + 2]*xyz[2]; } // Apply sRGB companding for (int i = 0; i < rgb.length; i++) { if (rgb[i] <= 0.0031308) { rgb[i] = 12.92*rgb[i]; } else { rgb[i] = 1.055*Math.pow(rgb[i], 1.0/2.4) - 0.055; } } return rgb; } /** * Converts color components from the CIE XYZ to the CIE L*u*v* color * space. If the luv array is {@code null}, a new one will be * created with the same size as the xyz array. * * http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Luv.html * * @param xyz Color components in the CIE XYZ color space. * @param luv Optional array for storing color components in the CIE L*u*v* * color space. * @return Color components in the CIE L*u*v* color space. */ public static double[] xyz2luv(double[] xyz, double[] luv) { double tmp = xyz[0] + 15.0*xyz[1] + 3.0*xyz[2]; if (tmp == 0.0) { tmp = 1.0; } double u1 = 4.0*xyz[0]/tmp; double v1 = 9.0*xyz[1]/tmp; // Relative luminance double yr = xyz[1]/XYZ_R_D50[1]; double ur = 4.0*XYZ_R_D50[0]/(XYZ_R_D50[0] + 15.0*XYZ_R_D50[1] + 3.0*XYZ_R_D50[2]); double vr = 9.0*XYZ_R_D50[1]/(XYZ_R_D50[0] + 15.0*XYZ_R_D50[1] + 3.0*XYZ_R_D50[2]); // Mapping relative luminance to lightness if (luv == null) { luv = new double[xyz.length]; } if (yr > CIE_EPSILON) { luv[0] = 116.0*Math.pow(yr, 1.0/3.0) - 16.0; } else { luv[0] = CIE_KAPPA*yr; } luv[1] = 13.0*luv[0]*(u1 - ur); luv[2] = 13.0*luv[0]*(v1 - vr); return luv; } /** * Converts color components from the CIE L*u*v* to the sRGB color space. * A D50 white point is assumed for the sRGB conversion. If the luv * array is {@code null}, a new one will be created with the same * size as the rgb array. * * @param rgb Color components in the sRGB color space. * @param luv Optional array for storing color components in the CIE L*u*v* * color space. * @return Color components in the CIE L*u*v* color space. */ public static double[] rgb2luv(double[] rgb, double[] luv) { double[] xyz = rgb2xyz(rgb, null); return xyz2luv(xyz, luv); } /** * Converts color components from the CIE L*u*v* to the sRGB color space. * A D50 white point is assumed for the sRGB conversion. If the rgb * array is {@code null}, a new one will be created with the same size * as the luv array. * * @param luv Color components in the CIE L*u*v* color space. * @param rgb Optional array for storing color components in the sRGB color * space. * @return Color components in sRGB color space. */ public static double[] luv2rgb(double[] luv, double[] rgb) { double[] xyz = luv2xyz(luv, null); return xyz2rgb(xyz, rgb); } /** * Linearly blends two colors with a defined weight. * @param color1 First color. * @param color2 Second color. * @param weight Weighting factor in the range 0 to 1 (0 means color1, 1 means second color) * @return New blended color */ public static Color blend(Color color1, Color color2, double weight) { double w2 = MathUtils.limit(weight, 0.0, 1.0); double w1 = 1.0 - w2; int r = (int) Math.round(w1*color1.getRed() + w2*color2.getRed()); int g = (int) Math.round(w1*color1.getGreen() + w2*color2.getGreen()); int b = (int) Math.round(w1*color1.getBlue() + w2*color2.getBlue()); int a = (int) Math.round(w1*color1.getAlpha() + w2*color2.getAlpha()); return new Color(r, g, b, a); } /** * Creates a new color with the same color components but a different * alpha value. * @param color Original color. * @param alpha Alpha value for new color. * @return New color with specified alpha value. */ public static Color deriveWithAlpha(Color color, int alpha) { return new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha); } /** * Creates a new darker version of a color by blending it with black. The * derived color has the same alpha value as the original color. * @param color Original color. * @return Darker color with same alpha value. */ public static Color deriveDarker(Color color) { return deriveWithAlpha(blend(color, Color.BLACK, 0.5), color.getAlpha()); } /** * Creates a new brighter version of a color by blending it with white. The * derived color has the same alpha value as the original color. * @param color Original color. * @return Brighter color with same alpha value. */ public static Color deriveBrighter(Color color) { return deriveWithAlpha(blend(color, Color.WHITE, 0.5), color.getAlpha()); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/HaltonSequence.java000066400000000000000000000044261267060725100274320ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.io.Serializable; import java.util.Iterator; /** * Class that calculates the values of the Halton sequence. */ public class HaltonSequence implements Iterator, Serializable { /** Version id for serialization. */ private static final long serialVersionUID = 7466395251522942013L; /** Base. */ private final int base; /** Current count. */ private long c; /** * Creates a new HaltonSequence object to the base of two. */ public HaltonSequence() { this(2); } /** * Creates a new instance with the specified base. * @param base Base value. */ public HaltonSequence(int base) { this.base = base; } /** * Returns whether the iteration has more elements. This means it returns * {@code true} if {@code next} would return an element rather * than throwing an exception. * @return {@code true} if the iterator has more elements. */ public boolean hasNext() { return true; } /** * Returns the next element in the iteration. * @return the next element in the iteration. */ public Double next() { long i, digit; double h, step; if (++c == Long.MAX_VALUE) { c = 0; } i = c; h = 0.0; step = 1.0 / base; while (i > 0) { digit = i % base; h += digit * step; i = (i - digit) / base; step /= base; } return h; } /** * Stub method to fulfill {@code Iterator} interface. */ public void remove() { } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/MathUtils.java000066400000000000000000000305251267060725100264250ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.util.List; import java.util.Random; /** * Abstract class that provides utility functions which are useful for * mathematical calculations. */ public abstract class MathUtils { /** Instance for random values. */ private static final Random RANDOM = new Random(); /** * Default constructor that prevents creation of class. */ private MathUtils() { throw new UnsupportedOperationException(); } /** * Check whether two floating point values match with a given precision. * @param a First value * @param b Second value * @param delta Precision * @return {@code true} if the difference of a and b is * smaller or equal than delta, otherwise {@code false} */ public static boolean almostEqual(double a, double b, double delta) { return Math.abs(a - b) <= delta; } /** * Mathematically rounds a number with a defined precision. * @param a Value * @param precision Precision * @return Rounded value */ public static double round(double a, double precision) { if (precision == 0.0) { return 0.0; } return Math.round(a/precision) * precision; } /** * Returns a rounded number smaller than {@code a} with a defined * precision. * @param a Value * @param precision Precision * @return Rounded value */ public static double floor(double a, double precision) { if (precision == 0.0) { return 0.0; } return Math.floor(a/precision) * precision; } /** * Returns a rounded number larger than {@code a} with a defined * precision. * @param a Value * @param precision Precision * @return Rounded value */ public static double ceil(double a, double precision) { if (precision == 0.0) { return 0.0; } return Math.ceil(a/precision) * precision; } /** * Perform a binary search on a sorted array {@code a} to find the * element with the nearest element to {@code key}. * @param a Array with ascending values * @param key Pivot value * @return Index of the array element whose value is nearly or exactly * {@code key} */ public static int binarySearch(double[] a, double key) { int l = 0; int h = a.length - 1; int i; do { i = (int)(((long)l + (long)h) / 2L); if (key > a[i]) { l = i + 1; } else if (key < a[i]) { h = i - 1; } else { return i; } } while (l <= h); return i; } /** * Perform a binary search on a sorted array {@code a} to find the * element with the smallest distance to {@code key}. The returned * element's value is always less than or equal to {@code key}. * @param a Array with ascending values * @param key Pivot value * @return Index of the array element whose value is less than or equal to * {@code key} */ public static int binarySearchFloor(double[] a, double key) { if (a.length == 0) { return -1; } int i = binarySearch(a, key); if (i >= 0 && a[i] > key) { i--; } return i; } /** * Perform a binary search on a sorted array {@code a} to find the * element with the smallest distance to {@code key}. The returned * element's value is always greater than or equal to {@code key}. * @param a Array with ascending values * @param key Pivot value * @return Index of the array element whose value is greater than or equal * to {@code key} */ public static int binarySearchCeil(double[] a, double key) { if (a.length == 0) { return -1; } int i = binarySearch(a, key); if (i >= 0 && a[i] < key) { i++; } return i; } /** * Clamps a number object to specified limits: if {@code value} is * greater than {@code max} then {@code max} will be returned. * If {@code value} is greater than {@code min} then * {@code min} will be returned. * @param Numeric data type * @param value Double value to be clamped * @param min Minimum * @param max Maximum * @return Clamped value */ public static T limit(T value, T min, T max) { if (value.doubleValue() > max.doubleValue()) { return max; } if (value.doubleValue() < min.doubleValue()) { return min; } return value; } /** * Clamps a double number to specified limits: if {@code value} is * greater than {@code max} then {@code max} will be returned. * If {@code value} is greater than {@code min} then * {@code min} will be returned. * @param value Double value to be clamped * @param min Minimum * @param max Maximum * @return Clamped value */ public static double limit(double value, double min, double max) { if (value > max) { return max; } if (value < min) { return min; } return value; } /** * Clamps a float number to specified limits: if {@code value} is * greater than {@code max} then {@code max} will be returned. * If {@code value} is greater than {@code min} then * {@code min} will be returned. * @param value Float value to be clamped * @param min Minimum * @param max Maximum * @return Clamped value */ public static float limit(float value, float min, float max) { if (value > max) { return max; } if (value < min) { return min; } return value; } /** * Clamps a integer number to specified limits: if {@code value} is * greater than {@code max} then {@code max} will be returned. * If {@code value} is greater than {@code min} then * {@code min} will be returned. * @param value Integer value to be clamped * @param min Minimum * @param max Maximum * @return Clamped value */ public static int limit(int value, int min, int max) { if (value > max) { return max; } if (value < min) { return min; } return value; } /** *

Perform a randomized search on an unsorted array {@code a} to * find the ith smallest element. The array contents are be modified * during the operation!

*

See Cormen et al. (2001): Introduction to Algorithms. 2nd edition. * p. 186

* @param Data type of the array * @param a Unsorted array * @param lower Starting index * @param upper End index * @param i Smallness rank of value to search * @return Index of the element that is the ith smallest in array * a */ public static > int randomizedSelect(List a, int lower, int upper, int i) { if (a.isEmpty()) { return -1; } if (lower == upper) { return lower; } int q = randomizedPartition(a, lower, upper); int k = q - lower + 1; if (i == k) { return q; } else if (i < k) { return randomizedSelect(a, lower, q - 1, i); } else { return randomizedSelect(a, q + 1, upper, i - k); } } /** * Rearranges an array in two partitions using random sampling. * The array is permuted so that the elements of the lower partition * are always smaller than those of the upper partition. * @param Data type of the array * @param a Unsorted array * @param lower Starting index * @param upper End index * @return Pivot point of the partitioned array * @see "Cormen et al. (2001): Introduction to Algorithms. 2nd Edition, page 154" */ private static > int randomizedPartition( List a, int lower, int upper) { int i = lower + RANDOM.nextInt(upper - lower + 1); exchange(a, upper, i); return partition(a, lower, upper); } /** * Performs QuickSort partitioning: Rearranges an array in two partitions. * The array is permuted so that the elements of the lower partition are * always smaller than those of the upper partition. * @param Data type of the array * @param a Unsorted array * @param lower Starting index * @param upper End index * @return Pivot point of the partitioned array * @see "Cormen et al. (2001): Introduction to Algorithms. 2nd Edition, page 146" */ private static > int partition( List a, int lower, int upper) { T x = a.get(upper); int i = lower - 1; for (int j = lower; j < upper; j++) { if (a.get(j).compareTo(x) <= 0) { i++; exchange(a, i, j); } } exchange(a, i + 1, upper); return i + 1; } /** * Swaps two elements at indexes {@code i1} and {@code i2} of an * array in-place. * @param Data type of the array * @param a Array * @param i1 First element index * @param i2 Second element index */ private static void exchange(List a, int i1, int i2) { T tmp = a.get(i2); a.set(i2, a.get(i1)); a.set(i1, tmp); } /** *

Returns the magnitude of the specified number. Example for magnitude * base 10:

* * * * * * *
-0.05 -0.01
0.05 0.01
3.14 1.00
54.32 10.00
123.45100.00
* @param base Base. * @param n Number. * @return Magnitude. */ public static double magnitude(double base, double n) { double logN = Math.log(Math.abs(n))/Math.log(base); return Math.signum(n) * Math.pow(base, Math.floor(logN)); } /** *

Utility method used to calculate arbitrary quantiles from a sorted * list of values. Currently only one method is implemented: the default * method that is used by R (method 7). The list must be sorted.

*

For more information see:

* * @param values Data values. * @param q Quantile in range [0, 1] * @return Quantile value */ public static double quantile(List values, double q) { // R type 7 parameters double a = 1.0, b = -1.0, c = 0.0, d = 1.0; // Number of samples int n = values.size(); double x = a + (n + b) * q - 1.0; double xInt = (int) x; double xFrac = x - xInt; if (xInt < 0) { return values.get(0); } else if (xInt >= n) { return values.get(n - 1); } int i = (int) xInt; if (xFrac == 0) { return values.get(i); } return values.get(i) + (values.get(i + 1) - values.get(i))*(c + d*xFrac); } /** * Returns whether a specified {@code java.lang.Number} object can be * used for calculations. {@code null} values, {@code NaN} values * or infinite values are considered as non-calculatable. * @param n Number object. * @return whether {@code n} can be used for calculations. */ public static boolean isCalculatable(Number n) { return (n != null) && isCalculatable(n.doubleValue()); } /** * Returns whether a specified double can be used for calculations. * {@code NaN} values or infinite values are considered * non-calculatable. * @param n double value * @return whether {@code n} can be used for calculations. */ public static boolean isCalculatable(double n) { return !Double.isNaN(n) && !Double.isInfinite(n); } /** * Converts an angle in degrees so that it lies between 0.0 and 360.0. * @param angle Arbitrary angle in degrees. * @return Angle between 0.0 and 360.0. */ public static double normalizeDegrees(double angle) { while (angle < 0.0) { angle += 360.0; } return angle%360.0; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/Messages.java000066400000000000000000000035621267060725100262630ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.util.MissingResourceException; import java.util.ResourceBundle; /** * Singleton class that globally provides translated message texts. */ public abstract class Messages { /** Name of resource bundle that contains message texts. */ private static final String BUNDLE_NAME = "messages"; //$NON-NLS-1$ /** Resource bundle that contains message texts. */ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle .getBundle(BUNDLE_NAME); /** * Private constructor. */ private Messages() { } /** * Returns a message text that is determined by the specified key. * A replacement text generated from the key is returned if the message * cannot be found. * @param key Key string that identifies the message * @return Translated message text, or default key if the message cannot * be found. */ public static String getString(String key) { try { return RESOURCE_BUNDLE.getString(key); } catch (MissingResourceException e) { return '!' + key + '!'; } } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/PointND.java000066400000000000000000000103271267060725100260240ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.awt.geom.Point2D; import java.io.Serializable; import java.text.MessageFormat; import java.util.Arrays; /** * Class for storing n-dimensional points. * @param Data type of the coordinates. */ public class PointND implements Serializable { /** Version id for serialization. */ private static final long serialVersionUID = 3552680202450906771L; /** Constant for accessing x-coordinate. */ public static final int X = 0; /** Constant for accessing y-coordinate. */ public static final int Y = 1; /** Constant for accessing z-coordinate. */ public static final int Z = 2; /** Coordinates along the axes that describe this point. */ private final T[] coordinates; /** * Constructor that initializes the point with a list of coordinates. * @param coordinates Coordinate values. */ public PointND(T... coordinates) { this.coordinates = Arrays.copyOf(coordinates, coordinates.length); } /** * Returns the number of dimensions. * @return Number of dimensions. */ public int getDimensions() { return coordinates.length; } /** * Returns the value of a specified dimension. * @param dimension Dimension. * @return Coordinate value. */ public T get(int dimension) { return coordinates[dimension]; } /** * Sets the value of a specified dimension. * @param dimension Dimension. * @param coordinate New coordinate value. */ public void set(int dimension, T coordinate) { coordinates[dimension] = coordinate; } /** * Sets all coordinate values at once. * @param coordinates Coordinate values. */ public void setLocation(T... coordinates) { if (getDimensions() != coordinates.length) { throw new IllegalArgumentException(MessageFormat.format( "Wrong number of dimensions: Expected {0,number,integer} values, got {1,number,integer}.", //$NON-NLS-1$ getDimensions(), coordinates.length)); } System.arraycopy(coordinates, 0, this.coordinates, 0, getDimensions()); } /** * Creates a two-dimensional point from the specified dimensions. * @param dimX Dimension for x coordinate. * @param dimY Dimension for y coordinate. * @return Two-dimensional point. */ public Point2D getPoint2D(int dimX, int dimY) { if (getDimensions() < 2) { throw new ArrayIndexOutOfBoundsException( "Can't create two-dimensional point from " + //$NON-NLS-1$ getDimensions() + "D data."); //$NON-NLS-1$ } return new Point2D.Double( get(dimX).doubleValue(), get(dimY).doubleValue()); } /** * Creates a two-dimensional point from dimensions 0 and 1. * @return Two-dimensional point. */ public Point2D getPoint2D() { return getPoint2D(X, Y); } @Override public String toString() { return getClass().getName() + Arrays.deepToString(coordinates); } @Override public boolean equals(Object obj) { if (!(obj instanceof PointND)) { return false; } PointND p = (PointND) obj; if (getDimensions() != p.getDimensions()) { return false; } for (int dim = 0; dim < coordinates.length; dim++) { Number dimA = get(dim); Number dimB = p.get(dim); if (dimA != null && dimB != null) { if (!dimA.equals(dimB)) { return false; } } else if (dimA != dimB) { return false; } } return true; } @Override public int hashCode() { int hashCode = 0; for (T coordinate : coordinates) { hashCode ^= coordinate.hashCode(); } return hashCode; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/SerializableArea.java000066400000000000000000000032451267060725100277110ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.awt.geom.Area; /** * A wrapper for creating serializable objects from instances of * {@link java.awt.geom.Area}. */ public class SerializableArea implements SerializationWrapper { /** Version id for serialization. */ private static final long serialVersionUID = -2861579645195882742L; /** Serialized instance. */ private final SerializableShape shape; /** * Initializes a new wrapper with an {@code Area} instance. * @param area Wrapped object. */ public SerializableArea(Area area) { shape = new SerializableShape(area); } /** * Creates a new instance of the wrapped class using the data from the * wrapper. This is used for deserialization. * @return An instance containing the data from the wrapper. */ public Area unwrap() { return new Area(shape.unwrap()); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/SerializableBasicStroke.java000066400000000000000000000042171267060725100312520ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.awt.BasicStroke; /** * A wrapper for creating serializable objects from instances of * {@link java.awt.BasicStroke}. */ public class SerializableBasicStroke implements SerializationWrapper { /** Version id for serialization. */ private static final long serialVersionUID = -9087891720495398485L; /** Line width. */ private final float width; /** End cap. */ private final int cap; /** Line join mode. */ private final int join; /** Miter limit. */ private final float miterlimit; /** Dash array. */ private final float[] dash; /** Dash phase. */ private final float dash_phase; /** * Initializes a new wrapper with a {@code BasicStroke} instance. * @param stroke Wrapped object. */ public SerializableBasicStroke(BasicStroke stroke) { width = stroke.getLineWidth(); cap = stroke.getEndCap(); join = stroke.getLineJoin(); miterlimit = stroke.getMiterLimit(); dash = stroke.getDashArray(); dash_phase = stroke.getDashPhase(); } /** * Creates a new stroke instance of the wrapped class using the data from * the wrapper. This is used for deserialization. * @return A stroke instance containing the data from the wrapper. */ public BasicStroke unwrap() { return new BasicStroke(width, cap, join, miterlimit, dash, dash_phase); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/SerializablePoint2D.java000066400000000000000000000040171267060725100303160ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.awt.geom.Point2D; /** * A wrapper for creating serializable objects from instances of * {@link java.awt.geom.Point2D.Double} and {@link java.awt.geom.Point2D.Float}. */ public class SerializablePoint2D implements SerializationWrapper { /** Version id for serialization. */ private static final long serialVersionUID = -8849270838795846599L; /** x coordinate. */ private final double x; /** y coordinate. */ private final double y; /** Flag to determine whether the class was of type Point2D.Double or Point2D.Float. */ private final boolean isDouble; /** * Initializes a new wrapper with a {@code Point2D} instance. * @param point Wrapped object. */ public SerializablePoint2D(Point2D point) { x = point.getX(); y = point.getY(); isDouble = point instanceof Point2D.Double; } /** * Creates a new point instance of the wrapped class using the data from * the wrapper. This is used for deserialization. * @return A point instance containing the data from the wrapper. */ public Point2D unwrap() { if (isDouble) { return new Point2D.Double(x, y); } else { return new Point2D.Float((float) x, (float) y); } } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/SerializableShape.java000066400000000000000000000037701267060725100301040ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.awt.Shape; import java.awt.geom.Path2D; import java.util.List; import de.erichseifert.gral.util.GeometryUtils.PathSegment; /** * A wrapper for creating serializable objects from instances of * {@link java.awt.Shape} (e.g. {@link java.awt.geom.Path2D}). */ public class SerializableShape implements SerializationWrapper { /** Version id for serialization. */ private static final long serialVersionUID = -8849270838795846599L; /** Shape segments. */ private final List segments; /** Flag to determine whether the class was of type Path2D.Double or Path2D.Float. */ private final boolean isDouble; /** * Initializes a new wrapper with a {@code Shape} instance. * @param shape Wrapped object. */ public SerializableShape(Shape shape) { segments = GeometryUtils.getSegments(shape); isDouble = !(shape instanceof Path2D.Float); } /** * Creates a new instance of the wrapped class using the data from the * wrapper. This is used for deserialization. * @return An instance containing the data from the wrapper. */ public Shape unwrap() { return GeometryUtils.getShape(segments, isDouble); } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/SerializationUtils.java000066400000000000000000000054021267060725100303450ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.awt.BasicStroke; import java.awt.Shape; import java.awt.geom.Area; import java.awt.geom.Point2D; import java.io.Serializable; /** * An abstract class containing utility functions for serialization. */ public abstract class SerializationUtils { /** * Default constructor that prevents creation of class. */ private SerializationUtils() { throw new UnsupportedOperationException(); } /** * Makes sure an object is serializable, otherwise a serializable wrapper * will be returned. * @param o Object to be serialized. * @return A serializable object, or a serializable wrapper. */ public static Serializable wrap(Object o) { if (o == null || o instanceof Serializable) { return (Serializable) o; } // See Java bug 4305099: // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4305099 if (o instanceof BasicStroke) { BasicStroke stroke = (BasicStroke) o; return new SerializableBasicStroke(stroke); } // See Java bug 4263142 until Java 1.6: // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4263142 if ((o instanceof Point2D.Double) || (o instanceof Point2D.Float)) { Point2D point = (Point2D) o; return new SerializablePoint2D(point); } if (o instanceof Area) { Area area = (Area) o; return new SerializableArea(area); } if (o instanceof Shape) { Shape shape = (Shape) o; return new SerializableShape(shape); } throw new IllegalArgumentException(String.format( "Failed to make value of type %s serializable.", o.getClass().getName() )); } /** * Makes sure a regular object is returned, wrappers for serialization will * be removed. * @param o Deserialized object. * @return A regular (unwrapped) object. */ public static Object unwrap(Serializable o) { if (o instanceof SerializationWrapper) { SerializationWrapper wrapper = (SerializationWrapper) o; return wrapper.unwrap(); } return o; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/SerializationWrapper.java000066400000000000000000000025241267060725100306670ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.io.Serializable; /** * Interface for classes used for wrapping non-serializable classes. * The wrapper can be unwrapped for deserialization. * * @param Class that the wrapper can handle. */ public interface SerializationWrapper extends Serializable { /** * Creates a new instance of the wrapped class using the data from the * wrapper. This can be used for deserialization. * @return A new instance of the wrapped class {@code T}. */ T unwrap(); } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/SortedList.java000066400000000000000000000052521267060725100266060ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.util.AbstractList; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; /** * Resizable implementation of the {@code List} interface that automatically * sorts all values. It implements the methods {@code get}, {@code size}, * {@code add}, and {@code size}. The stored elements must implement the * interface {@code Comparable}. * @param Data type of stored elements. */ public class SortedList> extends AbstractList { private final List elements; /** * Constructs an empty list with the specified initial capacity. * @param initialCapacity Initial capacity of the list. */ public SortedList(int initialCapacity) { elements = new ArrayList(initialCapacity); } /** * Constructs a list containing the elements of the specified collection. * @param c Collection whose elements are to be added. */ public SortedList(Collection c) { this(c.size()); for (T e : c) { add(e); } } /** * Constructs an empty list with an initial capacity of ten. */ public SortedList() { this(10); } @Override public T get(int index) { return elements.get(index); } @Override public int size() { return elements.size(); } @Override public boolean add(T e) { if (elements.isEmpty()) { elements.add(e); return true; } int index = Collections.binarySearch(elements, e); if (index < 0) { index = -index - 1; } elements.add(index, e); return true; } @Override public T remove(int index) { return elements.remove(index); } @Override @SuppressWarnings("unchecked") public int indexOf(Object o) { try { return Collections.binarySearch(elements, (T) o); } catch (NullPointerException e) { return -1; } catch (ClassCastException e) { return -1; } } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/StatefulTokenizer.java000066400000000000000000000231161267060725100301730ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * A tokenizing parser that can analyzes a string using different sets of * regular expression based parsing rules and produces a list of tokens. * * The class is intended to be sub-classed to implement new grammars. * Different sets of rules can be defined with the method * {@link #putRules(String, Rule[])}, e.g. for string processing. Each rule * in a set produces one token with a type name and it can switch to another * state or switch back to the previous state with the special state * {@code "#pop"}. The is a list of tokens with arbitrary type. * * The list of produced tokens can be filtered: tokens of same type can be * joined by adding the type with {@link #addJoinedType(Object)} and tokens can * be omitted from the result for easier post-processing by adding with * {@link #addIgnoredType(Object)}. */ public abstract class StatefulTokenizer { /** The name of the initial state. */ protected static final String INITIAL_STATE = ""; /** Token types that should be joined when adjacent tokens are found. */ private final Set joinedTypes; /** Token types that shouldn't be added to the output. */ private final Set ignoredTypes; /** Rules for specific states. */ private final Map grammar; /** * A token that designates a certain section of a text input. The absolute * position within the input stream as well as the relevant text are stored * for later processing. */ public static class Token { /** Absolute position where the token started in the input stream. */ private final int start; /** Absolute position where the token ended in the input stream. */ private int end; /** Type of the token as defined by the corresponding rule. */ private final Object type; /** The relevant content from the input stream. Its lengths can differ from length of the token. */ private final StringBuilder content; /** * Initializes a new token with absolute start and end position, a type * and text content. * @param start Absolute position where the token started in the input stream. * @param end Absolute position where the token ended in the input stream. * @param type Type of the token as defined by the corresponding rule. * @param content The relevant text content from the input stream. */ public Token(int start, int end, Object type, String content) { this.content = new StringBuilder(); this.start = start; this.end = end; this.type = type; this.content.append(content); } /** * Joins two tokens by appending the contents of another token to this * token. * @param t Another token that should be appended to this token */ public void append(Token t) { content.append(t.content); end = t.end; } /** * Returns the absolute position where the token starts in the input * stream. * @return Absolute position in the input stream. */ public int getStart() { return start; } /** * Returns the absolute position where the token ends in the input * stream. * @return Absolute position in the input stream. */ public int getEnd() { return end; } /** * Returns the type of the token. * @return Type of the token */ public Object getType() { return type; } /** * Returns the content of the token. * @return Content of the token */ public String getContent() { return content.toString(); } @Override public String toString() { return String.format("%s[start=%d, end=%d, type=%s, content=\"%s\"]", getClass().getSimpleName(), getStart(), getEnd(), getType(), getContent()); } } /** * A regular expression based rule for building a parsing grammar. * It stores a regular expression pattern for matching input data, a type * for tokens generated by this rule, and an optional name of a grammar * state that should be activated. * * The method {@link #getToken(String,int)} can be used to process input * data: If the rule matches a token is returned, otherwise {@code null} * will be returned. */ protected static class Rule { /** Compiled regular expression for analyzing the input stream. */ private final Pattern pattern; /** Type of the tokens generated by this rule. */ private final Object tokenType; /** The grammar state that be used next to analyze the input data if the rule matched. */ private final String nextState; /** * Initializes a new instance with the specified regular expression * pattern, a type for generated tokens, and a name of a grammar state * that should be triggered. * @param pattern A regular expression pattern string. * @param tokenType The type for the tokens generated by this rule. * @param nextState The grammar state that should be used next to * analyze the input data if the rule matched. */ public Rule(String pattern, Object tokenType, String nextState) { this.pattern = Pattern.compile(pattern); this.tokenType = tokenType; this.nextState = nextState; } /** * Initializes a new instance with the specified regular expression * pattern, a type for generated tokens. * @param pattern A regular expression pattern string. * @param tokenType The type for the tokens generated by this rule. */ public Rule(String pattern, Object tokenType) { this(pattern, tokenType, null); } /** * Analyzes the specified input data starting at the given position * and returns a token with the defined type, the content matched by * the regular expression if the rule matches. If the rule doesn't * match {@code null} will be returned. * @param data Input data. * @param pos Position to start looking for a match. * @return A token with information about the matched section of the * input data, or {@code null} if the rule didn't match. */ public Token getToken(String data, int pos) { Matcher m = pattern.matcher(data); m.region(pos, data.length()); if (!m.lookingAt()) { return null; } String content = (m.groupCount() > 0) ? m.group(1) : m.group(); Token token = new Token(m.start(), m.end(), tokenType, content); return token; } } /** * Initializes the internal data structures of a new instance. */ protected StatefulTokenizer() { joinedTypes = new HashSet(); ignoredTypes = new HashSet(); grammar = new HashMap(); } /** * Adds a token type to the set of tokens that should get joined in the * tokenizer output. * @param tokenType Type of the tokens that should be joined. */ protected void addJoinedType(Object tokenType) { joinedTypes.add(tokenType); } /** * Adds a token type to the set of tokens that should be ignored in the * tokenizer output. * @param tokenType Type of the tokens that should be ignored. */ protected void addIgnoredType(Object tokenType) { ignoredTypes.add(tokenType); } /** * Sets the rules for the initial state in the grammar. * @param rules A sequence or an array with rules to be added. */ protected void putRules(Rule... rules) { putRules(INITIAL_STATE, rules); } /** * Sets the rules for the specified state in the grammar. * @param name A unique name to identify the rule set. * @param rules A sequence or an array with rules to be added. */ protected void putRules(String name, Rule... rules) { grammar.put(name, rules); } /** * Analyzes the specified input string using different sets of rules and * returns a list of token objects describing the content structure. * @param data Input string. * @return List of tokens. */ public List tokenize(String data) { LinkedList tokens = new LinkedList(); Stack states = new Stack(); states.push(INITIAL_STATE); int pos = 0; Token tokenCur = null; while (pos < data.length() && !states.isEmpty()) { String state = states.peek(); Rule[] rules = grammar.get(state); for (Rule rule : rules) { Token token = rule.getToken(data, pos); if (token == null) { continue; } if (tokenCur != null && tokenCur.type.equals(token.type) && joinedTypes.contains(tokenCur.type)) { tokenCur.append(token); } else { if (tokenCur != null && !ignoredTypes.contains(tokenCur.type)) { tokens.add(tokenCur); } tokenCur = token; } pos = token.end; if ("#pop".equals(rule.nextState)) { states.pop(); } else if (rule.nextState != null) { states.push(rule.nextState); } break; } } if (tokenCur != null && !ignoredTypes.contains(tokenCur.type)) { tokens.add(tokenCur); } return tokens; } } gral-0.11/gral-core/src/main/java/de/erichseifert/gral/util/package-info.java000077500000000000000000000016541267060725100270430ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Common utility classes. */ package de.erichseifert.gral.util; gral-0.11/gral-core/src/main/resources/000077500000000000000000000000001267060725100177665ustar00rootroot00000000000000gral-0.11/gral-core/src/main/resources/datareaders.properties000066400000000000000000000023441267060725100243660ustar00rootroot00000000000000# # GRAL: GRAphing Library for Java(R) # # (C) Copyright 2009-2015 Erich Seifert , # Michael Seifert # # This file is part of GRAL. # # GRAL is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # GRAL is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with GRAL. If not, see . # text/csv=de.erichseifert.gral.io.data.CSVReader text/tab-separated-values=de.erichseifert.gral.io.data.CSVReader image/bmp=de.erichseifert.gral.io.data.ImageReader image/gif=de.erichseifert.gral.io.data.ImageReader image/jpeg=de.erichseifert.gral.io.data.ImageReader image/png=de.erichseifert.gral.io.data.ImageReader image/vnd.wap.wbmp=de.erichseifert.gral.io.data.ImageReader audio/wav=de.erichseifert.gral.io.data.AudioReadergral-0.11/gral-core/src/main/resources/datawriters.properties000066400000000000000000000022611267060725100244360ustar00rootroot00000000000000# # GRAL: GRAphing Library for Java(R) # # (C) Copyright 2009-2015 Erich Seifert , # Michael Seifert # # This file is part of GRAL. # # GRAL is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # GRAL is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with GRAL. If not, see . # text/csv=de.erichseifert.gral.io.data.CSVWriter text/tab-separated-values=de.erichseifert.gral.io.data.CSVWriter image/bmp=de.erichseifert.gral.io.data.ImageWriter image/gif=de.erichseifert.gral.io.data.ImageWriter image/jpeg=de.erichseifert.gral.io.data.ImageWriter image/png=de.erichseifert.gral.io.data.ImageWriter image/vnd.wap.wbmp=de.erichseifert.gral.io.data.ImageWritergral-0.11/gral-core/src/main/resources/drawablewriters.properties000066400000000000000000000024001267060725100253010ustar00rootroot00000000000000# # GRAL: GRAphing Library for Java(R) # # (C) Copyright 2009-2015 Erich Seifert , # Michael Seifert # # This file is part of GRAL. # # GRAL is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # GRAL is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with GRAL. If not, see . # image/bmp=de.erichseifert.gral.io.plots.BitmapWriter image/gif=de.erichseifert.gral.io.plots.BitmapWriter image/jpeg=de.erichseifert.gral.io.plots.BitmapWriter image/png=de.erichseifert.gral.io.plots.BitmapWriter image/vnd.wap.wbmp=de.erichseifert.gral.io.plots.BitmapWriter application/pdf=de.erichseifert.gral.io.plots.VectorWriter application/postscript=de.erichseifert.gral.io.plots.VectorWriter image/svg+xml=de.erichseifert.gral.io.plots.VectorWritergral-0.11/gral-core/src/main/resources/messages.properties000066400000000000000000000036071267060725100237210ustar00rootroot00000000000000# # GRAL: GRAphing Library for Java(R) # # (C) Copyright 2009-2015 Erich Seifert , # Michael Seifert # # This file is part of GRAL. # # GRAL is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # GRAL is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with GRAL. If not, see . # DataIO.wavDescription=RIFF WAVE DataIO.csvDescription=Comma separated values DataIO.tsvDescription=Tab separated values ImageIO.bmpDescription=Windows Bitmap ImageIO.gifDescription=Graphics Interchange Format ImageIO.jpegDescription=JPEG File Interchange Format ImageIO.pngDescription=Portable Network Graphics ImageIO.wbmpDescription=Wireless Application Protocol Bitmap ImageIO.epsDescription=Encapsulated PostScript ImageIO.pdfDescription=Portable Document Format ImageIO.svgDescription=Scalable Vector Graphics IO.formatDescription={0}: {1} ExportDialog.abort=Cancel ExportDialog.confirm=OK ExportDialog.exportOptionsTitle=Export options ExportDialog.height=Height ExportDialog.left=Left ExportDialog.top=Top ExportDialog.width=Width InteractivePanel.exportExistsWarning=The selected file already exists.\nWould you like to overwrite it? InteractivePanel.exportImage=Export image... InteractivePanel.exportImageTitle=Export image InteractivePanel.print=Print... InteractivePanel.resetView=Reset view InteractivePanel.warning=Warning InteractivePanel.zoomIn=Zoom in InteractivePanel.zoomOut=Zoom out gral-0.11/gral-core/src/main/resources/messages_de.properties000066400000000000000000000036671267060725100243770ustar00rootroot00000000000000# # GRAL: GRAphing Library for Java(R) # # (C) Copyright 2009-2015 Erich Seifert , # Michael Seifert # # This file is part of GRAL. # # GRAL is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # GRAL is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with GRAL. If not, see . # DataIO.wavDescription=RIFF WAVE DataIO.csvDescription=Komma-getrennte Werte DataIO.tsvDescription=Tab-getrennte Werte ImageIO.bmpDescription=Windows Bitmap ImageIO.gifDescription=Graphics Interchange Format ImageIO.jpegDescription=JPEG File Interchange Format ImageIO.pngDescription=Portable Network Graphics ImageIO.wbmpDescription=Wireless Application Protocol Bitmap ImageIO.epsDescription=Encapsulated PostScript ImageIO.pdfDescription=Portable Document Format ImageIO.svgDescription=Scalable Vector Graphics IO.formatDescription={0}: {1} ExportDialog.abort=Abbrechen ExportDialog.confirm=OK ExportDialog.exportOptionsTitle=Export-Einstellungen ExportDialog.height=H�he ExportDialog.left=Links ExportDialog.top=Oben ExportDialog.width=Breite InteractivePanel.exportExistsWarning=Die angegebene Datei existiert bereits.\nWollen Sie sie �berschreiben? InteractivePanel.exportImage=Bild exportieren... InteractivePanel.exportImageTitle=Bild exportieren InteractivePanel.print=Drucken... InteractivePanel.resetView=Ansicht zur�cksetzen InteractivePanel.warning=Warnung InteractivePanel.zoomIn=Vergr��ern InteractivePanel.zoomOut=Verkleinern gral-0.11/gral-core/src/rst/000077500000000000000000000000001267060725100156405ustar00rootroot00000000000000gral-0.11/gral-core/src/rst/documentation_en.rst000066400000000000000000000703201267060725100217270ustar00rootroot00000000000000Data administration =================== The first step, before we are able to plot anything, is to load or create data, a process which GRAL provides several ways for. The basic interface that will be used when you have to provide data is ``DataSource``. Think of it as a table with a (theoretically) arbitrary number of rows and columns. Every column has its own data type, but only ``Comparable`` values are allowed. The functions a ``DataSource`` provides are solely for retrieving data rows, but it also supports statistics on the contained data, as well as the capability to listen for data changes. The following sections describe the different ways for providing and manipulating data. Creating data ------------- Assuming you have computed some values you want to plot, how can you store your data in a ``DataSource``? You can do so through the class ``DataTable``. ``DataTable`` is an implementation of ``DataSource`` (or ``AbstractDataSource`` to be more precise) and supports operations like adding and removing rows. The values you must match the number of columns and their types, which both had already been specified in the constructor. .. code:: java // Create the table with the specified column types DataTable table = new DataTable(Double.class, Double.class); // Iterate your available data. In this case, an Iterable or Double[][] for (Double[] coords : data) { double x = coords[0]; double y = coords[1]; table.add(x, y); } You might want to have a ``DataTable`` for testing purposes only and do not want to create random values for it at each start. In this case, the class ``DummyData`` is your remedy. ``DummyData`` is a ``DataSource`` filled with a single value. As I already mentioned, this is not used very often, but suited very well for testing due to its efficiency, especially when dealing with large tables. .. code:: java DummyData data = new DummyData(3, 100, 42.0); Sorting data ------------ Often, data has to be reordered, e.g. for filtering. The sorting criteria in GRAL can be handled very flexible: for example the rows of a data source could be rearranged so that the first column is sorted ascending and as a second criterion the second column is sorted descending when values of the first column are equal. GRAL uses two classes to define the sorting options: ``Ascending`` and ``Descending``. In order to create one of them you must pass the index of the column that should be sorted to the constructor. .. code:: java // Sort the primary column (1) ascending, // the secondary column (0) descending, and // the ternary column (2) ascending table.sort(new Ascending(1), new Descending(0), new Ascending(2)); Filtering data -------------- ``DataTables`` are not the only data source for plots. A plot also accepts filtered data. In GRAL data can be filtered either by columns or by rows. Filtering columns ~~~~~~~~~~~~~~~~~ The main tasks for filtering by columns are to create subsets (*series*) of columns and to reorder columns for certain plot types. Using the class ``DataSeries`` a data source with four columns *A, B, C, D* could be divided into two series: one containing columns *A, B* and one containing columns *C, D*. The series could also overlap, for example the first series could contain the columns *A, B* and the second the columns *B, C*. Furthermore, data series can be used to reorder columns. It is possible to map columns *A, B, C, D* to *D, B, C, A* or just *D, C*. A ``DataSeries`` is created using at least two parameters: the original data source and a number of columns, which will appear in the order they are passed. Optionally a name can be passed as first argument. In Plots this name is used for example to display captions in the plot legend. .. code:: java // Create a new series from columns 0 and 1 DataSeries series1 = new DataSeries("Series 1", table, 0, 1); // Create a new series from columns 2 and 0 DataSeries series2 = new DataSeries("Series 2", table, 2, 0); // Create a new series from column 1 DataSeries series3 = new DataSeries("Series 3", table, 1); Filtering rows ~~~~~~~~~~~~~~ Another way of filtering is to filter data sources by rows. This way a data subset which matches certain criteria can be extracted. For example, this could be used to form clusters which could then be plotted or processed separately. In order to use the ``DataSubset`` a new class has to be created which implements the method ``accept(Row)``. This method is used to decide whether a certain row should be kept in the subset. .. code:: java // Keep only rows where the first column has an even value RowSubset data = new RowSubset(table) { @Override public boolean accept(Row row) { Number n = (Number) row.get(0); return (n.doubleValue() % 2.0) == 0.0; } }; Processing data --------------- An integral part of GRAL's pipeline is preprocessing of data. The simplest case would be to extract several statistics per column such as minimum, maximum, arithmetic mean, or median. But GRAL also covers more complex cases such as generating histograms or convolution filtering of data. The latter can be used to smooth or sharpen data in various ways. Statistics ~~~~~~~~~~ The most basic statistical functionality of GRAL is to query various aggregated measures for columns using the class Statistics. It is part of every ``DataSource`` instance and can be easily accessed with the method ``getStatistics(int)``. .. code:: java // Get the maximum for the second column double max = table.getColumn(1).getStatistics(Statistics.MAX); ``N`` The number of values in the column. ``SUM`` The sum of all column values. ``MIN`` The smallest value of the column. ``MAX`` The largest value of the column. ``MEAN`` The arithmetic mean describing the average value of the column. ``MEAN_DEVIATION`` The mean deviation describing the dispersion of the column's values. ``MEDIAN`` The median value which divides the column values in two equal halves. ``VARIANCE`` The variance value describing the dispersion of the column's values. ``SKEWNESS`` The skewness value describing the asymmetry of the probability distribution of the column's values. ``KURTOSIS`` The kurtosis value describing the "peakedness" of the probability distribution of the column's values. ``QUARTILE_1`` The value that delimits the lower 25% of all data values. ``QUARTILE_2`` The value that delimits 50% of all data values. This is the same as the median value. ``QUARTILE_3`` The value that delimits the upper 25% of all data values. Histograms are a more complex way for aggregating data. In a histogram all values are assigned to specified categories. In GRAL's ``Histogram`` class categories are defined as value ranges. For example all values from 0 to 5 would be in category A and all values from 5 to 10 in category B. Then, the histogram would generate two rows for each column that contain the number of values in category A and B, respectively. .. code:: java // Use 4 equally spaced breaks Histogram histogram = new Histogram1D(table, Orientation.VERTICAL, 4); .. code:: java // Use custom breaks for each column Number[] breaksCol1 = {1.0, 2.0, 3.0, 4.0, 5.0}; Number[] breaksCol2 = {1.0, 3.0, 5.0, 7.0, 9.0}; Histogram histogram = new Histogram1D(table, Orientation.VERTICAL, breaksCol1, breaksCol2); Convolution ~~~~~~~~~~~ Often, it is necessary to change existing data by smoothing it, so that noise or fine-scale structures are reduced. Another frequent use case is to boost or extract exactly those fine-scale structures. Both cases can be handled in GRAL using the convolution operation. Mathematically, convolution is the combination of two functions: the data function and a kernel function. By varying th kernel function various operations can be achieved: smoothing (low-pass filter), deriving (high-pass filter), sharpening, moving average, and much more. Besides the class ``DataSource`` GRAL provides two additional classes for convolution: the class ``Kernel`` defines the kernel function and the class ``Convolution`` is responsible for processing the data source. The ``Convolution`` instance can finally be used as a data source for plots. .. code:: java // Create a moving average of width 3 Kernel kernel = new Kernel(1.0, 1.0, 1.0).normalize(); // Filter columns 0 and 1 and omit boundary values if necessary Convolution filter = new Convolution(table, kernel, Filter.Mode.OMIT, 0, 1); .. code:: java // Create a smoothing kernel with a variance of 2 Kernel kernel = KernelUtils.getBinomial(2.0).normalize(); // Filter column 1 and start over for boundary values if necessary Convolution filter = new Convolution(table, kernel, Filter.Mode.CIRCULAR, 1); .. code:: java // Create a smoothing kernel with a variance of 3 Kernel kernel = KernelUtils.getBinomial(3.0).normalize() // Subtract the original values kernel = kernel.negate().add(new Kernel(1.0)); // Filter column 1 and repeat boundary values if necessary Convolution filter = new Convolution(table, kernel, Filter.Mode.REPEAT, 1); Exchanging data --------------- GRAL allows you to interchange data values through its extensible plug-in system. Arbitrary sources and sinks can be accessed, like plain files, databases, or even web services. The current version of GRAL already supports file formats like simple CSV files (*Comma-Separated Values*). Importing ~~~~~~~~~ Loading data from a source in GRAL needs two steps: First, you have to get a ``DataReader`` the desired file format via its MIME type from an instance of ``DataReaderFactory``. Then, you have to call the method read of the reader with two (or more) parameters: an ``InputStream`` instance to read from and the column data types. The method finally reads the data and returns a new ``DataSource`` containing all values that have been extracted from the source. .. code:: java DataReader reader = DataReaderFactory.getInstance().get("text/csv"); InputStream file = new FileInputStream("foobar.csv"); DataSource data = reader.read(file, Integer.class, Double.class, Double.class); .. code:: java DataReader reader = DataReaderFactory.getInstance().get("image/png"); reader.setSetting("factor", 1.0/255.0); reader.setSetting("offset", 1); InputStream file = new FileInputStream("foobar.png"); DataSource data = reader.read(file); Exporting ~~~~~~~~~ Saving data in GRAL is even easier than loading. First, you need to get an instance of ``DataWriterFactory`` and then you fetch a ``DataWriter`` for the desired file format via its MIME type. Then, you have to call the method ``write`` with two parameters: a ``DataSource`` and an ``OutputStream`` instance to write to. .. code:: java DataWriter writer = DataWriterFactory.getInstance().get("text/csv"); FileOutputStream file = new FileOutputStream("foobar.csv"); writer.write(table, file); .. code:: java DataWriter writer = DataWriterFactory.getInstance().get("image/png"); writer.setSetting("factor", 255); writer.setSetting("offset", -255); FileOutputStream file = new FileOutputStream("foobar.png"); writer.write(table, file); Displaying data =============== The main purpose of GRAL is to plot diagrams. It offers several types of plots which can be customized and exported for publishing. In this chapter you will find an overview of plot types and their options for customization as well as examples how to export the plotted graphics in various formats. The components of a plot in GRAL are: - Each plot has one or more instances of ``DataSource`` - The area where the actual data is plotted is called plot area and the class used to display the area is ``PlotArea2D``, correspondingly. - Depending on its type a plot can have an arbitrary number of axes which are created with the class Axis. Each Axis is displayed by an instance of ``AxisRenderer``. - Data points on the plot area are rendered by an instance of ``PointRenderer``. - Connections between data points are rendered by an instance of ``LineRenderer`` - In order to fill the area below data points an instance of ``AreaRenderer`` is used. Plot types ---------- Currently, GRAL has three main plot types: xy-plot, bar plot, and pie plot. This section presents those plot types and show how to adjust their visual settings and to derive many more types. For example, xy-plots can be turned into line plots, or area plots and a pie chart can be made into a doughnut plot with just one command. XY-Plot ~~~~~~~ ``XYPlot``: XY-Plots are usually the most common plot type. Used it whenever you want to create a line plot, a scatter plot, a bubble plot, or an area plot. .. code:: java Plot plot = new XYPlot(series1, series2); Legends ^^^^^^^ Legends explain the symbols used in plot by the symbols and a description in a table-like representation. GRAL's ``Legend`` class can be either vertically (default) or horizontally oriented. Its options determine the positioning inside the plot as well as its background color, its border, or its spacings. .. code:: java plot.setLegendVisible(true); Bar plot ~~~~~~~~ Usually, bar plots are used to show rectangular bars with lengths proportional to their corresponding values. GRAL provides a ``BarPlot`` class which is in fact a special case of an xy-plot. .. code:: java Plot plot = new BarPlot(series); Box-and-whisker plot ~~~~~~~~~~~~~~~~~~~~ Box-and-whisker, or short box plots, are used to display the statistics like minimum, maximum, median, or quantiles in a concise plot. GRAL's class ``BoxPlot`` is used to create this type of plot. .. code:: java Plot plot = new BoxPlot(series); The data series must provide six columns for each plot element: - x position of the box-whisker-plot - y position of the center bar (e.g. median) - y position of the lower whisker (e.g. minimum) - upper edge of the box (e.g. first quartile) - lower edge of the box (e.g. third quartile) - y position of the upper whisker (e.g. maximum) A utility method of ``BoxPlot`` can be used to generate a suitable data source from an existing data source: .. code:: java DataSource series = BoxPlot.createBoxData(data); Plot plot = new BoxPlot(series); Pie plot ~~~~~~~~ Pie plots are circles divided into sectors to illustrate the proportions of the corresponding data values. GRAL's class ``PiePlot`` is used to create this type of plot. .. code:: java Plot plot = new PiePlot(series); Raster plot ~~~~~~~~~~~ Raster plots are used to display a two-dimensional grid with filled grid tiles. GRAL's class ``RasterPlot`` is used to create this type of plot. .. code:: java Plot plot = new RasterPlot(series); The data series must provide three columns for each grid tile: - x position of the grid tile - y position of the grid tile - value of the grid tile A utility method of ``RasterPlot`` can be used to generate a suitable data source from an existing data source: .. code:: java DataSource series = RasterPlot.createBoxData(data); Plot plot = new RasterPlot(series); Customization ------------- The visual appearance of most classes in GRAL can be queried and changed using the ``get`` and ``set`` methods for each property. This way, properties like colors, borders, margins, or positions can be easily customized. Customizing the plot ~~~~~~~~~~~~~~~~~~~~ Plots provide the canvas for painting all plot components (see section "Plotting"). It controls how the background will be drawn the way the components are positioned. Another important setting is the plot title. The following example shows how to set the title of an xy-plot. .. code:: java Plot plot = new XYPlot(data); plot.getTitle().setText("My First XY Plot"); In the next example you can see how a background gradient can be assigned to the whole plot. .. code:: java Plot plot = new PiePlot(data); Paint gradient = new LinearGradientPaint( 0f,0f, // Coordinates of gradient start point 1f,0f, // Coordinates of gradient end point new float[] {0f, 1f}, // Relative fractions new Color[] {Color.GRAY, Color.WHITE} // Gradient colors ); plot.setBackground(gradient); The ``PlotArea2D`` is the container for plotting the data. It must be fetched from a plot with the method, ``getPlotArea`` as each ``Plot`` type can also have its own plot area type. In the following example you can see how to hide the plot area itself completely. .. code:: java PlotArea2D plotArea = plot.getPlotArea(); plotArea.setBackground(null); plotArea.setBorder(null); Often, a legend has to added to a plot. Every plot already has a ``Legend`` which just has to be turned on explicitly. Then, the positioning, orientation, spacing, as well as the legend background can be changed. The following example shows how to add a horizontal legend to the the bottom left corner of a plot. .. code:: java plot.setLegendVisible(true); plot.setLegendLocation(Location.SOUTH_WEST); Legend legend = plot.getLegend(); legend.setOrientation(Orientation.HORIZONTAL); Customizing axes ~~~~~~~~~~~~~~~~ Axes of a plot have reasonable defaults for displaying. Sometimes however, it's necessary to add an axis title, adjust the spacing of the tick marks, or change the formatting of the data values along an axis. All those properties are controlled by the interface ``AxisRenderer``. Each axis in a plot has its own instance and can have different settings. .. code:: java AxisRenderer axisRendererX = plot.getAxisRenderer(XYPlot.AXIS_X); axisRendererX.setTickSpacing(5.0); There are to implementations of ``AxisRenderer``: for axes with a linear scale (the default case) ``LinearRenderer2D`` is used; for axes with a logarithmic scale the class ``LogarithmicRenderer2D`` is used: .. code:: java XYPlot plot = new XYPlot(seriesLog, seriesLin); AxisRenderer2D axisRendererX = new LogarithmicRenderer2D(); axisRendererX.setLabel("Logarithmic data"); plot.setAxisRenderer(XYPlot.AXIS_X, axisRendererX); .. code:: java AxisRenderer2D axisRendererX = new LogarithmicRenderer2D(); Format dateFormat = DateFormat.getTimeInstance(); axisRendererX.setTickLabelFormat(dateFormat); .. code:: java Map labels = new HashMap(); labels.put(2.0, "Doubled"); labels.put(1.5, "One and a half times"); axisRendererX.setCustomTicks(labels); Customizing points ~~~~~~~~~~~~~~~~~~ The display of data points in a plot is done by instances of ``PointRenderer``. A point renderer defines the shape, the color, the size, and even the position of each point. A custom renderer can be implemented using either the interface ``PointRenderer`` itself or using the abstract class ``AbstractPointRenderer`` which is the preferred way. Every point renderer has to implement two methods: ``Shape getPointShape(PointData)`` returns the vector shape of a specified data point, and ``Drawable getPoint(PointData, Shape)`` returns a drawable component which then renders the points. The class ``AbstractPointRenderer`` implements the interface ``PointRenderer`` and additionally it provides everything that's necessary to manage settings and draw basic elements. In the following example you can see how to implement a simple renderer. .. code:: java public class SimplePointRenderer extends DefaultPointRenderer2D { @Override public Drawable getPoint(final PointData data, final Shape shape) { Drawable drawable = new AbstractDrawable() { @Override public void draw(DrawingContext context) { Paint paint = SimplePointRenderer.this.getColor(); Shape point = getPointShape(data); // Put your custom code here ... GraphicsUtils.fillPaintedShape(context.getGraphics(), point, paint, null); } }; return drawable; } } Customizing lines ~~~~~~~~~~~~~~~~~ Data points can be connected using lines. To draw these lines instances of ``LineRenderer`` are used. A line renderer has full control over the line's shape, the stroke patterns, and the colors which will be used when drawing. Custom renderers can be easily implemented using either the interface ``LineRenderer`` itself or using the abstract class ``AbstractLineRenderer2D`` which is the preferred way for two-dimensional applications. Every line renderer has to implement two methods: ``Shape getLineShape(List)`` returns a vector shape for the line, and ``Drawable getLine(List, Shape)`` returns a drawable component to display the line. The class ``AbstractLineRenderer2D`` implements the interface ``LineRenderer`` for two-dimensional data and additionally provides everything that's necessary to manage settings and draw basic elements. In the following example you can see how to implement a simple renderer. .. code:: java public class SimpleLineRenderer2D extends AbstractLineRenderer2D { @Override public Shape getLineShape(final List points) { Path2D line = new Path2D.Double(); for (DataPoint point : points) { Point2D pos = point.position.getPoint2D(); if (line.getCurrentPoint() == null) { line.moveTo(pos.getX(), pos.getY()); } else { line.lineTo(pos.getX(), pos.getY()); } } Shape lineShape = punch(line, points); return lineShape; } @Override public Drawable getLine(final List points, final Shape shape) { Drawable d = new AbstractDrawable() { @Override public void draw(DrawingContext context) { Paint paint = SimpleLineRenderer2D.this.getColor(); GraphicsUtils.fillPaintedShape(context.getGraphics(), shape, paint, null); } }; return d; } } Customizing areas ~~~~~~~~~~~~~~~~~ In order to display filled or hatched areas in plots so called area renderers are used. They all derive from the interface ``AreaRenderer`` and they control the colors, the fillings, and also the shape of the rendered area. Custom renderers can be easily implemented using either the interface ``AreaRenderer`` itself or using the abstract class ``AbstractAreaRenderer`` which is the preferred way. Every area renderer has to implement one method: ``Shape getAreaShape(List)`` returns a vector shape for the area, and ``Drawable getArea(List, Shape)`` returns a drawable component to display the area. The class ``AbstractAreaRenderer`` implements the interface ``AreaRenderer`` and additionally it provides everything that's necessary to manage settings and draw basic elements. In the following example you can see how to implement a simple renderer. .. code:: java public class SimpleAreaRenderer extends AbstractAreaRenderer { @Override public Drawable getArea(final List points, final Shape shape) { Shape path = getAreaShape(points); final Shape area = punch(path, points); return new AbstractDrawable() { @Override public void draw(DrawingContext context) { Paint paint = SimpleAreaRenderer.this.getColor(); GraphicsUtils.fillPaintedShape(context.getGraphics(), area, paint, area.getBounds2D()); } }; } public Shape getAreaShape(final List points) { Shape shape = null; // Code to construct the shape return shape; } } Exporting plot images ~~~~~~~~~~~~~~~~~~~~~ Usage similar to data import/export. Bitmap formats like PNG, JPEG, BMP, or GIF and vector formats like SVG, PDF, or EPS. .. code:: java XYPlot plot = new XYPlot(data); DrawableWriter writer = DrawableWriterFactory.getInstance().get("image/svg+xml"); FileOutputStream file = new FileOutputStream("xyplot.svg"); double width = 320.0, height = 240.0; writer.write(plot, file, width, height); Extending GRAL ============== GRAL can be extended in numerous ways to better suit your needs. For example, you can write your own plot types, line types, axes, or data exchange plug-ins. The following chapter shows you how to use GRAL's application programming interface to tailor it for your requirements. Writing a new plot type ----------------------- ``Plot`` class, ``DataListener`` interface. .. code:: java public class MyPlot extends Plot implements DataListener { private double mySetting; public MyPlot(DataSource data) { super(data); mySetting = 1.0; ... dataChanged(data); data.addDataListener(this); } @Override public void dataChanged(DataSource data) { ... } } Writing a data importer ----------------------- ``DataReaderFactory`` and ``DataReader``. .. code:: java public class MyReader extends IOCapabilitiesStorage implements DataReader { static { addCapabilities(new IOCapabilities( "My Format", "My custom file format", "application/x-myformat", "myf" )); } private final Map settings; private final Map defaults; private final String mimeType; public MyReader(String mimeType) { this.mimeType = mimeType; settings = new HashMap(); defaults = new HashMap(); defaults.put("my setting", "foobar"); } @Override public DataSource read(InputStream input, Class... types) throws IOException, ParseException; ... } /** * Returns the MIME type. * @return MIME type string. */ public String getMimeType() { return mimeType; } @Override public T getSetting(String key) { if (!settings.containsKey(key)) { return (T) defaults.get(key); } return (T) settings.get(key); } @Override public void setSetting(String key, T value) { settings.put(key, value); } } Writing a data exporter ----------------------- ``DataWriterFactory`` and ``DataWriter``. .. code:: java public class MyWriter extends IOCapabilitiesStorage implements DataWriter { static { addCapabilities(new IOCapabilities( "My Format", "My custom file format", "application/x-myformat", "myf" )); } private final Map settings; private final Map defaults; private final String mimeType; public MyWriter(String mimeType) { this.mimeType = mimeType; settings = new HashMap(); defaults = new HashMap(); defaults.put("my setting", "foobar"); } @Override public void write(DataSource data, OutputStream output) throws IOException { ... } /** * Returns the MIME type. * @return MIME type string. */ public String getMimeType() { return mimeType; } @Override public T getSetting(String key) { if (!settings.containsKey(key)) { return (T) defaults.get(key); } return (T) settings.get(key); } @Override public void setSetting(String key, T value) { settings.put(key, value); } } Writing a plot exporter ----------------------- ``DrawableWriterFactory`` and ``DrawableWriter``. Either ``BitmapWriter`` or ``VectorWriter``. Limitations =========== Due to its early stage of development, GRAL still has several limitations: - At the moment it's not very fast for large data sets - The API isn't stable yet, and major changes can happen before version 1.0 - Despite we try our best to ensure code quality there can always be bugs gral-0.11/gral-core/src/test/000077500000000000000000000000001267060725100160075ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/000077500000000000000000000000001267060725100167305ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/000077500000000000000000000000001267060725100173205ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/000077500000000000000000000000001267060725100217745ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/000077500000000000000000000000001267060725100227215ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/AllTests.java000066400000000000000000000030041267060725100253140ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral; import org.junit.runner.RunWith; import org.junit.runners.Suite; import de.erichseifert.gral.data.DataTests; import de.erichseifert.gral.graphics.GraphicsTests; import de.erichseifert.gral.io.IoTests; import de.erichseifert.gral.navigation.NavigationTests; import de.erichseifert.gral.plots.PlotsTests; import de.erichseifert.gral.ui.UiTests; import de.erichseifert.gral.util.UtilTests; @RunWith(Suite.class) @Suite.SuiteClasses({ TestUtilsTest.class, UtilTests.class, DataTests.class, GraphicsTests.class, NavigationTests.class, PlotsTests.class, IoTests.class, UiTests.class }) public class AllTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/DummyJdbc.java000066400000000000000000001410451267060725100254470ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral; import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.MalformedURLException; import java.net.URL; import java.sql.Array; import java.sql.Blob; import java.sql.CallableStatement; import java.sql.Clob; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.Date; import java.sql.NClob; import java.sql.ParameterMetaData; import java.sql.PreparedStatement; import java.sql.Ref; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.RowId; import java.sql.SQLClientInfoException; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.SQLXML; import java.sql.Savepoint; import java.sql.Statement; import java.sql.Struct; import java.sql.Time; import java.sql.Timestamp; import java.sql.Types; import java.util.Calendar; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executor; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DummyData; public class DummyJdbc implements Connection { private final DataSource data; private boolean closed; public DummyJdbc(DataSource data) { this.data = data; this.closed = false; } public void clearWarnings() throws SQLException { throw new UnsupportedOperationException(); } public void close() throws SQLException { closed = true; } public void commit() throws SQLException { throw new UnsupportedOperationException(); } public Statement createStatement() throws SQLException { throw new UnsupportedOperationException(); } public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { throw new UnsupportedOperationException(); } public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { throw new UnsupportedOperationException(); } public boolean getAutoCommit() throws SQLException { throw new UnsupportedOperationException(); } public String getCatalog() throws SQLException { throw new UnsupportedOperationException(); } public int getHoldability() throws SQLException { throw new UnsupportedOperationException(); } public DatabaseMetaData getMetaData() throws SQLException { throw new UnsupportedOperationException(); } public int getTransactionIsolation() throws SQLException { throw new UnsupportedOperationException(); } public Map> getTypeMap() throws SQLException { throw new UnsupportedOperationException(); } public SQLWarning getWarnings() throws SQLException { throw new UnsupportedOperationException(); } public boolean isClosed() throws SQLException { return closed; } public boolean isReadOnly() throws SQLException { throw new UnsupportedOperationException(); } public String nativeSQL(String sql) throws SQLException { throw new UnsupportedOperationException(); } public CallableStatement prepareCall(String sql) throws SQLException { throw new UnsupportedOperationException(); } public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { throw new UnsupportedOperationException(); } public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { throw new UnsupportedOperationException(); } public PreparedStatement prepareStatement(String sql) throws SQLException { return new DummyPreparedStatement(this, data); } public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { return new DummyPreparedStatement(this, data); } public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { return new DummyPreparedStatement(this, data); } public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { return new DummyPreparedStatement(this, data); } public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { return prepareStatement(sql, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT); } public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { if (sql.toUpperCase().startsWith("SELECT COUNT(*) FROM ")) { return new DummyPreparedStatement(this, new DummyData(1, 1, data.getRowCount())); } return new DummyPreparedStatement(this, data); } public void releaseSavepoint(Savepoint savepoint) throws SQLException { throw new UnsupportedOperationException(); } public void rollback() throws SQLException { throw new UnsupportedOperationException(); } public void rollback(Savepoint savepoint) throws SQLException { throw new UnsupportedOperationException(); } public void setAutoCommit(boolean autoCommit) throws SQLException { throw new UnsupportedOperationException(); } public void setCatalog(String catalog) throws SQLException { throw new UnsupportedOperationException(); } public void setHoldability(int holdability) throws SQLException { throw new UnsupportedOperationException(); } public void setReadOnly(boolean readOnly) throws SQLException { throw new UnsupportedOperationException(); } public Savepoint setSavepoint() throws SQLException { throw new UnsupportedOperationException(); } public Savepoint setSavepoint(String name) throws SQLException { throw new UnsupportedOperationException(); } public void setTransactionIsolation(int level) throws SQLException { throw new UnsupportedOperationException(); } public void setTypeMap(Map> map) throws SQLException { throw new UnsupportedOperationException(); } public boolean isWrapperFor(Class iface) throws SQLException { throw new UnsupportedOperationException(); } public T unwrap(Class iface) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public Array createArrayOf(String typeName, Object[] elements) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public Blob createBlob() throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public Clob createClob() throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public NClob createNClob() throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public SQLXML createSQLXML() throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public Struct createStruct(String typeName, Object[] attributes) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public Properties getClientInfo() throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public String getClientInfo(String name) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public boolean isValid(int timeout) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setClientInfo(Properties properties) throws SQLClientInfoException { throw new UnsupportedOperationException(); } // Java 1.6 public void setClientInfo(String name, String value) throws SQLClientInfoException { throw new UnsupportedOperationException(); } // Java 1.7 public void abort(Executor executor) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.7 public int getNetworkTimeout() throws SQLException { throw new UnsupportedOperationException(); } // Java 1.7 public String getSchema() throws SQLException { throw new UnsupportedOperationException(); } // Java 1.7 public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.7 public void setSchema(String schema) throws SQLException { throw new UnsupportedOperationException(); } } class DummyResultSet implements ResultSet { private final DataSource data; private int rowIndex = -1; private boolean closed; public DummyResultSet(DataSource data) { this.data = data; } public boolean absolute(int row) throws SQLException { rowIndex = row - 1; return !isBeforeFirst() && !isAfterLast(); } public void afterLast() throws SQLException { rowIndex = data.getRowCount(); } public void beforeFirst() throws SQLException { rowIndex = -1; } public void cancelRowUpdates() throws SQLException { throw new UnsupportedOperationException(); } public void clearWarnings() throws SQLException { throw new UnsupportedOperationException(); } public void close() throws SQLException { closed = true; } public void deleteRow() throws SQLException { throw new UnsupportedOperationException(); } public int findColumn(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public boolean first() throws SQLException { rowIndex = 0; return !isBeforeFirst() && !isAfterLast(); } public Array getArray(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Array getArray(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public BigDecimal getBigDecimal(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public BigDecimal getBigDecimal(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { throw new UnsupportedOperationException(); } public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException { throw new UnsupportedOperationException(); } public Blob getBlob(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Blob getBlob(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public boolean getBoolean(int columnIndex) throws SQLException { return (Boolean) data.get(columnIndex - 1, rowIndex); } public boolean getBoolean(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public byte getByte(int columnIndex) throws SQLException { return ((Number) data.get(columnIndex - 1, rowIndex)).byteValue(); } public byte getByte(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public byte[] getBytes(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public byte[] getBytes(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Clob getClob(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Clob getClob(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public int getConcurrency() throws SQLException { throw new UnsupportedOperationException(); } public String getCursorName() throws SQLException { throw new UnsupportedOperationException(); } public Date getDate(int columnIndex) throws SQLException { return (Date) data.get(columnIndex - 1, rowIndex); } public Date getDate(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Date getDate(int columnIndex, Calendar cal) throws SQLException { // TODO Use calendar return (Date) data.get(columnIndex - 1, rowIndex); } public Date getDate(String columnLabel, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public double getDouble(int columnIndex) throws SQLException { return ((Number) data.get(columnIndex - 1, rowIndex)).doubleValue(); } public double getDouble(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public int getFetchDirection() throws SQLException { throw new UnsupportedOperationException(); } public int getFetchSize() throws SQLException { throw new UnsupportedOperationException(); } public float getFloat(int columnIndex) throws SQLException { return ((Number) data.get(columnIndex - 1, rowIndex)).floatValue(); } public float getFloat(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public int getInt(int columnIndex) throws SQLException { return ((Number) data.get(columnIndex - 1, rowIndex)).intValue(); } public int getInt(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public long getLong(int columnIndex) throws SQLException { return ((Number) data.get(columnIndex - 1, rowIndex)).longValue(); } public long getLong(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public ResultSetMetaData getMetaData() throws SQLException { throw new UnsupportedOperationException(); } public Object getObject(int columnIndex) throws SQLException { return data.get(columnIndex - 1, rowIndex); } public Object getObject(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Object getObject(int columnIndex, Map> map) throws SQLException { throw new UnsupportedOperationException(); } public Object getObject(String columnLabel, Map> map) throws SQLException { throw new UnsupportedOperationException(); } public Ref getRef(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public Ref getRef(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public int getRow() throws SQLException { throw new UnsupportedOperationException(); } public short getShort(int columnIndex) throws SQLException { return ((Number) data.get(columnIndex - 1, rowIndex)).shortValue(); } public short getShort(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Statement getStatement() throws SQLException { throw new UnsupportedOperationException(); } public String getString(int columnIndex) throws SQLException { return String.valueOf(data.get(columnIndex - 1, rowIndex)); } public String getString(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Time getTime(int columnIndex) throws SQLException { return (Time) data.get(columnIndex - 1, rowIndex); } public Time getTime(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Time getTime(int columnIndex, Calendar cal) throws SQLException { // TODO Use calendar return (Time) data.get(columnIndex - 1, rowIndex); } public Time getTime(String columnLabel, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public Timestamp getTimestamp(int columnIndex) throws SQLException { return (Timestamp) data.get(columnIndex - 1, rowIndex); } public Timestamp getTimestamp(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { // TODO Use calendar return (Timestamp) data.get(columnIndex - 1, rowIndex); } public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public int getType() throws SQLException { throw new UnsupportedOperationException(); } public URL getURL(int columnIndex) throws SQLException { Object obj = getObject(columnIndex); if (obj == null) { return null; } try { return new URL(obj.toString()); } catch (MalformedURLException e) { throw new SQLException(e); } } public URL getURL(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public InputStream getUnicodeStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public InputStream getUnicodeStream(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public SQLWarning getWarnings() throws SQLException { throw new UnsupportedOperationException(); } public void insertRow() throws SQLException { throw new UnsupportedOperationException(); } public boolean isAfterLast() throws SQLException { return rowIndex >= data.getRowCount(); } public boolean isBeforeFirst() throws SQLException { return rowIndex < 0; } public boolean isFirst() throws SQLException { return rowIndex == 0; } public boolean isLast() throws SQLException { return rowIndex == data.getRowCount() - 1; } public boolean last() throws SQLException { rowIndex = data.getRowCount() - 1; return rowIndex >= 0 && rowIndex < data.getRowCount(); } public void moveToCurrentRow() throws SQLException { throw new UnsupportedOperationException(); } public void moveToInsertRow() throws SQLException { throw new UnsupportedOperationException(); } public boolean next() throws SQLException { rowIndex++; if (rowIndex > data.getRowCount()) { rowIndex = data.getRowCount(); } return !isBeforeFirst() && !isAfterLast(); } public boolean previous() throws SQLException { rowIndex--; if (rowIndex < 0) { rowIndex = -1; } return !isBeforeFirst() && !isAfterLast(); } public void refreshRow() throws SQLException { throw new UnsupportedOperationException(); } public boolean relative(int rows) throws SQLException { throw new UnsupportedOperationException(); } public boolean rowDeleted() throws SQLException { throw new UnsupportedOperationException(); } public boolean rowInserted() throws SQLException { throw new UnsupportedOperationException(); } public boolean rowUpdated() throws SQLException { throw new UnsupportedOperationException(); } public void setFetchDirection(int direction) throws SQLException { throw new UnsupportedOperationException(); } public void setFetchSize(int rows) throws SQLException { throw new UnsupportedOperationException(); } public void updateArray(int columnIndex, Array x) throws SQLException { throw new UnsupportedOperationException(); } public void updateArray(String columnLabel, Array x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob(int columnIndex, Blob x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob(String columnLabel, Blob x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateBoolean(int columnIndex, boolean x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBoolean(String columnLabel, boolean x) throws SQLException { throw new UnsupportedOperationException(); } public void updateByte(int columnIndex, byte x) throws SQLException { throw new UnsupportedOperationException(); } public void updateByte(String columnLabel, byte x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBytes(int columnIndex, byte[] x) throws SQLException { throw new UnsupportedOperationException(); } public void updateBytes(String columnLabel, byte[] x) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob(int columnIndex, Clob x) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob(String columnLabel, Clob x) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob(int columnIndex, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob(String columnLabel, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob(int columnIndex, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateClob(String columnLabel, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void updateDate(int columnIndex, Date x) throws SQLException { throw new UnsupportedOperationException(); } public void updateDate(String columnLabel, Date x) throws SQLException { throw new UnsupportedOperationException(); } public void updateDouble(int columnIndex, double x) throws SQLException { throw new UnsupportedOperationException(); } public void updateDouble(String columnLabel, double x) throws SQLException { throw new UnsupportedOperationException(); } public void updateFloat(int columnIndex, float x) throws SQLException { throw new UnsupportedOperationException(); } public void updateFloat(String columnLabel, float x) throws SQLException { throw new UnsupportedOperationException(); } public void updateInt(int columnIndex, int x) throws SQLException { throw new UnsupportedOperationException(); } public void updateInt(String columnLabel, int x) throws SQLException { throw new UnsupportedOperationException(); } public void updateLong(int columnIndex, long x) throws SQLException { throw new UnsupportedOperationException(); } public void updateLong(String columnLabel, long x) throws SQLException { throw new UnsupportedOperationException(); } public void updateNull(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } public void updateNull(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } public void updateObject(int columnIndex, Object x) throws SQLException { throw new UnsupportedOperationException(); } public void updateObject(String columnLabel, Object x) throws SQLException { throw new UnsupportedOperationException(); } public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException { throw new UnsupportedOperationException(); } public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException { throw new UnsupportedOperationException(); } public void updateRef(int columnIndex, Ref x) throws SQLException { throw new UnsupportedOperationException(); } public void updateRef(String columnLabel, Ref x) throws SQLException { throw new UnsupportedOperationException(); } public void updateRow() throws SQLException { throw new UnsupportedOperationException(); } public void updateShort(int columnIndex, short x) throws SQLException { throw new UnsupportedOperationException(); } public void updateShort(String columnLabel, short x) throws SQLException { throw new UnsupportedOperationException(); } public void updateString(int columnIndex, String x) throws SQLException { throw new UnsupportedOperationException(); } public void updateString(String columnLabel, String x) throws SQLException { throw new UnsupportedOperationException(); } public void updateTime(int columnIndex, Time x) throws SQLException { throw new UnsupportedOperationException(); } public void updateTime(String columnLabel, Time x) throws SQLException { throw new UnsupportedOperationException(); } public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { throw new UnsupportedOperationException(); } public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException { throw new UnsupportedOperationException(); } public boolean wasNull() throws SQLException { throw new UnsupportedOperationException(); } public boolean isWrapperFor(Class iface) throws SQLException { throw new UnsupportedOperationException(); } public T unwrap(Class iface) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public InputStream getAsciiStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public InputStream getAsciiStream(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public InputStream getBinaryStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public InputStream getBinaryStream(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public Reader getCharacterStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public Reader getCharacterStream(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public int getHoldability() throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public Reader getNCharacterStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public Reader getNCharacterStream(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public NClob getNClob(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public NClob getNClob(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public String getNString(int columnIndex) throws SQLException { return getString(columnIndex); } // Java 1.6 public String getNString(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public RowId getRowId(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public RowId getRowId(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public SQLXML getSQLXML(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public SQLXML getSQLXML(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public boolean isClosed() throws SQLException { return closed; } // Java 1.6 public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { } // Java 1.6 public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateBinaryStream(String columnLabel, InputStream x, int length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateCharacterStream(int columnIndex, Reader x) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateCharacterStream(String columnLabel, Reader reader, int length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateNClob(int columnIndex, NClob nClob) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateNClob(String columnLabel, NClob nClob) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateNClob(int columnIndex, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateNClob(String columnLabel, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateNString(int columnIndex, String nString) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateNString(String columnLabel, String nString) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateRowId(int columnIndex, RowId x) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateRowId(String columnLabel, RowId x) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.7 public T getObject(int columnIndex, Class type) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.7 public T getObject(String columnLabel, Class type) throws SQLException { throw new UnsupportedOperationException(); } } class DummyResultSetMetaData implements ResultSetMetaData { private final DataSource data; public DummyResultSetMetaData(DataSource data) { this.data = data; } public String getCatalogName(int column) throws SQLException { throw new UnsupportedOperationException(); } public String getColumnClassName(int column) throws SQLException { throw new UnsupportedOperationException(); } public int getColumnCount() throws SQLException { return data.getColumnCount(); } public int getColumnDisplaySize(int column) throws SQLException { throw new UnsupportedOperationException(); } public String getColumnLabel(int column) throws SQLException { throw new UnsupportedOperationException(); } public String getColumnName(int column) throws SQLException { throw new UnsupportedOperationException(); } public int getColumnType(int column) throws SQLException { return getJdbcColumnType(column); } private int getJdbcColumnType(int column) { Class> javaType = data.getColumnTypes()[column - 1]; if (Byte.class.equals(javaType)) { return Types.TINYINT; } else if (Short.class.equals(javaType)) { return Types.SMALLINT; } else if (Integer.class.equals(javaType)) { return Types.INTEGER; } else if (Long.class.equals(javaType)) { return Types.BIGINT; } else if (Byte.class.equals(javaType)) { return Types.TINYINT; } else if (Float.class.equals(javaType)) { return Types.REAL; } else if (Double.class.equals(javaType)) { return Types.FLOAT; } else if (Date.class.equals(javaType)) { return Types.DATE; } else if (Time.class.equals(javaType)) { return Types.TIME; } else if (Timestamp.class.equals(javaType)) { return Types.TIMESTAMP; } else if (String.class.equals(javaType)) { return Types.VARCHAR; } throw new IllegalArgumentException(String.format("Unkown java data type: %s", javaType.getName())); } public String getColumnTypeName(int column) throws SQLException { throw new UnsupportedOperationException(); } public int getPrecision(int column) throws SQLException { throw new UnsupportedOperationException(); } public int getScale(int column) throws SQLException { throw new UnsupportedOperationException(); } public String getSchemaName(int column) throws SQLException { throw new UnsupportedOperationException(); } public String getTableName(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isAutoIncrement(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isCaseSensitive(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isCurrency(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isDefinitelyWritable(int column) throws SQLException { throw new UnsupportedOperationException(); } public int isNullable(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isReadOnly(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isSearchable(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isSigned(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isWritable(int column) throws SQLException { throw new UnsupportedOperationException(); } public boolean isWrapperFor(Class iface) throws SQLException { throw new UnsupportedOperationException(); } public T unwrap(Class iface) throws SQLException { throw new UnsupportedOperationException(); } } class DummyPreparedStatement implements PreparedStatement { private final Connection connection; private final DataSource data; public DummyPreparedStatement(Connection connection, DataSource data) { this.connection = connection; this.data = data; } public void addBatch() throws SQLException { throw new UnsupportedOperationException(); } public void clearParameters() throws SQLException { throw new UnsupportedOperationException(); } public boolean execute() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet executeQuery() throws SQLException { return new DummyResultSet(data); } public int executeUpdate() throws SQLException { throw new UnsupportedOperationException(); } public ResultSetMetaData getMetaData() throws SQLException { return new DummyResultSetMetaData(data); } public ParameterMetaData getParameterMetaData() throws SQLException { throw new UnsupportedOperationException(); } public void setArray(int parameterIndex, Array x) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { throw new UnsupportedOperationException(); } public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { throw new UnsupportedOperationException(); } public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { throw new UnsupportedOperationException(); } public void setBlob(int parameterIndex, Blob x) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { throw new UnsupportedOperationException(); } public void setBoolean(int parameterIndex, boolean x) throws SQLException { throw new UnsupportedOperationException(); } public void setByte(int parameterIndex, byte x) throws SQLException { throw new UnsupportedOperationException(); } public void setBytes(int parameterIndex, byte[] x) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void setClob(int parameterIndex, Clob x) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setClob(int parameterIndex, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } public void setDate(int parameterIndex, Date x) throws SQLException { throw new UnsupportedOperationException(); } public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public void setDouble(int parameterIndex, double x) throws SQLException { throw new UnsupportedOperationException(); } public void setFloat(int parameterIndex, float x) throws SQLException { throw new UnsupportedOperationException(); } public void setInt(int parameterIndex, int x) throws SQLException { throw new UnsupportedOperationException(); } public void setLong(int parameterIndex, long x) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setNClob(int parameterIndex, NClob value) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setNClob(int parameterIndex, Reader reader) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setNString(int parameterIndex, String value) throws SQLException { throw new UnsupportedOperationException(); } public void setNull(int parameterIndex, int sqlType) throws SQLException { throw new UnsupportedOperationException(); } public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { throw new UnsupportedOperationException(); } public void setObject(int parameterIndex, Object x) throws SQLException { throw new UnsupportedOperationException(); } public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { throw new UnsupportedOperationException(); } public void setRef(int parameterIndex, Ref x) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setRowId(int parameterIndex, RowId x) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.6 public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { throw new UnsupportedOperationException(); } public void setShort(int parameterIndex, short x) throws SQLException { throw new UnsupportedOperationException(); } public void setString(int parameterIndex, String x) throws SQLException { throw new UnsupportedOperationException(); } public void setTime(int parameterIndex, Time x) throws SQLException { throw new UnsupportedOperationException(); } public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { throw new UnsupportedOperationException(); } public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { throw new UnsupportedOperationException(); } public void setURL(int parameterIndex, URL x) throws SQLException { throw new UnsupportedOperationException(); } public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { throw new UnsupportedOperationException(); } public void addBatch(String sql) throws SQLException { throw new UnsupportedOperationException(); } public void cancel() throws SQLException { throw new UnsupportedOperationException(); } public void clearBatch() throws SQLException { throw new UnsupportedOperationException(); } public void clearWarnings() throws SQLException { throw new UnsupportedOperationException(); } public void close() throws SQLException { connection.close(); } public boolean execute(String sql) throws SQLException { throw new UnsupportedOperationException(); } public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { throw new UnsupportedOperationException(); } public boolean execute(String sql, int[] columnIndexes) throws SQLException { throw new UnsupportedOperationException(); } public boolean execute(String sql, String[] columnNames) throws SQLException { throw new UnsupportedOperationException(); } public int[] executeBatch() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet executeQuery(String sql) throws SQLException { throw new UnsupportedOperationException(); } public int executeUpdate(String sql) throws SQLException { throw new UnsupportedOperationException(); } public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { throw new UnsupportedOperationException(); } public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { throw new UnsupportedOperationException(); } public int executeUpdate(String sql, String[] columnNames) throws SQLException { throw new UnsupportedOperationException(); } public Connection getConnection() throws SQLException { throw new UnsupportedOperationException(); } public int getFetchDirection() throws SQLException { throw new UnsupportedOperationException(); } public int getFetchSize() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getGeneratedKeys() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxFieldSize() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxRows() throws SQLException { throw new UnsupportedOperationException(); } public boolean getMoreResults() throws SQLException { throw new UnsupportedOperationException(); } public boolean getMoreResults(int current) throws SQLException { throw new UnsupportedOperationException(); } public int getQueryTimeout() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getResultSet() throws SQLException { throw new UnsupportedOperationException(); } public int getResultSetConcurrency() throws SQLException { throw new UnsupportedOperationException(); } public int getResultSetHoldability() throws SQLException { throw new UnsupportedOperationException(); } public int getResultSetType() throws SQLException { throw new UnsupportedOperationException(); } public int getUpdateCount() throws SQLException { throw new UnsupportedOperationException(); } public SQLWarning getWarnings() throws SQLException { throw new UnsupportedOperationException(); } public boolean isClosed() throws SQLException { return connection.isClosed(); } public boolean isPoolable() throws SQLException { throw new UnsupportedOperationException(); } public void setCursorName(String name) throws SQLException { throw new UnsupportedOperationException(); } public void setEscapeProcessing(boolean enable) throws SQLException { throw new UnsupportedOperationException(); } public void setFetchDirection(int direction) throws SQLException { throw new UnsupportedOperationException(); } public void setFetchSize(int rows) throws SQLException { throw new UnsupportedOperationException(); } public void setMaxFieldSize(int max) throws SQLException { throw new UnsupportedOperationException(); } public void setMaxRows(int max) throws SQLException { throw new UnsupportedOperationException(); } public void setPoolable(boolean poolable) throws SQLException { throw new UnsupportedOperationException(); } public void setQueryTimeout(int seconds) throws SQLException { throw new UnsupportedOperationException(); } public boolean isWrapperFor(Class iface) throws SQLException { throw new UnsupportedOperationException(); } public T unwrap(Class iface) throws SQLException { throw new UnsupportedOperationException(); } // Java 1.7 public void closeOnCompletion() throws SQLException { throw new UnsupportedOperationException(); } // Java 1.7 public boolean isCloseOnCompletion() throws SQLException { throw new UnsupportedOperationException(); } }gral-0.11/gral-core/src/test/java/de/erichseifert/gral/TestUtils.java000066400000000000000000000213171267060725100255300ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.awt.Shape; import java.awt.geom.Line2D; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.NotSerializableException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.List; import de.erichseifert.gral.util.GeometryUtils; import de.erichseifert.gral.util.GeometryUtils.PathSegment; public class TestUtils { /** Default precision for unit tests. **/ public static final double DELTA = 1e-15; /** * Creates a new writable image for running a unit test. * @return A writable image instance. */ public static BufferedImage createTestImage() { return new BufferedImage(40, 30, BufferedImage.TYPE_INT_ARGB); } /** * Fails if the image is not empty and prints a specified message. The * image is considered as empty when it contains only transparent pixels * (alpha < 0). * @param message Custom message. * @param image Image to test. */ public static void assertEmpty(String message, BufferedImage image) { if (!isEmpty(image)) { fail((String.valueOf(message) + " Image is not empty.").trim()); } } /** * Fails if the image is not empty. The image is considered as empty when * it contains only transparent pixels (alpha < 0). * @param image Image to test. */ public static void assertEmpty(BufferedImage image) { assertEmpty("", image); } /** * Fails if the image is empty and prints a specified message. The image is * considered as not empty when it contains at least one transparent pixel * (alpha > 0). * @param message Custom message. * @param image Image to test. */ public static void assertNotEmpty(String message, BufferedImage image) { // An image without data is considered empty assertTrue(image.getWidth() > 0); assertTrue(image.getHeight() > 0); if (isEmpty(image)) { fail((String.valueOf(message) + " Image is empty.").trim()); } } /** * Fails if the image is empty. The image is considered as not empty when * it contains at least one transparent pixel (alpha > 0). * @param image Image to test. */ public static void assertNotEmpty(BufferedImage image) { assertNotEmpty("", image); } /** * Returns whether the specified image is empty. The image is considered * as empty when it contains only transparent pixels (alpha < 0). * @param image Image to test. * @return {@code true} when the image is empty, otherwise {@code false} */ private static boolean isEmpty(BufferedImage image) { // Check whether there are non-transparent pixel values DataBufferInt buf = (DataBufferInt) image.getRaster().getDataBuffer(); int[] data = buf.getData(); for (int color : data) { int alpha = color & 0xFF000000; if (alpha != 0) { return false; } } return true; } /** * Fails if the contents of two images aren't equal and prints a specified message. * @param message Custom message. * @param image1 First image. * @param image2 Second image. */ public static void assertEquals(String message, BufferedImage image1, BufferedImage image2) { if (!isEqual(image1, image2)) { fail((String.valueOf(message) + " Image contents are different.").trim()); } } /** * Fails if the contents of two images aren't equal. * @param image1 First image. * @param image2 Second image. */ public static void assertEquals(BufferedImage image1, BufferedImage image2) { assertEquals("", image1, image2); } /** * Fails if the contents of two images are equal and prints a specified message. * @param message Custom message. * @param image1 First image. * @param image2 Second image. */ public static void assertNotEquals(String message, BufferedImage image1, BufferedImage image2) { if (isEqual(image1, image2)) { fail((String.valueOf(message) + " Image contents are identical.").trim()); } } /** * Fails if the contents of two images are equal. * @param image1 First image. * @param image2 Second image. */ public static void assertNotEquals(BufferedImage image1, BufferedImage image2) { assertNotEquals("", image1, image2); } /** * Returns whether two images contain the same pixels. * @param image1 First image. * @param image2 Second image. * @return {@code true} when the images are equal, otherwise {@code false} */ private static boolean isEqual(BufferedImage image1, BufferedImage image2) { DataBufferInt buf1 = (DataBufferInt) image1.getRaster().getDataBuffer(); DataBufferInt buf2 = (DataBufferInt) image2.getRaster().getDataBuffer(); // If the image dimensions are different, the images are considered as // not equal if (buf1.getSize() != buf2.getSize()) { return false; } // Check whether there are different pixel values int[] data1 = buf1.getData(); int[] data2 = buf2.getData(); for (int i = 0; i < data1.length; i++) { int color1 = data1[i]; int color2 = data2[i]; if (color1 != color2) { return false; } } return true; } @SuppressWarnings("unchecked") public static T serializeAndDeserialize(T original) throws IOException, ClassNotFoundException { // Serialize ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(out); try { oos.writeObject(original); } catch(NotSerializableException e) { e.printStackTrace(); } finally { oos.close(); } assertTrue("Serialization failed.", out.size() > 0); // Deserialize byte[] serializedData = out.toByteArray(); InputStream in = new ByteArrayInputStream(serializedData); ObjectInputStream ois = new ObjectInputStream(in); Object o = ois.readObject(); assertNotSame(original, o); return (T) o; } public static void assertEquals(String message, Line2D expected, Line2D actual) { org.junit.Assert.assertEquals(message, expected.getP1(), actual.getP1()); org.junit.Assert.assertEquals(message, expected.getP2(), actual.getP2()); } public static void assertSetting(String message, T expected, T actual) { // Line2D instances can't be compared. See Java bug 5057070 // if (expected instanceof Line2D) { assertEquals(message, (Line2D) expected, (Line2D) actual); } else if (expected instanceof Shape) { List segsExpected = GeometryUtils.getSegments((Shape) expected); List segsActual = GeometryUtils.getSegments((Shape) actual); org.junit.Assert.assertEquals(message, segsExpected.size(), segsActual.size()); for (int i = 0; i < segsExpected.size(); i++) { PathSegment segExpected = segsExpected.get(i); PathSegment segActual = segsActual.get(i); org.junit.Assert.assertEquals(message, segExpected.type, segActual.type); org.junit.Assert.assertEquals(message, segExpected.start, segActual.start); org.junit.Assert.assertEquals(message, segExpected.end, segActual.end); org.junit.Assert.assertArrayEquals(message, segExpected.coords, segActual.coords, DELTA); } } else { org.junit.Assert.assertEquals(message, expected, actual); } } public static void assertEquals(Line2D expected, Line2D actual) { if (expected == null && actual == null) { return; } if (expected != null && expected.equals(actual)) { return; } if (expected == null || actual == null) { fail(); } org.junit.Assert.assertEquals(expected.getP1(), actual.getP1()); org.junit.Assert.assertEquals(expected.getP2(), actual.getP2()); } public static void assertEquals(Shape expected, Shape actual) { if (expected instanceof Line2D && actual instanceof Line2D) { assertEquals((Line2D) expected, (Line2D) actual); } else { org.junit.Assert.assertEquals(expected, actual); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/TestUtilsTest.java000066400000000000000000000064641267060725100263760ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.awt.Color; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import org.junit.Test; public class TestUtilsTest { @Test public void testCreateTestImage() { BufferedImage image = createTestImage(); assertNotNull(image); assertTrue(image.getWidth() > 0); assertTrue(image.getHeight() > 0); assertEquals(BufferedImage.TYPE_INT_ARGB, image.getType()); } @Test public void testAssertNonEmptyImage() { BufferedImage image = new BufferedImage(40, 30, BufferedImage.TYPE_INT_ARGB); // Assert must fail on empty image try { assertNotEmpty(image); fail(); } catch (AssertionError e) { } // Assert must succeed on empty image Color color = Color.BLACK; image.setRGB(0, 0, color.getRGB()); assertNotEmpty(image); } @Test public void testAssertEqualsShape() { Rectangle2D s1 = new Rectangle2D.Double(); try { TestUtils.assertEquals(s1, null); fail(); } catch (AssertionError e) { } try { TestUtils.assertEquals(null, s1); fail(); } catch (AssertionError e) { } Rectangle2D s2 = new Rectangle2D.Double(); TestUtils.assertEquals(s1, s2); TestUtils.assertEquals(s2, s1); s1.setFrame(1.0, 1.0, 10.0, 10.0); try { TestUtils.assertEquals(s1, s2); fail(); } catch (AssertionError e) { } try { TestUtils.assertEquals(s2, s1); fail(); } catch (AssertionError e) { } s2.setFrame(1.0, 1.0, 10.0, 10.0); TestUtils.assertEquals(s1, s2); TestUtils.assertEquals(s2, s1); } @Test public void testAssertEqualsLine2D() { Line2D l1 = new Line2D.Double(); try { TestUtils.assertEquals(l1, null); fail(); } catch (AssertionError e) { } try { TestUtils.assertEquals(null, l1); fail(); } catch (AssertionError e) { } Line2D l2 = new Line2D.Double(); TestUtils.assertEquals(l1, l2); TestUtils.assertEquals(l2, l1); l2.setLine(0.0, 0.0, 1.0, 1.0); try { TestUtils.assertEquals(l1, l2); fail(); } catch (AssertionError e) { } try { TestUtils.assertEquals(l2, l1); fail(); } catch (AssertionError e) { } l1.setLine(0.0, 0.0, 1.0, 1.0); TestUtils.assertEquals(l1, l2); TestUtils.assertEquals(l2, l1); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/000077500000000000000000000000001267060725100236325ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/AbstractDataSourceTest.java000066400000000000000000000030101267060725100310450ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import static org.junit.Assert.assertEquals; import org.junit.Test; public class AbstractDataSourceTest { protected class StubAbstractDataSource extends AbstractDataSource { public StubAbstractDataSource() { } public StubAbstractDataSource(String name) { super(name); } @Override public Comparable get(int col, int row) { return null; } @Override public int getRowCount() { return 0; } } @Test public void testGetName() { StubAbstractDataSource source = new StubAbstractDataSource(); assertEquals(null, source.getName()); source = new StubAbstractDataSource("name"); assertEquals("name", source.getName()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/ColumnTest.java000066400000000000000000000064511267060725100266000ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import java.io.IOException; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.statistics.Statistics; public class ColumnTest { private static final double DELTA = TestUtils.DELTA; private static DataTable table; @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { table = new DataTable(Integer.class, Integer.class); table.add(1, 1); // 0 table.add(2, 3); // 1 table.add(3, 2); // 2 table.add(4, 6); // 3 table.add(5, 4); // 4 table.add(6, 8); // 5 table.add(7, 9); // 6 table.add(8, 11); // 7 } @Test public void testCreation() { Column col1 = new Column(table, 0); assertEquals(table, col1.getSource()); assertEquals(0, col1.getIndex()); assertEquals(table.getRowCount(), col1.size()); Column col2 = new Column(table, 1); assertEquals(table, col2.getSource()); assertEquals(1, col2.getIndex()); assertEquals(table.getRowCount(), col2.size()); } @Test public void testGet() { Column col1 = new Column(table, 0); assertEquals(table.get(0, 0), col1.get(0)); assertEquals(table.get(0, 1), col1.get(1)); Column col2 = new Column(null, 1); assertEquals(null, col2.get(0)); assertEquals(null, col2.get(1)); } @Test public void testEquality() { // TODO Test column equality } @Test public void testToString() { Column col1 = new Column(table, 1); Column col2 = new Column(table, 1); assertNotNull(col1.toString()); assertFalse(col1.toString().isEmpty()); assertEquals(col1.toString(), col2.toString()); } @Test public void testStatistics() { Column col1 = new Column(table, 1); assertEquals( 8.0, col1.getStatistics(Statistics.N), DELTA); assertEquals( 1.0, col1.getStatistics(Statistics.MIN), DELTA); assertEquals(11.0, col1.getStatistics(Statistics.MAX), DELTA); assertEquals(44.0, col1.getStatistics(Statistics.SUM), DELTA); } @Test public void testSerialization() throws IOException, ClassNotFoundException { DataAccessor original = new Column(table, 1); DataAccessor deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(table.getColumnCount(), deserialized.getSource().getColumnCount()); assertEquals(table.getRowCount(), deserialized.getSource().getRowCount()); assertEquals(1, deserialized.getIndex()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/DataSeriesTest.java000066400000000000000000000072341267060725100273670ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import org.junit.BeforeClass; import org.junit.Test; public class DataSeriesTest { private static DataTable table; @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { table = new DataTable(Integer.class, Integer.class, Integer.class); table.add(1, 3, 5); // 0 table.add(2, 8, 2); // 1 table.add(3, 5, 6); // 2 table.add(4, 6, 2); // 3 table.add(5, 4, 1); // 4 table.add(6, 9, 5); // 5 table.add(7, 8, 7); // 6 table.add(8, 1, 9); // 7 } @Test public void testCreate() { // without name DataSeries unnamed = new DataSeries(table, 2, 1); assertEquals(2, unnamed.getColumnCount()); assertEquals(table.getRowCount(), unnamed.getRowCount()); assertEquals(unnamed.getColumnCount(), unnamed.getColumnTypes().length); assertEquals(null, unnamed.getName()); // with name DataSeries named = new DataSeries("foo", table, 2, 1); assertEquals(2, named.getColumnCount()); assertEquals(table.getRowCount(), named.getRowCount()); assertEquals(named.getColumnCount(), named.getColumnTypes().length); assertEquals("foo", named.getName()); // without columns DataSeries allCols = new DataSeries("bar", table); assertEquals(table.getColumnCount(), allCols.getColumnCount()); assertEquals(table.getRowCount(), allCols.getRowCount()); assertEquals(allCols.getColumnCount(), allCols.getColumnTypes().length); assertEquals("bar", allCols.getName()); } @Test public void testGetInt() { DataSeries series = new DataSeries(table, 2, 1); for (int row = 0; row < series.getRowCount(); row++) { Row rowTable = table.getRow(row); Row rowSeries = series.getRow(row); assertEquals(rowTable.get(2), rowSeries.get(0)); assertEquals(rowTable.get(1), rowSeries.get(1)); assertEquals(2, rowSeries.size()); } // Invalid (negative) index assertNotNull(series.getRow(-1)); // Invalid (positive) index assertNotNull(series.getRow(series.getRowCount())); } @Test public void testGetIntInt() { DataSeries series = new DataSeries(table, 2, 1); for (int row = 0; row < series.getRowCount(); row++) { assertEquals(table.get(2, row), series.get(0, row)); assertEquals(table.get(1, row), series.get(1, row)); } // Invalid (negative) index assertNull(series.get(-1, -1)); // Invalid (positive) index assertNull(series.get(series.getColumnCount(), series.getRowCount())); } @Test public void testGetColumnCount() { DataSeries series = new DataSeries(table, 2, 1); assertEquals(2, series.getColumnCount()); } @Test public void testToString() { DataSeries series = new DataSeries("name", table, 2, 1); assertEquals("name", series.toString()); assertEquals(series.getName(), series.toString()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/DataTableConcurrencyTest.java000066400000000000000000000115371267060725100314000ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import static org.junit.Assert.assertEquals; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Before; import org.junit.Test; public class DataTableConcurrencyTest { private DataTable table; @Before @SuppressWarnings("unchecked") public void setUp() { table = new DataTable(Integer.class, Integer.class); } private static class DataTableReader extends Thread { private final DataTable table; public final AtomicInteger read; public DataTableReader(DataTable table) { this.table = table; read = new AtomicInteger(); } @Override public void run() { int cols = table.getColumnCount(); int rows = table.getRowCount(); for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { table.get(col, row); read.incrementAndGet(); } } } } private static class DataTableProducer extends Thread { private static final Random random = new Random(); private final DataTable table; public DataTableProducer(DataTable table) { this.table = table; } @Override public void run() { // Add row int value1 = random.nextInt(); int value2 = random.nextInt(); int row = table.add(value1, value2); // Verify assertEquals(value1, table.get(0, row)); assertEquals(value2, table.get(1, row)); } } private static class DataTableConsumer extends Thread { private final MutableDataSource table; public DataTableConsumer(MutableDataSource table) { this.table = table; } @Override public void run() { // Remove the first row table.remove(0); } } @Test public void testConcurrentRead() throws InterruptedException { table.add(1, 1); // 0 table.add(2, 3); // 1 table.add(3, 2); // 2 table.add(4, 6); // 3 table.add(5, 4); // 4 table.add(6, 8); // 5 table.add(7, 9); // 6 table.add(8, 11); // 7 DataTableReader[] readers = new DataTableReader[100]; for (int i = 0; i < readers.length; i++) { readers[i] = new DataTableReader(table); } for (DataTableReader reader : readers) { reader.start(); } for (DataTableReader reader : readers) { reader.join(); } } @Test public void testConcurrentWrite() throws InterruptedException { DataTableProducer[] producers = new DataTableProducer[100]; for (int i = 0; i < producers.length; i++) { producers[i] = new DataTableProducer(table); } for (DataTableProducer producer : producers) { producer.start(); } for (DataTableProducer producer : producers) { producer.join(); } assertEquals(producers.length, table.getRowCount()); } @Test public void testConcurrentReadWrite() throws InterruptedException { DataTableProducer[] producers = new DataTableProducer[100]; for (int i = 0; i < producers.length; i++) { producers[i] = new DataTableProducer(table); } DataTableReader[] readers = new DataTableReader[100]; for (int i = 0; i < readers.length; i++) { readers[i] = new DataTableReader(table); } for (DataTableProducer producer : producers) { producer.start(); } for (DataTableReader reader : readers) { reader.start(); } for (DataTableProducer producer : producers) { producer.join(); } for (DataTableReader reader : readers) { reader.join(); } assertEquals(producers.length, table.getRowCount()); } @Test public void testConcurrentProduceConsume() throws InterruptedException { DataTableProducer[] producers = new DataTableProducer[100]; for (int i = 0; i < producers.length; i++) { producers[i] = new DataTableProducer(table); } DataTableConsumer[] consumers = new DataTableConsumer[100]; for (int i = 0; i < consumers.length; i++) { consumers[i] = new DataTableConsumer(table); } for (DataTableProducer producer : producers) { producer.start(); } for (DataTableConsumer consumer : consumers) { consumer.start(); } for (DataTableProducer producer : producers) { producer.join(); } for (DataTableConsumer consumer : consumers) { consumer.join(); } assertEquals(0, table.getRowCount()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/DataTableTest.java000066400000000000000000000235311267060725100271620ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import java.io.IOException; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.comparators.Ascending; import de.erichseifert.gral.data.comparators.Descending; import de.erichseifert.gral.data.statistics.Statistics; import org.junit.Before; import org.junit.Test; public class DataTableTest { private static final double DELTA = TestUtils.DELTA; private static class MockDataListener implements DataListener { private DataChangeEvent[] added; private DataChangeEvent[] updated; private DataChangeEvent[] removed; public void dataAdded(DataSource source, DataChangeEvent... events) { added = events; } public void dataUpdated(DataSource source, DataChangeEvent... events) { updated = events; } public void dataRemoved(DataSource source, DataChangeEvent... events) { removed = events; } } private DataTable table; @Before @SuppressWarnings("unchecked") public void setUp() { table = new DataTable(Integer.class, Integer.class); table.add(1, 1); // 0 table.add(2, 3); // 1 table.add(3, 2); // 2 table.add(4, 6); // 3 table.add(5, 4); // 4 table.add(6, 8); // 5 table.add(7, 9); // 6 table.add(8, 11); // 7 } @Test @SuppressWarnings("unchecked") public void testCreate() { // Constructor with types DataTable table1 = new DataTable(Integer.class, Double.class, Long.class, Float.class); assertEquals(4, table1.getColumnCount()); assertEquals(0, table1.getRowCount()); Class>[] types1 = table1.getColumnTypes(); assertEquals(Integer.class, types1[0]); assertEquals(Double.class, types1[1]); assertEquals(Long.class, types1[2]); assertEquals(Float.class, types1[3]); // Constructor with single type DataTable table2 = new DataTable(3, Double.class); assertEquals(3, table2.getColumnCount()); assertEquals(0, table1.getRowCount()); Class>[] types2 = table2.getColumnTypes(); for (Class> aTypes2 : types2) { assertEquals(Double.class, aTypes2); } // Copy constructor DataTable table3 = new DataTable(table1); assertEquals(table1.getColumnCount(), table3.getColumnCount()); assertEquals(table1.getRowCount(), table3.getRowCount()); Class>[] types3 = table1.getColumnTypes(); for (int i = 0; i < types3.length; i++) { assertEquals(types1[i], types3[i]); } } @Test public void testAdd() { int sizeBefore = table.getRowCount(); table.add(0, -1); table.add(1, -2); int rowIndex = table.add(2, -3); assertEquals(sizeBefore + 3, table.getRowCount()); assertEquals(table.getRowCount() - 1, rowIndex); // Wrong number of columns try { table.add(1); fail("Expected IllegalArgumentException exception."); } catch (IllegalArgumentException e) { } // Wrong type of columns try { table.add(1.0, 1.0); fail("Expected IllegalArgumentException exception."); } catch (IllegalArgumentException e) { } } @Test public void testSet() { int sizeBefore = table.getRowCount(); table.set(1, 2, -1); assertEquals(sizeBefore, table.getRowCount()); assertEquals(-1, table.get(1, 2)); // Illegal column index try { table.set(2, 0, 1); fail("Expected IndexOutOfBoundsException exception."); } catch (IndexOutOfBoundsException e) { } } @Test public void testRemove() { int sizeBefore = table.getRowCount(); table.remove(0); assertEquals(sizeBefore - 1, table.getRowCount()); // Invalid (negative) index try { table.remove(-1); fail("Expected IndexOutOfBoundsException exception."); } catch (IndexOutOfBoundsException e) { } // Invalid (positive) index try { table.remove(table.getRowCount()); fail("Expected IndexOutOfBoundsException exception."); } catch (IndexOutOfBoundsException e) { } } @Test public void testGetIntInt() { assertEquals(6, table.get(1, 3)); assertEquals(5, table.get(0, 4)); assertEquals(1, table.get(0, 0)); assertEquals(11, table.get(1, 7)); } @Test public void testIterator() { int i = 0; int colCount = table.getColumnCount(); for (Comparable cell : table) { int col = i % colCount; int row = i / colCount; Comparable expected = table.get(col, row); assertEquals(expected, cell); i++; } } @Test @SuppressWarnings("unchecked") public void testSort() { DataTable table = new DataTable(Integer.class, Integer.class, Integer.class); int[] original = { 9, 1, 3, 4, 4, 2, 4, 2, 1, 8, 1, 9, 8, 1, 7, 6, 2, 4, 4, 6, 5, 3, 3, 5 }; int i = 0; while (i < original.length) { table.add(original[i++], original[i++], original[i++]); } table.sort(new Ascending(1), new Descending(0), new Ascending(2)); int[] expected = { 9, 1, 3, 8, 1, 7, 8, 1, 9, 6, 2, 4, 4, 2, 1, 3, 3, 5, 4, 4, 2, 4, 6, 5 }; i = 0; while (i < expected.length) { assertEquals(expected[i], table.get(i%3, i/3)); i++; } } @Test public void testClear() { table.clear(); assertEquals(0, table.getRowCount()); } @Test public void testEventsAdd() { table.add(12, 34); MockDataListener listener = new MockDataListener(); table.addDataListener(listener); assertNull(listener.added); assertNull(listener.updated); assertNull(listener.removed); int row = table.add(56, 78); assertNotNull(listener.added); assertNull(listener.updated); assertNull(listener.removed); assertEquals(2, listener.added.length); assertEquals(0, listener.added[0].getCol()); assertEquals(row, listener.added[0].getRow()); assertNull(listener.added[0].getOld()); assertEquals(56, listener.added[0].getNew()); assertEquals(1, listener.added[1].getCol()); assertEquals(row, listener.added[1].getRow()); assertNull(listener.added[1].getOld()); assertEquals(78, listener.added[1].getNew()); } @Test public void testEventsUpdate() { int row = table.add(12, 34); MockDataListener listener = new MockDataListener(); table.addDataListener(listener); assertNull(listener.added); assertNull(listener.updated); assertNull(listener.removed); Comparable valueOld = table.set(1, row, 42); assertNull(listener.added); assertNotNull(listener.updated); assertNull(listener.removed); assertEquals(34, valueOld); assertEquals(1, listener.updated.length); assertEquals(1, listener.updated[0].getCol()); assertEquals(row, listener.updated[0].getRow()); assertEquals(34, listener.updated[0].getOld()); assertEquals(42, listener.updated[0].getNew()); } @Test public void testEventsRemove() { int row = table.add(12, 34); MockDataListener listener = new MockDataListener(); table.addDataListener(listener); assertNull(listener.added); assertNull(listener.updated); assertNull(listener.removed); table.remove(row); assertNull(listener.added); assertNull(listener.updated); assertNotNull(listener.removed); assertEquals(2, listener.removed.length); assertEquals(0, listener.removed[0].getCol()); assertEquals(row, listener.removed[0].getRow()); assertEquals(12, listener.removed[0].getOld()); assertNull(listener.removed[0].getNew()); assertEquals(1, listener.removed[1].getCol()); assertEquals(row, listener.removed[1].getRow()); assertEquals(34, listener.removed[1].getOld()); assertNull(listener.removed[1].getNew()); } @Test public void testEventsClear() { MockDataListener listener = new MockDataListener(); table.addDataListener(listener); assertNull(listener.added); assertNull(listener.updated); assertNull(listener.removed); int cols = table.getColumnCount(); int rows = table.getRowCount(); table.clear(); assertNull(listener.added); assertNull(listener.updated); assertNotNull(listener.removed); assertEquals(cols * rows, listener.removed.length); } @Test public void testSerialization() throws IOException, ClassNotFoundException { DataSource original = table; DataSource deserialized = TestUtils.serializeAndDeserialize(original); // Test metadata assertArrayEquals(original.getColumnTypes(), deserialized.getColumnTypes()); assertEquals(original.getColumnCount(), deserialized.getColumnCount()); assertEquals(original.getRowCount(), deserialized.getRowCount()); // Test values for (int row = 0; row < original.getRowCount(); row++) { for (int col = 0; col < original.getColumnCount(); col++) { assertEquals( String.format("Wrong data at col=%d, row=%d.", col, row), original.get(col, row), deserialized.get(col, row)); } } // Test statistics String[] stats = { Statistics.N, Statistics.SUM, Statistics.MEAN, Statistics.VARIANCE }; for (String stat : stats) { assertEquals( original.getStatistics().get(stat), deserialized.getStatistics().get(stat), DELTA); } } @Test public void testSetName() { table.setName("name"); assertEquals("name", table.getName()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/DataTests.java000066400000000000000000000030341267060725100263710ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import org.junit.runner.RunWith; import org.junit.runners.Suite; import de.erichseifert.gral.data.comparators.ComparatorTest; import de.erichseifert.gral.data.filters.FiltersTests; import de.erichseifert.gral.data.statistics.StatisticsTests; @RunWith(Suite.class) @Suite.SuiteClasses({ // Tests for classes DataTableTest.class, DataTableConcurrencyTest.class, DataSeriesTest.class, RowSubsetTest.class, EnumeratedDataTest.class, DummyDataTest.class, RowTest.class, ColumnTest.class, JdbcDataTest.class, // Tests for sub-packages ComparatorTest.class, StatisticsTests.class, FiltersTests.class }) public class DataTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/DummyDataTest.java000066400000000000000000000052301267060725100272220ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import java.io.IOException; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.statistics.Statistics; public class DummyDataTest { private static final double DELTA = TestUtils.DELTA; @Test public void testCreate() { Comparable[] expected = {42, 1.23, "foobar" }; for (Comparable value : expected) { DummyData integer = new DummyData(2, 3, value); assertEquals(2, integer.getColumnCount()); assertEquals(3, integer.getRowCount()); assertEquals(integer.getColumnCount(), integer.getColumnTypes().length); for (Comparable cell : integer) { assertEquals(value, cell); } } } @Test public void testSerialization() throws IOException, ClassNotFoundException { DataSource original = new DummyData(2, 3, "foobar"); DataSource deserialized = TestUtils.serializeAndDeserialize(original); // Test metadata assertArrayEquals(original.getColumnTypes(), deserialized.getColumnTypes()); assertEquals(original.getColumnCount(), deserialized.getColumnCount()); assertEquals(original.getRowCount(), deserialized.getRowCount()); // Test values for (int row = 0; row < original.getRowCount(); row++) { for (int col = 0; col < original.getColumnCount(); col++) { assertEquals( String.format("Wrong data at col=%d, row=%d.", col, row), original.get(col, row), deserialized.get(col, row)); } } // Test statistics String[] stats = { Statistics.N, Statistics.SUM, Statistics.MEAN, Statistics.VARIANCE }; for (String stat : stats) { assertEquals( original.getStatistics().get(stat), deserialized.getStatistics().get(stat), DELTA); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/EnumeratedDataTest.java000066400000000000000000000066751267060725100302360ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import java.io.IOException; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.statistics.Statistics; public class EnumeratedDataTest { private static final double DELTA = TestUtils.DELTA; private static DataTable table; @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { table = new DataTable(Integer.class, Integer.class); table.add(3, 1); // 0 table.add(2, 3); // 1 table.add(1, 2); // 2 } @Test public void testCreate() { // without parameters EnumeratedData withoutParams = new EnumeratedData(table); assertEquals(table.getColumnCount() + 1, withoutParams.getColumnCount()); assertEquals(table.getRowCount(), withoutParams.getRowCount()); assertEquals(0.0, ((Number) withoutParams.get(0, 0)).doubleValue(), DELTA); assertEquals(1.0, ((Number) withoutParams.get(0, 1)).doubleValue(), DELTA); assertEquals(2.0, ((Number) withoutParams.get(0, 2)).doubleValue(), DELTA); // with parameters EnumeratedData withParams = new EnumeratedData(table, -1, 2.0); assertEquals(table.getColumnCount() + 1, withParams.getColumnCount()); assertEquals(table.getRowCount(), withParams.getRowCount()); assertEquals(-1.0, ((Number) withParams.get(0, 0)).doubleValue(), DELTA); assertEquals( 1.0, ((Number) withParams.get(0, 1)).doubleValue(), DELTA); assertEquals( 3.0, ((Number) withParams.get(0, 2)).doubleValue(), DELTA); } @Test public void testSerialization() throws IOException, ClassNotFoundException { DataSource original = new EnumeratedData(table); DataSource deserialized = TestUtils.serializeAndDeserialize(original); // Test metadata assertArrayEquals(original.getColumnTypes(), deserialized.getColumnTypes()); assertEquals(original.getColumnCount(), deserialized.getColumnCount()); assertEquals(original.getRowCount(), deserialized.getRowCount()); // Test values for (int row = 0; row < original.getRowCount(); row++) { for (int col = 0; col < original.getColumnCount(); col++) { assertEquals( String.format("Wrong data at col=%d, row=%d.", col, row), original.get(col, row), deserialized.get(col, row)); } } // Test statistics String[] stats = { Statistics.N, Statistics.SUM, Statistics.MEAN, Statistics.VARIANCE }; for (String stat : stats) { assertEquals( original.getStatistics().get(stat), deserialized.getStatistics().get(stat), DELTA); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/JdbcDataTest.java000066400000000000000000000072241267060725100267760ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import java.io.IOException; import java.sql.Connection; import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.DummyJdbc; import de.erichseifert.gral.TestUtils; public class JdbcDataTest { private Connection connection; private DataTable table; @Before @SuppressWarnings("unchecked") public void setUpBeforeClass() { table = new DataTable( Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Date.class, Time.class, Timestamp.class, String.class ); table.add((byte) 3, (short) 5, 1, 9L, 4.8f, 5.9, new Date(6), new Time(1), new Timestamp(8), "Jan"); // 0 table.add((byte) 8, (short) 2, 2, 8L, 2.7f, 2.4, new Date(3), new Time(5), new Timestamp(2), "Feb"); // 1 table.add((byte) 5, (short) 6, 3, 7L, 6.3f, 6.6, new Date(4), new Time(4), new Timestamp(7), "Mar"); // 2 table.add((byte) 6, (short) 2, 4, 6L, 3.4f, 2.1, new Date(7), new Time(6), new Timestamp(1), "Apr"); // 3 table.add((byte) 4, (short) 1, 5, 5L, 5.1f, 1.0, new Date(2), new Time(2), new Timestamp(6), "May"); // 4 table.add((byte) 9, (short) 5, 6, 4L, 1.5f, 5.8, new Date(5), new Time(7), new Timestamp(4), "Jun"); // 5 table.add((byte) 8, (short) 7, 7, 3L, 7.2f, 7.3, new Date(1), new Time(3), new Timestamp(3), "Jul"); // 6 table.add((byte) 1, (short) 9, 8, 2L, 8.6f, 9.2, new Date(8), new Time(8), new Timestamp(5), "Aug"); // 7 connection = new DummyJdbc(table); } @Test public void testCreate() { JdbcData data = new JdbcData(connection, "foobar"); assertEquals(10, data.getColumnCount()); assertEquals(8, data.getRowCount()); Class>[] typesExpected = table.getColumnTypes(); Class>[] typesActual = data.getColumnTypes(); assertEquals(data.getColumnCount(), typesActual.length); assertArrayEquals(typesExpected, typesActual); } @Test public void testGetIntInt() { JdbcData data = new JdbcData(connection, "foobar"); for (int rowIndex = 0; rowIndex < table.getRowCount(); rowIndex++) { for (int colIndex = 0; colIndex < table.getColumnCount(); colIndex++) { Comparable expected = table.get(colIndex, rowIndex); Comparable actual = data.get(colIndex, rowIndex); assertEquals( String.format("Wrong value at col=%d, row=%d.", colIndex, rowIndex), expected, actual ); } } } @Test public void testXyz() { } @Test(expected=UnsupportedOperationException.class) @SuppressWarnings("unused") public void testSerialization() throws IOException, ClassNotFoundException { DataSource original = new JdbcData(connection, "foobar"); DataSource deserialized = TestUtils.serializeAndDeserialize(original); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/RowSubsetTest.java000066400000000000000000000111371267060725100272750ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.statistics.Statistics; public class RowSubsetTest { private static final double DELTA = TestUtils.DELTA; private static final class MockRowSubset extends RowSubset { /** Version id for serialization. */ private static final long serialVersionUID = -601722212974379219L; public MockRowSubset(DataSource original) { super(original); } @Override public boolean accept(Row row) { Comparable cell = row.get(0); return (cell instanceof Number) && (((Number) cell).doubleValue() % 2.0) == 0.0; } } private DataTable table; private RowSubset data; @Before @SuppressWarnings("unchecked") public void setUp() { table = new DataTable(Integer.class, Integer.class); table.add(1, 1); // 0 table.add(2, 3); // 1 table.add(3, 2); // 2 table.add(4, 6); // 3 table.add(5, 4); // 4 table.add(6, 8); // 5 table.add(7, 9); // 6 table.add(8, 11); // 7 data = new MockRowSubset(table); } @Test public void testCreate() { assertEquals(table.getColumnCount(), data.getColumnCount()); assertEquals(table.getRowCount()/2, data.getRowCount()); assertArrayEquals(table.getColumnTypes(), data.getColumnTypes()); } @Test public void testGetIntInt() { assertEquals( 2, data.get(0, 0)); assertEquals( 4, data.get(0, 1)); assertEquals( 6, data.get(0, 2)); assertEquals( 8, data.get(0, 3)); assertEquals( 3, data.get(1, 0)); assertEquals( 6, data.get(1, 1)); assertEquals( 8, data.get(1, 2)); assertEquals(11, data.get(1, 3)); } @Test public void testGetInt() { assertEquals(table.getRow(1), data.getRow(0)); assertEquals(table.getRow(3), data.getRow(1)); assertEquals(table.getRow(5), data.getRow(2)); assertEquals(table.getRow(7), data.getRow(3)); } @Test public void testDataAdded() { int sizeBefore = data.getRowCount(); table.add(10, -1); assertTrue(data.getRowCount() > sizeBefore); } @Test public void testDataUpdated() { int sizeBefore = data.getRowCount(); // Change one rows to be included in subset table.set(0, 1, -2); assertEquals(sizeBefore, data.getRowCount()); // Change one rows to be excluded from subset table.set(0, 1, -3); assertTrue(data.getRowCount() < sizeBefore); // Change two rows to be included in subset table.set(0, 1, -2); table.set(0, 2, -2); assertTrue(data.getRowCount() > sizeBefore); } @Test public void testDataRemoved() { int sizeBefore = data.getRowCount(); table.remove(1); assertTrue(data.getRowCount() < sizeBefore); } @Test public void testSerialization() throws IOException, ClassNotFoundException { DataSource original = data; DataSource deserialized = TestUtils.serializeAndDeserialize(original); // Test metadata assertArrayEquals(original.getColumnTypes(), deserialized.getColumnTypes()); assertEquals(original.getColumnCount(), deserialized.getColumnCount()); assertEquals(original.getRowCount(), deserialized.getRowCount()); // Test values for (int row = 0; row < original.getRowCount(); row++) { for (int col = 0; col < original.getColumnCount(); col++) { assertEquals( String.format("Wrong data at col=%d, row=%d.", col, row), original.get(col, row), deserialized.get(col, row)); } } // Test statistics String[] stats = { Statistics.N, Statistics.SUM, Statistics.MEAN, Statistics.VARIANCE }; for (String stat : stats) { assertEquals( original.getStatistics().get(stat), deserialized.getStatistics().get(stat), DELTA); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/RowTest.java000066400000000000000000000101131267060725100261000ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.statistics.Statistics; public class RowTest { private static final double DELTA = TestUtils.DELTA; private static DataTable table; @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { table = new DataTable(Integer.class, Integer.class); table.add(1, 1); // 0 table.add(2, 3); // 1 table.add(3, 2); // 2 table.add(4, 6); // 3 table.add(5, 4); // 4 table.add(6, 8); // 5 table.add(7, 9); // 6 table.add(8, 11); // 7 } @Test public void testCreation() { Row row1 = new Row(table, 0); assertEquals(table, row1.getSource()); assertEquals(0, row1.getIndex()); assertEquals(table.getColumnCount(), row1.size()); Row row2 = new Row(table, 1); assertEquals(table, row2.getSource()); assertEquals(1, row2.getIndex()); assertEquals(table.getColumnCount(), row2.size()); } @Test public void testGet() { Row row1 = new Row(table, 1); assertEquals(table.get(0, 1), row1.get(0)); assertEquals(table.get(1, 1), row1.get(1)); Row row2 = new Row(null, 1); assertEquals(null, row2.get(0)); assertEquals(null, row2.get(1)); } @Test @SuppressWarnings("unchecked") public void testEquality() { Row row1 = new Row(table, 1); Row row2 = new Row(table, 1); Row row3 = new Row(table, 2); assertTrue(row1.equals(row2)); assertFalse(row1.equals(row3)); assertFalse(row1.equals(null)); assertFalse(row1.equals(new Object())); // Different data source shouldn't matter DataTable table1 = new DataTable(Integer.class, Integer.class); table1.add(2, 3); assertTrue(row1.equals(new Row(table1, 0))); // Different column count should yield error DataTable table2 = new DataTable(Integer.class, Integer.class, Integer.class); table2.add(2, 3, 0); assertFalse(row1.equals(new Row(table2, 0))); // Different data types should yield error DataTable table3 = new DataTable(Integer.class, Double.class); table3.add(2, 3.0); assertFalse(row1.equals(new Row(table3, 0))); } @Test public void testToString() { Row row1 = new Row(table, 1); Row row2 = new Row(table, 1); assertNotNull(row1.toString()); assertFalse(row1.toString().isEmpty()); assertEquals(row1.toString(), row2.toString()); } @Test public void testStatistics() { Row row1 = new Row(table, 1); assertEquals( 2.0, row1.getStatistics(Statistics.N), DELTA); assertEquals( 2.0, row1.getStatistics(Statistics.MIN), DELTA); assertEquals( 3.0, row1.getStatistics(Statistics.MAX), DELTA); assertEquals( 5.0, row1.getStatistics(Statistics.SUM), DELTA); } @Test public void testSerialization() throws IOException, ClassNotFoundException { DataAccessor original = new Row(table, 1); DataAccessor deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(table.getColumnCount(), deserialized.getSource().getColumnCount()); assertEquals(table.getRowCount(), deserialized.getSource().getRowCount()); assertEquals(1, deserialized.getIndex()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/comparators/000077500000000000000000000000001267060725100261645ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/comparators/ComparatorTest.java000066400000000000000000000101341267060725100317750ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.comparators; import static org.junit.Assert.assertEquals; import java.io.IOException; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.DataTable; public class ComparatorTest { private static DataTable data; private Comparable[] row1, row2, row3, row4; @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { data = new DataTable(Double.class, Double.class, Double.class, String.class); data.add(1.0, 2.0, 4.0, "foo"); data.add(2.0, 2.0, 3.0, "bar"); data.add(3.0, 2.0, 2.0, null); data.add(4.0, 2.0, 1.0, null); } @Before public void setUp() { row1 = data.getRow(0).toArray(null); row2 = data.getRow(1).toArray(null); row3 = data.getRow(2).toArray(null); row4 = data.getRow(3).toArray(null); } @Test public void testColumn() { DataComparator comparator; comparator = new Ascending(0); assertEquals(0, comparator.getColumn()); comparator = new Ascending(1); assertEquals(1, comparator.getColumn()); comparator = new Ascending(2); assertEquals(2, comparator.getColumn()); } @Test public void testAscending() { int[][] expected = { { -1, 0, 1, 4 }, { -1, 0, 1, -1 }, { 1, 0, -1, 1 }, { -1, 0, 1, 0 } }; for (int i = 0; i < data.getColumnCount(); i++) { DataComparator comparator = new Ascending(i); assertEquals(expected[0][i], comparator.compare(row1, row2)); assertEquals(expected[1][i], comparator.compare(row2, row3)); assertEquals(expected[2][i], comparator.compare(row3, row1)); assertEquals(expected[3][i], comparator.compare(row3, row4)); assertEquals(0, comparator.compare(row1, row1)); assertEquals(0, comparator.compare(row2, row2)); assertEquals(0, comparator.compare(row3, row3)); assertEquals(0, comparator.compare(row4, row4)); } } @Test public void testDescending() { int[][] expected = { { 1, 0, -1, -4 }, { 1, 0, -1, 1 }, { -1, 0, 1, -1 }, { 1, 0, -1, 0 } }; for (int i = 0; i < data.getColumnCount(); i++) { DataComparator comparator = new Descending(i); assertEquals(expected[0][i], comparator.compare(row1, row2)); assertEquals(expected[1][i], comparator.compare(row2, row3)); assertEquals(expected[2][i], comparator.compare(row3, row1)); assertEquals(expected[3][i], comparator.compare(row3, row4)); assertEquals(0, comparator.compare(row1, row1)); assertEquals(0, comparator.compare(row2, row2)); assertEquals(0, comparator.compare(row3, row3)); assertEquals(0, comparator.compare(row4, row4)); } } @Test public void testAscendingSerialization() throws IOException, ClassNotFoundException { DataComparator original = new Ascending(0); DataComparator deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getColumn(), deserialized.getColumn()); } @Test public void testDescendingSerialization() throws IOException, ClassNotFoundException { DataComparator original = new Descending(0); DataComparator deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getColumn(), deserialized.getColumn()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/comparators/package-info.java000077500000000000000000000017461267060725100313660ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.data.comparators} package. */ package de.erichseifert.gral.data.comparators; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/filters/000077500000000000000000000000001267060725100253025ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/filters/ConvolutionTest.java000066400000000000000000000163211267060725100313270ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.filters; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.data.statistics.Statistics; public class ConvolutionTest { private static final double DELTA = TestUtils.DELTA; private static DataTable table; private static Kernel kernel; @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { table = new DataTable(Double.class, Double.class, String.class); table.add(1.0, 1.0, "a"); // 0 table.add(2.0, 1.0, "b"); // 1 table.add(3.0, 1.0, "c"); // 2 table.add(4.0, 1.0, "d"); // 3 table.add(5.0, 1.0, "e"); // 4 table.add(6.0, 1.0, "f"); // 5 table.add(7.0, 1.0, "g"); // 6 table.add(8.0, 1.0, "h"); // 7 kernel = new Kernel(1.0, 1.0, 1.0); } @Test public void testCreate() { Convolution filter = new Convolution(table, kernel, Filter.Mode.ZERO, 0, 1); assertEquals(table.getColumnCount(), filter.getColumnCount()); assertEquals(table.getRowCount(), filter.getRowCount()); assertEquals(table.getColumnCount(), filter.getColumnTypes().length); try { new Convolution(table, kernel, Filter.Mode.ZERO, 0, 2); fail("Filtering a non-numeric column must raise an IllegalArgumentException."); } catch (IllegalArgumentException e) { } } @Test public void testKernel() { Convolution filter = new Convolution(table, kernel, Filter.Mode.ZERO, 0, 1); assertEquals(kernel, filter.getKernel()); } @Test public void testMode() { Convolution filter = new Convolution(table, kernel, Filter.Mode.OMIT, 0, 1); for (Filter.Mode mode : Filter.Mode.values()) { filter.setMode(mode); assertEquals(mode, filter.getMode()); } } @Test public void testColumns() { Convolution filter = new Convolution(table, kernel, Filter.Mode.ZERO, 0); assertEquals(3.0, ((Number) filter.get(0, 0)).doubleValue(), DELTA); assertEquals(6.0, ((Number) filter.get(0, 1)).doubleValue(), DELTA); assertEquals(9.0, ((Number) filter.get(0, 2)).doubleValue(), DELTA); assertEquals(1.0, ((Number) filter.get(1, 0)).doubleValue(), DELTA); assertEquals(1.0, ((Number) filter.get(1, 1)).doubleValue(), DELTA); assertEquals(1.0, ((Number) filter.get(1, 2)).doubleValue(), DELTA); } @Test public void testModeOmit() { Convolution filter = new Convolution(table, kernel, Filter.Mode.OMIT, 0, 1); assertTrue(Double.isNaN(((Number) filter.get(0, 0)).doubleValue())); assertEquals(6.0, ((Number) filter.get(0, 1)).doubleValue(), DELTA); assertTrue(Double.isNaN(((Number) filter.get(0, 7)).doubleValue())); assertTrue(Double.isNaN(((Number) filter.get(1, 0)).doubleValue())); assertEquals(3.0, ((Number) filter.get(1, 1)).doubleValue(), DELTA); assertTrue(Double.isNaN(((Number) filter.get(1, 7)).doubleValue())); } @Test public void testModeZero() { Convolution filter = new Convolution(table, kernel, Filter.Mode.ZERO, 0, 1); assertEquals( 3.0, ((Number) filter.get(0, 0)).doubleValue(), DELTA); assertEquals( 6.0, ((Number) filter.get(0, 1)).doubleValue(), DELTA); assertEquals(15.0, ((Number) filter.get(0, 7)).doubleValue(), DELTA); assertEquals( 2.0, ((Number) filter.get(1, 0)).doubleValue(), DELTA); assertEquals( 3.0, ((Number) filter.get(1, 1)).doubleValue(), DELTA); assertEquals( 2.0, ((Number) filter.get(1, 7)).doubleValue(), DELTA); } @Test public void testModeRepeat() { Convolution filter = new Convolution(table, kernel, Filter.Mode.REPEAT, 0, 1); assertEquals( 4.0, ((Number) filter.get(0, 0)).doubleValue(), DELTA); assertEquals( 6.0, ((Number) filter.get(0, 1)).doubleValue(), DELTA); assertEquals(23.0, ((Number) filter.get(0, 7)).doubleValue(), DELTA); assertEquals( 3.0, ((Number) filter.get(1, 0)).doubleValue(), DELTA); assertEquals( 3.0, ((Number) filter.get(1, 1)).doubleValue(), DELTA); assertEquals( 3.0, ((Number) filter.get(1, 7)).doubleValue(), DELTA); } @Test public void testModeMirror() { Convolution filter = new Convolution(table, kernel, Filter.Mode.MIRROR, 0, 1); assertEquals( 5.0, ((Number) filter.get(0, 0)).doubleValue(), DELTA); assertEquals( 6.0, ((Number) filter.get(0, 1)).doubleValue(), DELTA); assertEquals(22.0, ((Number) filter.get(0, 7)).doubleValue(), DELTA); assertEquals( 3.0, ((Number) filter.get(1, 0)).doubleValue(), DELTA); assertEquals( 3.0, ((Number) filter.get(1, 1)).doubleValue(), DELTA); assertEquals( 3.0, ((Number) filter.get(1, 7)).doubleValue(), DELTA); } @Test public void testModeCircular() { Convolution filter = new Convolution(table, kernel, Filter.Mode.CIRCULAR, 0, 1); assertEquals(11.0, ((Number) filter.get(0, 0)).doubleValue(), DELTA); assertEquals( 6.0, ((Number) filter.get(0, 1)).doubleValue(), DELTA); assertEquals(16.0, ((Number) filter.get(0, 7)).doubleValue(), DELTA); assertEquals( 3.0, ((Number) filter.get(1, 0)).doubleValue(), DELTA); assertEquals( 3.0, ((Number) filter.get(1, 1)).doubleValue(), DELTA); assertEquals( 3.0, ((Number) filter.get(1, 7)).doubleValue(), DELTA); } @Test public void testSerialization() throws IOException, ClassNotFoundException { Convolution original = new Convolution(table, kernel, Filter.Mode.ZERO, 0, 1); Convolution deserialized = TestUtils.serializeAndDeserialize(original); // Test metadata assertEquals(original.getKernel().size(), deserialized.getKernel().size()); assertEquals(original.getMode(), deserialized.getMode()); assertArrayEquals(original.getColumnTypes(), deserialized.getColumnTypes()); assertEquals(original.getColumnCount(), deserialized.getColumnCount()); assertEquals(original.getRowCount(), deserialized.getRowCount()); // Test values for (int row = 0; row < original.getRowCount(); row++) { for (int col = 0; col < original.getColumnCount(); col++) { assertEquals( String.format("Wrong data at col=%d, row=%d.", col, row), original.get(col, row), deserialized.get(col, row)); } } // Test statistics String[] stats = { Statistics.N, Statistics.SUM, Statistics.MEAN, Statistics.VARIANCE }; for (String stat : stats) { assertEquals( original.getStatistics().get(stat), deserialized.getStatistics().get(stat), DELTA); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/filters/FiltersTests.java000066400000000000000000000021731267060725100306030ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.filters; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ KernelTest.class, ConvolutionTest.class, MedianTest.class, ResizeTest.class }) public class FiltersTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/filters/KernelTest.java000066400000000000000000000107211267060725100302260ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.filters; import java.io.IOException; import static org.junit.Assert.assertEquals; import de.erichseifert.gral.TestUtils; import org.junit.Test; public class KernelTest { private static final double DELTA = TestUtils.DELTA; @Test public void testSimpleKernel() { Kernel k = new Kernel(1.0); assertEquals(0.0, k.get(-1), DELTA); assertEquals(1.0, k.get( 0), DELTA); assertEquals(0.0, k.get( 1), DELTA); } @Test public void testBinomial() { Kernel kernel; // Small kernel kernel = Kernel.getBinomial(2); assertEquals(2, kernel.size()); assertEquals(1, kernel.getOffset()); assertEquals(0.00, kernel.get(-2), DELTA); assertEquals(0.50, kernel.get(-1), DELTA); assertEquals(0.50, kernel.get( 0), DELTA); assertEquals(0.00, kernel.get( 1), DELTA); assertEquals(0.00, kernel.get( 2), DELTA); // Large kernel kernel = Kernel.getBinomial(13); assertEquals(13, kernel.size()); assertEquals(6, kernel.getOffset()); assertEquals(0.1933593750, kernel.get(-1), DELTA); assertEquals(0.2255859375, kernel.get( 0), DELTA); assertEquals(0.1933593750, kernel.get( 1), DELTA); // Kernel with specified variance kernel = Kernel.getBinomial(1.0); assertEquals(5, kernel.size()); assertEquals(2, kernel.getOffset()); } @Test public void testUniform() { Kernel kernel = Kernel.getUniform(13, 0, 1.0); assertEquals(13, kernel.size()); assertEquals(0, kernel.getOffset()); assertEquals(0.0, kernel.get(-1), DELTA); assertEquals(1.0, kernel.get( 0), DELTA); assertEquals(1.0, kernel.get(12), DELTA); assertEquals(0.0, kernel.get(13), DELTA); } @Test public void testOffset() { Kernel k1 = new Kernel(0, new double[] {1.0, 2.0, 3.0}); assertEquals(0.0, k1.get(-1), DELTA); assertEquals(1.0, k1.get( 0), DELTA); assertEquals(2.0, k1.get( 1), DELTA); assertEquals(3.0, k1.get( 2), DELTA); assertEquals(0.0, k1.get( 3), DELTA); Kernel k2 = new Kernel(1, new double[] {1.0, 2.0, 3.0}); assertEquals(0.0, k2.get(-2), DELTA); assertEquals(1.0, k2.get(-1), DELTA); assertEquals(2.0, k2.get( 0), DELTA); assertEquals(3.0, k2.get( 1), DELTA); assertEquals(0.0, k2.get( 2), DELTA); Kernel k3 = new Kernel(1.0, 2.0, 3.0, 4.0); assertEquals(2, k3.getOffset()); } @Test public void testIndexes() { Kernel k = new Kernel(1.0, 2.0, 3.0, 4.0); assertEquals(-2, k.getMinIndex()); assertEquals( 1, k.getMaxIndex()); } @Test public void testAdd() { Kernel k1 = new Kernel(1.0, 2.0); Kernel k2 = new Kernel(3.0); k1.add(k2); assertEquals(5.0, k1.get(0), DELTA); k1.add(1.0); assertEquals(6.0, k1.get(0), DELTA); } @Test public void testMul() { Kernel k1 = new Kernel(1.0, 2.0); Kernel k2 = new Kernel(3.0); k1.mul(k2); assertEquals(6.0, k1.get(0), DELTA); k1.mul(2.0); assertEquals(12.0, k1.get(0), DELTA); } @Test public void testNormalize() { Kernel k = new Kernel(1.0, 1.0); k.normalize(); assertEquals(0.5, k.get(-1), DELTA); assertEquals(0.5, k.get( 0), DELTA); } @Test public void testNegate() { Kernel k = new Kernel(1.0, 1.0); k.negate(); assertEquals(-1.0, k.get(-1), DELTA); assertEquals(-1.0, k.get( 0), DELTA); } @Test public void testSerialization() throws IOException, ClassNotFoundException { Kernel original = new Kernel(1.0, 2.0, 3.0, 4.0); Kernel deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getOffset(), deserialized.getOffset()); assertEquals(original.size(), deserialized.size()); for (int i = 0; i < original.size(); i++) { assertEquals( String.format("Wrong value at index %d.", i), original.get(i), deserialized.get(i), DELTA); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/filters/MedianTest.java000066400000000000000000000072211267060725100302040ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.filters; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import java.io.IOException; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.data.statistics.Statistics; public class MedianTest { private static final double DELTA = TestUtils.DELTA; private static DataTable table; @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { table = new DataTable(Integer.class, Integer.class, Integer.class); table.add(1, 3, 5); // 0 table.add(2, 8, 2); // 1 table.add(3, 5, 6); // 2 table.add(4, 6, 2); // 3 table.add(5, 4, 1); // 4 table.add(6, 9, 5); // 5 table.add(7, 8, 7); // 6 table.add(8, 1, 9); // 7 } @Test public void testCreate() { Median filter = new Median(table, 3, 1, Filter.Mode.REPEAT, 0); assertEquals(table.getColumnCount(), filter.getColumnCount()); assertEquals(table.getRowCount(), filter.getRowCount()); } @Test public void testMode() { Median filter = new Median(table, 3, 1, Filter.Mode.REPEAT, 0); for (Filter.Mode mode : Filter.Mode.values()) { filter.setMode(mode); assertEquals(mode, filter.getMode()); } } @Test public void testWindowSize() { Median filter = new Median(table, 3, 1, Filter.Mode.REPEAT, 0); assertEquals(3, filter.getWindowSize()); filter.setWindowSize(1); assertEquals(1, filter.getWindowSize()); } @Test public void testOffset() { Median filter = new Median(table, 3, 1, Filter.Mode.REPEAT, 0); assertEquals(1, filter.getOffset()); filter.setOffset(0); assertEquals(0, filter.getOffset()); } @Test public void testSerialization() throws IOException, ClassNotFoundException { Filter original = new Median(table, 3, 1, Filter.Mode.REPEAT, 0); Filter deserialized = TestUtils.serializeAndDeserialize(original); // Test metadata assertEquals(original.getMode(), deserialized.getMode()); assertArrayEquals(original.getColumnTypes(), deserialized.getColumnTypes()); assertEquals(original.getColumnCount(), deserialized.getColumnCount()); assertEquals(original.getRowCount(), deserialized.getRowCount()); // Test values for (int row = 0; row < original.getRowCount(); row++) { for (int col = 0; col < original.getColumnCount(); col++) { assertEquals( String.format("Wrong data at col=%d, row=%d.", col, row), original.get(col, row), deserialized.get(col, row)); } } // Test statistics String[] stats = { Statistics.N, Statistics.SUM, Statistics.MEAN, Statistics.VARIANCE }; for (String stat : stats) { assertEquals( original.getStatistics().get(stat), deserialized.getStatistics().get(stat), DELTA); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/filters/ResizeTest.java000066400000000000000000000132621267060725100302520ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.filters; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import java.io.IOException; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.data.statistics.Statistics; public class ResizeTest { private static final double DELTA = 1e-15; private static DataTable dataEmpty; private static DataTable dataHorizontal; private static DataTable dataVertical; private static DataTable dataDiagonal; @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { dataEmpty = new DataTable(Double.class, Double.class, Double.class); dataEmpty.add(0.0, 0.0, 0.0); // 0 dataEmpty.add(0.0, 0.0, 0.0); // 1 dataEmpty.add(0.0, 0.0, 0.0); // 2 dataHorizontal = new DataTable(Double.class, Double.class, Double.class); dataHorizontal.add(0.0, 0.0, 0.0); // 0 dataHorizontal.add(1.0, 1.0, 1.0); // 1 dataHorizontal.add(0.0, 0.0, 0.0); // 2 dataVertical = new DataTable(Double.class, Double.class, Double.class); dataVertical.add(0.0, 1.0, 0.0); // 0 dataVertical.add(0.0, 1.0, 0.0); // 1 dataVertical.add(0.0, 1.0, 0.0); // 2 dataDiagonal = new DataTable(Double.class, Double.class, Double.class); dataDiagonal.add(1.0, 0.0, 0.0); // 0 dataDiagonal.add(0.0, 1.0, 0.0); // 1 dataDiagonal.add(0.0, 0.0, 1.0); // 2 } private void assertFiltered(DataSource data, int cols, int rows, double[] expected) { Resize filter = new Resize(data, cols, rows); assertEquals((cols > 0) ? cols : data.getColumnCount(), filter.getColumnCount()); assertEquals((rows > 0) ? rows : data.getRowCount(), filter.getRowCount()); for (int i = 0; i < expected.length; i++) { int col = i % filter.getColumnCount(); int row = i / filter.getColumnCount(); assertEquals(expected[i], ((Number) filter.get(col, row)).doubleValue(), DELTA); } } private void assertIdentity(DataSource data) { assertFiltered(data, data.getColumnCount(), data.getRowCount(), new double[] { ((Number) data.get(0, 0)).doubleValue(), ((Number) data.get(1, 0)).doubleValue(), ((Number) data.get(2, 0)).doubleValue(), ((Number) data.get(0, 1)).doubleValue(), ((Number) data.get(1, 1)).doubleValue(), ((Number) data.get(2, 1)).doubleValue(), ((Number) data.get(0, 2)).doubleValue(), ((Number) data.get(1, 2)).doubleValue(), ((Number) data.get(2, 2)).doubleValue(), }); } @Test public void testIdentity() { assertIdentity(dataEmpty); assertIdentity(dataHorizontal); assertIdentity(dataVertical); assertIdentity(dataDiagonal); } @Test public void testHorizontal() { assertFiltered(dataEmpty, 1, 0, new double[] { 0.0/3.0, 0.0/3.0, 0.0/3.0 }); assertFiltered(dataHorizontal, 1, 0, new double[] { 0.0/3.0, 3.0/3.0, 0.0/3.0 }); assertFiltered(dataVertical, 1, 0, new double[] { 1.0/3.0, 1.0/3.0, 1.0/3.0 }); assertFiltered(dataDiagonal, 1, 0, new double[] { 1.0/3.0, 1.0/3.0, 1.0/3.0 }); } @Test public void testVertical() { assertFiltered(dataEmpty, 0, 1, new double[] { 0.0/3.0, 0.0/3.0, 0.0/3.0 }); assertFiltered(dataHorizontal, 0, 1, new double[] { 1.0/3.0, 1.0/3.0, 1.0/3.0 }); assertFiltered(dataVertical, 0, 1, new double[] { 0.0/3.0, 3.0/3.0, 0.0/3.0 }); assertFiltered(dataDiagonal, 0, 1, new double[] { 1.0/3.0, 1.0/3.0, 1.0/3.0 }); } @Test public void testResize() { assertFiltered(dataEmpty, 0, 1, new double[] { 0.0/9.0 }); assertFiltered(dataHorizontal, 1, 1, new double[] { 3.0/9.0 }); assertFiltered(dataVertical, 1, 1, new double[] { 3.0/9.0 }); assertFiltered(dataDiagonal, 1, 1, new double[] { 3.0/9.0 }); } @Test public void testSerialization() throws IOException, ClassNotFoundException { Filter original = new Resize(dataDiagonal, 2, 2); Filter deserialized = TestUtils.serializeAndDeserialize(original); // Test metadata assertEquals(original.getMode(), deserialized.getMode()); assertArrayEquals(original.getColumnTypes(), deserialized.getColumnTypes()); assertEquals(original.getColumnCount(), deserialized.getColumnCount()); assertEquals(original.getRowCount(), deserialized.getRowCount()); // Test values for (int row = 0; row < original.getRowCount(); row++) { for (int col = 0; col < original.getColumnCount(); col++) { assertEquals( String.format("Wrong data at col=%d, row=%d.", col, row), original.get(col, row), deserialized.get(col, row)); } } // Test statistics String[] stats = { Statistics.N, Statistics.SUM, Statistics.MEAN, Statistics.VARIANCE }; for (String stat : stats) { assertEquals( original.getStatistics().get(stat), deserialized.getStatistics().get(stat), DELTA); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/filters/package-info.java000077500000000000000000000017361267060725100305030ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.data.filters} package. */ package de.erichseifert.gral.data.filters; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/package-info.java000077500000000000000000000017161267060725100270310ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.data} package. */ package de.erichseifert.gral.data; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/statistics/000077500000000000000000000000001267060725100260245ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/statistics/HistogramTest.java000066400000000000000000000100201267060725100314550ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.statistics; import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.graphics.Orientation; public class HistogramTest { private DataTable table; @Before @SuppressWarnings("unchecked") public void setUp() { table = new DataTable(Integer.class, Integer.class); table.add(1, 1); // 0 table.add(1, 3); // 1 table.add(2, 2); // 2 table.add(2, 2); // 3 table.add(5, 4); // 4 table.add(1, 2); // 5 table.add(2, 9); // 6 table.add(4, 1); // 7 } @Test public void testCreate() { Histogram histogram = new Histogram1D(table, Orientation.VERTICAL, 4); assertEquals(table.getColumnCount(), histogram.getColumnCount()); assertEquals(4, histogram.getRowCount()); } @Test public void testEqualBreaks() { Histogram histogram = new Histogram1D(table, Orientation.VERTICAL, 4); long[] expected = { 3L, 5L, // 1.0-2.0, 1.0-3.0 3L, 2L, // 2.0-3.0, 3.0-5.0 0L, 0L, // 3.0-4.0, 5.0-7.0 1L, 0L // 4.0-5.0, 7.0-9.0 }; int i = 0; while (i < expected.length) { int col = i%2, row = i/2; assertEquals("column " + (col+1)+", row " + (row+1)+":", expected[i], histogram.get(col, row)); i++; } } @Test public void testCustomBreaks() { Histogram histogram = new Histogram1D(table, Orientation.VERTICAL, new Number[][] {{1.0, 2.0, 3.0, 4.0, 5.0}, {1.0, 3.0, 5.0, 7.0, 9.0}}); long[] expected = { 3L, 5L, // 1.0-2.0, 1.0-3.0 3L, 2L, // 2.0-3.0, 3.0-5.0 0L, 0L, // 3.0-4.0, 5.0-7.0 1L, 0L // 4.0-5.0, 7.0-9.0 }; int i = 0; while (i < expected.length) { int col = i%2, row = i/2; assertEquals("column " + (col+1)+", row " + (row+1)+":", expected[i], histogram.get(col, row)); i++; } } @Test public void testGet() { Histogram histogram = new Histogram1D(table, Orientation.VERTICAL, 4); assertEquals(3L, histogram.get(0, 0)); assertEquals(5L, histogram.get(1, 0)); assertEquals(3L, histogram.get(0, 1)); assertEquals(2L, histogram.get(1, 1)); assertEquals(0L, histogram.get(0, 2)); assertEquals(0L, histogram.get(1, 2)); assertEquals(1L, histogram.get(0, 3)); assertEquals(0L, histogram.get(1, 3)); } @Test public void testCellLimits() { Histogram1D histogram = new Histogram1D(table, Orientation.VERTICAL, 4); Number[][] expected = new Number[][] {{1.0, 2.0, 3.0, 4.0, 5.0}, {1.0, 3.0, 5.0, 7.0, 9.0}}; for (int colIndex = 0; colIndex < histogram.getColumnCount(); colIndex++) { Number[] col = expected[colIndex]; for (int rowIndex = 0; rowIndex < col.length-1; rowIndex++) { Number[] cellLimits = histogram.getCellLimits(colIndex, rowIndex); assertEquals(col[rowIndex], cellLimits[0]); assertEquals(col[rowIndex + 1], cellLimits[1]); } } } @Test public void testDataAdd() { Histogram histogram = new Histogram1D(table, Orientation.VERTICAL, 4); assertEquals(3L, histogram.get(0, 0)); table.add(1, 1); assertEquals(4L, histogram.get(0, 0)); } @Test public void testDataRemove() { Histogram histogram = new Histogram1D(table, Orientation.VERTICAL, 4); assertEquals(3L, histogram.get(0, 0)); table.remove(0); assertEquals(2L, histogram.get(0, 0)); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/statistics/StatisticsTest.java000066400000000000000000000301421267060725100316610ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.statistics; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.graphics.Orientation; public class StatisticsTest { private static final double DELTA = 1e-10; private DataTable table; private Statistics stats; @Before @SuppressWarnings("unchecked") public void setUp() { table = new DataTable(Integer.class, Integer.class, Integer.class); table.add(0, 1, 2); // 0 table.add(1, 3, 3); // 1 table.add(2, 2, 4); // 2 table.add(2, 2, 5); // 3 table.add(5, 4, 6); // 4 table.add(1, 2, 7); // 5 table.add(2, 9, 8); // 6 table.add(4, 1, 9); // 7 stats = table.getStatistics(); } @Test public void testSum() { assertEquals(85.0, stats.get(Statistics.SUM), DELTA); // Horizontal assertEquals( 3.0, stats.get(Statistics.SUM, Orientation.HORIZONTAL, 0), DELTA); assertEquals( 7.0, stats.get(Statistics.SUM, Orientation.HORIZONTAL, 1), DELTA); assertEquals( 8.0, stats.get(Statistics.SUM, Orientation.HORIZONTAL, 2), DELTA); // Vertical assertEquals(17.0, stats.get(Statistics.SUM, Orientation.VERTICAL, 0), DELTA); assertEquals(24.0, stats.get(Statistics.SUM, Orientation.VERTICAL, 1), DELTA); assertEquals(44.0, stats.get(Statistics.SUM, Orientation.VERTICAL, 2), DELTA); } @Test public void testMean() { assertEquals(85.0/24.0, stats.get(Statistics.MEAN), DELTA); // Horizontal assertEquals( 3.0/ 3.0, stats.get(Statistics.MEAN, Orientation.HORIZONTAL, 0), DELTA); assertEquals( 7.0/ 3.0, stats.get(Statistics.MEAN, Orientation.HORIZONTAL, 1), DELTA); assertEquals( 8.0/ 3.0, stats.get(Statistics.MEAN, Orientation.HORIZONTAL, 2), DELTA); // Vertical assertEquals(17.0/ 8.0, stats.get(Statistics.MEAN, Orientation.VERTICAL, 0), DELTA); assertEquals(24.0/ 8.0, stats.get(Statistics.MEAN, Orientation.VERTICAL, 1), DELTA); assertEquals(44.0/ 8.0, stats.get(Statistics.MEAN, Orientation.VERTICAL, 2), DELTA); } @Test public void testMin() { assertEquals(0.0, stats.get(Statistics.MIN), DELTA); // Horizontal assertEquals(0.0, stats.get(Statistics.MIN, Orientation.HORIZONTAL, 0), DELTA); assertEquals(1.0, stats.get(Statistics.MIN, Orientation.HORIZONTAL, 1), DELTA); assertEquals(2.0, stats.get(Statistics.MIN, Orientation.HORIZONTAL, 2), DELTA); // Vertical assertEquals(0.0, stats.get(Statistics.MIN, Orientation.VERTICAL, 0), DELTA); assertEquals(1.0, stats.get(Statistics.MIN, Orientation.VERTICAL, 1), DELTA); assertEquals(2.0, stats.get(Statistics.MIN, Orientation.VERTICAL, 2), DELTA); } @Test public void testMax() { assertEquals(9.0, stats.get(Statistics.MAX), DELTA); // Horizontal assertEquals(2.0, stats.get(Statistics.MAX, Orientation.HORIZONTAL, 0), DELTA); assertEquals(3.0, stats.get(Statistics.MAX, Orientation.HORIZONTAL, 1), DELTA); assertEquals(4.0, stats.get(Statistics.MAX, Orientation.HORIZONTAL, 2), DELTA); // Vertical assertEquals(5.0, stats.get(Statistics.MAX, Orientation.VERTICAL, 0), DELTA); assertEquals(9.0, stats.get(Statistics.MAX, Orientation.VERTICAL, 1), DELTA); assertEquals(9.0, stats.get(Statistics.MAX, Orientation.VERTICAL, 2), DELTA); } @Test public void testN() { assertEquals(24.0, stats.get(Statistics.N), DELTA); // Horizontal assertEquals( 3.0, stats.get(Statistics.N, Orientation.HORIZONTAL, 0), DELTA); assertEquals( 3.0, stats.get(Statistics.N, Orientation.HORIZONTAL, 1), DELTA); assertEquals( 3.0, stats.get(Statistics.N, Orientation.HORIZONTAL, 2), DELTA); // Vertical assertEquals( 8.0, stats.get(Statistics.N, Orientation.VERTICAL, 0), DELTA); assertEquals( 8.0, stats.get(Statistics.N, Orientation.VERTICAL, 1), DELTA); assertEquals( 8.0, stats.get(Statistics.N, Orientation.VERTICAL, 2), DELTA); } @Test public void testSumOfDiffSquares() { assertEquals(157.95833333333337, stats.get(Statistics.SUM_OF_DIFF_SQUARES), DELTA); // Horizontal assertEquals( 2.00000000000000, stats.get(Statistics.SUM_OF_DIFF_SQUARES, Orientation.HORIZONTAL, 0), DELTA); assertEquals( 2.66666666666666, stats.get(Statistics.SUM_OF_DIFF_SQUARES, Orientation.HORIZONTAL, 1), DELTA); assertEquals( 2.66666666666666, stats.get(Statistics.SUM_OF_DIFF_SQUARES, Orientation.HORIZONTAL, 2), DELTA); // Vertical assertEquals( 18.87500000000000, stats.get(Statistics.SUM_OF_DIFF_SQUARES, Orientation.VERTICAL, 0), DELTA); assertEquals( 48.00000000000000, stats.get(Statistics.SUM_OF_DIFF_SQUARES, Orientation.VERTICAL, 1), DELTA); assertEquals( 42.00000000000000, stats.get(Statistics.SUM_OF_DIFF_SQUARES, Orientation.VERTICAL, 2), DELTA); } @Test public void testSumOfDiffCubics() { assertEquals(340.50347222222221, stats.get(Statistics.SUM_OF_DIFF_CUBICS), DELTA); // Horizontal assertEquals( 0.00000000000000, stats.get(Statistics.SUM_OF_DIFF_CUBICS, Orientation.HORIZONTAL, 0), DELTA); assertEquals( -1.77777777777777, stats.get(Statistics.SUM_OF_DIFF_CUBICS, Orientation.HORIZONTAL, 1), DELTA); assertEquals( 1.77777777777777, stats.get(Statistics.SUM_OF_DIFF_CUBICS, Orientation.HORIZONTAL, 2), DELTA); // Vertical assertEquals( 17.90625000000000, stats.get(Statistics.SUM_OF_DIFF_CUBICS, Orientation.VERTICAL, 0), DELTA); assertEquals(198.00000000000000, stats.get(Statistics.SUM_OF_DIFF_CUBICS, Orientation.VERTICAL, 1), DELTA); assertEquals( 0.00000000000000, stats.get(Statistics.SUM_OF_DIFF_CUBICS, Orientation.VERTICAL, 2), DELTA); } @Test public void testSumOfDiffQuads() { assertEquals(2723.1039496527756, stats.get(Statistics.SUM_OF_DIFF_QUADS), DELTA); // Horizontal assertEquals( 2.0000000000000, stats.get(Statistics.SUM_OF_DIFF_QUADS, Orientation.HORIZONTAL, 0), DELTA); assertEquals( 3.5555555555555, stats.get(Statistics.SUM_OF_DIFF_QUADS, Orientation.HORIZONTAL, 1), DELTA); assertEquals( 3.5555555555555, stats.get(Statistics.SUM_OF_DIFF_QUADS, Orientation.HORIZONTAL, 2), DELTA); // Vertical assertEquals( 104.2753906250000, stats.get(Statistics.SUM_OF_DIFF_QUADS, Orientation.VERTICAL, 0), DELTA); assertEquals(1332.0000000000000, stats.get(Statistics.SUM_OF_DIFF_QUADS, Orientation.VERTICAL, 1), DELTA); assertEquals( 388.5000000000000, stats.get(Statistics.SUM_OF_DIFF_QUADS, Orientation.VERTICAL, 2), DELTA); } /** * Tests skewness of a table, of its rows, and its columns for correctness. * The results of R "moments" package are used for validation. */ @Test public void testSkewness() { assertEquals( -2.1597406540506, stats.get(Statistics.SKEWNESS), DELTA); // Horizontal assertEquals( -3.0000000000000, stats.get(Statistics.SKEWNESS, Orientation.HORIZONTAL, 0), DELTA); assertEquals( -3.7071067811865, stats.get(Statistics.SKEWNESS, Orientation.HORIZONTAL, 1), DELTA); assertEquals( -2.2928932188134, stats.get(Statistics.SKEWNESS, Orientation.HORIZONTAL, 2), DELTA); // Vertical assertEquals( -2.3823830637406, stats.get(Statistics.SKEWNESS, Orientation.VERTICAL, 0), DELTA); assertEquals( -1.3159758018366, stats.get(Statistics.SKEWNESS, Orientation.VERTICAL, 1), DELTA); assertEquals( -3.0000000000000, stats.get(Statistics.SKEWNESS, Orientation.VERTICAL, 2), DELTA); } /** * Tests kurtosis of a table, of its rows, and its columns for correctness. * The results of R "moments" package are used for validation. */ @Test public void testKurtosis() { assertEquals( -0.3806690393420, stats.get(Statistics.KURTOSIS), DELTA); // Horizontal assertEquals( -1.5000000000000, stats.get(Statistics.KURTOSIS, Orientation.HORIZONTAL, 0), DELTA); assertEquals( -1.5000000000000, stats.get(Statistics.KURTOSIS, Orientation.HORIZONTAL, 1), DELTA); assertEquals( -1.5000000000000, stats.get(Statistics.KURTOSIS, Orientation.HORIZONTAL, 2), DELTA); // Vertical assertEquals( -0.6584798912328, stats.get(Statistics.KURTOSIS, Orientation.VERTICAL, 0), DELTA); assertEquals( 1.6250000000000, stats.get(Statistics.KURTOSIS, Orientation.VERTICAL, 1), DELTA); assertEquals( -1.2380952380952, stats.get(Statistics.KURTOSIS, Orientation.VERTICAL, 2), DELTA); } @Test public void testQuartiles() { // Quartile 1 assertEquals(2.00, stats.get(Statistics.QUARTILE_1), DELTA); // Horizontal assertEquals(0.50, stats.get(Statistics.QUARTILE_1, Orientation.HORIZONTAL, 0), DELTA); assertEquals(2.00, stats.get(Statistics.QUARTILE_1, Orientation.HORIZONTAL, 1), DELTA); assertEquals(2.00, stats.get(Statistics.QUARTILE_1, Orientation.HORIZONTAL, 2), DELTA); // Vertical assertEquals(1.00, stats.get(Statistics.QUARTILE_1, Orientation.VERTICAL, 0), DELTA); assertEquals(1.75, stats.get(Statistics.QUARTILE_1, Orientation.VERTICAL, 1), DELTA); assertEquals(3.75, stats.get(Statistics.QUARTILE_1, Orientation.VERTICAL, 2), DELTA); // Quartile 2 assertEquals(2.50, stats.get(Statistics.QUARTILE_2), DELTA); // Horizontal assertEquals(1.00, stats.get(Statistics.QUARTILE_2, Orientation.HORIZONTAL, 0), DELTA); assertEquals(3.00, stats.get(Statistics.QUARTILE_2, Orientation.HORIZONTAL, 1), DELTA); assertEquals(2.00, stats.get(Statistics.QUARTILE_2, Orientation.HORIZONTAL, 2), DELTA); // Vertical assertEquals(2.00, stats.get(Statistics.QUARTILE_2, Orientation.VERTICAL, 0), DELTA); assertEquals(2.00, stats.get(Statistics.QUARTILE_2, Orientation.VERTICAL, 1), DELTA); assertEquals(5.50, stats.get(Statistics.QUARTILE_2, Orientation.VERTICAL, 2), DELTA); // Quartile 3 assertEquals(5.00, stats.get(Statistics.QUARTILE_3), DELTA); // Horizontal assertEquals(1.50, stats.get(Statistics.QUARTILE_3, Orientation.HORIZONTAL, 0), DELTA); assertEquals(3.00, stats.get(Statistics.QUARTILE_3, Orientation.HORIZONTAL, 1), DELTA); assertEquals(3.00, stats.get(Statistics.QUARTILE_3, Orientation.HORIZONTAL, 2), DELTA); // Vertical assertEquals(2.50, stats.get(Statistics.QUARTILE_3, Orientation.VERTICAL, 0), DELTA); assertEquals(3.25, stats.get(Statistics.QUARTILE_3, Orientation.VERTICAL, 1), DELTA); assertEquals(7.25, stats.get(Statistics.QUARTILE_3, Orientation.VERTICAL, 2), DELTA); // Median == Quartile 2 assertEquals(stats.get(Statistics.MEDIAN), stats.get(Statistics.QUARTILE_2), DELTA); } @Test public void testNonExistant() { assertTrue(Double.isNaN(stats.get("foobar"))); } // FIXME Change test to cause invocation of dataUpdate only @Test public void testDataUpdate() { // Modify table data to cause update table.add(24, -11, 42); table.set(1, 1, -42); // Check statistics assertEquals( 27.0, stats.get(Statistics.N), DELTA); assertEquals(-42.0, stats.get(Statistics.MIN), DELTA); assertEquals( 42.0, stats.get(Statistics.MAX), DELTA); assertEquals( 95.0, stats.get(Statistics.SUM), DELTA); // Horizontal assertEquals( 3.0, stats.get(Statistics.N, Orientation.HORIZONTAL, 1), DELTA); assertEquals(-42.0, stats.get(Statistics.MIN, Orientation.HORIZONTAL, 1), DELTA); assertEquals( 3.0, stats.get(Statistics.MAX, Orientation.HORIZONTAL, 1), DELTA); assertEquals(-38.0, stats.get(Statistics.SUM, Orientation.HORIZONTAL, 1), DELTA); // Vertical assertEquals( 9.0, stats.get(Statistics.N, Orientation.VERTICAL, 1), DELTA); assertEquals(-42.0, stats.get(Statistics.MIN, Orientation.VERTICAL, 1), DELTA); assertEquals( 9.0, stats.get(Statistics.MAX, Orientation.VERTICAL, 1), DELTA); assertEquals(-32.0, stats.get(Statistics.SUM, Orientation.VERTICAL, 1), DELTA); } // TODO Add tests for dataAdded and dataRemoved } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/statistics/StatisticsTests.java000066400000000000000000000021331267060725100320430ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.data.statistics; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ StatisticsTest.class, HistogramTest.class }) public class StatisticsTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/data/statistics/package-info.java000077500000000000000000000017441267060725100312240ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.data.statistics} package. */ package de.erichseifert.gral.data.statistics; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/000077500000000000000000000000001267060725100245215ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/ContainerTest.java000066400000000000000000000173561267060725100301620ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.awt.geom.Dimension2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import de.erichseifert.gral.graphics.layout.EdgeLayout; import de.erichseifert.gral.graphics.layout.Layout; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; public class ContainerTest { private DrawableContainer container; private static final class MockDrawable extends AbstractDrawable { /** Version id for serialization. */ private static final long serialVersionUID = 1802598562530415902L; private boolean isDrawn; private final Dimension2D preferredSize = new de.erichseifert.gral.graphics.Dimension2D.Double(); public void draw(DrawingContext context) { isDrawn = true; } @Override public Dimension2D getPreferredSize() { return preferredSize; } } @Before public void setUp() { container = new DrawableContainer(); } @Test public void testCreate() { assertEquals(new Rectangle2D.Double(), container.getBounds()); assertEquals(new de.erichseifert.gral.graphics.Dimension2D.Double(), container.getPreferredSize()); assertEquals(new Insets2D.Double(), container.getInsets()); assertEquals(null, container.getLayout()); } @Test public void testAdd() { assertEquals(0, container.size()); Drawable d = new MockDrawable(); container.add(d); assertEquals(1, container.size()); } @Test(expected=IllegalArgumentException.class) public void testAddSelf() { container.add(container); } @Test public void testContains() { // TODO: Allow null values? assertFalse(container.contains(container)); Drawable d1 = new MockDrawable(); assertFalse(container.contains(d1)); container.add(d1); assertTrue(container.contains(d1)); Drawable d2 = new MockDrawable(); container.add(d2); assertTrue(container.contains(d1)); assertTrue(container.contains(d2)); container.remove(d1); assertFalse(container.contains(d1)); assertTrue(container.contains(d2)); } @Test public void testConstraints() { Drawable d = new MockDrawable(); container.add(d, "foo"); assertEquals("foo", container.getConstraints(d)); } @Test public void testRemove() { assertEquals(0, container.size()); Drawable d = new MockDrawable(); container.add(d); assertEquals(1, container.size()); container.remove(d); assertEquals(0, container.size()); } @Test public void testDraw() { Drawable d = new MockDrawable(); container.add(d); for (Drawable c : container) { assertFalse(((MockDrawable) c).isDrawn); } container.draw(null); for (Drawable c : container) { assertTrue(((MockDrawable) c).isDrawn); } } @Test public void testInsets() { assertEquals(new Insets2D.Double(), container.getInsets()); Insets2D insets = new Insets2D.Double(1.2, 3.4, 5.6, 7.8); container.setInsets(insets); assertEquals(insets, container.getInsets()); container.setInsets(insets); assertEquals(insets, container.getInsets()); } @Test public void testLayout() { assertEquals(null, container.getLayout()); Layout layout = new EdgeLayout(); container.setLayout(layout); assertEquals(layout, container.getLayout()); } @Test public void testGetDrawableAt() { Point2D[] points = { new Point2D.Double(-0.5, -0.5), new Point2D.Double(0.0, 0.0), new Point2D.Double(0.5, 0.5), new Point2D.Double(1.0, 1.0), new Point2D.Double(1.5, 1.5), new Point2D.Double(2.0, 2.0) }; for (Point2D point : points) { assertEquals(Collections.emptyList(), container.getDrawablesAt(point)); } MockDrawable d = new MockDrawable(); d.setBounds(0.0, 0.0, 1.0, 1.0); container.add(d); DrawableContainer nestedContainer = new DrawableContainer(); nestedContainer.setBounds(1.0, 1.0, 1.0, 1.0); container.add(nestedContainer); MockDrawable nestedDrawable = new MockDrawable(); nestedDrawable.setBounds(1.5, 1.5, 0.5, 0.5); nestedContainer.add(nestedDrawable); List dList = new ArrayList(1); dList.add(d); List dPlusNestedContainerList = new ArrayList(2); dPlusNestedContainerList.add(nestedContainer); dPlusNestedContainerList.add(d); List nestedContainerList = new ArrayList(1); nestedContainerList.add(nestedContainer); List nestedDrawableList = new ArrayList(1); nestedDrawableList.add(nestedDrawable); nestedDrawableList.add(nestedContainer); List[] expected = { Collections.emptyList(), dList, dList, nestedContainerList, nestedDrawableList, Collections.emptyList() }; for (int i = 0; i < points.length; i++) { assertEquals(String.format("Unexpected result at %s:", points[i]), expected[i], container.getDrawablesAt(points[i])); } } @Test public void testGetDrawables() { assertNotNull(container.getDrawables()); assertTrue(container.getDrawables().isEmpty()); Drawable d1 = new MockDrawable(); container.add(d1); List drawables = container.getDrawables(); assertEquals(1, drawables.size()); assertEquals(d1, drawables.get(0)); Drawable d2 = new MockDrawable(); container.add(d2); drawables = container.getDrawables(); assertEquals(2, drawables.size()); assertEquals(d1, drawables.get(0)); assertEquals(d2, drawables.get(1)); container.remove(d1); drawables = container.getDrawables(); assertEquals(1, drawables.size()); assertEquals(d2, drawables.get(0)); } @Test public void testGetDrawableAtOrder() { // Create two overlapping drawables MockDrawable d1 = new MockDrawable(); MockDrawable d2 = new MockDrawable(); Rectangle2D bounds = new Rectangle2D.Double(0.0, 0.0, 1.0, 1.0); d1.setBounds(bounds); d2.setBounds(bounds); container.add(d1); container.add(d2); List resultList = new ArrayList(2); resultList.add(d2); resultList.add(d1); Point2D point = new Point2D.Double(bounds.getCenterX(), bounds.getCenterY()); assertEquals(resultList, container.getDrawablesAt(point)); // Clear container container.remove(d1); container.remove(d2); assertEquals(0, container.size()); // Re-add drawables in inverse order container.add(d2); container.add(d1); Collections.reverse(resultList); assertEquals(resultList, container.getDrawablesAt(point)); } @Test public void testSerialization() throws IOException, ClassNotFoundException { DrawableContainer original = container; DrawableContainer deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.size(), deserialized.size()); assertEquals(original.getPreferredSize(), deserialized.getPreferredSize()); assertEquals(original.getInsets(), deserialized.getInsets()); assertEquals(original.getLayout(), deserialized.getLayout()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/Dimension2DTest.java000066400000000000000000000061501267060725100303410ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; import java.awt.geom.Dimension2D; import java.io.IOException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import de.erichseifert.gral.TestUtils; import org.junit.Test; public class Dimension2DTest { public static final double DELTA = 1e-15; @Test public void testCreate() { Dimension2D dim; // Standard constructor dim = new de.erichseifert.gral.graphics.Dimension2D.Double(); assertEquals(0.0, dim.getWidth(), DELTA); assertEquals(0.0, dim.getHeight(), DELTA); // Constructor with width and height dim = new de.erichseifert.gral.graphics.Dimension2D.Double(1.0, 2.0); assertEquals(1.0, dim.getWidth(), DELTA); assertEquals(2.0, dim.getHeight(), DELTA); } @Test public void testChange() { Dimension2D dim = new de.erichseifert.gral.graphics.Dimension2D.Double(1.0, 2.0); Dimension2D dim2 = new de.erichseifert.gral.graphics.Dimension2D.Double(3.0, 4.0); // setSize(Dimension2D) dim.setSize(dim2); assertEquals(dim2.getWidth(), dim.getWidth(), DELTA); assertEquals(dim2.getHeight(), dim.getHeight(), DELTA); // setSize(double, double) dim.setSize(5.0, 6.0); assertEquals(5.0, dim.getWidth(), DELTA); assertEquals(6.0, dim.getHeight(), DELTA); } @Test public void testToString() { Dimension2D dim = new de.erichseifert.gral.graphics.Dimension2D.Double(1.0, 2.0); assertEquals(dim.getClass().getName() + "[width=1.000000, height=2.000000]", dim.toString()); } @Test public void testEquality() { Dimension2D dim1 = new de.erichseifert.gral.graphics.Dimension2D.Double(1.0, 2.0); Dimension2D dim2 = new de.erichseifert.gral.graphics.Dimension2D.Double(1.0, 2.0); // Equals assertTrue(dim1.equals(dim2)); assertFalse(dim1.equals(null)); assertFalse(dim2.equals(null)); // Hash code assertEquals(dim1.hashCode(), dim2.hashCode()); } @Test public void testSerialization() throws IOException, ClassNotFoundException { Dimension2D original = new de.erichseifert.gral.graphics.Dimension2D.Double(1.2, 3.4); Dimension2D deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getWidth(), deserialized.getWidth(), DELTA); assertEquals(original.getHeight(), deserialized.getHeight(), DELTA); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/DrawableTest.java000066400000000000000000000073371267060725100277570ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; import java.awt.geom.Dimension2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import de.erichseifert.gral.TestUtils; import org.junit.Before; import org.junit.Test; public class DrawableTest { private static final double DELTA = TestUtils.DELTA; private static final Rectangle2D BOUNDS = new Rectangle2D.Double(1.2, 3.4, 56.7, 89.0); private static final Dimension2D PREFERRED_SIZE = new de.erichseifert.gral.graphics.Dimension2D.Double(12.3, 45.6); private MockDrawable drawable; private static final class MockDrawable extends AbstractDrawable { /** Version id for serialization. */ private static final long serialVersionUID = 6148480638542875770L; private boolean isDrawn; private final Dimension2D preferredSize = new de.erichseifert.gral.graphics.Dimension2D.Double(); public void draw(DrawingContext context) { isDrawn = true; } @Override public Dimension2D getPreferredSize() { return preferredSize; } } @Before public void setUp() { drawable = new MockDrawable(); } @Test public void testCreate() { assertEquals(new Rectangle2D.Double(), drawable.getBounds()); assertEquals(drawable.getBounds().getX(), drawable.getX(), DELTA); assertEquals(drawable.getBounds().getY(), drawable.getY(), DELTA); assertEquals(drawable.getBounds().getWidth(), drawable.getWidth(), DELTA); assertEquals(drawable.getBounds().getHeight(), drawable.getHeight(), DELTA); assertEquals(new de.erichseifert.gral.graphics.Dimension2D.Double(), drawable.getPreferredSize()); } @Test public void testBounds() { assertEquals(new Rectangle2D.Double(), drawable.getBounds()); drawable.setBounds(BOUNDS); assertEquals(BOUNDS, drawable.getBounds()); } @Test public void testPreferredSize() { assertEquals(new de.erichseifert.gral.graphics.Dimension2D.Double(), drawable.getPreferredSize()); drawable.preferredSize.setSize(PREFERRED_SIZE); assertEquals(PREFERRED_SIZE, drawable.getPreferredSize()); } @Test public void testDraw() { assertFalse(drawable.isDrawn); drawable.draw(null); assertTrue(drawable.isDrawn); } @Test public void testSetPosition() { drawable.setPosition(4.0, 2.0); assertEquals(4.0, drawable.getBounds().getX(), DELTA); assertEquals(2.0, drawable.getBounds().getY(), DELTA); drawable.setPosition(-4.0, -2.0); assertEquals(-4.0, drawable.getBounds().getX(), DELTA); assertEquals(-2.0, drawable.getBounds().getY(), DELTA); } @Test public void testSerialization() throws IOException, ClassNotFoundException { MockDrawable original = drawable; MockDrawable deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getBounds(), deserialized.getBounds()); assertEquals(original.getPreferredSize(), deserialized.getPreferredSize()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/DrawingContextTest.java000066400000000000000000000036761267060725100312000ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; import static org.junit.Assert.assertEquals; import java.awt.Graphics2D; import java.awt.Image; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.graphics.DrawingContext.Quality; import de.erichseifert.gral.graphics.DrawingContext.Target; public class DrawingContextTest { private Image testImage; private Graphics2D graphics; private DrawingContext context; @Before public void setUp() { testImage = TestUtils.createTestImage(); graphics = (Graphics2D) testImage.getGraphics(); context = new DrawingContext(graphics); } @Test public void testCreateDefault() { assertEquals(graphics, context.getGraphics()); assertEquals(Quality.NORMAL, context.getQuality()); assertEquals(Target.BITMAP, context.getTarget()); } @Test public void testCreateParams() { DrawingContext context = new DrawingContext(graphics, Quality.QUALITY, Target.VECTOR); assertEquals(graphics, context.getGraphics()); assertEquals(Quality.QUALITY, context.getQuality()); assertEquals(Target.VECTOR, context.getTarget()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/GraphicsTests.java000066400000000000000000000024071267060725100301520ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; import de.erichseifert.gral.graphics.layout.LayoutTests; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ // Tests for subpackages LayoutTests.class, // Tests for classes DrawingContextTest.class, DrawableTest.class, ContainerTest.class, LabelTest.class, Dimension2DTest.class, Insets2DTest.class }) public class GraphicsTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/Insets2DTest.java000066400000000000000000000100601267060725100276540ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; import java.io.IOException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import de.erichseifert.gral.TestUtils; import org.junit.Test; public class Insets2DTest { public static final double DELTA = TestUtils.DELTA; @Test public void testCreate() { Insets2D insets; // Standard constructor insets = new Insets2D.Double(); assertEquals(0.0, insets.getTop(), DELTA); assertEquals(0.0, insets.getLeft(), DELTA); assertEquals(0.0, insets.getBottom(), DELTA); assertEquals(0.0, insets.getRight(), DELTA); // Constructor with a single value for all sides insets = new Insets2D.Double(1.0); assertEquals(1.0, insets.getTop(), DELTA); assertEquals(1.0, insets.getLeft(), DELTA); assertEquals(1.0, insets.getBottom(), DELTA); assertEquals(1.0, insets.getRight(), DELTA); // Constructor with four values insets = new Insets2D.Double(1.0, 2.0, 3.0, 4.0); assertEquals(1.0, insets.getTop(), DELTA); assertEquals(2.0, insets.getLeft(), DELTA); assertEquals(3.0, insets.getBottom(), DELTA); assertEquals(4.0, insets.getRight(), DELTA); } @Test public void testChange() { Insets2D insets = new Insets2D.Double(1.0, 2.0, 3.0, 4.0); Insets2D insets2 = new Insets2D.Double(10.0, 20.0, 30.0, 40.0); // setInsets(Insets2D) insets.setInsets(insets2); assertEquals(insets2.getTop(), insets.getTop(), DELTA); assertEquals(insets2.getLeft(), insets.getLeft(), DELTA); assertEquals(insets2.getBottom(), insets.getBottom(), DELTA); assertEquals(insets2.getRight(), insets.getRight(), DELTA); insets.setInsets(null); assertEquals(insets2.getTop(), insets.getTop(), DELTA); assertEquals(insets2.getLeft(), insets.getLeft(), DELTA); assertEquals(insets2.getBottom(), insets.getBottom(), DELTA); assertEquals(insets2.getRight(), insets.getRight(), DELTA); // setSize(double, double, double, double) insets.setInsets(5.0, 6.0, 7.0, 8.0); assertEquals(5.0, insets.getTop(), DELTA); assertEquals(6.0, insets.getLeft(), DELTA); assertEquals(7.0, insets.getBottom(), DELTA); assertEquals(8.0, insets.getRight(), DELTA); } @Test public void testToString() { Insets2D insets = new Insets2D.Double(1.0, 2.0, 3.0, 4.0); assertEquals(insets.getClass().getName() + "[top=1.000000, left=2.000000, bottom=3.000000, right=4.000000]", insets.toString()); } @Test public void testEquality() { Insets2D insets1 = new Insets2D.Double(1.0, 2.0, 3.0, 4.0); Insets2D insets2 = new Insets2D.Double(1.0, 2.0, 3.0, 4.0); // Equals assertTrue(insets1.equals(insets2)); assertFalse(insets1.equals(null)); assertFalse(insets2.equals(null)); // Hash code assertEquals(insets1.hashCode(), insets2.hashCode()); } @Test public void testSerialization() throws IOException, ClassNotFoundException { Insets2D original = new Insets2D.Double(1.0, 2.0, 3.0, 4.0); Insets2D deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getTop(), deserialized.getTop(), DELTA); assertEquals(original.getLeft(), deserialized.getLeft(), DELTA); assertEquals(original.getBottom(), deserialized.getBottom(), DELTA); assertEquals(original.getRight(), deserialized.getRight(), DELTA); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/LabelTest.java000066400000000000000000000101541267060725100272440ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; public class LabelTest { private static final double DELTA = TestUtils.DELTA; private static class MockLabel extends Label { /** Version id for serialization. */ private static final long serialVersionUID = 7291791651477766692L; public boolean isDrawn; public MockLabel() { super(); } public MockLabel(String text) { super(text); } @Override public void draw(DrawingContext context) { super.draw(context); isDrawn = true; } } @Before public void setUp() { } @Test public void testCreation() { Label empty = new MockLabel(); assertEquals("", empty.getText()); assertEquals(0.0, empty.getX(), DELTA); assertEquals(0.0, empty.getY(), DELTA); assertEquals(0.0, empty.getWidth(), DELTA); assertEquals(0.0, empty.getHeight(), DELTA); assertEquals(new Dimension2D.Double(), empty.getPreferredSize()); Label text = new MockLabel("foobar"); assertEquals("foobar", text.getText()); assertEquals(0.0, text.getX(), DELTA); assertEquals(0.0, text.getY(), DELTA); assertTrue(text.getPreferredSize().getWidth() > 0.0); assertTrue(text.getPreferredSize().getHeight() > 0.0); } @Test public void testSettings() { Label label = new MockLabel("foobar"); assertEquals(0.5, label.getAlignmentX(), DELTA); assertEquals(0.5, label.getAlignmentY(), DELTA); assertEquals(Color.BLACK, label.getColor()); assertEquals(Font.decode(null), label.getFont()); assertEquals(0.0, label.getRotation(), DELTA); // Set label.setColor(Color.RED); assertEquals(Color.RED, label.getColor()); } @Test public void testDraw() { MockLabel empty = new MockLabel(); MockLabel text = new MockLabel("foobar"); MockLabel rotated = new MockLabel("foobar"); rotated.setRotation(45.0); MockLabel[] labels = { empty, text, rotated }; for (MockLabel label : labels) { BufferedImage image = createTestImage(); label.setBounds(0.0, 0.0, image.getWidth(), image.getHeight()); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); label.draw(context); assertTrue(label.isDrawn); if (!label.getText().isEmpty()) { assertNotEmpty(image); } } } @Test public void testSerialization() throws IOException, ClassNotFoundException { Label original = new MockLabel("foobar"); Label deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getAlignmentX(), deserialized.getAlignmentX(), DELTA); assertEquals(original.getAlignmentY(), deserialized.getAlignmentY(), DELTA); assertEquals(original.getFont(), deserialized.getFont()); assertEquals(original.getRotation(), deserialized.getRotation(), DELTA); assertEquals(original.getColor(), deserialized.getColor()); assertEquals(original.getTextAlignment(), deserialized.getTextAlignment(), DELTA); assertEquals(original.isWordWrapEnabled(), deserialized.isWordWrapEnabled()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/layout/000077500000000000000000000000001267060725100260365ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/layout/AbstractLayoutTest.java000066400000000000000000000043401267060725100325030ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics.layout; import static org.junit.Assert.assertEquals; import java.awt.geom.Dimension2D; import java.io.IOException; import de.erichseifert.gral.graphics.Container; import org.junit.Test; import de.erichseifert.gral.TestUtils; public class AbstractLayoutTest { private static final double DELTA = 1e-15; private static final double GAP_H = 5.0; private static final double GAP_V = 10.0; private static class MockAbstractLayout extends AbstractLayout { private static final long serialVersionUID = 5812320021345698270L; public MockAbstractLayout(double gapX, double gapY) { super(gapX, gapY); } @Override public void layout(Container container) { } @Override public Dimension2D getPreferredSize(Container container) { return new de.erichseifert.gral.graphics.Dimension2D.Double(); } } @Test public void testCreate() { AbstractLayout gapped = new MockAbstractLayout(GAP_H, GAP_V); assertEquals(GAP_H, gapped.getGapX(), DELTA); assertEquals(GAP_V, gapped.getGapY(), DELTA); } @Test public void testSerialization() throws IOException, ClassNotFoundException { AbstractLayout original = new MockAbstractLayout(GAP_H, GAP_V); AbstractLayout deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getGapX(), deserialized.getGapX(), DELTA); assertEquals(original.getGapY(), deserialized.getGapY(), DELTA); } } AbstractOrientedLayoutTest.java000066400000000000000000000045631267060725100341250ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/layout/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics.layout; import static org.junit.Assert.assertEquals; import java.awt.geom.Dimension2D; import java.io.IOException; import de.erichseifert.gral.graphics.Container; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.graphics.Orientation; public class AbstractOrientedLayoutTest { private static final double DELTA = 1e-15; private static final double GAP_H = 5.0; private static final double GAP_V = 10.0; private static class MockAbstractOrientedLayout extends AbstractOrientedLayout { private static final long serialVersionUID = -1588960524707247633L; public MockAbstractOrientedLayout(Orientation orientation, double gapX, double gapY) { super(orientation, gapX, gapY); } @Override public void layout(Container container) { } @Override public Dimension2D getPreferredSize(Container container) { return new de.erichseifert.gral.graphics.Dimension2D.Double(); } } @Test public void testCreate() { AbstractOrientedLayout gapped = new MockAbstractOrientedLayout(Orientation.HORIZONTAL, GAP_H, GAP_V); assertEquals(GAP_H, gapped.getGapX(), DELTA); assertEquals(GAP_V, gapped.getGapY(), DELTA); } @Test public void testSerialization() throws IOException, ClassNotFoundException { AbstractOrientedLayout original = new MockAbstractOrientedLayout(Orientation.VERTICAL, GAP_H, GAP_V); AbstractOrientedLayout deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getOrientation(), deserialized.getOrientation()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/layout/EdgeLayoutTest.java000066400000000000000000000116361267060725100316120ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics.layout; import static org.junit.Assert.assertEquals; import java.awt.geom.Dimension2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawableContainer; import de.erichseifert.gral.graphics.DrawingContext; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.graphics.Location; public class EdgeLayoutTest { private static final double DELTA = 1e-15; private static final double GAP_H = 5.0; private static final double GAP_V = 10.0; private static final double COMP_WIDTH = 10.0; private static final double COMP_HEIGHT = 5.0; private DrawableContainer container; private EdgeLayout layout; private Drawable nn, nw, ww, sw, ss, se, ee, ne, ce; private static final class TestDrawable extends AbstractDrawable { /** Version id for serialization. */ private static final long serialVersionUID = -8968220580916982445L; public void draw(DrawingContext context) { } @Override public Dimension2D getPreferredSize() { Dimension2D size = super.getPreferredSize(); size.setSize(COMP_WIDTH, COMP_HEIGHT); return size; } } @Before public void setUp() { layout = new EdgeLayout(GAP_H, GAP_V); container = new DrawableContainer(null); nn = new TestDrawable(); nw = new TestDrawable(); ww = new TestDrawable(); sw = new TestDrawable(); ss = new TestDrawable(); se = new TestDrawable(); ee = new TestDrawable(); ne = new TestDrawable(); ce = new TestDrawable(); container.add(nn, Location.NORTH); container.add(nw, Location.NORTH_WEST); container.add(ww, Location.WEST); container.add(sw, Location.SOUTH_WEST); container.add(ss, Location.SOUTH); container.add(se, Location.SOUTH_EAST); container.add(ee, Location.EAST); container.add(ne, Location.NORTH_EAST); container.add(ce, Location.CENTER); } @Test public void testCreate() { EdgeLayout noGap = new EdgeLayout(); assertEquals(0.0, noGap.getGapX(), DELTA); assertEquals(0.0, noGap.getGapY(), DELTA); EdgeLayout gapped = new EdgeLayout(GAP_H, GAP_V); assertEquals(GAP_H, gapped.getGapX(), DELTA); assertEquals(GAP_V, gapped.getGapY(), DELTA); } @Test public void testPreferredSize() { Dimension2D size = layout.getPreferredSize(container); assertEquals(3.0*COMP_WIDTH + 2.0*GAP_H, size.getWidth(), DELTA); assertEquals(3.0*COMP_HEIGHT + 2.0*GAP_V, size.getHeight(), DELTA); } @Test public void testLayout() { Rectangle2D bounds = new Rectangle2D.Double(5.0, 5.0, 50.0, 50.0); container.setBounds(bounds); layout.layout(container); // Test x coordinates assertEquals(bounds.getMinX(), nw.getX(), DELTA); assertEquals(bounds.getMinX(), ww.getX(), DELTA); assertEquals(bounds.getMinX(), sw.getX(), DELTA); assertEquals(bounds.getMinX() + COMP_WIDTH + GAP_H, nn.getX(), DELTA); assertEquals(bounds.getMinX() + COMP_WIDTH + GAP_H, ce.getX(), DELTA); assertEquals(bounds.getMinX() + COMP_WIDTH + GAP_H, ss.getX(), DELTA); assertEquals(bounds.getMaxX() - COMP_WIDTH, ne.getX(), DELTA); assertEquals(bounds.getMaxX() - COMP_WIDTH, ee.getX(), DELTA); assertEquals(bounds.getMaxX() - COMP_WIDTH, se.getX(), DELTA); // Test y coordinates assertEquals(bounds.getMinY(), nw.getY(), DELTA); assertEquals(bounds.getMinY(), nn.getY(), DELTA); assertEquals(bounds.getMinY(), ne.getY(), DELTA); assertEquals(bounds.getMinY() + COMP_HEIGHT + GAP_V, ww.getY(), DELTA); assertEquals(bounds.getMinY() + COMP_HEIGHT + GAP_V, ce.getY(), DELTA); assertEquals(bounds.getMinY() + COMP_HEIGHT + GAP_V, ee.getY(), DELTA); assertEquals(bounds.getMaxY() - COMP_HEIGHT, sw.getY(), DELTA); assertEquals(bounds.getMaxY() - COMP_HEIGHT, ss.getY(), DELTA); assertEquals(bounds.getMaxY() - COMP_HEIGHT, se.getY(), DELTA); // TODO Test width and height } @Test public void testSerialization() throws IOException, ClassNotFoundException { EdgeLayout original = layout; EdgeLayout deserialized = TestUtils.serializeAndDeserialize(original); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/layout/LayoutTests.java000066400000000000000000000023161267060725100312030ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics.layout; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ // Tests for classes AbstractLayoutTest.class, AbstractOrientedLayoutTest.class, EdgeLayoutTest.class, // TODO Add test for OuterEdgeLayout StackedLayoutTest.class, TableLayoutTest.class, }) public class LayoutTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/layout/StackedLayoutTest.java000066400000000000000000000131251267060725100323170ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics.layout; import static org.junit.Assert.assertEquals; import java.awt.geom.Dimension2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawableContainer; import de.erichseifert.gral.graphics.DrawingContext; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.graphics.Orientation; public class StackedLayoutTest { private static final double DELTA = 1e-15; private static final double GAP_X = 5.0; private static final double GAP_Y = 10.0; private static final double COMP_WIDTH = 10.0; private static final double COMP_HEIGHT = 5.0; private DrawableContainer container; private Drawable a, b, c; private static final class TestDrawable extends AbstractDrawable { /** Version id for serialization. */ private static final long serialVersionUID = -5549638074327301904L; public void draw(DrawingContext context) { } @Override public Dimension2D getPreferredSize() { Dimension2D size = super.getPreferredSize(); size.setSize(COMP_WIDTH, COMP_HEIGHT); return size; } } @Before public void setUp() { container = new DrawableContainer(null); a = new TestDrawable(); b = new TestDrawable(); c = new TestDrawable(); container.add(a); container.add(b); container.add(c); } @Test public void testCreate() { StackedLayout noGap = new StackedLayout(Orientation.VERTICAL); assertEquals(Orientation.VERTICAL, noGap.getOrientation()); assertEquals(0.0, noGap.getGapX(), DELTA); assertEquals(0.0, noGap.getGapY(), DELTA); StackedLayout gapped = new StackedLayout(Orientation.HORIZONTAL, GAP_X, GAP_Y); assertEquals(Orientation.HORIZONTAL, gapped.getOrientation()); assertEquals(GAP_X, gapped.getGapX(), DELTA); assertEquals(GAP_Y, gapped.getGapY(), DELTA); } @Test public void testPreferredSizeVertical() { Layout layout = new StackedLayout(Orientation.VERTICAL, GAP_X, GAP_Y); Dimension2D size = layout.getPreferredSize(container); assertEquals(COMP_WIDTH, size.getWidth(), DELTA); assertEquals(3.0*COMP_HEIGHT + 2.0*GAP_Y, size.getHeight(), DELTA); } @Test public void testPreferredSizeHorizontal() { Layout layout = new StackedLayout(Orientation.HORIZONTAL, GAP_X, GAP_Y); Dimension2D size = layout.getPreferredSize(container); assertEquals(3.0*COMP_WIDTH + 2.0*GAP_X, size.getWidth(), DELTA); assertEquals(COMP_HEIGHT, size.getHeight(), DELTA); } @Test public void testLayoutVertical() { Layout layout = new StackedLayout(Orientation.VERTICAL, GAP_X, GAP_Y); Rectangle2D bounds = new Rectangle2D.Double(5.0, 5.0, 50.0, 50.0); container.setBounds(bounds); layout.layout(container); // Test x coordinates assertEquals(bounds.getMinX(), a.getX(), DELTA); assertEquals(bounds.getMinX(), b.getX(), DELTA); assertEquals(bounds.getMinX(), c.getX(), DELTA); // Test y coordinates assertEquals(12.5, a.getY(), DELTA); assertEquals(27.5, b.getY(), DELTA); assertEquals(42.5, c.getY(), DELTA); // TODO Test width and height } @Test public void testLayoutHorizontal() { Layout layout = new StackedLayout(Orientation.HORIZONTAL, GAP_X, GAP_Y); Rectangle2D bounds = new Rectangle2D.Double(5.0, 5.0, 50.0, 50.0); container.setBounds(bounds); layout.layout(container); // Test x coordinates assertEquals(10.0, a.getX(), DELTA); assertEquals(25.0, b.getX(), DELTA); assertEquals(40.0, c.getX(), DELTA); // Test y coordinates assertEquals(bounds.getMinY(), a.getY(), DELTA); assertEquals(bounds.getMinY(), b.getY(), DELTA); assertEquals(bounds.getMinY(), c.getY(), DELTA); // TODO Test width and height } @Test public void testOrientation() { StackedLayout layout; // Vertical layout = new StackedLayout(Orientation.VERTICAL); assertEquals(Orientation.VERTICAL, layout.getOrientation()); // Horizontal layout = new StackedLayout(Orientation.HORIZONTAL); assertEquals(Orientation.HORIZONTAL, layout.getOrientation()); } @Test public void testGap() { StackedLayout layout; // Vertical layout = new StackedLayout(Orientation.VERTICAL, GAP_X, GAP_Y); assertEquals(GAP_X, layout.getGapX(), DELTA); assertEquals(GAP_Y, layout.getGapY(), DELTA); // Horizontal layout = new StackedLayout(Orientation.HORIZONTAL, GAP_X, GAP_Y); assertEquals(GAP_X, layout.getGapX(), DELTA); assertEquals(GAP_Y, layout.getGapY(), DELTA); } @Test public void testSerialization() throws IOException, ClassNotFoundException { StackedLayout original = new StackedLayout(Orientation.VERTICAL, GAP_X, GAP_Y); StackedLayout deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getOrientation(), deserialized.getOrientation()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/layout/TableLayoutTest.java000066400000000000000000000124761267060725100320000ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.graphics.layout; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.awt.geom.Dimension2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawableContainer; import de.erichseifert.gral.graphics.DrawingContext; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; public class TableLayoutTest { private static final double DELTA = 1e-15; private static final double GAP_X = 5.0; private static final double GAP_Y = 10.0; private static final double COMP_WIDTH = 10.0; private static final double COMP_HEIGHT = 5.0; private DrawableContainer container; private Drawable a, b, c; private static final class TestDrawable extends AbstractDrawable { /** Version id for serialization. */ private static final long serialVersionUID = -7959953164953997440L; public void draw(DrawingContext context) { } @Override public Dimension2D getPreferredSize() { Dimension2D size = super.getPreferredSize(); size.setSize(COMP_WIDTH, COMP_HEIGHT); return size; } } @Before public void setUp() { container = new DrawableContainer(null); a = new TestDrawable(); b = new TestDrawable(); c = new TestDrawable(); container.add(a); container.add(b); container.add(c); } @Test public void testCreate() { TableLayout noGap = new TableLayout(1); assertEquals(0.0, noGap.getGapX(), DELTA); assertEquals(0.0, noGap.getGapY(), DELTA); TableLayout gapped = new TableLayout(1, GAP_X, GAP_Y); assertEquals(GAP_X, gapped.getGapX(), DELTA); assertEquals(GAP_Y, gapped.getGapY(), DELTA); } @Test public void testCreateInvalid() { try { new TableLayout(-1, GAP_X, GAP_Y); fail("Expected IllegalArgumentException because of negative column number."); } catch (IllegalArgumentException e) { } try { new TableLayout(0, GAP_X, GAP_Y); fail("Expected IllegalArgumentException because column number was zero."); } catch (IllegalArgumentException e) { } } @Test public void testPreferredSizeVertical() { Layout layout = new TableLayout(1, GAP_X, GAP_Y); Dimension2D size = layout.getPreferredSize(container); assertEquals(COMP_WIDTH, size.getWidth(), DELTA); assertEquals(3.0*COMP_HEIGHT + 2.0*GAP_Y, size.getHeight(), DELTA); } @Test public void testPreferredSizeHorizontal() { Layout layout = new TableLayout(3, GAP_X, GAP_Y); Dimension2D size = layout.getPreferredSize(container); assertEquals(3.0*COMP_WIDTH + 2.0*GAP_X, size.getWidth(), DELTA); assertEquals(COMP_HEIGHT, size.getHeight(), DELTA); } @Test public void testLayoutVertical() { Layout layout = new TableLayout(1, GAP_X, GAP_Y); Rectangle2D bounds = new Rectangle2D.Double(5.0, 5.0, 50.0, 50.0); container.setBounds(bounds); layout.layout(container); // Test x coordinates assertEquals(bounds.getMinX(), a.getX(), DELTA); assertEquals(bounds.getMinX(), b.getX(), DELTA); assertEquals(bounds.getMinX(), c.getX(), DELTA); // Test y coordinates double meanCompHeight = (bounds.getHeight() - 2.0*GAP_Y)/3.0; assertEquals(bounds.getMinY() + 0.0*meanCompHeight + 0.0*GAP_Y, a.getY(), DELTA); assertEquals(bounds.getMinY() + 1.0*meanCompHeight + 1.0*GAP_Y, b.getY(), DELTA); assertEquals(bounds.getMinY() + 2.0*meanCompHeight + 2.0*GAP_Y, c.getY(), DELTA); // TODO Test width and height } @Test public void testLayoutHorizontal() { Layout layout = new TableLayout(3, GAP_X, GAP_Y); Rectangle2D bounds = new Rectangle2D.Double(5.0, 5.0, 50.0, 50.0); container.setBounds(bounds); layout.layout(container); // Test x coordinates double meanCompWidth = (bounds.getWidth() - 2.0*GAP_X)/3.0; assertEquals(bounds.getMinX() + 0.0*meanCompWidth + 0.0*GAP_X, a.getX(), DELTA); assertEquals(bounds.getMinX() + 1.0*meanCompWidth + 1.0*GAP_X, b.getX(), DELTA); assertEquals(bounds.getMinX() + 2.0*meanCompWidth + 2.0*GAP_X, c.getX(), DELTA); // Test y coordinates assertEquals(bounds.getMinY(), a.getY(), DELTA); assertEquals(bounds.getMinY(), b.getY(), DELTA); assertEquals(bounds.getMinY(), c.getY(), DELTA); // TODO Test width and height } @Test public void testSerialization() throws IOException, ClassNotFoundException { TableLayout original = new TableLayout(3, GAP_X, GAP_Y); TableLayout deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getColumns(), deserialized.getColumns()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/graphics/package-info.java000066400000000000000000000016751267060725100277210ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.graphics} package. */ package de.erichseifert.gral.graphics; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/000077500000000000000000000000001267060725100233305ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/AbstractIoFactoryTest.java000066400000000000000000000042131267060725100304160ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; import java.util.List; import org.junit.Test; public class AbstractIoFactoryTest { private static final class TestIOFactory extends AbstractIOFactory { public TestIOFactory(String propFileName) throws IOException { super(propFileName); } @Override public Object get(String mimeType) { return null; } } @Test(expected=IOException.class) public void testCreation() throws IOException { new TestIOFactory("fail"); } @Test public void testCapabilities() { TestIOFactory f = null; try { f = new TestIOFactory("datareaders.properties"); } catch (IOException e) { fail("Creation of IOFactory failed: "+e); } List caps = f.getCapabilities(); assertTrue(caps.size() > 0); } @Test public void testFormats() { TestIOFactory f = null; try { f = new TestIOFactory("datareaders.properties"); } catch (IOException e) { fail("Creation of IOFactory failed: "+e); } String[] formats = f.getSupportedFormats(); assertTrue(formats.length > 0); assertFalse(f.isFormatSupported("fail")); for (String mimeType : formats) { assertTrue(f.isFormatSupported(mimeType)); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/IoTests.java000066400000000000000000000023651267060725100255730ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io; import org.junit.runner.RunWith; import org.junit.runners.Suite; import de.erichseifert.gral.io.data.DataTests; import de.erichseifert.gral.io.plots.PlotsTests; @RunWith(Suite.class) @Suite.SuiteClasses({ // Tests for classes AbstractIoFactoryTest.class, // Tests for sub-packages DataTests.class, PlotsTests.class }) public class IoTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/data/000077500000000000000000000000001267060725100242415ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/data/CSVReaderTest.java000066400000000000000000000202561267060725100275270ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.text.ParseException; import org.junit.Test; import de.erichseifert.gral.data.DataSource; public class CSVReaderTest { @Test @SuppressWarnings("unchecked") public void testMimeTypes() throws IOException { String[] formats = { "text/csv", "text/tab-separated-values" }; String[] dataStrings = { "0,10.0,20\r\n" + "1,11.0,21\r\n" + "2,12.0,22\r\n", "0\t10.0\t20\r\n" + "1\t11.0\t21\r\n" + "2\t12.0\t22\r\n" }; for (int i = 0; i < formats.length; i++) { DataReader reader = DataReaderFactory.getInstance().get(formats[i]); ByteArrayInputStream input = new ByteArrayInputStream(dataStrings[i].getBytes()); DataSource data = reader.read(input, Integer.class, Double.class, Double.class); assertEquals( 0, data.get(0, 0)); assertEquals( 1, data.get(0, 1)); assertEquals( 2, data.get(0, 2)); assertEquals(10.0, data.get(1, 0)); assertEquals(11.0, data.get(1, 1)); assertEquals(12.0, data.get(1, 2)); assertEquals(20.0, data.get(2, 0)); assertEquals(21.0, data.get(2, 1)); assertEquals(22.0, data.get(2, 2)); } } @Test @SuppressWarnings("unchecked") public void testSeparator() throws IOException { InputStream input = new ByteArrayInputStream(( "0;10.0;20\r\n" + "1;11.0;21\r\n" + "2;12.0;22\r\n" ).getBytes()); DataReader reader = DataReaderFactory.getInstance().get("text/csv"); reader.setSetting(CSVReader.SEPARATOR_CHAR, ';'); DataSource data = reader.read(input, Integer.class, Double.class, Double.class); assertEquals( 0, data.get(0, 0)); assertEquals( 1, data.get(0, 1)); assertEquals( 2, data.get(0, 2)); assertEquals(10.0, data.get(1, 0)); assertEquals(11.0, data.get(1, 1)); assertEquals(12.0, data.get(1, 2)); assertEquals(20.0, data.get(2, 0)); assertEquals(21.0, data.get(2, 1)); assertEquals(22.0, data.get(2, 2)); } @Test @SuppressWarnings("unchecked") public void testQuotedNumbers() throws IOException { InputStream input = new ByteArrayInputStream(( "\"0\",\"10.0\",\"20\"\r\n" + "\"1\",\"11.0\",\"21\"\r\n" + "\"2\",\"12.0\",\"22\"\r\n" ).getBytes()); DataReader reader = DataReaderFactory.getInstance().get("text/csv"); DataSource data = reader.read(input, Integer.class, Double.class, Double.class); assertEquals( 0, data.get(0, 0)); assertEquals( 1, data.get(0, 1)); assertEquals( 2, data.get(0, 2)); assertEquals(10.0, data.get(1, 0)); assertEquals(11.0, data.get(1, 1)); assertEquals(12.0, data.get(1, 2)); assertEquals(20.0, data.get(2, 0)); assertEquals(21.0, data.get(2, 1)); assertEquals(22.0, data.get(2, 2)); } @Test @SuppressWarnings("unchecked") public void testQuotedString() throws IOException { InputStream input = new ByteArrayInputStream(( "\"foo\tbar\"\tfoo bar\r\n" + "foobar\t\"foo \"\"the\"\" bar\"\r\n" ).getBytes()); DataReader reader = DataReaderFactory.getInstance().get("text/tab-separated-values"); DataSource data = reader.read(input, String.class, String.class); assertEquals("foo\tbar", data.get(0, 0)); assertEquals("foo bar", data.get(1, 0)); assertEquals("foobar", data.get(0, 1)); assertEquals("foo \"the\" bar", data.get(1, 1)); } @Test @SuppressWarnings("unchecked") public void testLineSeparators() throws IOException { String[] dataStrings = { "0,10.0,20\r\n" + "1,11.0,21\r\n" + "2,12.0,22\r\n", "0,10.0,20\r" + "1,11.0,21\r" + "2,12.0,22\r", "0,10.0,20\n" + "1,11.0,21\n" + "2,12.0,22\n", "0,10.0,20\r\n" + "1,11.0,21\r\n" + "2,12.0,22", "0,10.0,20\r" + "1,11.0,21\r" + "2,12.0,22", "0,10.0,20\n" + "1,11.0,21\n" + "2,12.0,22" }; for (String dataString : dataStrings) { DataReader reader = DataReaderFactory.getInstance().get("text/csv"); ByteArrayInputStream input = new ByteArrayInputStream(dataString.getBytes()); DataSource data = reader.read(input, Integer.class, Double.class, Double.class); assertEquals( 0, data.get(0, 0)); assertEquals( 1, data.get(0, 1)); assertEquals( 2, data.get(0, 2)); assertEquals(10.0, data.get(1, 0)); assertEquals(11.0, data.get(1, 1)); assertEquals(12.0, data.get(1, 2)); assertEquals(20.0, data.get(2, 0)); assertEquals(21.0, data.get(2, 1)); assertEquals(22.0, data.get(2, 2)); } } @Test @SuppressWarnings("unchecked") public void testIllegalType() throws IOException { InputStream input = new ByteArrayInputStream(( "0.0,10.0,20\r\n" + "1,11.0,21\r\n" + "2,12.0,22\r\n" ).getBytes()); DataReader reader = DataReaderFactory.getInstance().get("text/csv"); try { reader.read(input, Integer.class, Double.class, Double.class); fail("Expected IOException"); } catch (IOException e) { } } @Test @SuppressWarnings("unchecked") public void testNotEnoughColumns() throws IOException, ParseException { InputStream input = new ByteArrayInputStream(( "0,10.0,20\r\n" + "1,11.0\r\n" + "2,12.0,22\r\n" ).getBytes()); DataReader reader = DataReaderFactory.getInstance().get("text/csv"); try { reader.read(input, Integer.class, Double.class, Double.class); fail("Expected IllegalArgumentException because there are not enough columns."); } catch (IllegalArgumentException e) { } } @Test @SuppressWarnings("unchecked") public void testTooManyColumns() throws IOException, ParseException { InputStream input = new ByteArrayInputStream(( "0,10.0,20\r\n" + "1,11.0,21,42\r\n" + "2,12.0,22\r\n" ).getBytes()); DataReader reader = DataReaderFactory.getInstance().get("text/csv"); try { reader.read(input, Integer.class, Double.class, Double.class); fail("Expected IllegalArgumentException because there are too many columns."); } catch (IllegalArgumentException e) { } } @Test @SuppressWarnings("unchecked") public void testEmptyValues() throws IOException, ParseException { InputStream input = new ByteArrayInputStream(( "0,10.0,\r\n" + "1,,21\r\n" + ",,3\r\n" ).getBytes()); DataReader reader = DataReaderFactory.getInstance().get("text/csv"); DataSource data = reader.read(input, Integer.class, Double.class, Double.class); assertEquals( 0, data.get(0, 0)); assertEquals(10.0, data.get(1, 0)); assertNull( data.get(2, 0)); assertEquals( 1, data.get(0, 1)); assertNull( data.get(1, 1)); assertEquals(21.0, data.get(2, 1)); assertNull( data.get(0, 2)); assertNull( data.get(1, 2)); assertEquals( 3.0, data.get(2, 2)); } @Test @SuppressWarnings("unchecked") public void testNegativeIntegerValues() throws IOException, ParseException { InputStream input = new ByteArrayInputStream(( "-0,-10.0,-20\r\n" + "-1,-11.0,-21\r\n" + "-2,-12.0,-22\r\n" ).getBytes()); DataReader reader = DataReaderFactory.getInstance().get("text/csv"); DataSource data = reader.read(input, Integer.class, Double.class, Double.class); assertEquals( 0, data.get(0, 0)); assertEquals( -1, data.get(0, 1)); assertEquals( -2, data.get(0, 2)); assertEquals(-10.0, data.get(1, 0)); assertEquals(-11.0, data.get(1, 1)); assertEquals(-12.0, data.get(1, 2)); assertEquals(-20.0, data.get(2, 0)); assertEquals(-21.0, data.get(2, 1)); assertEquals(-22.0, data.get(2, 2)); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/data/CSVWriterTest.java000066400000000000000000000045011267060725100275740ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import static org.junit.Assert.assertEquals; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.data.DataTable; public class CSVWriterTest { private static DataTable data; @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { data = new DataTable(Double.class, Double.class, Integer.class); data.add(0.0, 10.0, 20); data.add(1.0, 11.0, 21); data.add(2.0, 12.0, 22); } @Test public void testWriter() throws IOException { String[] formats = { "text/csv", "text/tab-separated-values" }; String[] expected = { "0.0,10.0,20\r\n" + "1.0,11.0,21\r\n" + "2.0,12.0,22\r\n", "0.0\t10.0\t20\r\n" + "1.0\t11.0\t21\r\n" + "2.0\t12.0\t22\r\n", }; for (int i = 0; i < formats.length; i++) { DataWriter writer = DataWriterFactory.getInstance().get(formats[i]); OutputStream output = new ByteArrayOutputStream(); writer.write(data, output); assertEquals(expected[i], output.toString()); } } @Test public void testSeparator() throws IOException { OutputStream output = new ByteArrayOutputStream(); DataWriter writer = DataWriterFactory.getInstance().get("text/csv"); writer.setSetting(CSVWriter.SEPARATOR_CHAR, ';'); writer.write(data, output); assertEquals( "0.0;10.0;20\r\n" + "1.0;11.0;21\r\n" + "2.0;12.0;22\r\n", output.toString() ); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/data/DataReaderFactoryTest.java000066400000000000000000000030651267060725100312740ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; import org.junit.Test; public class DataReaderFactoryTest { @Test public void testInstance() { DataReaderFactory instance1 = DataReaderFactory.getInstance(); assertNotNull(instance1); DataReaderFactory instance2 = DataReaderFactory.getInstance(); assertSame(instance1, instance2); } @Test public void testGet() { DataReader r = DataReaderFactory.getInstance().get("text/csv"); assertNotNull(r); try { DataReaderFactory.getInstance().get("fail"); fail("Expected IllegalArgumentException exception."); } catch (IllegalArgumentException e) { } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/data/DataTests.java000066400000000000000000000022741267060725100270050ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ DataReaderFactoryTest.class, DataWriterFactoryTest.class, CSVReaderTest.class, CSVWriterTest.class, ImageReaderTest.class, ImageWriterTest.class }) public class DataTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/data/DataWriterFactoryTest.java000066400000000000000000000030651267060725100313460ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; import org.junit.Test; public class DataWriterFactoryTest { @Test public void testInstance() { DataWriterFactory instance1 = DataWriterFactory.getInstance(); assertNotNull(instance1); DataWriterFactory instance2 = DataWriterFactory.getInstance(); assertSame(instance1, instance2); } @Test public void testGet() { DataWriter r = DataWriterFactory.getInstance().get("text/csv"); assertNotNull(r); try { DataWriterFactory.getInstance().get("fail"); fail("Expected IllegalArgumentException exception."); } catch (IllegalArgumentException e) { } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/data/ImageReaderTest.java000066400000000000000000000052751267060725100301220ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import static org.junit.Assert.assertEquals; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.text.ParseException; import javax.imageio.ImageIO; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.data.DataSource; public class ImageReaderTest { private static final double DELTA = 1e-15; private static InputStream imageData; private static int rgb(double value) { int v = (int) Math.round(value); return (255 << 24) | (v << 16) | (v << 8) | v; } @BeforeClass public static void setUpBeforeClass() { BufferedImage image = new BufferedImage(3, 4, BufferedImage.TYPE_BYTE_GRAY); int[] rgbData = { rgb(255.0), rgb( 0.0), rgb( 0.0), rgb( 0.0), rgb(255.0), rgb( 0.0), rgb( 0.0), rgb( 0.0), rgb(255.0), rgb(127.0), rgb(127.0), rgb(127.0) }; image.setRGB(0, 0, image.getWidth(), image.getHeight(), rgbData, 0, image.getWidth()); ByteArrayOutputStream out = new ByteArrayOutputStream(); try { ImageIO.write(image, "png", out); } catch (IOException e) { } imageData = new ByteArrayInputStream(out.toByteArray()); } @Test @SuppressWarnings("unchecked") public void testReader() throws IOException, ParseException { DataReader reader = DataReaderFactory.getInstance().get("image/png"); DataSource data = reader.read(imageData); assertEquals(3, data.getColumnCount()); assertEquals(4, data.getRowCount()); double[] expected = new double[] { 255.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 255.0, 127.0, 127.0, 127.0 }; for (int i = 0; i < expected.length; i++) { int col = i % 3; int row = i / 3; double value = ((Number) data.get(col, row)).doubleValue(); assertEquals(expected[i], value, DELTA); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/data/ImageWriterTest.java000066400000000000000000000046631267060725100301740ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.data; import static org.junit.Assert.assertEquals; import java.awt.image.BufferedImage; import java.awt.image.DataBufferByte; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import javax.imageio.ImageIO; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.data.DataTable; public class ImageWriterTest { private static final double DELTA = 1e-15; private static DataTable data; @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { data = new DataTable(Double.class, Double.class, Integer.class); data.add(255.0, 0.0, 0); data.add( 0.0, 255.0, 0); data.add( 0.0, 0.0, 255); data.add(127.0, 127.0, 127); } @Test public void testWriter() throws IOException { ByteArrayOutputStream output = new ByteArrayOutputStream(); DataWriter writer = DataWriterFactory.getInstance().get("image/png"); writer.write(data, output); ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray()); BufferedImage image = ImageIO.read(input); assertEquals(data.getColumnCount(), image.getWidth()); assertEquals(data.getRowCount(), image.getHeight()); byte[] imageData = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); for (int i = 0; i < imageData.length; i++) { int col = i % image.getWidth(); int row = i / image.getWidth(); double expected = ((Number) data.get(col, row)).doubleValue(); double value = imageData[i]; if (value < 0.0) { value += 256.0; } assertEquals(expected, value, DELTA); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/data/package-info.java000077500000000000000000000017241267060725100274370ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.io.data} package. */ package de.erichseifert.gral.io.data; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/package-info.java000077500000000000000000000017121267060725100265230ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.io} package. */ package de.erichseifert.gral.io; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/plots/000077500000000000000000000000001267060725100244715ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/plots/DrawableWriterFactoryTest.java000066400000000000000000000022711267060725100324440ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.plots; import static org.junit.Assert.fail; import org.junit.Test; public class DrawableWriterFactoryTest { @Test public void testGet() { DrawableWriterFactory f = DrawableWriterFactory.getInstance(); try { f.get("fail"); fail("Expected IllegalArgumentException."); } catch (IllegalArgumentException e) { } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/plots/DrawableWriterTest.java000066400000000000000000000033621267060725100311160ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.plots; import static org.junit.Assert.fail; import java.io.ByteArrayOutputStream; import java.io.IOException; import org.junit.Test; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawableContainer; public class DrawableWriterTest { private static final String[] FORMATS = new String[] { "image/bmp", "image/gif", "image/jpeg", "image/png", "image/vnd.wap.wbmp", "application/pdf", "application/postscript", "image/svg+xml" }; @Test public void testWrite() { Drawable d = new DrawableContainer(); for (String format : FORMATS) { ByteArrayOutputStream dest = new ByteArrayOutputStream(); DrawableWriter writer = DrawableWriterFactory.getInstance().get(format); try { writer.write(d, dest, 320, 240); } catch (IOException e) { fail("Error writing Drawable to " + format + "image: " + e.getMessage()); } } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/plots/PlotsTests.java000066400000000000000000000021361267060725100274620ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.io.plots; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ DrawableWriterFactoryTest.class, DrawableWriterTest.class }) public class PlotsTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/io/plots/package-info.java000077500000000000000000000017261267060725100276710ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.io.plots} package. */ package de.erichseifert.gral.io.plots; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/navigation/000077500000000000000000000000001267060725100250605ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/navigation/MockNavigationDirection.java000066400000000000000000000017011267060725100324740ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.navigation; enum MockNavigationDirection implements NavigationDirection { FOO, BAR } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/navigation/MockNavigator.java000066400000000000000000000054231267060725100304730ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.navigation; import de.erichseifert.gral.util.PointND; final class MockNavigator extends AbstractNavigator { private final PointND center; private double zoom; private final PointND centerDefault; private double zoomDefault; public MockNavigator() { center = new PointND(0.0, 0.0); zoom = 1.0; centerDefault = new PointND(0.0, 0.0); setDefaultState(); } public double getZoom() { return zoom; } public void setZoom(double zoomNew) { if (!isZoomable()) { return; } double zoomOld = zoom; if (zoomNew != zoomOld) { zoom = zoomNew; NavigationEvent event = new NavigationEvent(this, zoomOld, zoomNew); fireZoomChanged(event); } } public PointND getCenter() { PointND center = new PointND( this.center.get(PointND.X), this.center.get(PointND.Y) ); return center; } public void setCenter(PointND center) { if (!isPannable()) { return; } PointND centerOld = getCenter(); if (!center.equals(centerOld)) { this.center.setLocation( center.get(PointND.X).doubleValue(), center.get(PointND.Y).doubleValue() ); PointND centerNew = getCenter(); NavigationEvent> event = new NavigationEvent>(this, centerOld, centerNew); fireCenterChanged(event); } } public void pan(PointND deltas) { setCenter(new PointND( center.get(PointND.X) + deltas.get(PointND.X).doubleValue(), center.get(PointND.Y) + deltas.get(PointND.Y).doubleValue() )); } public void setDefaultState() { centerDefault.setLocation( center.get(PointND.X), center.get(PointND.Y) ); zoomDefault = zoom; } public void reset() { setCenter(new PointND( centerDefault.get(PointND.X), centerDefault.get(PointND.Y) )); setZoom(zoomDefault); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/navigation/NavigationEventTest.java000066400000000000000000000027221267060725100316670ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.navigation; import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; public class NavigationEventTest { private static final double DELTA = TestUtils.DELTA; private static final Navigator SOURCE = new MockNavigator(); private NavigationEvent event; @Before public void setUp() { event = new NavigationEvent(SOURCE, 1.2, 3.4); } @Test public void testCreate() { assertEquals(SOURCE, event.getSource()); assertEquals(1.2, event.getValueOld(), DELTA); assertEquals(3.4, event.getValueNew(), DELTA); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/navigation/NavigationListenerTest.java000066400000000000000000000046531267060725100324000ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.navigation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.util.PointND; public class NavigationListenerTest { private static final double DELTA = TestUtils.DELTA; private static final class MockNavigationListener implements NavigationListener { PointND center; Double zoom; public void centerChanged( NavigationEvent> event) { center = event.getValueNew(); } public void zoomChanged(NavigationEvent event) { zoom = event.getValueNew(); } } private Navigator navigator; private MockNavigationListener listener; @Before public void setUp() { navigator = new MockNavigator(); listener = new MockNavigationListener(); navigator.addNavigationListener(listener); } @Test public void testCenterChanged() { assertNull(listener.center); PointND centerNew = new PointND(1.2, 3.4); navigator.setCenter(centerNew); assertEquals(centerNew, listener.center); } @Test public void testZoomChanged() { assertNull(listener.zoom); double zoomNew = 2.0; navigator.setZoom(zoomNew); assertEquals(zoomNew, listener.zoom, DELTA); } @Test public void testRemove() { navigator.removeNavigationListener(listener); PointND centerNew = new PointND(1.2, 3.4); navigator.setCenter(centerNew); assertNull(listener.zoom); double zoomNew = 2.0; navigator.setZoom(zoomNew); assertNull(listener.zoom); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/navigation/NavigationTests.java000066400000000000000000000021311267060725100310420ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.navigation; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ NavigatorTest.class, NavigationEventTest.class, NavigationListenerTest.class }) public class NavigationTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/navigation/NavigatorTest.java000066400000000000000000000124241267060725100305200ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.navigation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.util.PointND; public class NavigatorTest { private static final double DELTA = TestUtils.DELTA; private MockNavigator navigator; @Before public void setUp() { navigator = new MockNavigator(); } @Test public void testCreate() { assertEquals(AbstractNavigator.DEFAULT_ZOOM_FACTOR, navigator.getZoomFactor(), DELTA); assertEquals(AbstractNavigator.DEFAULT_ZOOM_MIN, navigator.getZoomMin(), DELTA); assertEquals(AbstractNavigator.DEFAULT_ZOOM_MAX, navigator.getZoomMax(), DELTA); assertNull(navigator.getDirection()); assertEquals(new PointND(0.0, 0.0), navigator.getCenter()); assertEquals(1.0, navigator.getZoom(), DELTA); } @Test public void testZoom() { navigator.setZoom(2.0); assertEquals(2.0, navigator.getZoom(), DELTA); } @Test public void testZoomIn() { double zoomOld = navigator.getZoom(); navigator.zoomIn(); assertEquals(zoomOld*navigator.getZoomFactor(), navigator.getZoom(), DELTA); } @Test public void testZoomOut() { double zoomOld = navigator.getZoom(); navigator.zoomOut(); assertEquals(zoomOld/navigator.getZoomFactor(), navigator.getZoom(), DELTA); } @Test public void testZoomable() { double zoomOld = navigator.getZoom(); navigator.setZoomable(false); navigator.setZoom(zoomOld + 2.0); assertEquals(zoomOld, navigator.getZoom(), DELTA); navigator.zoomIn(); assertEquals(zoomOld, navigator.getZoom(), DELTA); navigator.zoomOut(); assertEquals(zoomOld, navigator.getZoom(), DELTA); } @Test public void testCenter() { PointND centerNew = new PointND(1.2, 3.4); navigator.setCenter(centerNew); assertEquals(centerNew, navigator.getCenter()); } @Test public void testPan() { PointND centerOld = navigator.getCenter(); PointND deltas = new PointND(-3.2, -1.0); PointND expected = new PointND( centerOld.get(0).doubleValue() + deltas.get(0), centerOld.get(1).doubleValue() + deltas.get(1) ); navigator.pan(deltas); assertEquals(expected, navigator.getCenter()); } @Test public void testPannable() { PointND centerOld = navigator.getCenter(); PointND centerNew = new PointND(1.2, 3.4); PointND deltas = new PointND(-3.2, -1.0); navigator.setPannable(false); navigator.setCenter(centerNew); assertEquals(centerOld, navigator.getCenter()); navigator.pan(deltas); assertEquals(centerOld, navigator.getCenter()); } @Test public void testZoomFactor() { double zoomFactorNew = AbstractNavigator.DEFAULT_ZOOM_FACTOR + 2.0; navigator.setZoomFactor(zoomFactorNew); assertEquals(zoomFactorNew, navigator.getZoomFactor(), DELTA); } @Test public void testZoomMin() { double zoomMinNew = AbstractNavigator.DEFAULT_ZOOM_MIN + 2.0; navigator.setZoomMin(zoomMinNew); assertEquals(zoomMinNew, navigator.getZoomMin(), DELTA); } @Test public void testZoomMax() { double zoomMaxNew = AbstractNavigator.DEFAULT_ZOOM_MAX + 2.0; navigator.setZoomMax(zoomMaxNew); assertEquals(zoomMaxNew, navigator.getZoomMax(), DELTA); } @Test public void testDirection() { NavigationDirection directionNew = MockNavigationDirection.BAR; navigator.setDirection(directionNew); assertEquals(directionNew, navigator.getDirection()); } @Test public void testConnect() { Navigator navigator2 = new MockNavigator(); navigator.connect(navigator2); PointND centerNew = new PointND(1.2, 3.4); navigator.setCenter(centerNew); assertEquals(navigator.getCenter(), navigator2.getCenter()); navigator.setZoom(2.0); assertEquals(navigator.getZoom(), navigator2.getZoom(), DELTA); } @Test public void testDisconnect() { Navigator navigator2 = new MockNavigator(); navigator.connect(navigator2); navigator.setCenter(new PointND(1.2, 3.4)); assertEquals(navigator.getCenter(), navigator2.getCenter()); navigator.setZoom(2.0); assertEquals(navigator.getZoom(), navigator2.getZoom(), DELTA); navigator2.disconnect(navigator); navigator.setCenter(new PointND(3.2, -1.0)); assertFalse(navigator.getCenter().equals(navigator2.getCenter())); navigator.setZoom(3.0); assertFalse(navigator.getZoom() == navigator2.getZoom()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/navigation/package-info.java000066400000000000000000000017011267060725100302460ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.navigation} package. */ package de.erichseifert.gral.navigation; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/package-info.java000077500000000000000000000016331267060725100261160ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests. */ package de.erichseifert.gral; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/000077500000000000000000000000001267060725100240625ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/BarPlotTest.java000066400000000000000000000110551267060725100271320ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import java.awt.BasicStroke; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DummyData; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.BarPlot.BarRenderer; import de.erichseifert.gral.plots.points.PointRenderer; import org.junit.Before; import org.junit.Test; public class BarPlotTest { private static final double DELTA = TestUtils.DELTA; private MockBarPlot plot; private static final class MockBarPlot extends BarPlot { /** Version id for serialization. */ private static final long serialVersionUID = -6215127935611125964L; public boolean isDrawn; public MockBarPlot(DataSource... data) { super(data); } @Override public void draw(DrawingContext context) { super.draw(context); isDrawn = true; } } @Before public void setUp() { DataSource data = new DummyData(2, 1, 1.0); plot = new MockBarPlot(data); BarRenderer pointRenderer = (BarRenderer) plot.getPointRenderers(data).get(0); pointRenderer.setBorderStroke(new BasicStroke()); } @Test public void testDraw() { plot.getAxis(BarPlot.AXIS_X).setRange(-1.0, 3.0); plot.getAxis(BarPlot.AXIS_Y).setRange(-1.0, 2.0); BufferedImage image = new BufferedImage(320, 240, BufferedImage.TYPE_INT_ARGB); plot.setBounds(0.0, 0.0, image.getWidth(), image.getHeight()); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); plot.draw(context); assertTrue(plot.isDrawn); } @Test public void testSerialization() throws IOException, ClassNotFoundException { BarPlot original = plot; BarPlot deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getBackground(), deserialized.getBackground()); assertEquals(original.getBorderStroke(), deserialized.getBorderStroke()); assertEquals(original.getBorderColor(), deserialized.getBorderColor()); assertEquals(original.isLegendVisible(), deserialized.isLegendVisible()); assertEquals(original.getLegendLocation(), deserialized.getLegendLocation()); assertEquals(original.getLegendDistance(), deserialized.getLegendDistance(), DELTA); assertEquals(original.getBarWidth(), deserialized.getBarWidth(), DELTA); assertEquals(original.getBarHeightMin(), deserialized.getBarHeightMin(), DELTA); assertEquals(original.isPaintAllBars(), deserialized.isPaintAllBars()); List dataSourcesOriginal = original.getData(); List dataSourcesDeserialized = deserialized.getData(); assertEquals(dataSourcesOriginal.size(), dataSourcesDeserialized.size()); for (int index = 0; index < dataSourcesOriginal.size(); index++) { List pointRenderersOriginal = original.getPointRenderers( dataSourcesOriginal.get(index)); List pointRenderersDeserialized = deserialized.getPointRenderers( dataSourcesDeserialized.get(index)); testPointRendererSerialization(pointRenderersOriginal, pointRenderersDeserialized); } } private static void testPointRendererSerialization( List originalRenderers, List deserializedRenderers) { for (int rendererIndex = 0; rendererIndex < originalRenderers.size(); rendererIndex++) { BarRenderer original = (BarRenderer) originalRenderers.get(rendererIndex); BarRenderer deserialized = (BarRenderer) deserializedRenderers.get(rendererIndex); assertEquals(original.getBorderStroke(), deserialized.getBorderStroke()); assertEquals(original.getBorderColor(), deserialized.getBorderColor()); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/BoxPlotTest.java000066400000000000000000000132751267060725100271640ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.List; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DummyData; import de.erichseifert.gral.data.EnumeratedData; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.BoxPlot.BoxWhiskerRenderer; import de.erichseifert.gral.plots.points.PointRenderer; import org.junit.Before; import org.junit.Test; public class BoxPlotTest { private static final double DELTA = TestUtils.DELTA; private DataSource data; private MockBoxPlot plot; private static final class MockBoxPlot extends BoxPlot { /** Version id for serialization. */ private static final long serialVersionUID = 4497026503195874443L; public boolean isDrawn; public MockBoxPlot(DataSource data) { super(data); } @Override public void draw(DrawingContext context) { super.draw(context); isDrawn = true; } } @Before public void setUp() { data = new EnumeratedData(new DummyData(5, 3, 1.0)); plot = new MockBoxPlot(data); } @Test public void testDraw() { plot.getAxis(BarPlot.AXIS_X).setRange(-1.0, 3.0); plot.getAxis(BarPlot.AXIS_Y).setRange(-1.0, 2.0); BufferedImage image = createTestImage(); plot.setBounds(0.0, 0.0, image.getWidth(), image.getHeight()); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); plot.draw(context); assertTrue(plot.isDrawn); assertNotEmpty(image); } @Test public void testAddRemoveData() { plot.remove(data); assertEquals(0, plot.getData().size()); plot.add(data); assertEquals(1, plot.getData().size()); try { plot.add(data); fail(); } catch (IllegalArgumentException e) { } } @Test public void testSerialization() throws IOException, ClassNotFoundException { BoxPlot original = plot; BoxPlot deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getBackground(), deserialized.getBackground()); assertEquals(original.getBorderStroke(), deserialized.getBorderStroke()); assertEquals(original.getBorderColor(), deserialized.getBorderColor()); assertEquals(original.isLegendVisible(), deserialized.isLegendVisible()); assertEquals(original.getLegendLocation(), deserialized.getLegendLocation()); assertEquals(original.getLegendDistance(), deserialized.getLegendDistance(), DELTA); List dataSourcesOriginal = original.getData(); List dataSourcesDeserialized = deserialized.getData(); assertEquals(dataSourcesOriginal.size(), dataSourcesDeserialized.size()); for (int index = 0; index < dataSourcesOriginal.size(); index++) { List pointRenderersOriginal = original.getPointRenderers( dataSourcesOriginal.get(index)); List pointRenderersDeserialized = deserialized.getPointRenderers( dataSourcesDeserialized.get(index)); testPointRendererSerialization(pointRenderersOriginal, pointRenderersDeserialized); } } private static void testPointRendererSerialization( List originalRenderers, List deserializedRenderers) { for (int rendererIndex = 0; rendererIndex < originalRenderers.size(); rendererIndex++) { BoxWhiskerRenderer original = (BoxWhiskerRenderer) originalRenderers.get(rendererIndex); BoxWhiskerRenderer deserialized = (BoxWhiskerRenderer) deserializedRenderers.get(rendererIndex); assertEquals(original.getPositionColumn(), deserialized.getPositionColumn()); assertEquals(original.getCenterBarColumn(), deserialized.getCenterBarColumn()); assertEquals(original.getBottomBarColumn(), deserialized.getBottomBarColumn()); assertEquals(original.getBoxBottomColumn(), deserialized.getBoxBottomColumn()); assertEquals(original.getBoxTopColumn(), deserialized.getBoxTopColumn()); assertEquals(original.getTopBarColumn(), deserialized.getTopBarColumn()); assertEquals(original.getBoxWidth(), deserialized.getBoxWidth(), DELTA); assertEquals(original.getBoxBackground(), deserialized.getBoxBackground()); assertEquals(original.getBoxBorderColor(), deserialized.getBoxBorderColor()); assertEquals(original.getBoxBorderStroke(), deserialized.getBoxBorderStroke()); assertEquals(original.getWhiskerColor(), deserialized.getWhiskerColor()); assertEquals(original.getWhiskerStroke(), deserialized.getWhiskerStroke()); assertEquals(original.getBarWidth(), deserialized.getBarWidth(), DELTA); assertEquals(original.getCenterBarColor(), deserialized.getCenterBarColor()); assertEquals(original.getCenterBarStroke(), deserialized.getCenterBarStroke()); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/PiePlotTest.java000066400000000000000000000112441267060725100271430ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.List; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DummyData; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.PiePlot.PieSliceRenderer; import de.erichseifert.gral.plots.points.PointRenderer; public class PiePlotTest { private static final double DELTA = TestUtils.DELTA; private DataSource data; private MockPiePlot plot; private static final class MockPiePlot extends PiePlot { /** Version id for serialization. */ private static final long serialVersionUID = -4466331273825538939L; public boolean isDrawn; public MockPiePlot(DataSource data) { super(data); } @Override public void draw(DrawingContext context) { super.draw(context); isDrawn = true; } } @Before public void setUp() { data = new DummyData(1, 3, 1.0); plot = new MockPiePlot(data); } @Test public void testDraw() { BufferedImage image = createTestImage(); plot.setBounds(0.0, 0.0, image.getWidth(), image.getHeight()); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); plot.draw(context); assertTrue(plot.isDrawn); assertNotEmpty(image); } @Test public void testAddRemoveData() { plot.remove(data); assertEquals(0, plot.getData().size()); plot.add(data); assertEquals(1, plot.getData().size()); try { plot.add(data); fail(); } catch (IllegalArgumentException e) { } } @Test public void testSerialization() throws IOException, ClassNotFoundException { PiePlot original = plot; PiePlot deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getBackground(), deserialized.getBackground()); assertEquals(original.getBorderStroke(), deserialized.getBorderStroke()); assertEquals(original.getBorderColor(), deserialized.getBorderColor()); assertEquals(original.isLegendVisible(), deserialized.isLegendVisible()); assertEquals(original.getLegendLocation(), deserialized.getLegendLocation()); assertEquals(original.getLegendDistance(), deserialized.getLegendDistance(), DELTA); assertEquals(original.getCenter(), deserialized.getCenter()); assertEquals(original.getRadius(), deserialized.getRadius(), DELTA); assertEquals(original.getStart(), deserialized.getStart(), DELTA); assertEquals(original.isClockwise(), deserialized.isClockwise()); List dataSourcesOriginal = original.getData(); List dataSourcesDeserialized = deserialized.getData(); assertEquals(dataSourcesOriginal.size(), dataSourcesDeserialized.size()); for (int index = 0; index < dataSourcesOriginal.size(); index++) { PointRenderer pointRendererOriginal = original.getPointRenderer( dataSourcesOriginal.get(index)); PointRenderer pointRendererDeserialized = deserialized.getPointRenderer( dataSourcesDeserialized.get(index)); testPointRendererSerialization(pointRendererOriginal, pointRendererDeserialized); } } private static void testPointRendererSerialization( PointRenderer originalRenderer, PointRenderer deserializedRenderer) { PieSliceRenderer original = (PieSliceRenderer) originalRenderer; PieSliceRenderer deserialized = (PieSliceRenderer) deserializedRenderer; assertEquals(original.getInnerRadius(), deserialized.getInnerRadius(), DELTA); assertEquals(original.getOuterRadius(), deserialized.getOuterRadius(), DELTA); assertEquals(original.getGap(), deserialized.getGap(), DELTA); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/PlotAreaTest.java000066400000000000000000000054321267060725100273000ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.graphics.DrawingContext; public class PlotAreaTest { private MockPlotArea2D plotArea; private static final class MockPlotArea2D extends PlotArea { /** Version id for serialization. */ private static final long serialVersionUID = 9136184486930965257L; public boolean isDrawn; public void draw(DrawingContext context) { drawBackground(context); drawBorder(context); drawPlot(context); } @Override protected void drawPlot(DrawingContext context) { isDrawn = true; } } @Before public void setUp() { plotArea = new MockPlotArea2D(); } @Test public void testDraw() { plotArea.setBackground(Color.WHITE); plotArea.setBorderStroke(new BasicStroke(1f)); BufferedImage image = createTestImage(); plotArea.setBounds(0.0, 0.0, image.getWidth(), image.getHeight()); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); plotArea.draw(context); assertTrue(plotArea.isDrawn); assertNotEmpty(image); } @Test public void testSerialization() throws IOException, ClassNotFoundException { MockPlotArea2D original = plotArea; MockPlotArea2D deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getBackground(), deserialized.getBackground()); assertEquals(original.getBorderStroke(), deserialized.getBorderStroke()); assertEquals(original.getBorderColor(), deserialized.getBorderColor()); assertEquals(original.getClippingOffset(), deserialized.getClippingOffset()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/PlotNavigatorTest.java000066400000000000000000000103411267060725100303550ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.data.DataSeries; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.util.PointND; public class PlotNavigatorTest { private static final double DELTA = 1e-15; private static DataTable table; private static DataSeries series1, series2; private Plot plot; private PlotNavigator nav; @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { table = new DataTable(Integer.class, Integer.class, Integer.class); table.add(1, 3, 5); // 0 table.add(2, 8, 2); // 1 table.add(3, 5, 6); // 2 table.add(4, 6, 2); // 3 table.add(5, 4, 1); // 4 table.add(6, 9, 5); // 5 table.add(7, 8, 7); // 6 table.add(8, 1, 9); // 7 series1 = new DataSeries("series1", table, 0, 1); series2 = new DataSeries("series2", table, 1, 2); } @Before public void setUp() { plot = new XYPlot(series1, series2); plot.setBounds(0, 0, 100, 100); nav = new XYPlot.XYPlotNavigator((XYPlot) plot); } @Test public void testCreate() { // Valid initialization assertEquals(plot, nav.getPlot()); assertEquals(1.0, nav.getZoom(), DELTA); assertEquals(PlotNavigator.DEFAULT_ZOOM_FACTOR, nav.getZoomFactor(), DELTA); assertEquals(PlotNavigator.DEFAULT_ZOOM_MIN, nav.getZoomMin(), DELTA); assertEquals(PlotNavigator.DEFAULT_ZOOM_MAX, nav.getZoomMax(), DELTA); Axis axisX = plot.getAxis(XYPlot.AXIS_X); Axis axisY = plot.getAxis(XYPlot.AXIS_Y); PointND center = nav.getCenter(); assertEquals(axisX.getMin().doubleValue() + 0.5*axisX.getRange(), center.get(0).doubleValue(), DELTA); assertEquals(axisY.getMin().doubleValue() + 0.5*axisY.getRange(), center.get(1).doubleValue(), DELTA); // Invalid initialization try { new XYPlot.XYPlotNavigator(null); fail("Expected NullPointerException."); } catch (NullPointerException e) { } } @Test public void testZoomLimits() { nav.setZoomMin(1e-3); nav.setZoomMax(1e+3); assertEquals(1e-3, nav.getZoomMin(), DELTA); assertEquals(1e+3, nav.getZoomMax(), DELTA); } @Test public void testZoom() { Axis axisX = plot.getAxis(XYPlot.AXIS_X); // Valid zoom nav.setZoom(2.0); assertEquals(2.0, nav.getZoom(), DELTA); assertEquals(3.0, axisX.getMin().doubleValue(), DELTA); assertEquals(7.0, axisX.getMax().doubleValue(), DELTA); // Negative zoom doesn't get set nav.setZoom(-1.0); assertEquals(2.0, nav.getZoom(), DELTA); // Too small zoom is limited to minimum nav.setZoom(nav.getZoomMin() / 2.0); assertEquals(nav.getZoomMin(), nav.getZoom(), DELTA); // Too large zoom is limited to maximum nav.setZoom(nav.getZoomMax() * 2.0); assertEquals(nav.getZoomMax(), nav.getZoom(), DELTA); } @Test public void testCenter() { nav.setCenter(new PointND(0.0, 0.0)); assertEquals(-4.0, plot.getAxis(XYPlot.AXIS_X).getMin().doubleValue(), DELTA); assertEquals(4.0, plot.getAxis(XYPlot.AXIS_X).getMax().doubleValue(), DELTA); } @Test public void testReset() { nav.setZoom(2.0); nav.setCenter(new PointND(6.0, 0.0)); nav.reset(); assertEquals(1.0, plot.getAxis(XYPlot.AXIS_X).getMin().doubleValue(), DELTA); assertEquals(9.0, plot.getAxis(XYPlot.AXIS_X).getMax().doubleValue(), DELTA); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/PlotTest.java000066400000000000000000000170451267060725100265120ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.List; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.DataSeries; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.graphics.Label; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.graphics.Insets2D; public class PlotTest { private static final double DELTA = 1e-15; private static DataTable table; private static DataSeries series1, series2; private Plot plot; private static class MockPlot extends AbstractPlot { /** Version id for serialization. */ private static final long serialVersionUID = -6303533550164303679L; public boolean drawn; public MockPlot(DataSource... data) { super(data); } @Override public void draw(DrawingContext context) { super.draw(context); drawn = true; } public boolean isDrawn() { return drawn; } } @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { table = new DataTable(Integer.class, Integer.class, Integer.class); table.add(1, 3, 5); // 0 table.add(2, 8, 2); // 1 table.add(3, 5, 6); // 2 table.add(4, 6, 2); // 3 table.add(5, 4, 1); // 4 table.add(6, 9, 5); // 5 table.add(7, 8, 7); // 6 table.add(8, 1, 9); // 7 series1 = new DataSeries("series1", table, 0, 1); series2 = new DataSeries("series2", table, 1, 2); } @Before public void setUp() { plot = new MockPlot(series1, series2); } @Test public void testBounds() { Rectangle2D bounds = plot.getBounds(); assertEquals(0.0, bounds.getX(), DELTA); assertEquals(0.0, bounds.getY(), DELTA); assertEquals(0.0, bounds.getWidth(), DELTA); assertEquals(0.0, bounds.getHeight(), DELTA); assertEquals(bounds.getX(), plot.getX(), DELTA); assertEquals(bounds.getY(), plot.getY(), DELTA); assertEquals(bounds.getWidth(), plot.getWidth(), DELTA); assertEquals(bounds.getHeight(), plot.getHeight(), DELTA); } @Test public void testInsets() { Insets2D insets = plot.getInsets(); assertEquals(0.0, insets.getTop(), DELTA); assertEquals(0.0, insets.getLeft(), DELTA); assertEquals(0.0, insets.getBottom(), DELTA); assertEquals(0.0, insets.getRight(), DELTA); } @Test public void testTitle() { Label title = plot.getTitle(); assertNotNull(title); } @Test public void testPlotArea() { PlotArea plotArea = plot.getPlotArea(); assertNull(plotArea); } @Test public void testLegend() { // Get assertNull(plot.getLegend()); } @Test public void testAxis() { // Get assertNull(plot.getAxis("a")); assertNull(plot.getAxis("b")); // Set Axis a = new Axis(); Axis b = new Axis(); a.setRange(0.0, 1.0); b.setRange(2.0, 3.0); plot.setAxis("a", a); plot.setAxis("b", b); assertEquals(a, plot.getAxis("a")); assertEquals(b, plot.getAxis("b")); // Remove plot.removeAxis("a"); plot.setAxis("b", null); assertNull(plot.getAxis("a")); assertNull(plot.getAxis("b")); } @Test public void testDraw() { plot.getTitle().setText("foobar"); plot.setBackground(Color.WHITE); plot.setBorderStroke(new BasicStroke(1f)); BufferedImage image = createTestImage(); plot.setBounds(0.0, 0.0, image.getWidth(), image.getHeight()); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); plot.draw(context); assertTrue(((MockPlot) plot).isDrawn()); assertNotEmpty(image); } @Test public void testDataContains() { // Series assertTrue(plot.contains(series1)); assertTrue(plot.contains(series2)); // Complete data List data = plot.getData(); assertEquals(2, data.size()); assertEquals(series1, data.get(0)); assertEquals(series2, data.get(1)); } @Test public void testDataClear() { plot.clear(); assertEquals(0, plot.getData().size()); } @Test public void testDataGet() { assertEquals(series1, plot.get(0)); assertEquals(series2, plot.get(1)); } @Test public void testDataRemove() { int sizeBefore, size; // Remove sizeBefore = plot.getData().size(); plot.remove(series1); size = plot.getData().size(); assertEquals(sizeBefore -1, size); assertEquals(series2, plot.get(0)); // Clear plot.clear(); assertEquals(0, plot.getData().size()); } @Test public void testDataAdd() { int sizeBefore, size; // Append DataSeries series3 = new DataSeries("series3", table, 0, 2); sizeBefore = plot.getData().size(); plot.add(series3); size = plot.getData().size(); assertEquals(sizeBefore + 1, size); assertEquals(series3, plot.get(size - 1)); // Insert DataSeries series4 = new DataSeries("series4", table, 0); sizeBefore = plot.getData().size(); plot.add(0, series4, false); size = plot.getData().size(); assertEquals(sizeBefore + 1, size); assertEquals(series4, plot.get(0)); assertFalse(plot.isVisible(series4)); } @Test public void testDataVisibility() { // get assertTrue(plot.isVisible(series1)); assertTrue(plot.isVisible(series2)); // set plot.setVisible(series1, false); assertFalse(plot.isVisible(series1)); plot.setVisible(series1, true); assertTrue(plot.isVisible(series1)); // get all List all = plot.getData(); List visible = plot.getVisibleData(); assertEquals(all.size(), visible.size()); for (int i = 0; i < all.size(); i++) { assertEquals(all.get(i), visible.get(i)); } plot.setVisible(series1, false); assertEquals(visible.size() - 1, plot.getVisibleData().size()); assertEquals(all.get(1), plot.getVisibleData().get(0)); } @Test public void testSerialization() throws IOException, ClassNotFoundException { Plot original = plot; Plot deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getBackground(), deserialized.getBackground()); assertEquals(original.getBorderStroke(), deserialized.getBorderStroke()); assertEquals(original.getBorderColor(), deserialized.getBorderColor()); assertEquals(original.isLegendVisible(), deserialized.isLegendVisible()); assertEquals(original.getLegendLocation(), deserialized.getLegendLocation()); assertEquals(original.getLegendDistance(), deserialized.getLegendDistance(), DELTA); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/PlotsTests.java000066400000000000000000000033011267060725100270460ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import org.junit.runner.RunWith; import org.junit.runners.Suite; import de.erichseifert.gral.plots.areas.AreasTests; import de.erichseifert.gral.plots.axes.AxesTests; import de.erichseifert.gral.plots.colors.ColorsTests; import de.erichseifert.gral.plots.legends.LegendsTests; import de.erichseifert.gral.plots.lines.LinesTests; import de.erichseifert.gral.plots.points.PointsTests; @RunWith(Suite.class) @Suite.SuiteClasses({ // Tests for sub-packages AxesTests.class, ColorsTests.class, AreasTests.class, LinesTests.class, PointsTests.class, LegendsTests.class, // Tests for classes PlotAreaTest.class, PlotTest.class, XYPlotTest.class, PiePlotTest.class, BarPlotTest.class, BoxPlotTest.class, RasterPlotTest.class, PlotNavigatorTest.class }) public class PlotsTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/RasterPlotTest.java000066400000000000000000000115431267060725100276700ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.List; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DummyData; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.RasterPlot.RasterRenderer; import de.erichseifert.gral.plots.points.PointRenderer; import org.junit.Before; import org.junit.Test; public class RasterPlotTest { private static final double DELTA = TestUtils.DELTA; private DataSource data; private MockRasterPlot plot; private static final class MockRasterPlot extends RasterPlot { /** Version id for serialization. */ private static final long serialVersionUID = 1043958957664771847L; public boolean isDrawn; public MockRasterPlot(DataSource data) { super(data); } @Override public void draw(DrawingContext context) { super.draw(context); isDrawn = true; } } @Before public void setUp() { data = new DummyData(2, 12, 1.0); plot = new MockRasterPlot(data); } @Test public void testDraw() { plot.getAxis(BarPlot.AXIS_X).setRange(-1.0, 3.0); plot.getAxis(BarPlot.AXIS_Y).setRange(-1.0, 2.0); BufferedImage image = createTestImage(); plot.setBounds(0.0, 0.0, image.getWidth(), image.getHeight()); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); plot.draw(context); assertTrue(plot.isDrawn); assertNotEmpty(image); } @Test public void testAddRemoveData() { plot.remove(data); assertEquals(0, plot.getData().size()); plot.add(data); assertEquals(1, plot.getData().size()); try { plot.add(data); fail(); } catch (IllegalArgumentException e) { } } @Test public void testSerialization() throws IOException, ClassNotFoundException { RasterPlot original = plot; RasterPlot deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getBackground(), deserialized.getBackground()); assertEquals(original.getBorderStroke(), deserialized.getBorderStroke()); assertEquals(original.getBorderColor(), deserialized.getBorderColor()); assertEquals(original.isLegendVisible(), deserialized.isLegendVisible()); assertEquals(original.getLegendLocation(), deserialized.getLegendLocation()); assertEquals(original.getLegendDistance(), deserialized.getLegendDistance(), DELTA); assertEquals(original.getOffset(), deserialized.getOffset()); assertEquals(original.getDistance(), deserialized.getDistance()); assertEquals(original.getColors(), deserialized.getColors()); List dataSourcesOriginal = original.getData(); List dataSourcesDeserialized = deserialized.getData(); assertEquals(dataSourcesOriginal.size(), dataSourcesDeserialized.size()); for (int index = 0; index < dataSourcesOriginal.size(); index++) { List pointRenderersOriginal = original.getPointRenderers( dataSourcesOriginal.get(index)); List pointRenderersDeserialized = deserialized.getPointRenderers( dataSourcesDeserialized.get(index)); testPointRendererSerialization(pointRenderersOriginal, pointRenderersDeserialized); } } private static void testPointRendererSerialization( List originalRenderers, List deserializedRenderers) { for (int rendererIndex = 0; rendererIndex < originalRenderers.size(); rendererIndex++) { RasterRenderer original = (RasterRenderer) originalRenderers.get(rendererIndex); RasterRenderer deserialized = (RasterRenderer) deserializedRenderers.get(rendererIndex); assertEquals(original.getXColumn(), deserialized.getXColumn()); assertEquals(original.getYColumn(), deserialized.getYColumn()); assertEquals(original.getValueColumn(), deserialized.getValueColumn()); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/XYPlotTest.java000066400000000000000000000240121267060725100267630ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.geom.Ellipse2D; import java.awt.geom.Line2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DummyData; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.graphics.Location; import de.erichseifert.gral.plots.XYPlot.XYPlotArea2D; import de.erichseifert.gral.plots.areas.AreaRenderer; import de.erichseifert.gral.plots.areas.DefaultAreaRenderer2D; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.lines.DefaultLineRenderer2D; import de.erichseifert.gral.plots.lines.LineRenderer; import de.erichseifert.gral.plots.points.DefaultPointRenderer2D; import de.erichseifert.gral.plots.points.PointData; import de.erichseifert.gral.plots.points.PointRenderer; import de.erichseifert.gral.util.PointND; import org.junit.Before; import org.junit.Test; public class XYPlotTest { private static final double DELTA = TestUtils.DELTA; private List plots; private static class MockXYPlot extends XYPlot { /** Version id for serialization. */ private static final long serialVersionUID = -4211015243684983841L; private boolean drawn; public MockXYPlot(DataSource... data) { super(data); } @Override public void draw(DrawingContext context) { super.draw(context); drawn = true; } public boolean isDrawn() { return drawn; } } @Before public void setUp() { DataSource data = new DummyData(2, 2, 1.0); plots = new LinkedList(); MockXYPlot plot; // XYPlot with all options turned on plot = new MockXYPlot(data); plot.getTitle().setText("foobar"); XYPlotArea2D plotArea = (XYPlotArea2D) plot.getPlotArea(); plotArea.setMajorGridX(true); plotArea.setMajorGridY(true); plotArea.setMajorGridColor(Color.BLUE); plotArea.setMinorGridX(true); plotArea.setMinorGridY(true); plotArea.setMinorGridColor(Color.BLUE); plot.setLegendVisible(true); plot.setLegendLocation(Location.SOUTH); plot.setLegendDistance(2.0); plot.setBorderColor(Color.RED); plot.setBorderStroke(new BasicStroke(1.5f)); plot.getAxisRenderer(XYPlot.AXIS_X).setTickSpacing(0.2); plot.getAxisRenderer(XYPlot.AXIS_Y).setTickSpacing(0.2); plots.add(plot); plot = new MockXYPlot(data); plot.getTitle().setText(null); ((XYPlotArea2D) plot.getPlotArea()).setMajorGridX(false); ((XYPlotArea2D) plot.getPlotArea()).setMinorGridX(false); plot.setLegendVisible(false); plot.setBorderColor(null); plot.getAxisRenderer(XYPlot.AXIS_X).setTickSpacing(0.0); plot.getAxisRenderer(XYPlot.AXIS_Y).setTickSpacing(0.0); plots.add(plot); } @Test public void testDraw() { for (MockXYPlot plot : plots) { BufferedImage image = createTestImage(); plot.setBounds(0.0, 0.0, image.getWidth(), image.getHeight()); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); plot.draw(context); assertTrue(plot.isDrawn()); assertNotEmpty(image); } } @Test public void testGetPointRenderers() { DataSource data = new DummyData(2, 1, 1.0); MockXYPlot plot = new MockXYPlot(data); PointRenderer renderer1 = new DefaultPointRenderer2D(); PointRenderer renderer2 = new DefaultPointRenderer2D(); plot.setPointRenderers(data, renderer1, renderer2); assertNotNull(plot.getPointRenderers(new DummyData(4, 2, 0.0))); assertNotNull(plot.getPointRenderers(null)); List renderers = plot.getPointRenderers(data); assertTrue(renderers.contains(renderer1)); assertTrue(renderers.contains(renderer2)); assertEquals(renderers.size(), 2); } @Test public void testGetLineRenderers() { DataSource data = new DummyData(2, 1, 1.0); MockXYPlot plot = new MockXYPlot(data); LineRenderer renderer = new DefaultLineRenderer2D(); plot.setLineRenderers(data, renderer); assertNotNull(plot.getLineRenderers(new DummyData(4, 2, 0.0))); assertNotNull(plot.getLineRenderers(null)); List renderers = plot.getLineRenderers(data); assertTrue(renderers.contains(renderer)); assertEquals(renderers.size(), 1); } @Test public void testSetLineRenderers() { DataSource data = new DummyData(2, 1, 1.0); MockXYPlot plot = new MockXYPlot(); LineRenderer renderer1 = new DefaultLineRenderer2D(); LineRenderer renderer2 = new DefaultLineRenderer2D(); plot.setLineRenderers(data, Arrays.asList(renderer1, renderer2)); List renderers = plot.getLineRenderers(data); assertTrue(renderers.contains(renderer1)); assertTrue(renderers.contains(renderer2)); assertEquals(renderers.size(), 2); } @Test public void testGetAreaRenderers() { DataSource data = new DummyData(2, 1, 1.0); MockXYPlot plot = new MockXYPlot(data); AreaRenderer renderer = new DefaultAreaRenderer2D(); plot.setAreaRenderers(data, renderer); assertNotNull(plot.getAreaRenderers(new DummyData(4, 2, 0.0))); assertNotNull(plot.getAreaRenderers(null)); List renderers = plot.getAreaRenderers(data); assertTrue(renderers.contains(renderer)); assertEquals(renderers.size(), 1); } @Test public void testSetAreaRenderers() { DataSource data = new DummyData(2, 1, 1.0); MockXYPlot plot = new MockXYPlot(); AreaRenderer renderer1 = new DefaultAreaRenderer2D(); AreaRenderer renderer2 = new DefaultAreaRenderer2D(); plot.setAreaRenderers(data, Arrays.asList(renderer1, renderer2)); List renderers = plot.getAreaRenderers(data); assertTrue(renderers.contains(renderer1)); assertTrue(renderers.contains(renderer2)); assertEquals(renderers.size(), 2); } @Test public void testPunch() { XYPlot plot = new XYPlot(); Axis axisX = plot.getAxis(XYPlot.AXIS_X); Axis axisY = plot.getAxis(XYPlot.AXIS_Y); AxisRenderer axisRendererX = plot.getAxisRenderer(XYPlot.AXIS_X); AxisRenderer axisRendererY = plot.getAxisRenderer(XYPlot.AXIS_Y); PointData data = new PointData( Arrays.asList(axisX, axisY), Arrays.asList(axisRendererX, axisRendererY), null, 0); Shape line = new Line2D.Double(-1.0, -1.0, 2.0, 2.0); List points = Arrays.asList( new DataPoint(data, new PointND(0.0, 0.0)), new DataPoint(data, new PointND(1.0, 1.0)) ); XYPlotArea2D plotArea = (XYPlotArea2D) plot.getPlotArea(); Shape punchShape = new Ellipse2D.Double(-0.25, -0.25, 0.50, 0.50); Shape punched = plotArea.punch(line, points, Arrays.asList(punchShape, punchShape), 1.0, false); assertNotSame(line, punched); } @Test public void testAddPointRenderer() { DataSource data = new DummyData(2, 1, 1); MockXYPlot plot = new MockXYPlot(); assertTrue(plot.getPointRenderers(data).isEmpty()); PointRenderer renderer = new DefaultPointRenderer2D(); plot.addPointRenderer(data, renderer); List pointRenderers = plot.getPointRenderers(data); assertEquals(pointRenderers.size(), 1); assertEquals(pointRenderers.get(0), renderer); } @Test public void testRemovePointRenderer() { DataSource data = new DummyData(2, 1, 1); MockXYPlot plot = new MockXYPlot(); plot.removePointRenderer(null, null); plot.removePointRenderer(data, null); PointRenderer renderer = new DefaultPointRenderer2D(); plot.addPointRenderer(data, renderer); plot.removePointRenderer(data, renderer); assertTrue(plot.getPointRenderers(data).isEmpty()); } @Test public void testSerialization() throws IOException, ClassNotFoundException { MockXYPlot original = plots.get(0); MockXYPlot deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getBackground(), deserialized.getBackground()); assertEquals(original.getBorderStroke(), deserialized.getBorderStroke()); assertEquals(original.getBorderColor(), deserialized.getBorderColor()); assertEquals(original.isLegendVisible(), deserialized.isLegendVisible()); assertEquals(original.getLegendLocation(), deserialized.getLegendLocation()); assertEquals(original.getLegendDistance(), deserialized.getLegendDistance(), DELTA); testPlotAreaSerialization(original.getPlotArea(), deserialized.getPlotArea()); } private static void testPlotAreaSerialization(PlotArea originalPlotArea, PlotArea deserializedPlotArea) { XYPlotArea2D original = (XYPlotArea2D) originalPlotArea; XYPlotArea2D deserialized = (XYPlotArea2D) deserializedPlotArea; assertEquals(original.isMajorGridX(), deserialized.isMajorGridX()); assertEquals(original.isMajorGridY(), deserialized.isMajorGridY()); assertEquals(original.getMajorGridColor(), deserialized.getMajorGridColor()); assertEquals(original.isMinorGridX(), deserialized.isMinorGridX()); assertEquals(original.isMinorGridY(), deserialized.isMinorGridY()); assertEquals(original.getMinorGridColor(), deserialized.getMinorGridColor()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/areas/000077500000000000000000000000001267060725100251555ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/areas/AbstractAreaRendererTest.java000066400000000000000000000052151267060725100327060ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.areas; import static org.junit.Assert.assertEquals; import java.awt.Color; import java.awt.Shape; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.util.List; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.DataPoint; public class AbstractAreaRendererTest { private static final double DELTA = TestUtils.DELTA; private static class MockAbstractAreaRenderer extends AbstractAreaRenderer { public MockAbstractAreaRenderer() { } @Override public Shape getAreaShape(List points) { return new Rectangle2D.Float(0, 0, 10, 10); } @Override public Drawable getArea(List points, final Shape shape) { return new AbstractDrawable() { @Override public void draw(DrawingContext context) { context.getGraphics().draw(shape); } }; } } @Test public void testProperties() { double gap = 1.23; boolean gapRounded = true; Color color = Color.RED; MockAbstractAreaRenderer r = new MockAbstractAreaRenderer(); r.setGap(gap); r.setGapRounded(gapRounded); r.setColor(color); assertEquals(gap, r.getGap(), DELTA); assertEquals(gapRounded, r.isGapRounded()); assertEquals(color, r.getColor()); } @Test public void testSerialization() throws IOException, ClassNotFoundException { AreaRenderer original = new MockAbstractAreaRenderer(); AreaRenderer deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getGap(), deserialized.getGap(), DELTA); assertEquals(original.isGapRounded(), deserialized.isGapRounded()); assertEquals(original.getColor(), deserialized.getColor()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/areas/AreasTests.java000066400000000000000000000022041267060725100300740ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.areas; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ AbstractAreaRendererTest.class, DefaultAreaRendererTest.class, LineAreaRendererTest.class }) public class AreasTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/areas/DefaultAreaRendererTest.java000066400000000000000000000123341267060725100325270ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.areas; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Arrays; import java.util.List; import static de.erichseifert.gral.TestUtils.assertEmpty; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertNotNull; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.DataPoint; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.axes.LinearRenderer2D; import de.erichseifert.gral.plots.points.PointData; import de.erichseifert.gral.util.PointND; import org.junit.Before; import org.junit.Test; public class DefaultAreaRendererTest { private PointData data; @Before public void setUp() { Axis axisX = new Axis(-5.0, 5.0); Axis axisY = new Axis(-5.0, 5.0); AxisRenderer axisRendererX = new LinearRenderer2D(); AxisRenderer axisRendererY = new LinearRenderer2D(); data = new PointData( Arrays.asList(axisX, axisY), Arrays.asList(axisRendererX, axisRendererY), null, 0); } @Test public void testArea() { // Get area AreaRenderer r = new DefaultAreaRenderer2D(); List points = Arrays.asList( new DataPoint(data, new PointND(0.0, 0.0)), new DataPoint(data, new PointND(1.0, 1.0)) ); Shape shape = r.getAreaShape(points); Drawable area = r.getArea(points, shape); assertNotNull(area); // Draw area BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); area.draw(context); assertNotEmpty(image); } @Test public void testNullRenderer() { PointData data2 = new PointData( data.axes, Arrays.asList((AxisRenderer) null, null), null, 0); // Get area AreaRenderer r = new DefaultAreaRenderer2D(); List points = Arrays.asList( new DataPoint(data2, new PointND(0.0, 0.0)), new DataPoint(data2, new PointND(1.0, 1.0)) ); Shape shape = r.getAreaShape(points); Drawable area = r.getArea(points, shape); assertNotNull(area); // Draw area BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); area.draw(context); assertEmpty(image); } @Test public void testEmptyShape() { // Get area AreaRenderer r = new DefaultAreaRenderer2D(); List points = Arrays.asList(); Drawable area = r.getArea(points, null); assertNotNull(area); // Draw area BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); area.draw(context); assertEmpty(image); } @Test public void testNullPoint() { // Get area AreaRenderer r = new DefaultAreaRenderer2D(); List points = Arrays.asList((DataPoint) null); Shape shape = r.getAreaShape(points); Drawable area = r.getArea(points, shape); assertNotNull(area); // Draw area BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); area.draw(context); assertEmpty(image); } @Test public void testGap() { AreaRenderer r = new DefaultAreaRenderer2D(); List points = Arrays.asList( new DataPoint(data, new PointND(0.0, 0.0)), new DataPoint(data, new PointND(1.0, 1.0)) ); List gaps = Arrays.asList(Double.NaN, 0.0, 1.0); List roundedValues = Arrays.asList(false, true); // Test different gap sizes for (Double gap : gaps) { r.setGap(gap); // Draw non-rounded and non rounded gaps for (Boolean rounded : roundedValues) { r.setGapRounded(rounded); Shape shape = r.getAreaShape(points); Drawable area = r.getArea(points, shape); assertNotNull(area); BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); area.draw(context); assertNotEmpty(image); } } } @Test public void testSerialization() throws IOException, ClassNotFoundException { AreaRenderer original = new DefaultAreaRenderer2D(); @SuppressWarnings("unused") AreaRenderer deserialized = TestUtils.serializeAndDeserialize(original); } }gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/areas/LineAreaRendererTest.java000066400000000000000000000073531267060725100320370ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.areas; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.DataPoint; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.axes.LinearRenderer2D; import de.erichseifert.gral.plots.points.PointData; import de.erichseifert.gral.util.PointND; import org.junit.Before; import org.junit.Test; public class LineAreaRendererTest { private PointData data; @Before public void setUp() { Axis axisX = new Axis(-5.0, 5.0); Axis axisY = new Axis(-5.0, 5.0); AxisRenderer axisRendererX = new LinearRenderer2D(); AxisRenderer axisRendererY = new LinearRenderer2D(); data = new PointData( Arrays.asList(axisX, axisY), Arrays.asList(axisRendererX, axisRendererY), null, 0); } @Test public void testArea() { // Get line AreaRenderer r = new LineAreaRenderer2D(); List points = Arrays.asList( new DataPoint(data, new PointND(0.0, 0.0)), new DataPoint(data, new PointND(1.0, 1.0)) ); Shape shape = r.getAreaShape(points); Drawable area = r.getArea(points, shape); assertNotNull(area); // Draw area BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); area.draw(context); assertNotEmpty(image); } @Test public void testShapeNoPoints() { AreaRenderer r = new LineAreaRenderer2D(); List points = new LinkedList(); Shape shape = r.getAreaShape(points); assertNull(shape); } @Test public void testShapeNullPoints() { AreaRenderer r = new LineAreaRenderer2D(); List points = Arrays.asList((DataPoint) null); Shape shape = r.getAreaShape(points); assertNull(shape); } @Test public void testShapeNullRenderer() { AreaRenderer r = new LineAreaRenderer2D(); PointData data2 = new PointData( data.axes, Arrays.asList((AxisRenderer) null, null), null, 0); List points = Arrays.asList( new DataPoint(data2, new PointND(0.0, 0.0)), new DataPoint(data2, new PointND(1.0, 1.0)) ); Shape shape = r.getAreaShape(points); assertNotNull(shape); } @Test public void testSerialization() throws IOException, ClassNotFoundException { AreaRenderer original = new DefaultAreaRenderer2D(); @SuppressWarnings("unused") AreaRenderer deserialized = TestUtils.serializeAndDeserialize(original); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/areas/package-info.java000077500000000000000000000017341267060725100303540ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.plots.areas} package. */ package de.erichseifert.gral.plots.areas; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/axes/000077500000000000000000000000001267060725100250225ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/axes/AbstractAxisRenderer2DTest.java000066400000000000000000000104001267060725100327650ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.axes; import static org.junit.Assert.assertEquals; import java.io.IOException; import java.util.List; import java.util.Set; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; public class AbstractAxisRenderer2DTest { private static final double DELTA = 1e-10; private AbstractAxisRenderer2D renderer; private static class MockAbstractAxisRenderer2D extends AbstractAxisRenderer2D { @Override public double worldToView(Axis axis, Number value, boolean extrapolate) { return value.doubleValue(); } @Override public Number viewToWorld(Axis axis, double value, boolean extrapolate) { return value; } @Override protected void createTicks(List ticks, Axis axis, double min, double max, Set tickPositions, boolean isAutoSpacing) { } } @Before public void setUp() { renderer = new MockAbstractAxisRenderer2D(); } @Test public void testSerialization() throws IOException, ClassNotFoundException { AbstractAxisRenderer2D original = renderer; AbstractAxisRenderer2D deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getIntersection(), deserialized.getIntersection()); TestUtils.assertEquals(original.getShape(), deserialized.getShape()); assertEquals(original.isShapeVisible(), deserialized.isShapeVisible()); assertEquals(original.isShapeNormalOrientationClockwise(), deserialized.isShapeNormalOrientationClockwise()); assertEquals(original.getShapeColor(), deserialized.getShapeColor()); assertEquals(original.getShapeStroke(), deserialized.getShapeStroke()); assertEquals(original.isShapeDirectionSwapped(), deserialized.isShapeDirectionSwapped()); assertEquals(original.isTicksVisible(), deserialized.isTicksVisible()); assertEquals(original.getTickSpacing(), deserialized.getTickSpacing()); assertEquals(original.isTicksAutoSpaced(), deserialized.isTicksAutoSpaced()); assertEquals(original.getTickLength(), deserialized.getTickLength(), DELTA); assertEquals(original.getTickStroke(), deserialized.getTickStroke()); assertEquals(original.getTickAlignment(), deserialized.getTickAlignment(), DELTA); assertEquals(original.getTickFont(), deserialized.getTickFont()); assertEquals(original.getTickColor(), deserialized.getTickColor()); assertEquals(original.isTickLabelsVisible(), deserialized.isTickLabelsVisible()); assertEquals(original.getTickLabelFormat(), deserialized.getTickLabelFormat()); assertEquals(original.getTickLabelDistance(), deserialized.getTickLabelDistance(), DELTA); assertEquals(original.isTickLabelsOutside(), deserialized.isTickLabelsOutside()); assertEquals(original.getTickLabelRotation(), deserialized.getTickLabelRotation(), DELTA); assertEquals(original.isMinorTicksVisible(), deserialized.isMinorTicksVisible()); assertEquals(original.getMinorTicksCount(), deserialized.getMinorTicksCount()); assertEquals(original.getMinorTickLength(), deserialized.getMinorTickLength(), DELTA); assertEquals(original.getMinorTickStroke(), deserialized.getMinorTickStroke()); assertEquals(original.getMinorTickAlignment(), deserialized.getMinorTickAlignment(), DELTA); assertEquals(original.getMinorTickColor(), deserialized.getMinorTickColor()); assertEquals(original.getCustomTicks(), deserialized.getCustomTicks()); assertEquals(original.getLabel(), deserialized.getLabel()); assertEquals(original.getLabelDistance(), deserialized.getLabelDistance(), DELTA); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/axes/AxesTests.java000066400000000000000000000022301267060725100276050ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.axes; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ AxisTest.class, AbstractAxisRenderer2DTest.class, LinearRenderer2DTest.class, LogarithmicRenderer2DTest.class }) public class AxesTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/axes/AxisTest.java000066400000000000000000000061341267060725100274350ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.axes; import static org.junit.Assert.assertEquals; import java.io.IOException; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; public class AxisTest { private static final double DELTA = TestUtils.DELTA; private Axis axis; @Before public void setUp() { axis = new Axis(-5.0, 5.0); } @Test public void testMin() { assertEquals(-5.0, axis.getMin().doubleValue(), DELTA); axis.setMin(10.0); assertEquals(10.0, axis.getMin().doubleValue(), DELTA); // Test auto-scaling mode axis.setAutoscaled(true); assertEquals(10.0, axis.getMin().doubleValue(), DELTA); } @Test public void testMax() { assertEquals(5.0, axis.getMax().doubleValue(), DELTA); axis.setMax(10.0); assertEquals(10.0, axis.getMax().doubleValue(), DELTA); // Test auto-scaling mode axis.setAutoscaled(true); assertEquals(10.0, axis.getMax().doubleValue(), DELTA); } @Test public void testRange() { assertEquals(10.0, axis.getRange(), DELTA); axis.setRange(1.0, 3.0); assertEquals(2.0, axis.getRange(), DELTA); // Test auto-scaling mode axis.setAutoscaled(true); assertEquals(2.0, axis.getRange(), DELTA); } private static final class AxisListenerTest implements AxisListener { public Axis axis = null; public Number min = null; public Number max = null; public void rangeChanged(Axis axis, Number min, Number max) { this.axis = axis; this.min = min; this.max = max; } } @Test public void testAxisListeners() { AxisListenerTest l = new AxisListenerTest(); axis.addAxisListener(l); axis.setRange(0.0, 1.0); assertEquals(axis, l.axis); assertEquals(0.0, l.min.doubleValue(), DELTA); assertEquals(1.0, l.max.doubleValue(), DELTA); axis.removeAxisListener(l); axis.setRange(2.0, 3.0); assertEquals(axis, l.axis); assertEquals(0.0, l.min.doubleValue(), DELTA); assertEquals(1.0, l.max.doubleValue(), DELTA); } @Test public void testSerialization() throws IOException, ClassNotFoundException { Axis original = axis; Axis deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getMin(), deserialized.getMin()); assertEquals(original.getMax(), deserialized.getMax()); assertEquals(original.getRange(), deserialized.getRange(), DELTA); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/axes/LinearRenderer2DTest.java000066400000000000000000000102731267060725100316170ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.axes; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; public class LinearRenderer2DTest { private static final double DELTA = 1e-15; private Axis axis; private AxisRenderer renderer; @Before public void setUp() { axis = new Axis(); axis.setRange(-5.0, 5.0); renderer = new LinearRenderer2D(); } @Test public void testDraw() { Drawable d = renderer.getRendererComponent(axis); assertNotNull(d); BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); d.draw(context); assertNotEmpty(image); } @Test public void testWorldToView() { assertEquals( 0.0, renderer.worldToView(axis, -5.0, false), DELTA); assertEquals( 1.0, renderer.worldToView(axis, 5.0, false), DELTA); assertEquals( 0.5, renderer.worldToView(axis, 0.0, false), DELTA); assertEquals( 0.0, renderer.worldToView(axis, -10.0, false), DELTA); assertEquals( 1.0, renderer.worldToView(axis, 10.0, false), DELTA); assertEquals( 0.8, renderer.worldToView(axis, 3.0, false), DELTA); assertEquals( 0.0, renderer.worldToView(axis, -5.0, true), DELTA); assertEquals( 1.0, renderer.worldToView(axis, 5.0, true), DELTA); assertEquals( 0.5, renderer.worldToView(axis, 0.0, true), DELTA); assertEquals(-0.5, renderer.worldToView(axis, -10.0, true), DELTA); assertEquals( 1.5, renderer.worldToView(axis, 10.0, true), DELTA); assertEquals( 0.8, renderer.worldToView(axis, 3.0, true), DELTA); } @Test public void testViewToWorld() { assertEquals( -5.0, renderer.viewToWorld(axis, 0.0, false)); assertEquals( 0.0, renderer.viewToWorld(axis, 0.5, false)); assertEquals( 3.0, renderer.viewToWorld(axis, 0.8, false)); assertEquals( 5.0, renderer.viewToWorld(axis, 1.0, false)); assertEquals(-10.0, renderer.viewToWorld(axis, -0.5, true)); assertEquals( -5.0, renderer.viewToWorld(axis, 0.0, true)); assertEquals( 0.0, renderer.viewToWorld(axis, 0.5, true)); assertEquals( 3.0, renderer.viewToWorld(axis, 0.8, true)); assertEquals( 5.0, renderer.viewToWorld(axis, 1.0, true)); assertEquals( 10.0, renderer.viewToWorld(axis, 1.5, true)); } @Test public void testViewToView() { double[] values = {-0.5, 0.0, 0.5, 0.8, 1.0, 1.5}; for (double v: values) { Number world = renderer.viewToWorld(axis, v, true); double view = renderer.worldToView(axis, world, true); assertEquals(v, view, DELTA); } } @Test public void testWorldToWorld() { double[] values = {-0.5, 0.0, 0.5, 0.8, 1.0, 1.5}; for (double v: values) { double view = renderer.worldToView(axis, v, true); double world = renderer.viewToWorld(axis, view, true).doubleValue(); assertEquals(v, world, DELTA); } } @Test public void testSerialization() throws IOException, ClassNotFoundException { AxisRenderer original = renderer; @SuppressWarnings("unused") AxisRenderer deserialized = TestUtils.serializeAndDeserialize(original); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/axes/LogarithmicRenderer2DTest.java000066400000000000000000000122741267060725100326520ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.axes; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.List; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; public class LogarithmicRenderer2DTest { private static final double DELTA = 1e-14; private Axis axis; private AxisRenderer renderer; @Before public void setUp() { axis = new Axis(0.0, 10.0); renderer = new LogarithmicRenderer2D(); } @Test public void testDraw() { Axis axis = new Axis(); axis.setRange(0.1, 10.0); Drawable d = renderer.getRendererComponent(axis); assertNotNull(d); BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); d.draw(context); assertNotEmpty(image); } @Test public void testWorldToView() { assertEquals(Double.NEGATIVE_INFINITY, renderer.worldToView(axis, 0.0, true), DELTA); assertEquals(Math.log10( 0.1), renderer.worldToView(axis, 0.1, true), DELTA); assertEquals(Math.log10( 1.0), renderer.worldToView(axis, 1.0, true), DELTA); assertEquals(Math.log10( 5.0), renderer.worldToView(axis, 5.0, true), DELTA); assertEquals(Math.log10( 9.0), renderer.worldToView(axis, 9.0, true), DELTA); assertEquals(Math.log10(10.0), renderer.worldToView(axis, 10.0, true), DELTA); } @Test public void testViewToWorld() { boolean extrapolate = true; assertEquals( 0.00, renderer.viewToWorld(axis, Double.NEGATIVE_INFINITY, extrapolate).doubleValue(), DELTA); assertEquals( 0.01, renderer.viewToWorld(axis, Math.log10( 0.01), extrapolate).doubleValue(), DELTA); assertEquals( 0.10, renderer.viewToWorld(axis, Math.log10( 0.10), extrapolate).doubleValue(), DELTA); assertEquals( 1.00, renderer.viewToWorld(axis, Math.log10( 1.00), extrapolate).doubleValue(), DELTA); assertEquals( 5.00, renderer.viewToWorld(axis, Math.log10( 5.00), extrapolate).doubleValue(), DELTA); assertEquals( 9.00, renderer.viewToWorld(axis, Math.log10( 9.00), extrapolate).doubleValue(), DELTA); assertEquals(10.00, renderer.viewToWorld(axis, Math.log10(10.00), extrapolate).doubleValue(), DELTA); assertEquals(15.00, renderer.viewToWorld(axis, Math.log10(15.00), extrapolate).doubleValue(), DELTA); extrapolate = false; assertEquals( 0.00, renderer.viewToWorld(axis, Double.NEGATIVE_INFINITY, extrapolate).doubleValue(), DELTA); assertEquals( 0.00, renderer.viewToWorld(axis, Math.log10( 0.01), extrapolate).doubleValue(), DELTA); assertEquals( 0.00, renderer.viewToWorld(axis, Math.log10( 0.10), extrapolate).doubleValue(), DELTA); assertEquals( 0.00, renderer.viewToWorld(axis, Math.log10( 1.00), extrapolate).doubleValue(), DELTA); assertEquals( 5.00, renderer.viewToWorld(axis, Math.log10( 5.00), extrapolate).doubleValue(), DELTA); assertEquals( 9.00, renderer.viewToWorld(axis, Math.log10( 9.00), extrapolate).doubleValue(), DELTA); assertEquals(10.00, renderer.viewToWorld(axis, Math.log10(10.00), extrapolate).doubleValue(), DELTA); assertEquals(10.00, renderer.viewToWorld(axis, Math.log10(15.00), extrapolate).doubleValue(), DELTA); } @Test public void testViewToView() { double[] values = {0.01, 0.10, 1.00, 5.00, 9.00, 10.00, 15.00}; for (double v: values) { Number world = renderer.viewToWorld(axis, v, true); double view = renderer.worldToView(axis, world, true); assertEquals(v, view, DELTA); } } @Test public void testWorldToWorld() { double[] values = {0.01, 0.10, 1.00, 5.00, 9.00, 10.00, 15.00}; for (double v: values) { double view = renderer.worldToView(axis, v, true); double world = renderer.viewToWorld(axis, view, true).doubleValue(); assertEquals(v, world, DELTA); } } @Test public void testTicks() { Axis axis = new Axis(0.2, 10.0); List ticks = renderer.getTicks(axis); assertEquals(36, ticks.size()); // 18 major ticks, 18 minor ticks } @Test public void testSerialization() throws IOException, ClassNotFoundException { AxisRenderer original = renderer; @SuppressWarnings("unused") AxisRenderer deserialized = TestUtils.serializeAndDeserialize(original); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/axes/package-info.java000077500000000000000000000017321267060725100302170ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.plots.axes} package. */ package de.erichseifert.gral.plots.axes; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/colors/000077500000000000000000000000001267060725100253635ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/colors/ColorsTests.java000066400000000000000000000025171267060725100305170ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ ContinuousColorMapperTest.class, IndexedColorMapperTest.class, ScaledColorMapperTest.class, GrayscaleTest.class, RainbowColorsTest.class, SingleColorTest.class, MultiColorTest.class, HeatMapTest.class, IndexedColorsTest.class, RandomColorsTest.class, QuasiRandomColorsTest.class }) public class ColorsTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/colors/ContinuousColorMapperTest.java000066400000000000000000000065231267060725100334060ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import java.awt.Color; import java.awt.Paint; import java.io.IOException; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.plots.colors.ColorMapper.Mode; import de.erichseifert.gral.util.MathUtils; public class ContinuousColorMapperTest { private static final class MockContinuousColorMapper extends ContinuousColorMapper { /** Version id for serialization. */ private static final long serialVersionUID = 2862456675214994497L; @Override public Paint get(double value) { Double v = applyMode(value, 0.0, 1.0); if (!MathUtils.isCalculatable(v)) { return null; } float c = v.floatValue(); return new Color(c, c, c); } } @Test public void testGetNumber() { MockContinuousColorMapper c = new MockContinuousColorMapper(); assertEquals(c.get(0.5), c.get(0.5f)); } @Test public void testGetOmit() { MockContinuousColorMapper c = new MockContinuousColorMapper(); c.setMode(Mode.OMIT); assertNull(c.get(-0.5)); assertEquals(new Color( 0, 0, 0), c.get( 0.0)); assertEquals(new Color(128, 128, 128), c.get( 0.5)); assertEquals(new Color(255, 255, 255), c.get( 1.0)); assertNull(c.get( 1.5)); } @Test public void testGetRepeat() { MockContinuousColorMapper c = new MockContinuousColorMapper(); c.setMode(Mode.REPEAT); assertEquals(new Color( 0, 0, 0), c.get(-0.5)); assertEquals(new Color( 0, 0, 0), c.get( 0.0)); assertEquals(new Color(128, 128, 128), c.get( 0.5)); assertEquals(new Color(255, 255, 255), c.get( 1.0)); assertEquals(new Color(255, 255, 255), c.get( 1.5)); } @Test public void testGetCircular() { MockContinuousColorMapper c = new MockContinuousColorMapper(); c.setMode(Mode.CIRCULAR); assertEquals(new Color(128, 128, 128), c.get(-0.5)); assertEquals(new Color( 0, 0, 0), c.get( 0.0)); assertEquals(new Color(128, 128, 128), c.get( 0.5)); assertEquals(new Color(255, 255, 255), c.get( 1.0)); assertEquals(new Color(128, 128, 128), c.get( 1.5)); } @Test public void testSerialization() throws IOException, ClassNotFoundException { MockContinuousColorMapper original = new MockContinuousColorMapper(); MockContinuousColorMapper deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getMode(), deserialized.getMode()); for (double x = -0.5; x <= 1.5; x += 0.5) { assertEquals(original.get(x), deserialized.get(x)); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/colors/GrayscaleTest.java000066400000000000000000000032571267060725100310070ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import static org.junit.Assert.assertEquals; import java.awt.Color; import java.io.IOException; import org.junit.Test; import de.erichseifert.gral.TestUtils; public class GrayscaleTest { @Test public void testGet() { Grayscale c = new Grayscale(); assertEquals(new Color( 0, 0, 0), c.get(0.0)); assertEquals(new Color(119, 119, 119), c.get(0.5)); assertEquals(new Color(255, 255, 255), c.get(1.0)); } @Test public void testSerialization() throws IOException, ClassNotFoundException { ScaledContinuousColorMapper original = new Grayscale(); ScaledContinuousColorMapper deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getMode(), deserialized.getMode()); for (double x=0.0; x<=1.0; x+=0.5) { assertEquals(original.get(x), deserialized.get(x)); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/colors/HeatMapTest.java000066400000000000000000000034301267060725100304050ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import static org.junit.Assert.assertEquals; import java.awt.Color; import java.io.IOException; import org.junit.Test; import de.erichseifert.gral.TestUtils; public class HeatMapTest { @Test public void testGet() { HeatMap c = new HeatMap(); assertEquals(new Color( 0, 0, 0), c.get(0.00)); assertEquals(new Color( 67, 13, 109), c.get(0.25)); assertEquals(new Color(175, 80, 80), c.get(0.50)); assertEquals(new Color(242, 188, 93), c.get(0.75)); assertEquals(new Color(255, 255, 255), c.get(1.00)); } @Test public void testSerialization() throws IOException, ClassNotFoundException { ScaledContinuousColorMapper original = new HeatMap(); ScaledContinuousColorMapper deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getMode(), deserialized.getMode()); for (double x=0.0; x<=1.0; x+=0.5) { assertEquals(original.get(x), deserialized.get(x)); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/colors/IndexedColorMapperTest.java000066400000000000000000000063521267060725100326200ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import java.awt.Color; import java.awt.Paint; import java.io.IOException; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.plots.colors.ColorMapper.Mode; import de.erichseifert.gral.util.MathUtils; public class IndexedColorMapperTest { private static final class MockIndexedColorMapper extends IndexedColorMapper { /** Version id for serialization. */ private static final long serialVersionUID = -516834950305649435L; @Override public Paint get(int value) { Integer i = applyMode(value, 0, 255); if (!MathUtils.isCalculatable(i)) { return null; } int c = i; return new Color(c, c, c); } } @Test public void testGetNumber() { MockIndexedColorMapper c = new MockIndexedColorMapper(); assertEquals(c.get(128), c.get(128.0)); } @Test public void testGetOmit() { MockIndexedColorMapper c = new MockIndexedColorMapper(); c.setMode(Mode.OMIT); assertNull(c.get(-128)); assertEquals(new Color(0, 0, 0), c.get(0)); assertEquals(new Color(128, 128, 128), c.get(128)); assertEquals(new Color(255, 255, 255), c.get(255)); assertNull(c.get(384)); } @Test public void testGetRepeat() { MockIndexedColorMapper c = new MockIndexedColorMapper(); c.setMode(Mode.REPEAT); assertEquals(new Color(0, 0, 0), c.get(-128)); assertEquals(new Color(0, 0, 0), c.get(0)); assertEquals(new Color(128, 128, 128), c.get(128)); assertEquals(new Color(255, 255, 255), c.get(255)); assertEquals(new Color(255, 255, 255), c.get(384)); } @Test public void testGetCircular() { MockIndexedColorMapper c = new MockIndexedColorMapper(); c.setMode(Mode.CIRCULAR); assertEquals(new Color(128, 128, 128), c.get(-128)); assertEquals(new Color(0, 0, 0), c.get(0)); assertEquals(new Color(128, 128, 128), c.get(128)); assertEquals(new Color(255, 255, 255), c.get(255)); assertEquals(new Color(128, 128, 128), c.get(384)); } @Test public void testSerialization() throws IOException, ClassNotFoundException { MockIndexedColorMapper original = new MockIndexedColorMapper(); MockIndexedColorMapper deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getMode(), deserialized.getMode()); for (int i = -128; i <= 384; i += 128) { assertEquals(original.get(i), deserialized.get(i)); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/colors/IndexedColorsTest.java000066400000000000000000000056261267060725100316410ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import java.awt.Color; import java.io.IOException; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.plots.colors.ColorMapper.Mode; public class IndexedColorsTest { @Test public void testCreate() { IndexedColors c = new IndexedColors(Color.RED, Color.GREEN, Color.BLUE); assertEquals(3, c.getColors().size()); } @Test public void testColor() { IndexedColors c = new IndexedColors(Color.RED, Color.GREEN, Color.BLUE); assertEquals(3, c.getColors().size()); } @Test public void testGetOmit() { IndexedColors c = new IndexedColors(Color.RED, Color.GREEN, Color.BLUE); c.setMode(Mode.OMIT); assertNull(c.get(-1)); assertEquals(Color.RED, c.get(0)); assertEquals(Color.GREEN, c.get(1)); assertEquals(Color.BLUE, c.get(2)); assertNull(c.get(3)); } @Test public void testGetRepeat() { IndexedColors c = new IndexedColors(Color.RED, Color.GREEN, Color.BLUE); c.setMode(Mode.REPEAT); assertEquals(Color.RED, c.get(-1)); assertEquals(Color.RED, c.get(0)); assertEquals(Color.GREEN, c.get(1)); assertEquals(Color.BLUE, c.get(2)); assertEquals(Color.BLUE, c.get(3)); } @Test public void testGetCiricular() { IndexedColors c = new IndexedColors(Color.RED, Color.GREEN, Color.BLUE); c.setMode(Mode.CIRCULAR); assertEquals(Color.BLUE, c.get(-1)); assertEquals(Color.RED, c.get(0)); assertEquals(Color.GREEN, c.get(1)); assertEquals(Color.BLUE, c.get(2)); assertEquals(Color.RED, c.get(3)); } @Test public void testSerialization() throws IOException, ClassNotFoundException { IndexedColors original = new IndexedColors(Color.RED, Color.GREEN, Color.BLUE); IndexedColors deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getMode(), deserialized.getMode()); assertEquals(original.getColors().size(), deserialized.getColors().size()); for (int i = -1; i <= 3; i++) { assertEquals(original.get(i), deserialized.get(i)); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/colors/MultiColorTest.java000066400000000000000000000046451267060725100311700ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import static org.junit.Assert.assertEquals; import java.awt.Color; import java.io.IOException; import java.util.List; import org.junit.Test; import de.erichseifert.gral.TestUtils; public class MultiColorTest { private static final double DELTA = TestUtils.DELTA; @Test public void testCreation() { LinearGradient c = new LinearGradient(Color.WHITE, Color.BLACK); List colors = c.getColors(); assertEquals(2, colors.size()); assertEquals(Color.WHITE, colors.get(0)); assertEquals(Color.BLACK, colors.get(1)); } @Test public void testColor() { LinearGradient c = new LinearGradient(Color.RED, Color.GREEN, Color.BLUE); List colors = c.getColors(); assertEquals(3, colors.size()); assertEquals(new Color(255, 0, 0), c.get(0.00)); assertEquals(new Color(128, 128, 0), c.get(0.25)); assertEquals(new Color( 0, 255, 0), c.get(0.50)); assertEquals(new Color( 0, 128, 128), c.get(0.75)); assertEquals(new Color( 0, 0, 255), c.get(1.00)); } @Test public void testSerialization() throws IOException, ClassNotFoundException { ScaledContinuousColorMapper original = new LinearGradient(Color.RED, Color.GREEN, Color.BLUE); ScaledContinuousColorMapper deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getMode(), deserialized.getMode()); assertEquals(original.getOffset(), deserialized.getOffset(), DELTA); assertEquals(original.getScale(), deserialized.getScale(), DELTA); for (double x=0.0; x<=1.0; x+=0.25) { assertEquals(original.get(x), deserialized.get(x)); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/colors/QuasiRandomColorsTest.java000066400000000000000000000036111267060725100324740ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import java.awt.Paint; import java.io.IOException; import org.junit.Test; import de.erichseifert.gral.TestUtils; public class QuasiRandomColorsTest { private static final float DELTA_FLOAT = 1e-7f; @Test public void testGet() { QuasiRandomColors c = new QuasiRandomColors(); final int STEPS = 10; Paint prv = null; for (int i = 0; i < STEPS; i++) { Paint cur = c.get(i); assertNotNull(cur); assertFalse(cur.equals(prv)); prv = cur; } } @Test public void testSerialization() throws IOException, ClassNotFoundException { QuasiRandomColors original = new QuasiRandomColors(); QuasiRandomColors deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getMode(), deserialized.getMode()); assertArrayEquals(original.getColorVariance(), deserialized.getColorVariance(), DELTA_FLOAT); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/colors/RainbowColorsTest.java000066400000000000000000000033431267060725100316540ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import java.awt.Color; import java.io.IOException; import org.junit.Test; import de.erichseifert.gral.TestUtils; public class RainbowColorsTest { private static final float DELTA_FLOAT = 1e-7f; @Test public void testGet() { RainbowColors c = new RainbowColors(); for (double i = 0.0; i <= 1.0f; i += 0.1f) { assertEquals(Color.getHSBColor((float) i, 1f, 1f), c.get(i)); } } @Test public void testSerialization() throws IOException, ClassNotFoundException { QuasiRandomColors original = new QuasiRandomColors(); QuasiRandomColors deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getMode(), deserialized.getMode()); assertArrayEquals(original.getColorVariance(), deserialized.getColorVariance(), DELTA_FLOAT); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/colors/RandomColorsTest.java000066400000000000000000000052601267060725100314730ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import java.awt.Paint; import java.io.IOException; import org.junit.Test; import de.erichseifert.gral.TestUtils; public class RandomColorsTest { private static final float DELTA_FLOAT = 1e-7f; @Test public void testCreation() { RandomColors c = new RandomColors(); float[] expected = new float[] { 0.00f, 1.00f, // Hue 0.75f, 0.25f, // Saturation 0.25f, 0.75f // Brightness }; float[] actual = c.getColorVariance(); assertEquals(expected.length, actual.length); for (int i = 0; i < actual.length; i++) { assertEquals(expected[i], actual[i], DELTA_FLOAT); } } @Test public void testCreationInt() { RandomColors c1 = new RandomColors(0); RandomColors c2 = new RandomColors(0); for (int i = 0; i <= 10; i++) { assertEquals(c1.get(i), c2.get(i)); } } @Test public void testGet() { RandomColors c = new RandomColors(); int STEPS = 10; Paint[] actual = new Paint[STEPS]; // Test two runs in order to hit cache for (int run = 0; run < 2; run++) { Paint prv = null; for (int i = 0; i < STEPS; i++) { Paint cur = c.get(i); if (run == 0) { actual[i] = cur; } else { assertEquals(actual[i], cur); } assertNotNull(cur); assertFalse(cur.equals(prv)); prv = cur; } } } @Test public void testSerialization() throws IOException, ClassNotFoundException { QuasiRandomColors original = new QuasiRandomColors(); QuasiRandomColors deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getMode(), deserialized.getMode()); assertArrayEquals(original.getColorVariance(), deserialized.getColorVariance(), DELTA_FLOAT); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/colors/ScaledColorMapperTest.java000066400000000000000000000060121267060725100324240ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import static org.junit.Assert.assertEquals; import java.awt.Color; import java.awt.Paint; import java.io.IOException; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.util.MathUtils; public class ScaledColorMapperTest { private static final double DELTA = 1e-15; private ScaledContinuousColorMapper cm; private static final class ScaledContinuousColorMapperMock extends ScaledContinuousColorMapper { /** Version id for serialization. */ private static final long serialVersionUID = -3693380550336601398L; @Override public Paint get(double value) { double v = scale(value); v = applyMode(v, 0.0, 1.0); if (!MathUtils.isCalculatable(v)) { return null; } float i = (float) v; return new Color(i, i, i); } } @Before public void setUp() { cm = new ScaledContinuousColorMapperMock(); } @Test public void testOffset() { assertEquals(0.0, cm.getOffset(), DELTA); cm.setOffset(42.0); assertEquals(42.0, cm.getOffset(), DELTA); } @Test public void testScale() { assertEquals(1.0, cm.getScale(), DELTA); cm.setScale(42.0); assertEquals(42.0, cm.getScale(), DELTA); } private static void assertColor(double expected, Paint p) { Color c = (Color) p; int e = (int) MathUtils.limit(expected*255.0 + 0.5, 0, 255); assertEquals(e, c.getRed()); assertEquals(e, c.getGreen()); assertEquals(e, c.getBlue()); } @Test public void testScaleOp() { for (double x=0.0; x<=1.0; x+=0.5) { assertColor(x, cm.get(x)); } cm.setRange(0.25, 0.75); for (double x=0.0; x<=1.0; x+=0.5) { assertColor((x - 0.25)/0.5, cm.get(x)); } } @Test public void testSerialization() throws IOException, ClassNotFoundException { ScaledContinuousColorMapper original = cm; ScaledContinuousColorMapper deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getMode(), deserialized.getMode()); assertEquals(original.getOffset(), deserialized.getOffset(), DELTA); assertEquals(original.getScale(), deserialized.getScale(), DELTA); for (double x=0.0; x<=1.0; x+=0.5) { assertEquals(original.get(x), deserialized.get(x)); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/colors/SingleColorTest.java000066400000000000000000000037021267060725100313100ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.colors; import static org.junit.Assert.assertEquals; import java.awt.Color; import java.io.IOException; import org.junit.Test; import de.erichseifert.gral.TestUtils; public class SingleColorTest { @Test public void testCreate() { SingleColor c = new SingleColor(Color.WHITE); assertEquals(Color.WHITE, c.getColor()); } @Test public void testColor() { SingleColor c = new SingleColor(Color.BLUE); // Get assertEquals(Color.BLUE, c.getColor()); // Set c.setColor(Color.RED); assertEquals(Color.RED, c.getColor()); } @Test public void testGet() { SingleColor c = new SingleColor(Color.BLUE); for (int i = 0; i <= 10; i++) { assertEquals(Color.BLUE, c.get(i)); } } @Test public void testSerialization() throws IOException, ClassNotFoundException { SingleColor original = new SingleColor(new Color(0.12f, 0.34f, 0.56f, 0.78f)); SingleColor deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getColor(), deserialized.getColor()); for (int i = 0; i < 5; i++) { assertEquals(original.get(i), deserialized.get(i)); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/colors/package-info.java000077500000000000000000000017361267060725100305640ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.plots.colors} package. */ package de.erichseifert.gral.plots.colors; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/legends/000077500000000000000000000000001267060725100255035ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/legends/LegendTest.java000066400000000000000000000073561267060725100304170ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.legends; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import org.junit.Before; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DummyData; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; public class LegendTest { private static final double DELTA = 1e-10; private MockLegend legend; private static class MockLegend extends SeriesLegend { /** Version id for serialization. */ private static final long serialVersionUID = -6681407860400756446L; private boolean isDrawn; public Drawable getSymbol(Row data) { return new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = 7336075728956564691L; public void draw(DrawingContext context) { isDrawn = true; } }; } } @Before public void setUp() { legend = new MockLegend(); } @Test public void testDataSources() { DataSource source = new DummyData(1, 1, 1.0); assertFalse(legend.contains(source)); legend.add(source); assertTrue(legend.contains(source)); legend.remove(source); assertFalse(legend.contains(source)); } @Test public void testDraw() { legend.setBackground(Color.WHITE); legend.setBorderStroke(new BasicStroke(1f)); legend.add(new DummyData(1, 1, 1.0)); BufferedImage image = createTestImage(); legend.setBounds(0.0, 0.0, image.getWidth(), image.getHeight()); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); legend.draw(context); assertTrue(legend.isDrawn); assertNotEmpty(image); } @Test public void testSerialization() throws IOException, ClassNotFoundException { Legend original = legend; Legend deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getBackground(), deserialized.getBackground()); assertEquals(original.getBorderStroke(), deserialized.getBorderStroke()); assertEquals(original.getFont(), deserialized.getFont()); assertEquals(original.getBorderColor(), deserialized.getBorderColor()); assertEquals(original.getOrientation(), deserialized.getOrientation()); assertEquals(original.getAlignmentX(), deserialized.getAlignmentX(), DELTA); assertEquals(original.getAlignmentY(), deserialized.getAlignmentY(), DELTA); assertEquals(original.getGap(), deserialized.getGap()); assertEquals(original.getSymbolSize(), deserialized.getSymbolSize()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/legends/LegendsTests.java000066400000000000000000000020631267060725100307530ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.legends; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ LegendTest.class, ValueLegendTest.class }) public class LegendsTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/legends/ValueLegendTest.java000066400000000000000000000034331267060725100314040ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.legends; import static org.junit.Assert.assertEquals; import java.io.IOException; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; public class ValueLegendTest { private static class MockValueLegend extends ValueLegend { public Drawable getSymbol(Row data) { return new AbstractDrawable() { public void draw(DrawingContext context) { } }; } } @Test public void testSerialization() throws IOException, ClassNotFoundException { ValueLegend original = new MockValueLegend(); ValueLegend deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getLabelColumn(), deserialized.getLabelColumn()); assertEquals(original.getLabelFormat(), deserialized.getLabelFormat()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/legends/package-info.java000066400000000000000000000017071267060725100306770ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.plots.legends} package. */ package de.erichseifert.gral.plots.legends; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/lines/000077500000000000000000000000001267060725100251745ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/lines/AbstractLineRendererTest.java000066400000000000000000000104021267060725100327360ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.lines; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Shape; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.util.Arrays; import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawableContainer; import de.erichseifert.gral.plots.DataPoint; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.axes.LinearRenderer2D; import de.erichseifert.gral.plots.points.PointData; import de.erichseifert.gral.util.PointND; import org.junit.Before; import org.junit.Test; public class AbstractLineRendererTest { private static final double DELTA = TestUtils.DELTA; private PointData data; private static class MockLineRenderer extends AbstractLineRenderer2D { /** Version id for serialization. */ private static final long serialVersionUID = 7510746091876293498L; private final Shape shape; public MockLineRenderer() { this.shape = new Rectangle2D.Double(); } public Shape getLineShape(List points) { return shape; } public Drawable getLine(List points, Shape shape) { return new DrawableContainer(); } } @Before public void setUp() { Axis axisX = new Axis(-5.0, 5.0); Axis axisY = new Axis(-5.0, 5.0); AxisRenderer axisRendererX = new LinearRenderer2D(); AxisRenderer axisRendererY = new LinearRenderer2D(); data = new PointData( Arrays.asList(axisX, axisY), Arrays.asList(axisRendererX, axisRendererY), null, 0); } @Test public void testCreate() { LineRenderer r = new MockLineRenderer(); assertTrue(r.getStroke() instanceof BasicStroke); assertEquals(0.0, r.getGap(), DELTA); assertEquals(false, r.isGapRounded()); assertEquals(Color.BLACK, r.getColor()); } @Test public void testLine() { // Get line LineRenderer r = new MockLineRenderer(); List points = Arrays.asList( new DataPoint(data, new PointND(0.0, 0.0)), new DataPoint(data, new PointND(1.0, 1.0)) ); Shape shape = r.getLineShape(points); Drawable line = r.getLine(points, shape); assertNotNull(line); } @Test public void testStrokeNullLine() { MockLineRenderer r = new MockLineRenderer(); List points = Arrays.asList( new DataPoint(data, new PointND(0.0, 0.0)), new DataPoint(data, new PointND(1.0, 1.0)) ); Shape punched = r.stroke(null); assertNull(punched); } @Test public void testProperties() { Color color = Color.RED; BasicStroke stroke = new BasicStroke(1.5f); MockLineRenderer r = new MockLineRenderer(); r.setColor(color); r.setStroke(stroke); assertEquals(color, r.getColor()); assertEquals(stroke, r.getStroke()); } @Test public void testSerialization() throws IOException, ClassNotFoundException { LineRenderer original = new MockLineRenderer(); LineRenderer deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getStroke(), deserialized.getStroke()); assertEquals(original.getGap(), deserialized.getGap(), DELTA); assertEquals(original.isGapRounded(), deserialized.isGapRounded()); assertEquals(original.getColor(), deserialized.getColor()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/lines/DefaultLineRendererTest.java000066400000000000000000000072531267060725100325710ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.lines; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Arrays; import java.util.List; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertNotNull; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.DataPoint; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.axes.LinearRenderer2D; import de.erichseifert.gral.plots.points.PointData; import de.erichseifert.gral.util.PointND; import org.junit.Before; import org.junit.Test; public class DefaultLineRendererTest { private PointData data; @Before public void setUp() { Axis axisX = new Axis(-5.0, 5.0); Axis axisY = new Axis(-5.0, 5.0); AxisRenderer axisRendererX = new LinearRenderer2D(); AxisRenderer axisRendererY = new LinearRenderer2D(); data = new PointData( Arrays.asList(axisX, axisY), Arrays.asList(axisRendererX, axisRendererY), null, 0); } @Test public void testLine() { // Get line LineRenderer r = new DefaultLineRenderer2D(); List points = Arrays.asList( new DataPoint(data, new PointND(0.0, 0.0)), new DataPoint(data, new PointND(1.0, 1.0)) ); Shape shape = r.getLineShape(points); Drawable line = r.getLine(points, shape); assertNotNull(line); // Draw line BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); line.draw(context); assertNotEmpty(image); } @Test public void testGap() { LineRenderer r = new DefaultLineRenderer2D(); List points = Arrays.asList( new DataPoint(data, new PointND(0.0, 0.0)), new DataPoint(data, new PointND(1.0, 1.0)) ); List gaps = Arrays.asList(Double.NaN, 0.0, 1.0); List roundeds = Arrays.asList(false, true); // Test different gap sizes for (Double gap : gaps) { r.setGap(gap); // Draw non-rounded and non rounded gaps for (Boolean rounded : roundeds) { r.setGapRounded(rounded); Shape shape = r.getLineShape(points); Drawable line = r.getLine(points, shape); assertNotNull(line); BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); line.draw(context); assertNotEmpty(image); } } } @Test public void testSerialization() throws IOException, ClassNotFoundException { LineRenderer original = new DefaultLineRenderer2D(); @SuppressWarnings("unused") LineRenderer deserialized = TestUtils.serializeAndDeserialize(original); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/lines/DiscreteLineRendererTest.java000066400000000000000000000062511267060725100327440ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.lines; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Arrays; import java.util.List; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.graphics.Orientation; import de.erichseifert.gral.plots.DataPoint; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.axes.LinearRenderer2D; import de.erichseifert.gral.plots.points.PointData; import de.erichseifert.gral.util.PointND; import org.junit.Before; import org.junit.Test; public class DiscreteLineRendererTest { private PointData data; @Before public void setUp() { Axis axisX = new Axis(-5.0, 5.0); Axis axisY = new Axis(-5.0, 5.0); AxisRenderer axisRendererX = new LinearRenderer2D(); AxisRenderer axisRendererY = new LinearRenderer2D(); data = new PointData( Arrays.asList(axisX, axisY), Arrays.asList(axisRendererX, axisRendererY), null, 0); } @Test public void testLine() { // Get line DiscreteLineRenderer2D r = new DiscreteLineRenderer2D(); List points = Arrays.asList( new DataPoint(data, new PointND(0.0, 0.0)), new DataPoint(data, new PointND(1.0, 1.0)) ); BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); for (Orientation dir : Orientation.values()) { r.setAscentDirection(dir); Shape shape = r.getLineShape(points); Drawable line = r.getLine(points, shape); assertNotNull(line); line.draw(context); assertNotEmpty(image); } } @Test public void testSerialization() throws IOException, ClassNotFoundException { DiscreteLineRenderer2D original = new DiscreteLineRenderer2D(); DiscreteLineRenderer2D deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getAscentDirection(), deserialized.getAscentDirection()); assertEquals(original.getAscendingPoint(), deserialized.getAscendingPoint()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/lines/LinesTests.java000066400000000000000000000022461267060725100301400ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.lines; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ AbstractLineRendererTest.class, DefaultLineRendererTest.class, DiscreteLineRendererTest.class, SmoothLineRendererTest.class }) public class LinesTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/lines/SmoothLineRendererTest.java000066400000000000000000000075561267060725100324640ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.lines; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Arrays; import java.util.List; import static de.erichseifert.gral.TestUtils.assertEmpty; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.DataPoint; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.axes.LinearRenderer2D; import de.erichseifert.gral.plots.points.PointData; import de.erichseifert.gral.util.PointND; import org.junit.Before; import org.junit.Test; public class SmoothLineRendererTest { private PointData data; @Before public void setUp() { Axis axisX = new Axis(-5.0, 5.0); Axis axisY = new Axis(-5.0, 5.0); AxisRenderer axisRendererX = new LinearRenderer2D(); AxisRenderer axisRendererY = new LinearRenderer2D(); data = new PointData( Arrays.asList(axisX, axisY), Arrays.asList(axisRendererX, axisRendererY), null, 0); } @Test public void testLine() { // Get line SmoothLineRenderer2D r = new SmoothLineRenderer2D(); List points = Arrays.asList( new DataPoint(data, new PointND(0.0, 0.0)), new DataPoint(data, new PointND(1.0, 1.0)) ); r.setSmoothness(0.5); Shape shape = r.getLineShape(points); Drawable line = r.getLine(points, shape); assertNotNull(line); // Draw line BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); line.draw(context); assertNotEmpty(image); } @Test public void testNullPoint() { // Get line LineRenderer r = new SmoothLineRenderer2D(); List points = Arrays.asList((DataPoint) null); Shape shape = r.getLineShape(points); Drawable line = r.getLine(points, shape); assertNotNull(line); // Draw line BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); line.draw(context); assertEmpty(image); } @Test public void testEmptyShape() { // Get line LineRenderer r = new SmoothLineRenderer2D(); List points = Arrays.asList(); Drawable line = r.getLine(points, null); assertNotNull(line); // Draw line BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); line.draw(context); assertEmpty(image); } @Test public void testSerialization() throws IOException, ClassNotFoundException { SmoothLineRenderer2D original = new SmoothLineRenderer2D(); SmoothLineRenderer2D deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getSmoothness(), deserialized.getSmoothness()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/lines/package-info.java000077500000000000000000000017341267060725100303730ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.plots.lines} package. */ package de.erichseifert.gral.plots.lines; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/package-info.java000077500000000000000000000017201267060725100272540ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.plots} package. */ package de.erichseifert.gral.plots; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/points/000077500000000000000000000000001267060725100253765ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/points/AbstractPointRendererTest.java000066400000000000000000000161251267060725100333520ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.points; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Shape; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.text.NumberFormat; import java.util.Arrays; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.axes.LinearRenderer2D; import de.erichseifert.gral.plots.colors.ColorMapper; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.util.PointND; public class AbstractPointRendererTest { private static final double DELTA = TestUtils.DELTA; private static DataTable table; private static Row row; private static Axis axis; private static AxisRenderer axisRenderer; private static PointData data; private MockPointRenderer r; @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { table = new DataTable(Integer.class, String.class); table.add(1, "Jan"); // 0 table.add(2, "Feb"); // 1 table.add(3, "Mar"); // 2 table.add(4, "Apr"); // 3 table.add(5, "May"); // 4 table.add(6, "Jun"); // 5 table.add(7, "Jul"); // 6 table.add(8, "Aug"); // 7 row = new Row(table, 4); axis = new Axis(0.0, 10.0); axisRenderer = new LinearRenderer2D(); axisRenderer.setShape(new Line2D.Double(-5.0, 0.0, 5.0, 0.0)); data = new PointData( Arrays.asList(null, axis), Arrays.asList(null, axisRenderer), row, 0); } private static final class MockPointRenderer extends AbstractPointRenderer { private static final long serialVersionUID = -3361506388079000948L; public Drawable getPoint(final PointData data, final Shape shape) { return new AbstractDrawable() { private static final long serialVersionUID = 8239109584500117586L; public void draw(DrawingContext context) { MockPointRenderer renderer = MockPointRenderer.this; Graphics2D g = context.getGraphics(); Axis axis = data.axes.get(1); AxisRenderer axisRenderer = data.axisRenderers.get(1); Comparable cell = data.row.get(0); Number valueObj = (Number) cell; double value = valueObj.doubleValue(); double posX = 0.0; double posY = 0.0; // Calculate positions if (axisRenderer != null) { PointND pointValue = axisRenderer.getPosition( axis, value, true, false); posX = pointValue.get(PointND.X); posY = pointValue.get(PointND.Y); g.translate(posX, posY); ColorMapper colors = renderer.getColor(); Paint paint = colors.get(row.getIndex()); GraphicsUtils.fillPaintedShape(g, shape, paint, null); } if (axisRenderer != null) { g.translate(-posX, -posY); } } }; } public Shape getPointShape(PointData data) { return new Rectangle2D.Double(-1.3, -1.3, 3.0, 3.0); } public Drawable getValue(PointData data, Shape shape) { // TODO return null; } } @Before public void setUp() { r = new MockPointRenderer(); r.setColor(Color.RED); r.setValueVisible(true); r.setValueAlignmentX(0.0); r.setValueAlignmentY(0.0); r.setValueRotation(90.0); r.setValueDistance(1.0); r.setValueColor(Color.BLUE); r.setValueFont(Font.decode(null).deriveFont(42f)); r.setValueFormat(NumberFormat.getNumberInstance()); r.setErrorVisible(true); r.setErrorShape(new Line2D.Double(-1.0, 0.0, 1.0, 0.0)); r.setErrorColor(Color.BLACK); r.setErrorStroke(new BasicStroke(1.5f)); } private static void layout(BufferedImage image, AxisRenderer axisRenderer) { Line2D axisShape = new Line2D.Double( image.getWidth()/2.0, 0.0, image.getWidth()/2.0, image.getHeight() ); axisRenderer.setShape(axisShape); } @Test public void testDraw() { AxisRenderer axisRenderer = new LinearRenderer2D(); // Get point Drawable point = r.getPoint(data, r.getPointShape(data)); assertNotNull(point); // Draw point BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); layout(image, axisRenderer); point.draw(context); assertNotEmpty(image); } @Test public void testSerialization() throws IOException, ClassNotFoundException { PointRenderer original = r; PointRenderer deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getShape(), deserialized.getShape()); assertEquals(original.getColor(), deserialized.getColor()); assertEquals(original.isValueVisible(), deserialized.isValueVisible()); assertEquals(original.getValueColumn(), deserialized.getValueColumn()); assertEquals(original.getValueFormat(), deserialized.getValueFormat()); assertEquals(original.getValueLocation(), deserialized.getValueLocation()); assertEquals(original.getValueAlignmentX(), deserialized.getValueAlignmentX(), DELTA); assertEquals(original.getValueAlignmentY(), deserialized.getValueAlignmentY(), DELTA); assertEquals(original.getValueRotation(), deserialized.getValueRotation(), DELTA); assertEquals(original.getValueDistance(), deserialized.getValueDistance(), DELTA); assertEquals(original.getValueColor(), deserialized.getValueColor()); assertEquals(original.getValueFont(), deserialized.getValueFont()); assertEquals(original.isErrorVisible(), deserialized.isErrorVisible()); assertEquals(original.getErrorColumnTop(), deserialized.getErrorColumnTop()); assertEquals(original.getErrorColumnBottom(), deserialized.getErrorColumnBottom()); assertEquals(original.getErrorColor(), deserialized.getErrorColor()); TestUtils.assertEquals(original.getErrorShape(), deserialized.getErrorShape()); assertEquals(original.getErrorStroke(), deserialized.getErrorStroke()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/points/DefaultPointRenderer2DTest.java000066400000000000000000000163771267060725100333720ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.points; import static de.erichseifert.gral.TestUtils.assertEmpty; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.assertNotEquals; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertNotNull; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.geom.Line2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.text.Format; import java.text.NumberFormat; import java.util.Arrays; import java.util.List; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.axes.LinearRenderer2D; import de.erichseifert.gral.graphics.Location; public class DefaultPointRenderer2DTest { private static DataTable table; private static Row row; private static Axis axis; private static AxisRenderer axisRenderer; private static PointData data; private PointRenderer r; @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { table = new DataTable(Integer.class, Integer.class, String.class); table.add(1, 9, "Jan"); // 0 table.add(2, 8, "Feb"); // 1 table.add(3, 7, "Mar"); // 2 table.add(4, 6, "Apr"); // 3 table.add(5, 5, "May"); // 4 table.add(6, 4, "Jun"); // 5 table.add(7, 3, "Jul"); // 6 table.add(8, 1, "Aug"); // 7 row = new Row(table, 4); axis = new Axis(0.0, 10.0); axisRenderer = new LinearRenderer2D(); axisRenderer.setShape(new Line2D.Double(-5.0, 0.0, 5.0, 0.0)); data = new PointData( Arrays.asList(null, axis), Arrays.asList(null, axisRenderer), row, 0); } @Before public void setUp() { r = new DefaultPointRenderer2D(); } private static void layout(BufferedImage image, AxisRenderer axisRenderer) { Line2D axisShape = new Line2D.Double( image.getWidth()/2.0, 0.0, image.getWidth()/2.0, image.getHeight() ); axisRenderer.setShape(axisShape); } private static void assertPointRenderer(PointRenderer r) { // Get point Drawable point = r.getPoint(data, r.getPointShape(data)); assertNotNull(point); // Draw point BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); point.draw(context); assertNotEmpty(image); } @Test public void testPoint() { assertPointRenderer(r); } @Test public void testValueDisplayed() { DrawingContext context; Drawable point; // Draw without value labels BufferedImage unset = createTestImage(); context = new DrawingContext((Graphics2D) unset.getGraphics()); layout(unset, axisRenderer); r.setValueVisible(false); point = r.getValue(data, r.getPointShape(data)); point.draw(context); // Draw with value labels BufferedImage set = createTestImage(); context = new DrawingContext((Graphics2D) set.getGraphics()); layout(set, axisRenderer); r.setValueVisible(true); point = r.getValue(data, r.getPointShape(data)); point.draw(context); assertNotEquals(unset, set); } @Test public void testValueFormat() { List formats = Arrays.asList( (Format) null, NumberFormat.getInstance()); r.setValueVisible(true); for (Format format : formats) { r.setValueFormat(format); Drawable point = r.getValue(data, r.getPointShape(data)); assertNotNull(point); BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); layout(image, axisRenderer); point.draw(context); assertNotEmpty(image); } } @Test public void testValueDistance() { List distances = Arrays.asList(Double.NaN, 0.0, 1.0); r.setValueVisible(true); for (Double distance : distances) { r.setValueDistance(distance); Drawable point = r.getValue(data, r.getPointShape(data)); assertNotNull(point); BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); layout(image, axisRenderer); point.draw(context); assertNotEmpty(image); } } @Test public void testValueLocation() { Location[] locations = new Location[Location.values().length + 1]; System.arraycopy(Location.values(), 0, locations, 1, locations.length - 1); r.setValueVisible(true); r.setValueDistance(0.5); for (Location location : locations) { r.setValueLocation(location); Drawable point = r.getValue(data, r.getPointShape(data)); assertNotNull(point); BufferedImage image = createTestImage(); DrawingContext context = new DrawingContext((Graphics2D) image.getGraphics()); layout(image, axisRenderer); AffineTransform txOld = context.getGraphics().getTransform(); context.getGraphics().translate(image.getWidth()/2.0, image.getHeight()/2.0); point.draw(context); context.getGraphics().setTransform(txOld); assertNotEmpty(image); } } @Test public void testErrorDisplayed() { r.setErrorColumnTop(1); r.setErrorColumnBottom(1); DrawingContext context; Drawable point; // Draw without error bars r.setErrorVisible(false); BufferedImage unset = createTestImage(); context = new DrawingContext((Graphics2D) unset.getGraphics()); layout(unset, axisRenderer); point = r.getPoint(data, r.getPointShape(data)); point.draw(context); // Draw with error bars r.setErrorVisible(true); BufferedImage set = createTestImage(); context = new DrawingContext((Graphics2D) set.getGraphics()); layout(set, axisRenderer); point = r.getPoint(data, r.getPointShape(data)); point.draw(context); assertNotEquals(unset, set); } @Test public void testErrorNoAxisRenderer() { r.setShape(null); DrawingContext context; Drawable point; // Draw error bars r.setErrorVisible(true); BufferedImage image = createTestImage(); context = new DrawingContext((Graphics2D) image.getGraphics()); layout(image, axisRenderer); point = r.getPoint(data, r.getPointShape(data)); point.draw(context); assertEmpty(image); } @Test public void testSerialization() throws IOException, ClassNotFoundException { PointRenderer original = r; @SuppressWarnings("unused") PointRenderer deserialized = TestUtils.serializeAndDeserialize(original); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/points/LabelPointsRendererTest.java000066400000000000000000000065231267060725100330120ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.points; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import java.awt.Shape; import java.awt.geom.Line2D; import java.io.IOException; import java.util.Arrays; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.axes.LinearRenderer2D; public class LabelPointsRendererTest { private static final double DELTA = TestUtils.DELTA; private static DataTable table; private static Row row; private static Axis axis; private static AxisRenderer axisRenderer; private static PointData data; @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { table = new DataTable(Integer.class, Integer.class, Integer.class); table.add(1, 3, 1); // 0 table.add(2, null, 2); // 1 row = new Row(table, 0); axis = new Axis(-1.0, 1.0); axisRenderer = new LinearRenderer2D(); axisRenderer.setShape(new Line2D.Double(-5.0, 0.0, 5.0, 0.0)); data = new PointData(Arrays.asList(axis), Arrays.asList(axisRenderer), row, 0); } @Test public void testPointPath() { PointRenderer r = new LabelPointRenderer(); Shape path = r.getPointShape(data); assertNotNull(path); } @Test public void testInvalidColumn() { LabelPointRenderer r = new LabelPointRenderer(); r.setColumn(table.getColumnCount()); Shape path = r.getPointShape(data); assertNull(path); } @Test public void testNullLabel() { LabelPointRenderer r = new LabelPointRenderer(); r.setColumn(1); Row row2 = new Row(table, 1); assertNull(row2.get(1)); PointData data2 = new PointData(data.axes, data.axisRenderers, row2, 0); Shape path = r.getPointShape(data2); assertNull(path); } @Test public void testSerialization() throws IOException, ClassNotFoundException { LabelPointRenderer original = new LabelPointRenderer(); LabelPointRenderer deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getColumn(), deserialized.getColumn()); assertEquals(original.getFormat(), deserialized.getFormat()); assertEquals(original.getFont(), deserialized.getFont()); assertEquals(original.getAlignmentX(), deserialized.getAlignmentX(), DELTA); assertEquals(original.getAlignmentY(), deserialized.getAlignmentY(), DELTA); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/points/PointsTests.java000066400000000000000000000022571267060725100305460ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.points; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ AbstractPointRendererTest.class, DefaultPointRenderer2DTest.class, SizeablePointsRendererTest.class, LabelPointsRendererTest.class }) public class PointsTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/points/SizeablePointsRendererTest.java000066400000000000000000000106171267060725100335300ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.plots.points; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.util.Arrays; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.TestUtils; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.data.Row; import de.erichseifert.gral.plots.axes.Axis; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.axes.LinearRenderer2D; public class SizeablePointsRendererTest { private static DataTable table; private static Row row; private static Axis axis; private static AxisRenderer axisRenderer; private static PointData data; private static Shape shape; @BeforeClass @SuppressWarnings("unchecked") public static void setUpBeforeClass() { table = new DataTable(Integer.class, Integer.class, Integer.class); table.add(1, 3, 1); // 0 table.add(2, 5, 2); // 1 table.add(3, 2, -1); // 2 table.add(4, 1, 0); // 3 table.add(5, 4, null); // 4 row = new Row(table, 0); axis = new Axis(-1.0, 1.0); axisRenderer = new LinearRenderer2D(); axisRenderer.setShape(new Line2D.Double(-5.0, 0.0, 5.0, 0.0)); data = new PointData( Arrays.asList(null, axis), Arrays.asList(null, axisRenderer), row, 0); shape = new Rectangle2D.Double(-5.0, -5.0, 10.0, 10.0); } @Test public void testUnsized() { PointRenderer r = new SizeablePointRenderer(); r.setShape(shape); Shape expected = shape; Shape path = r.getPointShape(data); assertEquals(expected.getBounds2D(), path.getBounds2D()); } @Test public void testSized() { PointRenderer r = new SizeablePointRenderer(); r.setShape(shape); Shape expected = AffineTransform.getScaleInstance(2.0, 2.0) .createTransformedShape(shape); Row row2 = new Row(table, 1); PointData data2 = new PointData(data.axes, data.axisRenderers, row2, 0); Shape path = r.getPointShape(data2); assertEquals(expected.getBounds2D(), path.getBounds2D()); } @Test public void testNegativeSize() { PointRenderer r = new SizeablePointRenderer(); r.setShape(shape); Row row2 = new Row(table, 2); PointData data2 = new PointData(data.axes, data.axisRenderers, row2, 0); Shape path = r.getPointShape(data2); assertNull(path); } @Test public void testZeroSize() { PointRenderer r = new SizeablePointRenderer(); Row row2 = new Row(table, 3); PointData data2 = new PointData(data.axes, data.axisRenderers, row2, 0); Shape path = r.getPointShape(data2); assertNull(path); } @Test public void testNullSize() { PointRenderer r = new SizeablePointRenderer(); r.setShape(shape); Row row2 = new Row(table, 4); PointData data2 = new PointData(data.axes, data.axisRenderers, row2, 0); Shape path = r.getPointShape(data2); assertNull(path); } @Test public void testInvalidColumn() { SizeablePointRenderer r = new SizeablePointRenderer(); r.setShape(shape); Shape path; // Column index too big r.setColumn(table.getColumnCount()); path = r.getPointShape(data); assertEquals(shape, path); // Column index too small r.setColumn(-1); path = r.getPointShape(data); assertEquals(shape, path); } @Test public void testSerialization() throws IOException, ClassNotFoundException { SizeablePointRenderer original = new SizeablePointRenderer(); SizeablePointRenderer deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getColumn(), deserialized.getColumn()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/plots/points/package-info.java000077500000000000000000000017361267060725100305770ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.plots.shapes} package. */ package de.erichseifert.gral.plots.points; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/ui/000077500000000000000000000000001267060725100233365ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/ui/DrawablePanelTest.java000066400000000000000000000071141267060725100275450ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.ui; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.geom.Line2D; import java.awt.image.BufferedImage; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; public class DrawablePanelTest { private static final double DELTA = 1e-15; private static Drawable drawable; private DrawablePanel panel; @BeforeClass public static void setUpBeforeClass() { drawable = new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = -5709607259454319253L; public void draw(DrawingContext context) { Graphics2D g = context.getGraphics(); g.draw(new Line2D.Double(0.0, 0.0, 0.0, 0.0)); } }; } @Before public void setUp() { panel = new DrawablePanel(drawable); } @Test public void testCreation() { assertNotNull(panel.getMinimumSize()); assertSame(drawable, panel.getDrawable()); } @Test public void testBounds() { Rectangle bounds; // Get bounds = panel.getBounds(); assertEquals(0.0, bounds.getX(), DELTA); assertEquals(0.0, bounds.getY(), DELTA); assertEquals(0.0, bounds.getWidth(), DELTA); assertEquals(0.0, bounds.getHeight(), DELTA); assertEquals(bounds.getX(), panel.getX(), DELTA); assertEquals(bounds.getY(), panel.getY(), DELTA); assertEquals(bounds.getWidth(), panel.getWidth(), DELTA); assertEquals(bounds.getHeight(), panel.getHeight(), DELTA); // Set Rectangle object panel.setBounds(new Rectangle(1, 2, 10, 20)); bounds = panel.getBounds(); assertEquals( 1.0, bounds.getX(), DELTA); assertEquals( 2.0, bounds.getY(), DELTA); assertEquals(10.0, bounds.getWidth(), DELTA); assertEquals(20.0, bounds.getHeight(), DELTA); // Set values panel.setBounds(3, 4, 30, 40); bounds = panel.getBounds(); assertEquals( 3.0, bounds.getX(), DELTA); assertEquals( 4.0, bounds.getY(), DELTA); assertEquals(30.0, bounds.getWidth(), DELTA); assertEquals(40.0, bounds.getHeight(), DELTA); } @Test public void testSize() { Dimension size = panel.getPreferredSize(); assertEquals(0.0, size.getWidth(), DELTA); assertEquals(0.0, size.getHeight(), DELTA); } @Test public void testDraw() { BufferedImage image = createTestImage(); panel.setBounds(0, 0, image.getWidth(), image.getHeight()); panel.paint(image.getGraphics()); assertNotEmpty(image); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/ui/DrawableWriterFilterTest.java000066400000000000000000000033771267060725100311370ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.ui; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.io.IOCapabilities; public class DrawableWriterFilterTest { private static IOCapabilities capabilities; private DrawableWriterFilter filter; @BeforeClass public static void setUpBeforeClass() { capabilities = new IOCapabilities("Text", "Unformatted text", "text/plain", new String[] {"txt"}); } @Before public void setUp() { filter = new DrawableWriterFilter(capabilities); } @Test public void testCreation() { assertSame(capabilities, filter.getWriterCapabilities()); assertEquals("Text: Unformatted text", filter.getDescription()); } @Test public void testAccept() { // TODO Also test positive result assertFalse(filter.accept(null)); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/ui/ExportChooserTest.java000066400000000000000000000034511267060725100276500ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.ui; import static org.junit.Assert.assertEquals; import java.util.ArrayList; import java.util.List; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.io.IOCapabilities; public class ExportChooserTest { private static List capabilities; @BeforeClass public static void setUpBeforeClass() { capabilities = new ArrayList(2); capabilities.add(new IOCapabilities("Text", "Unformatted text", "text/plain", new String[] {"txt"})); capabilities.add(new IOCapabilities("HTML", "HyperText Markup Language", "text/html", new String[] {"html", "htm"})); } @Test public void testCreation() { ExportChooser strict = new ExportChooser(true, capabilities); assertEquals(capabilities.size(), strict.getChoosableFileFilters().length); ExportChooser relaxed = new ExportChooser(false, capabilities); assertEquals(capabilities.size() + 1, relaxed.getChoosableFileFilters().length); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/ui/ExportDialogTest.java000066400000000000000000000045031267060725100274440ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.ui; import static org.junit.Assert.assertEquals; import java.awt.Component; import java.awt.geom.Rectangle2D; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawableContainer; public class ExportDialogTest { private static Drawable drawable; private ExportDialog dialog; private static final class TestExportDialog extends ExportDialog { /** Version id for serialization. */ private static final long serialVersionUID = -610141271038116119L; public TestExportDialog(Component parent, Drawable drawable) { super(parent, drawable); } @Override public void setDocumentBounds(double x, double y, double w, double h) { super.setDocumentBounds(x, y, w, h); } } @BeforeClass public static void setUpBeforeClass() { drawable = new DrawableContainer(); } @Before public void setUp() { dialog = new TestExportDialog(null, drawable); } @Test public void testCreation() { assertEquals(drawable.getBounds(), dialog.getDocumentBounds()); assertEquals(ExportDialog.UserAction.CANCEL, dialog.getUserAction()); } @Test public void testDocumentBounds() { Rectangle2D expected = new Rectangle2D.Double(0.0, 1.0, 2.0, 3.0); for (int run = 0; run < 2; run++) { dialog.setDocumentBounds( expected.getX(), expected.getY(), expected.getWidth(), expected.getHeight()); assertEquals(expected, dialog.getDocumentBounds()); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/ui/InteractivePanelTest.java000066400000000000000000000053751267060725100303100ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.ui; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; import java.awt.Graphics2D; import java.awt.geom.Line2D; import java.awt.image.BufferedImage; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; public class InteractivePanelTest { private static Drawable drawable; private InteractivePanel panel; @BeforeClass public static void setUpBeforeClass() { drawable = new AbstractDrawable() { /** Version id for serialization. */ private static final long serialVersionUID = 243601807224242703L; public void draw(DrawingContext context) { Graphics2D g = context.getGraphics(); g.draw(new Line2D.Double(0.0, 0.0, 0.0, 0.0)); } }; } @Before public void setUp() { panel = new InteractivePanel(drawable); } @Test public void testCreation() { assertNotNull(panel.getMinimumSize()); assertSame(drawable, panel.getDrawable()); } @Test public void testPrint() throws PrinterException { BufferedImage image; PageFormat page = new PageFormat(); int ret; // Test valid page image = createTestImage(); ret = panel.print(image.getGraphics(), page, 0); assertEquals(Printable.PAGE_EXISTS, ret); assertNotEmpty(image); // Test invalid page image = createTestImage(); ret = panel.print(image.getGraphics(), page, 1); assertEquals(Printable.NO_SUCH_PAGE, ret); try { assertNotEmpty(image); fail(); } catch (AssertionError e) { } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/ui/UiTests.java000066400000000000000000000022031267060725100255760ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.ui; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ DrawablePanelTest.class, InteractivePanelTest.class, DrawableWriterFilterTest.class, ExportDialogTest.class, ExportChooserTest.class }) public class UiTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/ui/package-info.java000077500000000000000000000017121267060725100265310ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.ui} package. */ package de.erichseifert.gral.ui; gral-0.11/gral-core/src/test/java/de/erichseifert/gral/util/000077500000000000000000000000001267060725100236765ustar00rootroot00000000000000gral-0.11/gral-core/src/test/java/de/erichseifert/gral/util/GeometryUtilsTest.java000066400000000000000000000064361267060725100302260ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.awt.Shape; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.List; import org.junit.Test; public class GeometryUtilsTest { private static final double DELTA = 1e-14; @Test public void testIntersectionLineLine() { Line2D l1, l2; Point2D expected; l1 = new Line2D.Double(0.0, 0.0, 1.0, 1.0); l2 = new Line2D.Double(0.0, 1.0, 1.0, 0.0); expected = new Point2D.Double(0.5, 0.5); assertEquals(expected, GeometryUtils.intersection(l1, l2)); l1 = new Line2D.Double( 0.0, 0.0, -1.0, -1.0); l2 = new Line2D.Double( 0.0, -1.0, -1.0, 0.0); expected = new Point2D.Double(-0.5, -0.5); assertEquals(expected, GeometryUtils.intersection(l1, l2)); l1 = new Line2D.Double(0.0, 0.0, 1.0, 1.0); l2 = new Line2D.Double(0.0, 1.0, 1.0, 2.0); expected = null; assertEquals(expected, GeometryUtils.intersection(l1, l2)); } @Test public void testIntersectionShapeShape() { Shape s1 = new Rectangle2D.Double(0.0, 0.0, 1.0, 1.0); Shape s2 = new Rectangle2D.Double(0.5, 0.5, 1.0, 1.0); Point2D expected1 = new Point2D.Double(1.0, 0.5); Point2D expected2 = new Point2D.Double(0.5, 1.0); List intersections = GeometryUtils.intersection(s1, s2); assertTrue(intersections.contains(expected1)); assertTrue(intersections.contains(expected2)); } @Test public void testGrow() { Shape normal = new Rectangle2D.Double(0.0, 0.0, 1.0, 1.0); Shape grown = GeometryUtils.grow(normal, 0.5); Rectangle2D normalBounds = normal.getBounds2D(); Rectangle2D grownBounds = grown.getBounds2D(); // Test growth for (double coord=-0.25; coord<=1.25; coord+=0.25) { assertTrue(grown.contains(coord, coord)); } assertEquals(-0.5, grownBounds.getMinX(), DELTA); assertEquals(-0.5, grownBounds.getMinY(), DELTA); assertEquals( 1.5, grownBounds.getMaxX(), DELTA); assertEquals( 1.5, grownBounds.getMaxY(), DELTA); // Test zero growth grown = GeometryUtils.grow(normal, 0.0); grownBounds = grown.getBounds2D(); assertEquals(normalBounds, grownBounds); // Test shrinking grown = GeometryUtils.grow(normal, -0.25); grownBounds = grown.getBounds2D(); assertEquals(0.25, grownBounds.getMinX(), DELTA); assertEquals(0.25, grownBounds.getMinY(), DELTA); assertEquals(0.75, grownBounds.getMaxX(), DELTA); assertEquals(0.75, grownBounds.getMaxY(), DELTA); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/util/GraphicsUtilsTest.java000066400000000000000000000201571267060725100301670ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import static de.erichseifert.gral.TestUtils.assertNotEmpty; import static de.erichseifert.gral.TestUtils.createTestImage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Shape; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import org.junit.Test; public class GraphicsUtilsTest { private static final double DELTA = 1e-15; @Test public void testGetOutline() { Shape outline = GraphicsUtils.getOutline( "foobar", Font.decode(null), 0f, 0.5); assertNotNull(outline); Rectangle2D bounds = outline.getBounds2D(); assertTrue(bounds.getWidth() > 0.0); assertTrue(bounds.getHeight() > 0.0); } @Test public void testPaintedShape() { BufferedImage image; Shape shape = new Rectangle2D.Double(10.0, 10.0, 300.0, 220.0); Paint paint = Color.red; image = createTestImage(); GraphicsUtils.fillPaintedShape((Graphics2D) image.getGraphics(), shape, paint, null); assertNotEmpty(image); image = createTestImage(); Rectangle2D paintBounds = shape.getBounds2D(); GraphicsUtils.fillPaintedShape((Graphics2D) image.getGraphics(), shape, paint, paintBounds); assertNotEmpty(image); image = createTestImage(); GraphicsUtils.drawPaintedShape((Graphics2D) image.getGraphics(), shape, paint, paintBounds, null); assertNotEmpty(image); BasicStroke stroke = new BasicStroke(2f); image = createTestImage(); GraphicsUtils.drawPaintedShape((Graphics2D) image.getGraphics(), shape, paint, paintBounds, stroke); assertNotEmpty(image); } private static void assertEqualsArray(double[] expected, double[] actual, double delta) { assertEquals(expected.length, actual.length); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], actual[i], delta); } } @Test public void testRgb2Xyz() { double[] xyz = new double[3]; GraphicsUtils.rgb2xyz(new double[] { 0.0, 0.0, 0.0 }, xyz); assertEqualsArray(new double[] { 0.0, 0.0, 0.0}, xyz, DELTA); GraphicsUtils.rgb2xyz(new double[] { 0.0, 0.5, 1.0 }, xyz); assertEqualsArray(new double[] { 0.22551071734443490, 0.21406459587821420, 0.73496822304548560 }, xyz, DELTA); GraphicsUtils.rgb2xyz(new double[] { 0.5, 0.5, 0.5 }, xyz); assertEqualsArray(new double[] { 0.20638296936623524, 0.21404095726301628, 0.17662923071892103 }, xyz, DELTA); GraphicsUtils.rgb2xyz(new double[] { 1.0, 0.5, 0.0 }, xyz); assertEqualsArray(new double[] { 0.51847532834443490, 0.37593470787821420, 0.03471187504548562 }, xyz, DELTA); GraphicsUtils.rgb2xyz(new double[] { 1.0, 1.0, 1.0 }, xyz); assertEqualsArray(new double[] { 0.96422103200000000, 0.99999914400000000, 0.82521159400000000 }, xyz, DELTA); } @Test public void testLuv2Xyz() { double[] xyz = new double[3]; GraphicsUtils.luv2xyz(new double[] { 0.0, 0.0, 0.0 }, xyz); assertEqualsArray(new double[] { 0.0000000000000000000, 0.0000000000000000000, 0.00000000000000000000 }, xyz, DELTA); GraphicsUtils.luv2xyz(new double[] { 0.0, 0.5, 1.0 }, xyz); assertEqualsArray(new double[] { 0.0000000000000000000, 0.0000000000000000000, 0.00000000000000000000 }, xyz, DELTA); GraphicsUtils.luv2xyz(new double[] { 0.5, 0.5, 0.5 }, xyz); assertEqualsArray(new double[] { 0.0006306220545989307, 0.0005535282299397269,-0.00003874159659988680 }, xyz, DELTA); GraphicsUtils.luv2xyz(new double[] { 1.0, 0.5, 0.0 }, xyz); assertEqualsArray(new double[] { 0.0012637351588200229, 0.0011070564598794539, 0.00084812581097405170 }, xyz, DELTA); GraphicsUtils.luv2xyz(new double[] { 1.0, 1.0, 1.0 }, xyz); assertEqualsArray(new double[] { 0.0012612441091978614, 0.0011070564598794539,-0.00007748319319977360 }, xyz, DELTA); GraphicsUtils.luv2xyz(new double[] { 100.00000000000000, 1.7759188446137468, -18.705788588473464 }, xyz); assertEqualsArray(new double[] { 1.0000000000000000000, 1.0000000000000000000, 1.00000000000000000000 }, xyz, DELTA); } @Test public void testXyz2Rgb() { double[] rgb = new double[3]; GraphicsUtils.xyz2rgb(new double[] { 0.0, 0.0, 0.0 }, rgb); assertEqualsArray(new double[] { 0.0000000000000000, 0.0000000000000000, 0.0000000000000000 }, rgb, DELTA); GraphicsUtils.xyz2rgb(new double[] { 0.0, 0.5, 1.0 }, rgb); assertEqualsArray(new double[] {-16.7836995140000020, 0.9962651704966786, 1.1183734614873770 }, rgb, DELTA); GraphicsUtils.xyz2rgb(new double[] { 0.5, 0.5, 0.5 }, rgb); assertEqualsArray(new double[] { 0.7439767101458333, 0.7256668703074206, 0.8118445228904296 }, rgb, DELTA); GraphicsUtils.xyz2rgb(new double[] { 1.0, 0.5, 0.0 }, rgb); assertEqualsArray(new double[] { 1.4445522116235023,-0.2674136380000002,-0.5497511680000000 }, rgb, DELTA); GraphicsUtils.xyz2rgb(new double[] { 1.0, 1.0, 1.0 }, rgb); assertEqualsArray(new double[] { 1.0115059552563181, 0.9870652513165344, 1.1020986165231543 }, rgb, DELTA); GraphicsUtils.xyz2rgb(new double[] { 0.96422103200000000, 0.99999914400000000, 0.82521159400000000 }, rgb); assertEqualsArray(new double[] { 1.0000016663766877, 0.9999988622306825, 1.0000011147183525 }, rgb, DELTA); } @Test public void testXyz2Luv() { double[] luv = new double[3]; GraphicsUtils.xyz2luv(new double[] { 0.0, 0.0, 0.0 }, luv); assertEqualsArray(new double[] { 0.00000000000000, 0.0000000000000000, 0.000000000000000 }, luv, DELTA); GraphicsUtils.xyz2luv(new double[] { 0.0, 0.5, 1.0 }, luv); assertEqualsArray(new double[] { 76.06926101415557,-206.8386281184853600, -58.841402958935040 }, luv, DELTA); GraphicsUtils.xyz2luv(new double[] { 0.5, 0.5, 0.5 }, luv); assertEqualsArray(new double[] { 76.06926101415557, 1.3509283413088070, -14.229355146122007 }, luv, DELTA); GraphicsUtils.xyz2luv(new double[] { 1.0, 0.5, 0.0 }, luv); assertEqualsArray(new double[] { 76.06926101415557, 258.5262627916428000, 40.879645093235310 }, luv, DELTA); GraphicsUtils.xyz2luv(new double[] { 1.0, 1.0, 1.0 }, luv); assertEqualsArray(new double[] {100.00000000000000, 1.7759188446137468, -18.705788588473464 }, luv, DELTA); GraphicsUtils.xyz2luv(new double[] { 0.0012612441091978614, 0.0011070564598794539,-0.00007748319319977360 }, luv); assertEqualsArray(new double[] { 1.00000000000000, 1.0000000000000000, 1.000000000000000 }, luv, DELTA); } @Test public void testRgb2Luv() { double[] luv = new double[3]; GraphicsUtils.rgb2luv(new double[] { 0.0, 0.0, 0.0 }, luv); assertEqualsArray(new double[] { 0.00000000000000, 0.00000000000000000000, 0.000000000000000000000 }, luv, DELTA); GraphicsUtils.rgb2luv(new double[] { 0.0, 0.5, 1.0 }, luv); assertEqualsArray(new double[] { 53.39149927909138, -34.19278610160572000000,-101.728990843596360000000 }, luv, DELTA); GraphicsUtils.rgb2luv(new double[] { 0.5, 0.5, 0.5 }, luv); assertEqualsArray(new double[] { 53.38894494212407, 0.00009162075020892017, -0.000087416607597709690 }, luv, DELTA); GraphicsUtils.rgb2luv(new double[] { 1.0, 0.5, 0.0 }, luv); assertEqualsArray(new double[] { 67.71991853084089, 107.44568793469313000000, 46.013808290473584000000 }, luv, DELTA); GraphicsUtils.rgb2luv(new double[] { 1.0, 1.0, 1.0 }, luv); assertEqualsArray(new double[] { 99.99996690132389, 0.00017160990909819560, -0.000163735355247670150 }, luv, DELTA); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/util/HaltonSequenceTest.java000066400000000000000000000062651267060725100303300ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import org.junit.Test; import de.erichseifert.gral.TestUtils; public class HaltonSequenceTest { private static final double DELTA = 1e-15; @Test public void testHasNext() { HaltonSequence seq = new HaltonSequence(); for (int i = 0; i < 20; i++) { assertTrue(seq.hasNext()); } } @Test public void testBase2() { HaltonSequence seq = new HaltonSequence(); assertEquals(0.5000, seq.next(), DELTA); assertEquals(0.2500, seq.next(), DELTA); assertEquals(0.7500, seq.next(), DELTA); assertEquals(0.1250, seq.next(), DELTA); assertEquals(0.6250, seq.next(), DELTA); assertEquals(0.3750, seq.next(), DELTA); assertEquals(0.8750, seq.next(), DELTA); assertEquals(0.0625, seq.next(), DELTA); assertEquals(0.5625, seq.next(), DELTA); assertEquals(0.3125, seq.next(), DELTA); } @Test public void testBase3() { HaltonSequence seq = new HaltonSequence(3); assertEquals(0.3333333333333333, seq.next(), DELTA); assertEquals(0.6666666666666666, seq.next(), DELTA); assertEquals(0.1111111111111111, seq.next(), DELTA); assertEquals(0.4444444444444444, seq.next(), DELTA); assertEquals(0.7777777777777777, seq.next(), DELTA); assertEquals(0.2222222222222222, seq.next(), DELTA); assertEquals(0.5555555555555556, seq.next(), DELTA); assertEquals(0.8888888888888888, seq.next(), DELTA); assertEquals(0.0370370370370370, seq.next(), DELTA); assertEquals(0.3703703703703703, seq.next(), DELTA); } @Test public void testBase5() { HaltonSequence seq = new HaltonSequence(5); assertEquals(0.20, seq.next(), DELTA); assertEquals(0.40, seq.next(), DELTA); assertEquals(0.60, seq.next(), DELTA); assertEquals(0.80, seq.next(), DELTA); assertEquals(0.04, seq.next(), DELTA); assertEquals(0.24, seq.next(), DELTA); assertEquals(0.44, seq.next(), DELTA); assertEquals(0.64, seq.next(), DELTA); assertEquals(0.84, seq.next(), DELTA); assertEquals(0.08, seq.next(), DELTA); } @Test public void testSerialization() throws IOException, ClassNotFoundException { HaltonSequence original = new HaltonSequence(3); HaltonSequence deserialized = TestUtils.serializeAndDeserialize(original); for (int i = 0; i < 10; i++) { assertEquals(original.next(), deserialized.next(), DELTA); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/util/MathUtilsTest.java000066400000000000000000000175771267060725100273340ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.Collections; import java.util.List; import de.erichseifert.gral.TestUtils; import org.junit.Test; public class MathUtilsTest { public static final double DELTA = 1e-14; @Test public void testAlmostEqual() { double delta = 1e-5; assertTrue(MathUtils.almostEqual(1.0, 1.0, delta)); assertFalse(MathUtils.almostEqual(1.0, 2.0, delta)); assertTrue(MathUtils.almostEqual(1.0, 1.0 + 0.5*delta, delta)); assertFalse(MathUtils.almostEqual(1.0, 1.0 + 2.0*delta, delta)); } @Test public void testRound() { assertEquals(1.0, MathUtils.round(1.0/1.0, 1e-1), DELTA); assertEquals(0.7, MathUtils.round(2.0/3.0, 1e-1), DELTA); assertEquals(0.5, MathUtils.round(1.0/2.0, 1e-1), DELTA); assertEquals(0.3, MathUtils.round(1.0/3.0, 1e-1), DELTA); assertEquals(0.1, MathUtils.round(1.0/9.0, 1e-1), DELTA); assertEquals(1.00, MathUtils.round(1.0/1.0, 1e-2), DELTA); assertEquals(0.67, MathUtils.round(2.0/3.0, 1e-2), DELTA); assertEquals(0.50, MathUtils.round(1.0/2.0, 1e-2), DELTA); assertEquals(0.33, MathUtils.round(1.0/3.0, 1e-2), DELTA); assertEquals(0.11, MathUtils.round(1.0/9.0, 1e-2), DELTA); // Test with precision 0.0 assertEquals(0.0, MathUtils.round(1.0, 0.0), DELTA); } @Test public void testFloor() { assertEquals(1.0, MathUtils.floor(1.0/1.0, 1e-1), DELTA); assertEquals(0.6, MathUtils.floor(2.0/3.0, 1e-1), DELTA); assertEquals(0.5, MathUtils.floor(1.0/2.0, 1e-1), DELTA); assertEquals(0.3, MathUtils.floor(1.0/3.0, 1e-1), DELTA); assertEquals(0.1, MathUtils.floor(1.0/9.0, 1e-1), DELTA); assertEquals(1.00, MathUtils.floor(1.0/1.0, 1e-2), DELTA); assertEquals(0.66, MathUtils.floor(2.0/3.0, 1e-2), DELTA); assertEquals(0.50, MathUtils.floor(1.0/2.0, 1e-2), DELTA); assertEquals(0.33, MathUtils.floor(1.0/3.0, 1e-2), DELTA); assertEquals(0.11, MathUtils.floor(1.0/9.0, 1e-2), DELTA); // Test with precision 0.0 assertEquals(0.0, MathUtils.floor(1.0, 0.0), DELTA); } @Test public void testCeil() { assertEquals(1.0, MathUtils.ceil(1.0/1.0, 1e-1), DELTA); assertEquals(0.7, MathUtils.ceil(2.0/3.0, 1e-1), DELTA); assertEquals(0.5, MathUtils.ceil(1.0/2.0, 1e-1), DELTA); assertEquals(0.4, MathUtils.ceil(1.0/3.0, 1e-1), DELTA); assertEquals(0.2, MathUtils.ceil(1.0/9.0, 1e-1), DELTA); assertEquals(1.00, MathUtils.ceil(1.0/1.0, 1e-2), DELTA); assertEquals(0.67, MathUtils.ceil(2.0/3.0, 1e-2), DELTA); assertEquals(0.50, MathUtils.ceil(1.0/2.0, 1e-2), DELTA); assertEquals(0.34, MathUtils.ceil(1.0/3.0, 1e-2), DELTA); assertEquals(0.12, MathUtils.ceil(1.0/9.0, 1e-2), DELTA); // Test with precision 0.0 assertEquals(0.0, MathUtils.ceil(1.0, 0.0), DELTA); } @Test public void testLimitDouble() { assertEquals(0.0, MathUtils.limit(-0.5, 0.0, 1.0), DELTA); assertEquals(0.0, MathUtils.limit( 0.0, 0.0, 1.0), DELTA); assertEquals(0.5, MathUtils.limit( 0.5, 0.0, 1.0), DELTA); assertEquals(1.0, MathUtils.limit( 1.0, 0.0, 1.0), DELTA); assertEquals(1.0, MathUtils.limit( 1.5, 0.0, 1.0), DELTA); } @Test public void testLimitFloat() { assertEquals(0.0, MathUtils.limit(-0.5f, 0.0f, 1.0f), DELTA); assertEquals(0.0, MathUtils.limit( 0.0f, 0.0f, 1.0f), DELTA); assertEquals(0.5, MathUtils.limit( 0.5f, 0.0f, 1.0f), DELTA); assertEquals(1.0, MathUtils.limit( 1.0f, 0.0f, 1.0f), DELTA); assertEquals(1.0, MathUtils.limit( 1.5f, 0.0f, 1.0f), DELTA); } @Test public void testLimitInt() { assertEquals( 0, MathUtils.limit(-5, 0, 10)); assertEquals( 0, MathUtils.limit( 0, 0, 10)); assertEquals( 5, MathUtils.limit( 5, 0, 10)); assertEquals(10, MathUtils.limit(10, 0, 10)); assertEquals(10, MathUtils.limit(15, 0, 10)); } @Test public void testBinarySearch() { double[] a = {0.0, 1.0}; assertEquals(0, MathUtils.binarySearch(a, 0.0)); assertEquals(1, MathUtils.binarySearch(a, 0.5)); assertEquals(1, MathUtils.binarySearch(a, 1.0)); assertEquals(0, MathUtils.binarySearchFloor(a, 0.0)); assertEquals(0, MathUtils.binarySearchFloor(a, 0.5)); assertEquals(1, MathUtils.binarySearchFloor(a, 1.0)); assertEquals(0, MathUtils.binarySearchCeil(a, 0.0)); assertEquals(1, MathUtils.binarySearchCeil(a, 0.5)); assertEquals(1, MathUtils.binarySearchCeil(a, 1.0)); } @Test public void testRandomizedSelect() { List a = Arrays.asList(13.0, 5.0, 8.0, 3.0, 1.0, 2.0, 1.0); for (int i = 0; i < a.size(); i++) { assertEquals(i, MathUtils.randomizedSelect(a, 0, a.size() - 1, i + 1)); } // Check for integrity after sorting assertEquals(2, Collections.frequency(a, 1.0)); assertEquals(1, Collections.frequency(a, 2.0)); assertEquals(1, Collections.frequency(a, 3.0)); assertEquals(1, Collections.frequency(a, 5.0)); assertEquals(1, Collections.frequency(a, 8.0)); assertEquals(1, Collections.frequency(a, 13.0)); // Check behavior for empty lists List b = Arrays.asList(); assertEquals(-1, MathUtils.randomizedSelect(b, 0, a.size() - 1, 1)); } @Test public void testMagnitude() { assertEquals( -0.01, MathUtils.magnitude(10.0, -0.05), DELTA); assertEquals( 0.01, MathUtils.magnitude(10.0, 0.05), DELTA); assertEquals( 1.00, MathUtils.magnitude(10.0, 3.14), DELTA); assertEquals( 10.00, MathUtils.magnitude(10.0, 54.32), DELTA); assertEquals(100.00, MathUtils.magnitude(10.0, 123.45), DELTA); } @Test public void testQuantile() { List values = Arrays.asList( 11.4, 17.3, 21.3, 25.9, 40.1, 50.5, 60.0, 70.0, 75.0); assertEquals(11.40, MathUtils.quantile(values, 0.0), DELTA); assertEquals(16.12, MathUtils.quantile(values, 0.1), DELTA); assertEquals(19.70, MathUtils.quantile(values, 0.2), DELTA); assertEquals(23.14, MathUtils.quantile(values, 0.3), DELTA); assertEquals(28.74, MathUtils.quantile(values, 0.4), DELTA); assertEquals(40.10, MathUtils.quantile(values, 0.5), DELTA); assertEquals(48.42, MathUtils.quantile(values, 0.6), DELTA); assertEquals(56.20, MathUtils.quantile(values, 0.7), DELTA); assertEquals(64.00, MathUtils.quantile(values, 0.8), DELTA); assertEquals(71.00, MathUtils.quantile(values, 0.9), DELTA); assertEquals(75.00, MathUtils.quantile(values, 1.0), DELTA); } @Test public void testIsCalculatable() { // Number assertTrue(MathUtils.isCalculatable(Byte.valueOf((byte) 0))); assertTrue(MathUtils.isCalculatable(Integer.valueOf(0))); assertTrue(MathUtils.isCalculatable(Long.valueOf(0L))); assertTrue(MathUtils.isCalculatable(new Float(0f))); assertTrue(MathUtils.isCalculatable(new Double(0.0))); assertFalse(MathUtils.isCalculatable(null)); assertFalse(MathUtils.isCalculatable(new Double(Double.NaN))); assertFalse(MathUtils.isCalculatable(new Double(Double.NEGATIVE_INFINITY))); assertFalse(MathUtils.isCalculatable(new Double(Double.POSITIVE_INFINITY))); // double assertTrue(MathUtils.isCalculatable(0.0)); assertFalse(MathUtils.isCalculatable(Double.NaN)); assertFalse(MathUtils.isCalculatable(Double.NEGATIVE_INFINITY)); assertFalse(MathUtils.isCalculatable(Double.POSITIVE_INFINITY)); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/util/PointNDTest.java000066400000000000000000000075751267060725100267320ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import java.awt.geom.Point2D; import java.io.IOException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import de.erichseifert.gral.TestUtils; import org.junit.Test; public class PointNDTest { public static final double DELTA = TestUtils.DELTA; @Test public void testCreate() { PointND p; // Constructor with Number[] p = new PointND(1.0, 2.0, 3.0, 4.0); assertEquals(4, p.getDimensions()); } @Test public void testGet() { Double[] coordinates = {1.0, 2.0, 3.0, 4.0}; PointND p = new PointND(coordinates); for (int dim = 0; dim < coordinates.length; dim++) { assertEquals(coordinates[dim], p.get(dim)); } } @Test public void testSet() { Double[] coordinates = {1.0, 2.0, 3.0, 4.0}; PointND p = new PointND(coordinates); int dim = 1; p.set(dim, 0.0); assertFalse(coordinates[dim].equals(p.get(dim))); assertEquals(0.0, p.get(dim), DELTA); Double[] coordinatesNew = {0.0, 1.0, 3.0, 2.0}; p.setLocation(coordinatesNew); for (int d = 0; d < coordinates.length; d++) { assertEquals(coordinatesNew[d], p.get(d)); } try { Double[] coordinatesNew2 = {0.0, 1.0}; p.setLocation(coordinatesNew2); fail("Expected IllegalArgumentException exception."); } catch (IllegalArgumentException e) { } } @Test public void testToString() { PointND p = new PointND(1.0, 2.0); assertEquals("de.erichseifert.gral.util.PointND[1.0, 2.0]", p.toString()); } @Test public void testEquality() { PointND p1 = new PointND(1.0, 2.0); PointND p2 = new PointND(1.0, 2.0); PointND p3 = new PointND(1.0, 2.0, 3.0); PointND p4 = new PointND(1.0, 2.0, null); // Equals assertTrue(p1.equals(p2)); assertFalse(p1.equals(null)); assertFalse(p2.equals(null)); assertFalse(p1.equals(p3)); assertFalse(p3.equals(p1)); assertFalse(p4.equals(p3)); assertFalse(p3.equals(p4)); // Hash code assertEquals(p1.hashCode(), p2.hashCode()); } @Test public void testPoint2D() { PointND p4 = new PointND(1.0, 2.0, 3.0, 4.0); assertEquals(new Point2D.Double(1.0, 2.0), p4.getPoint2D()); assertEquals(new Point2D.Double(2.0, 3.0), p4.getPoint2D(1, 2)); PointND p1 = new PointND(1.0); try { p1.getPoint2D(); fail("Expected ArrayIndexOutOfBoundsException exception."); } catch (ArrayIndexOutOfBoundsException e) { } } @Test public void testSerialization() throws IOException, ClassNotFoundException { PointND original = new PointND(1.0, 2.0, 3.0, 4.0); PointND deserialized = TestUtils.serializeAndDeserialize(original); assertEquals(original.getDimensions(), deserialized.getDimensions()); for (int i = 0; i < original.getDimensions(); i++) { assertEquals(String.format("Serialized points differ at dimension %d.", i), original.get(i), deserialized.get(i), DELTA); } } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/util/SortedListTest.java000066400000000000000000000057021267060725100275010ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import static org.junit.Assert.assertEquals; import java.util.Arrays; import java.util.List; import de.erichseifert.gral.TestUtils; import org.junit.Test; public class SortedListTest { public static final double DELTA = TestUtils.DELTA; @Test public void testCreation() { SortedList standard = new SortedList(); assertEquals(0, standard.size()); SortedList capacity = new SortedList(20); assertEquals(0, capacity.size()); List data = Arrays.asList(0.0, 2.0, 1.0); SortedList collection = new SortedList(data); assertEquals(3, collection.size()); assertEquals(0.0, collection.get(0), DELTA); assertEquals(1.0, collection.get(1), DELTA); assertEquals(2.0, collection.get(2), DELTA); } @Test public void testSize() { SortedList l = new SortedList(); assertEquals(0, l.size()); l.add(0.0); assertEquals(1, l.size()); l.add(1.0); assertEquals(2, l.size()); l.add(0.0); assertEquals(3, l.size()); } @Test public void testAdd() { SortedList l = new SortedList(); l.add(2.0); l.add(1.0); l.add(2.0); assertEquals(3, l.size()); assertEquals(1.0, l.get(0), DELTA); assertEquals(2.0, l.get(1), DELTA); assertEquals(2.0, l.get(2), DELTA); } @Test public void testGet() { SortedList l = new SortedList(); l.add(2.0); l.add(1.0); l.add(2.0); l.add(-1.0); assertEquals(-1.0, l.get(0), DELTA); assertEquals( 1.0, l.get(1), DELTA); assertEquals( 2.0, l.get(2), DELTA); assertEquals( 2.0, l.get(3), DELTA); } @Test public void testIndexOf() { SortedList l = new SortedList(); l.add(0.0); l.add(0.0); l.add(1.0); assertEquals(1, l.indexOf(0.0)); assertEquals(2, l.indexOf(1.0)); assertEquals(-1, l.indexOf(-1.0)); assertEquals(-1, l.indexOf(null)); assertEquals(-4, l.indexOf(Double.NaN)); } @Test public void testRemove() { SortedList l = new SortedList(); l.add(0.0); l.add(0.0); l.add(1.0); assertEquals(3, l.size()); l.remove(1); l.remove(1); assertEquals(1, l.size()); } } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/util/UtilTests.java000066400000000000000000000022611267060725100265020ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.util; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ PointNDTest.class, MathUtilsTest.class, HaltonSequenceTest.class, GeometryUtilsTest.class, GraphicsUtilsTest.class, SortedListTest.class }) public class UtilTests { } gral-0.11/gral-core/src/test/java/de/erichseifert/gral/util/package-info.java000077500000000000000000000017161267060725100270750ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Unit tests for {@code de.erichseifert.gral.util} package. */ package de.erichseifert.gral.util; gral-0.11/gral-examples/000077500000000000000000000000001267060725100151275ustar00rootroot00000000000000gral-0.11/gral-examples/build.gradle000066400000000000000000000002671267060725100174130ustar00rootroot00000000000000description = 'GRAL example applications' dependencies { compile project(':gral-core') } jar { manifest { attributes('Main-Class': 'de.erichseifert.gral.examples.Browser') } } gral-0.11/gral-examples/src/000077500000000000000000000000001267060725100157165ustar00rootroot00000000000000gral-0.11/gral-examples/src/main/000077500000000000000000000000001267060725100166425ustar00rootroot00000000000000gral-0.11/gral-examples/src/main/java/000077500000000000000000000000001267060725100175635ustar00rootroot00000000000000gral-0.11/gral-examples/src/main/java/de/000077500000000000000000000000001267060725100201535ustar00rootroot00000000000000gral-0.11/gral-examples/src/main/java/de/erichseifert/000077500000000000000000000000001267060725100226275ustar00rootroot00000000000000gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/000077500000000000000000000000001267060725100235545ustar00rootroot00000000000000gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/000077500000000000000000000000001267060725100253725ustar00rootroot00000000000000gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/Browser.java000066400000000000000000000102201267060725100276530ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples; import java.awt.event.MouseEvent; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import de.erichseifert.gral.examples.barplot.HistogramPlot; import de.erichseifert.gral.examples.barplot.SimpleBarPlot; import de.erichseifert.gral.examples.boxplot.SimpleBoxPlot; import de.erichseifert.gral.examples.pieplot.DynamicPiePlot; import de.erichseifert.gral.examples.pieplot.SimplePiePlot; import de.erichseifert.gral.examples.rasterplot.SimpleRasterPlot; import de.erichseifert.gral.examples.xyplot.AreaPlot; import de.erichseifert.gral.examples.xyplot.ConvolutionExample; import de.erichseifert.gral.examples.xyplot.MemoryUsage; import de.erichseifert.gral.examples.xyplot.MultiplePointRenderers; import de.erichseifert.gral.examples.xyplot.ScatterPlot; import de.erichseifert.gral.examples.xyplot.SimpleXYPlot; import de.erichseifert.gral.examples.xyplot.SpiralPlot; import de.erichseifert.gral.examples.xyplot.StackedPlots; public class Browser extends JFrame implements ListSelectionListener { /** Version id for serialization. */ private static final long serialVersionUID = -3734045121668893200L; private static class ExamplesList extends JList { /** Version id for serialization. */ private static final long serialVersionUID = -5904920699472899791L; public ExamplesList(ExamplePanel[] examples) { super(examples); } @Override public String getToolTipText(MouseEvent event) { int index = locationToIndex(event.getPoint()); ExamplePanel item = (ExamplePanel) getModel().getElementAt(index); return item.getDescription(); } } private static final ExamplePanel[] examples = { new HistogramPlot(), new SimpleBarPlot(), new SimpleBoxPlot(), new DynamicPiePlot(), new SimplePiePlot(), new SimpleRasterPlot(), new AreaPlot(), new ConvolutionExample(), new MemoryUsage(), new ScatterPlot(), new SimpleXYPlot(), new SpiralPlot(), new StackedPlots(), new MultiplePointRenderers() }; private final JList examplesList; private final JScrollPane exampleScrollPane; public Browser() { super("GRAL examples"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); examplesList = new ExamplesList(examples); examplesList.addListSelectionListener(this); exampleScrollPane = new JScrollPane(); setExample(examples[0]); JSplitPane listExamplesSplitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); listExamplesSplitter.setLeftComponent(examplesList); listExamplesSplitter.setRightComponent(exampleScrollPane); listExamplesSplitter.setOneTouchExpandable(true); listExamplesSplitter.setContinuousLayout(true); getContentPane().add(listExamplesSplitter); pack(); setLocationRelativeTo(null); } private void setExample(ExamplePanel example) { if (example == exampleScrollPane.getViewport().getView()) { return; } exampleScrollPane.getViewport().setView(example); examplesList.setSelectedValue(example, true); } public void valueChanged(ListSelectionEvent e) { Object source = e.getSource(); if (source == examplesList) { setExample((ExamplePanel) examplesList.getSelectedValue()); } } public static void main(String[] args) { JFrame frame = new Browser(); frame.setVisible(true); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/ExamplePanel.java000066400000000000000000000046001267060725100306100ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import javax.swing.JFrame; import javax.swing.JPanel; /** * Abstract base class for all visual examples. */ public abstract class ExamplePanel extends JPanel { /** Version id for serialization. */ private static final long serialVersionUID = 8221256658243821951L; /** First corporate color used for normal coloring.*/ protected static final Color COLOR1 = new Color( 55, 170, 200); /** Second corporate color used as signal color */ protected static final Color COLOR2 = new Color(200, 80, 75); /** * Performs basic initialization of an example, * like setting a default size. */ public ExamplePanel() { super(new BorderLayout()); setPreferredSize(new Dimension(800, 600)); setBackground(Color.WHITE); } /** * Returns a short title for the example. * @return A title text. */ public abstract String getTitle(); /** * Returns a more detailed description of the example contents. * @return A description of the example. */ public abstract String getDescription(); /** * Opens a frame and shows the example in it. * @return the frame instance used for displaying the example. */ protected JFrame showInFrame() { JFrame frame = new JFrame(getTitle()); frame.getContentPane().add(this, BorderLayout.CENTER); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(getPreferredSize()); frame.setVisible(true); return frame; } @Override public String toString() { return getTitle(); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/LabelExample.java000066400000000000000000000032731267060725100305750ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples; import java.awt.Color; import java.awt.GradientPaint; import java.awt.geom.Point2D; import de.erichseifert.gral.graphics.Label; import de.erichseifert.gral.ui.DrawablePanel; import de.erichseifert.gral.ui.InteractivePanel; public class LabelExample extends ExamplePanel { public LabelExample() { Label label = new Label("TestLabel"); label.setFont(getFont().deriveFont(20f)); label.setBackground(new GradientPaint( new Point2D.Double(0.0, 0.0), Color.BLACK, new Point2D.Double(1.0, 1.0), Color.WHITE )); DrawablePanel panel = new InteractivePanel(label); add(panel); } @Override public String getTitle() { return "Label example"; } @Override public String getDescription() { return "Label with colored background"; } public static void main(String[] args) { new LabelExample().showInFrame(); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/barplot/000077500000000000000000000000001267060725100270355ustar00rootroot00000000000000gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/barplot/HistogramPlot.java000066400000000000000000000073051267060725100325010ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.barplot; import java.util.Random; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.data.EnumeratedData; import de.erichseifert.gral.data.statistics.Histogram1D; import de.erichseifert.gral.data.statistics.Statistics; import de.erichseifert.gral.examples.ExamplePanel; import de.erichseifert.gral.plots.BarPlot; import de.erichseifert.gral.plots.points.PointRenderer; import de.erichseifert.gral.ui.InteractivePanel; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.graphics.Insets2D; import de.erichseifert.gral.util.MathUtils; import de.erichseifert.gral.graphics.Orientation; public class HistogramPlot extends ExamplePanel { /** Version id for serialization. */ private static final long serialVersionUID = 4458280577519421950L; private static final int SAMPLE_COUNT = 1000; @SuppressWarnings("unchecked") public HistogramPlot() { // Create example data Random random = new Random(); DataTable data = new DataTable(Double.class); for (int i = 0; i < SAMPLE_COUNT; i++) { data.add(random.nextGaussian()); } // Create histogram from data Histogram1D histogram = new Histogram1D(data, Orientation.VERTICAL, new Number[] {-4.0, -3.2, -2.4, -1.6, -0.8, 0.0, 0.8, 1.6, 2.4, 3.6, 4.0}); // Create a second dimension (x axis) for plotting DataSource histogram2d = new EnumeratedData(histogram, (-4.0 + -3.2)/2.0, 0.8); // Create new bar plot BarPlot plot = new BarPlot(histogram2d); // Format plot plot.setInsets(new Insets2D.Double(20.0, 65.0, 50.0, 40.0)); plot.getTitle().setText( String.format("Distribution of %d random samples", data.getRowCount())); plot.setBarWidth(0.78); // Format x axis plot.getAxisRenderer(BarPlot.AXIS_X).setTickAlignment(0.0); plot.getAxisRenderer(BarPlot.AXIS_X).setTickSpacing(0.8); plot.getAxisRenderer(BarPlot.AXIS_X).setMinorTicksVisible(false); // Format y axis plot.getAxis(BarPlot.AXIS_Y).setRange(0.0, MathUtils.ceil(histogram.getStatistics().get(Statistics.MAX)*1.1, 25.0)); plot.getAxisRenderer(BarPlot.AXIS_Y).setTickAlignment(0.0); plot.getAxisRenderer(BarPlot.AXIS_Y).setMinorTicksVisible(false); plot.getAxisRenderer(BarPlot.AXIS_Y).setIntersection(-4.4); // Format bars PointRenderer barRenderer = plot.getPointRenderers(histogram2d).get(0); barRenderer.setColor(GraphicsUtils.deriveWithAlpha(COLOR1, 128)); barRenderer.setValueVisible(true); // Add plot to Swing component InteractivePanel panel = new InteractivePanel(plot); panel.setPannable(false); panel.setZoomable(false); add(panel); } @Override public String getTitle() { return "Histogram plot"; } @Override public String getDescription() { return String.format("Histogram of %d samples", SAMPLE_COUNT); } public static void main(String[] args) { new HistogramPlot().showInFrame(); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/barplot/SimpleBarPlot.java000066400000000000000000000062301267060725100324160ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.barplot; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.LinearGradientPaint; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.examples.ExamplePanel; import de.erichseifert.gral.plots.BarPlot; import de.erichseifert.gral.plots.BarPlot.BarRenderer; import de.erichseifert.gral.ui.InteractivePanel; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.graphics.Insets2D; import de.erichseifert.gral.graphics.Location; public class SimpleBarPlot extends ExamplePanel { /** Version id for serialization. */ private static final long serialVersionUID = -2793954497895054530L; @SuppressWarnings("unchecked") public SimpleBarPlot() { // Create example data DataTable data = new DataTable(Double.class, Integer.class, String.class); data.add(0.1, 1, "January"); data.add(0.2, 3, "February"); data.add(0.3, -2, "March"); data.add(0.4, 6, "April"); data.add(0.5, -4, "May"); data.add(0.6, 8, "June"); data.add(0.7, 9, "July"); data.add(0.8, 11, "August"); // Create new bar plot BarPlot plot = new BarPlot(data); // Format plot plot.setInsets(new Insets2D.Double(40.0, 40.0, 40.0, 40.0)); plot.setBarWidth(0.075); // Format bars BarRenderer pointRenderer = (BarRenderer) plot.getPointRenderers(data).get(0); pointRenderer.setColor( new LinearGradientPaint(0f,0f, 0f,1f, new float[] { 0.0f, 1.0f }, new Color[] { COLOR1, GraphicsUtils.deriveBrighter(COLOR1) } ) ); pointRenderer.setBorderStroke(new BasicStroke(3f)); pointRenderer.setBorderColor( new LinearGradientPaint(0f,0f, 0f,1f, new float[] { 0.0f, 1.0f }, new Color[] { GraphicsUtils.deriveBrighter(COLOR1), COLOR1 } ) ); pointRenderer.setValueVisible(true); pointRenderer.setValueColumn(2); pointRenderer.setValueLocation(Location.CENTER); pointRenderer.setValueColor(GraphicsUtils.deriveDarker(COLOR1)); pointRenderer.setValueFont(Font.decode(null).deriveFont(Font.BOLD)); // Add plot to Swing component add(new InteractivePanel(plot)); } @Override public String getTitle() { return "Bar plot"; } @Override public String getDescription() { return "Bar plot with example data and color gradients"; } public static void main(String[] args) { new SimpleBarPlot().showInFrame(); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/boxplot/000077500000000000000000000000001267060725100270615ustar00rootroot00000000000000gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/boxplot/SimpleBoxPlot.java000066400000000000000000000073171267060725100324750ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.boxplot; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Stroke; import java.util.Random; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.examples.ExamplePanel; import de.erichseifert.gral.plots.BoxPlot; import de.erichseifert.gral.plots.BoxPlot.BoxWhiskerRenderer; import de.erichseifert.gral.plots.XYPlot.XYNavigationDirection; import de.erichseifert.gral.plots.colors.LinearGradient; import de.erichseifert.gral.plots.colors.ScaledContinuousColorMapper; import de.erichseifert.gral.ui.InteractivePanel; import de.erichseifert.gral.util.DataUtils; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.graphics.Insets2D; public class SimpleBoxPlot extends ExamplePanel { /** Version id for serialization. */ private static final long serialVersionUID = 5228891435595348789L; private static final int SAMPLE_COUNT = 50; private static final Random random = new Random(); @SuppressWarnings("unchecked") public SimpleBoxPlot() { setPreferredSize(new Dimension(400, 600)); // Create example data DataTable data = new DataTable(Integer.class, Integer.class, Integer.class); for (int i = 0; i < SAMPLE_COUNT; i++) { int x = (int) Math.round(5.0*random.nextGaussian()); int y = (int) Math.round(5.0*random.nextGaussian()); int z = (int) Math.round(5.0*random.nextGaussian()); data.add(x, y, z); } // Create new box-and-whisker plot DataSource boxData = BoxPlot.createBoxData(data); BoxPlot plot = new BoxPlot(boxData); // Format plot plot.setInsets(new Insets2D.Double(20.0, 50.0, 40.0, 20.0)); // Format axes plot.getAxisRenderer(BoxPlot.AXIS_X).setCustomTicks( DataUtils.map( new Double[] {1.0, 2.0, 3.0}, new String[] {"Column 1", "Column 2", "Column 3"} ) ); // Format boxes Stroke stroke = new BasicStroke(2f); ScaledContinuousColorMapper colors = new LinearGradient(GraphicsUtils.deriveBrighter(COLOR1), Color.WHITE); colors.setRange(1.0, 3.0); BoxWhiskerRenderer pointRenderer = (BoxWhiskerRenderer) plot.getPointRenderers(boxData).get(0); pointRenderer.setWhiskerStroke(stroke); pointRenderer.setBoxBorderStroke(stroke); pointRenderer.setBoxBackground(colors); pointRenderer.setBoxBorderColor(COLOR1); pointRenderer.setWhiskerColor(COLOR1); pointRenderer.setCenterBarColor(COLOR1); plot.getNavigator().setDirection(XYNavigationDirection.VERTICAL); // Add plot to Swing component InteractivePanel panel = new InteractivePanel(plot); add(panel); } @Override public String getTitle() { return "Box-and-whisker plot"; } @Override public String getDescription() { return String.format("Three box-and-whisker plots created from %d random samples", SAMPLE_COUNT); } public static void main(String[] args) { new SimpleBoxPlot().showInFrame(); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/io/000077500000000000000000000000001267060725100260015ustar00rootroot00000000000000gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/io/DataWriterTest.java000066400000000000000000000040331267060725100315520ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.io; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import javax.swing.JFileChooser; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.io.data.DataWriter; import de.erichseifert.gral.io.data.DataWriterFactory; public class DataWriterTest { private final DataTable data; @SuppressWarnings("unchecked") public DataWriterTest() { data = new DataTable(Double.class, Double.class, Double.class, Double.class); data.add(1.0, 4.5, 4.3, 4.0); data.add(1.5, 5.5, 5.3, 5.0); data.add(3.0, 3.5, 3.7, 4.0); data.add(4.0, 4.7, 4.5, 4.3); } public void save() throws IOException { JFileChooser chooser = new JFileChooser(); int option = chooser.showSaveDialog(null); if (option == JFileChooser.APPROVE_OPTION) { File file = chooser.getSelectedFile(); OutputStream output = new FileOutputStream(file); DataWriter writer = DataWriterFactory.getInstance().get("text/csv"); writer.write(data, output); } } public static void main(String[] args) { DataWriterTest test = new DataWriterTest(); try { test.save(); } catch (IOException e) { e.printStackTrace(); } } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/io/DrawableWriterTest.java000066400000000000000000000055301267060725100324250ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.io; import java.awt.Color; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import javax.swing.JFileChooser; import de.erichseifert.gral.data.DataSeries; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.io.plots.DrawableWriter; import de.erichseifert.gral.io.plots.DrawableWriterFactory; import de.erichseifert.gral.plots.XYPlot; import de.erichseifert.gral.plots.lines.DefaultLineRenderer2D; import de.erichseifert.gral.plots.lines.LineRenderer; import de.erichseifert.gral.graphics.Insets2D; public class DrawableWriterTest { private final XYPlot plot; @SuppressWarnings("unchecked") public DrawableWriterTest() { DataTable data = new DataTable(Double.class, Double.class, Double.class, Double.class); data.add(1.0, 4.5, 4.3, 4.0); data.add(1.5, 5.5, 5.3, 5.0); data.add(3.0, 3.5, 3.7, 4.0); data.add(4.0, 4.7, 4.5, 4.3); DataSeries s1 = new DataSeries(data, 0, 1); DataSeries s2 = new DataSeries(data, 0, 2); DataSeries s3 = new DataSeries(data, 0, 3); plot = new XYPlot(s1, s2, s3); plot.setInsets(new Insets2D.Double(20, 50, 50, 20)); LineRenderer lr1 = new DefaultLineRenderer2D(); lr1.setColor(Color.RED); plot.setLineRenderers(s1, lr1); LineRenderer lr2 = new DefaultLineRenderer2D(); lr2.setColor(Color.GREEN); plot.setLineRenderers(s2, lr2); LineRenderer lr3 = new DefaultLineRenderer2D(); lr3.setColor(Color.BLUE); plot.setLineRenderers(s3, lr3); } public void save() { JFileChooser chooser = new JFileChooser(); int option = chooser.showSaveDialog(null); if (option == JFileChooser.APPROVE_OPTION) { File file = chooser.getSelectedFile(); try { DrawableWriter writer = DrawableWriterFactory.getInstance().get("application/postscript"); writer.write(plot, new FileOutputStream(file), 800, 600); } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { DrawableWriterTest test = new DrawableWriterTest(); test.save(); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/package-info.java000077500000000000000000000016641267060725100305730ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ /** * Small example applications. */ package de.erichseifert.gral.examples; gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/pieplot/000077500000000000000000000000001267060725100270465ustar00rootroot00000000000000gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/pieplot/DynamicPiePlot.java000066400000000000000000000100521267060725100325700ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.pieplot; import java.awt.BorderLayout; import java.text.MessageFormat; import java.util.Random; import javax.swing.JSlider; import javax.swing.border.EmptyBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.examples.ExamplePanel; import de.erichseifert.gral.plots.PiePlot; import de.erichseifert.gral.plots.PiePlot.PieSliceRenderer; import de.erichseifert.gral.plots.colors.LinearGradient; import de.erichseifert.gral.ui.InteractivePanel; import de.erichseifert.gral.graphics.Insets2D; public class DynamicPiePlot extends ExamplePanel implements ChangeListener { /** Version id for serialization. */ private static final long serialVersionUID = 6216017404657972412L; private static final int SAMPLE_COUNT = 5; /** Instance to generate random data values. */ private static final Random random = new Random(); private final DataTable data; private final PiePlot plot; private final JSlider valueCountSlider; @SuppressWarnings("unchecked") public DynamicPiePlot() { // Create initial data data = new DataTable(Integer.class); // Create new pie plot plot = new PiePlot(data); // Change relative size of pie plot.setRadius(0.9); // Change the starting angle of the first pie slice plot.setStart(90.0); // Add some margin to the plot area plot.setInsets(new Insets2D.Double(20.0)); PieSliceRenderer pointRenderer = (PieSliceRenderer) plot.getPointRenderer(data); // Change the width of gaps between segments pointRenderer.setGap(0.2); // Change the colors LinearGradient colors = new LinearGradient(COLOR1, COLOR2); pointRenderer.setColor(colors); // Add plot to Swing component InteractivePanel panel = new InteractivePanel(plot); add(panel, BorderLayout.CENTER); setValueCount(SAMPLE_COUNT); // Create a slider to change the number of data values valueCountSlider = new JSlider(0, 50, SAMPLE_COUNT); valueCountSlider.setBorder(new EmptyBorder(15, 15, 5, 15)); valueCountSlider.setMajorTickSpacing(10); valueCountSlider.setMinorTickSpacing(1); valueCountSlider.setSnapToTicks(true); valueCountSlider.setPaintTicks(true); valueCountSlider.addChangeListener(this); add(valueCountSlider, BorderLayout.SOUTH); } @Override public String getTitle() { return "Pie plot"; } @Override public String getDescription() { return "Pie with a changeable number of random data values"; } private void setValueCount(int count) { if (count == data.getRowCount()) { return; } while (data.getRowCount() != count) { if (data.getRowCount() < count) { int val = random.nextInt(10) + 1; data.add(val); } else { int rowIndexLast = data.getRowCount() - 1; data.remove(rowIndexLast); } } if (plot != null) { String title = MessageFormat.format("{0,number,integer} random values", data.getRowCount()); plot.getTitle().setText(title); } } public void stateChanged(ChangeEvent e) { Object source = e.getSource(); if (source == valueCountSlider) { int countNew = valueCountSlider.getValue(); setValueCount(countNew); repaint(); } } public static void main(String[] args) { new DynamicPiePlot().showInFrame(); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/pieplot/SimplePiePlot.java000066400000000000000000000061221267060725100324400ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.pieplot; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.util.Random; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.examples.ExamplePanel; import de.erichseifert.gral.plots.PiePlot; import de.erichseifert.gral.plots.PiePlot.PieSliceRenderer; import de.erichseifert.gral.plots.colors.LinearGradient; import de.erichseifert.gral.ui.InteractivePanel; import de.erichseifert.gral.graphics.Insets2D; public class SimplePiePlot extends ExamplePanel { /** Version id for serialization. */ private static final long serialVersionUID = -3039317265508932299L; private static final int SAMPLE_COUNT = 10; /** Instance to generate random data values. */ private static final Random random = new Random(); @SuppressWarnings("unchecked") public SimplePiePlot() { // Create data DataTable data = new DataTable(Integer.class); for (int i = 0; i < SAMPLE_COUNT; i++) { int val = random.nextInt(8) + 2; data.add((random.nextDouble() <= 0.15) ? -val : val); } // Create new pie plot PiePlot plot = new PiePlot(data); // Format plot plot.getTitle().setText(getDescription()); // Change relative size of pie plot.setRadius(0.9); // Display a legend plot.setLegendVisible(true); // Add some margin to the plot area plot.setInsets(new Insets2D.Double(20.0, 40.0, 40.0, 40.0)); PieSliceRenderer pointRenderer = (PieSliceRenderer) plot.getPointRenderer(data); // Change relative size of inner region pointRenderer.setInnerRadius(0.4); // Change the width of gaps between segments pointRenderer.setGap(0.2); // Change the colors LinearGradient colors = new LinearGradient(COLOR1, COLOR2); pointRenderer.setColor(colors); // Show labels pointRenderer.setValueVisible(true); pointRenderer.setValueColor(Color.WHITE); pointRenderer.setValueFont(Font.decode(null).deriveFont(Font.BOLD)); // Add plot to Swing component add(new InteractivePanel(plot), BorderLayout.CENTER); } @Override public String getTitle() { return "Donut plot"; } @Override public String getDescription() { return String.format("Donut plot of %d random data values", SAMPLE_COUNT); } public static void main(String[] args) { new SimplePiePlot().showInFrame(); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/rasterplot/000077500000000000000000000000001267060725100275715ustar00rootroot00000000000000gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/rasterplot/SimpleRasterPlot.java000066400000000000000000000056401267060725100337120ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.rasterplot; import java.awt.Color; import java.awt.Dimension; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.examples.ExamplePanel; import de.erichseifert.gral.plots.RasterPlot; import de.erichseifert.gral.plots.colors.LinearGradient; import de.erichseifert.gral.ui.InteractivePanel; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.graphics.Insets2D; public class SimpleRasterPlot extends ExamplePanel { /** Version id for serialization. */ private static final long serialVersionUID = -2515812178479580541L; private static final int SIZE = 64; private static final double ZOOM = 0.3; public SimpleRasterPlot() { setPreferredSize(new Dimension(600, 600)); // Create example data DataTable raster = new DataTable(SIZE, Double.class); for (int rowIndex = 0; rowIndex < raster.getColumnCount(); rowIndex++) { Comparable[] row = new Comparable[raster.getColumnCount()]; double y = ZOOM*rowIndex; for (int colIndex = 0; colIndex < row.length; colIndex++) { double x = ZOOM*colIndex; row[colIndex] = Math.cos(Math.hypot(x - ZOOM*SIZE/2.0, y - ZOOM*SIZE/2.0)) * Math.cos(Math.hypot(x + ZOOM*SIZE/2.0, y + ZOOM*SIZE/2.0)); } raster.add(row); } // Convert raster matrix to (x, y, value) DataSource valuesByCoord = RasterPlot.createRasterData(raster); // Create new bar plot RasterPlot plot = new RasterPlot(valuesByCoord); // Format plot plot.setInsets(new Insets2D.Double(20.0, 60.0, 40.0, 20.0)); plot.setColors(new LinearGradient(GraphicsUtils.deriveDarker(COLOR1), COLOR1, Color.WHITE)); // Add plot to Swing component InteractivePanel panel = new InteractivePanel(plot); panel.setPannable(false); panel.setZoomable(false); add(panel); } @Override public String getTitle() { return "Raster plot"; } @Override public String getDescription() { return String.format("Raster plot of %d×%d values", SIZE, SIZE); } public static void main(String[] args) { new SimpleRasterPlot().showInFrame(); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/xyplot/000077500000000000000000000000001267060725100267315ustar00rootroot00000000000000gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/xyplot/AreaPlot.java000066400000000000000000000104501267060725100313030ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.xyplot; import java.awt.Color; import java.util.Random; import de.erichseifert.gral.data.DataSeries; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.examples.ExamplePanel; import de.erichseifert.gral.plots.XYPlot; import de.erichseifert.gral.plots.areas.AreaRenderer; import de.erichseifert.gral.plots.areas.DefaultAreaRenderer2D; import de.erichseifert.gral.plots.areas.LineAreaRenderer2D; import de.erichseifert.gral.plots.lines.DefaultLineRenderer2D; import de.erichseifert.gral.plots.lines.LineRenderer; import de.erichseifert.gral.plots.points.DefaultPointRenderer2D; import de.erichseifert.gral.plots.points.PointRenderer; import de.erichseifert.gral.ui.InteractivePanel; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.graphics.Insets2D; public class AreaPlot extends ExamplePanel { /** Version id for serialization. */ private static final long serialVersionUID = 3287044991898775949L; /** Instance to generate random data values. */ private static final Random random = new Random(); @SuppressWarnings("unchecked") public AreaPlot() { // Generate data DataTable data = new DataTable(Double.class, Double.class, Double.class, Double.class); for (double x=0.0; x<2.5*Math.PI; x+=Math.PI/15.0) { double y1 = Double.NaN, y2 = Double.NaN, y3 = Double.NaN; if (x>=0.00*Math.PI && x<2.25*Math.PI) { y1 = 4.0*Math.sin(x + 0.5*Math.PI) + 0.1*random.nextGaussian(); } if (x>=0.25*Math.PI && x<2.50*Math.PI) { y2 = 4.0*Math.cos(x + 0.5*Math.PI) + 0.1*random.nextGaussian(); } if (x>=0.00*Math.PI && x<2.50*Math.PI) { y3 = 2.0*Math.sin(2.0*x/2.5) + 0.1*random.nextGaussian(); } data.add(x, y1, y2, y3); } // Create data series DataSeries data1 = new DataSeries("red", data, 0, 1); DataSeries data2 = new DataSeries("blue 1", data, 0, 2); DataSeries data3 = new DataSeries("blue 2", data, 0, 3); // Create new xy-plot XYPlot plot = new XYPlot(data1, data2, data3); plot.setLegendVisible(true); plot.setInsets(new Insets2D.Double(20.0, 40.0, 20.0, 20.0)); // Format data series formatFilledArea(plot, data1, COLOR2); formatFilledArea(plot, data2, COLOR1); formatLineArea(plot, data3, GraphicsUtils.deriveDarker(COLOR1)); // Add plot to Swing component add(new InteractivePanel(plot)); } private static void formatFilledArea(XYPlot plot, DataSource data, Color color) { PointRenderer point = new DefaultPointRenderer2D(); point.setColor(color); plot.setPointRenderers(data, point); LineRenderer line = new DefaultLineRenderer2D(); line.setColor(color); line.setGap(3.0); line.setGapRounded(true); plot.setLineRenderers(data, line); AreaRenderer area = new DefaultAreaRenderer2D(); area.setColor(GraphicsUtils.deriveWithAlpha(color, 64)); plot.setAreaRenderers(data, area); } private static void formatLineArea(XYPlot plot, DataSource data, Color color) { PointRenderer point = new DefaultPointRenderer2D(); point.setColor(color); plot.setPointRenderers(data, point); plot.setLineRenderers(data, null); AreaRenderer area = new LineAreaRenderer2D(); area.setGap(3.0); area.setColor(color); plot.setAreaRenderers(data, area); } @Override public String getTitle() { return "Area plot"; } @Override public String getDescription() { return "Area plot of three series with different styling"; } public static void main(String[] args) { new AreaPlot().showInFrame(); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/xyplot/ConvolutionExample.java000066400000000000000000000120101267060725100334210ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.xyplot; import java.awt.BorderLayout; import java.awt.Color; import java.util.Random; import de.erichseifert.gral.data.DataSeries; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.data.filters.Convolution; import de.erichseifert.gral.data.filters.Filter; import de.erichseifert.gral.data.filters.Kernel; import de.erichseifert.gral.data.filters.Median; import de.erichseifert.gral.examples.ExamplePanel; import de.erichseifert.gral.graphics.Insets2D; import de.erichseifert.gral.graphics.Orientation; import de.erichseifert.gral.plots.XYPlot; import de.erichseifert.gral.plots.lines.DefaultLineRenderer2D; import de.erichseifert.gral.ui.InteractivePanel; import de.erichseifert.gral.util.GraphicsUtils; /** * Example that shows how to use convultion filtering. */ public class ConvolutionExample extends ExamplePanel { /** Version id for serialization. */ private static final long serialVersionUID = 5084898568751883516L; private static final int SAMPLE_COUNT = 200; @SuppressWarnings("unchecked") public ConvolutionExample() { // Generate 200 data points DataTable data = new DataTable(Double.class, Double.class); Random r = new Random(); for (int i = 0; i < SAMPLE_COUNT; i++) { double x = i/2.0/Math.PI; double yError = Math.sqrt(3.0*0.1)*r.nextGaussian(); double y = 10.0*Math.sin(x/5.0) + yError*yError*yError; data.add(x, y); } DataSeries ds = new DataSeries("Data", data, 0, 1); final double KERNEL_VARIANCE = 5.0; // Create a smoothed data series from a binomial (near-gaussian) convolution filter Kernel kernelLowpass = Kernel.getBinomial(KERNEL_VARIANCE).normalize(); Filter dataLowpass = new Convolution(data, kernelLowpass, Filter.Mode.REPEAT, 1); DataSeries dsLowpass = new DataSeries("Lowpass", dataLowpass, 0, 1); // Create a derived data series from a binomial convolution filter Kernel kernelHighpass = Kernel.getBinomial(KERNEL_VARIANCE).normalize().negate().add(new Kernel(1.0)); Filter dataHighpass = new Convolution(data, kernelHighpass, Filter.Mode.REPEAT, 1); DataSeries dsHighpass = new DataSeries("Highpass", dataHighpass, 0, 1); // Create a new data series that calculates the moving average using a custom convolution kernel int kernelMovingAverageSize = (int)Math.round(4.0*KERNEL_VARIANCE); Kernel kernelMovingAverage = Kernel.getUniform(kernelMovingAverageSize, kernelMovingAverageSize - 1, 1.0).normalize(); Filter dataMovingAverage = new Convolution(data, kernelMovingAverage, Filter.Mode.OMIT, 1); DataSeries dsMovingAverage = new DataSeries("Moving Average", dataMovingAverage, 0, 1); // Create a new data series that calculates the moving median int kernelMovingMedianSize = (int)Math.round(4.0*KERNEL_VARIANCE); Filter dataMovingMedian = new Median(data, kernelMovingMedianSize, kernelMovingMedianSize - 1, Filter.Mode.OMIT, 1); DataSeries dsMovingMedian = new DataSeries("Moving Median", dataMovingMedian, 0, 1); // Create a new xy-plot XYPlot plot = new XYPlot(ds, dsLowpass, dsHighpass, dsMovingAverage, dsMovingMedian); // Format plot plot.setInsets(new Insets2D.Double(20.0, 40.0, 40.0, 40.0)); plot.setLegendVisible(true); // Format legend plot.getLegend().setOrientation(Orientation.HORIZONTAL); plot.getLegend().setAlignmentY(1.0); // Format data series as lines of different colors formatLine(plot, ds, Color.BLACK); formatLine(plot, dsLowpass, COLOR1); formatLine(plot, dsHighpass, GraphicsUtils.deriveDarker(COLOR1)); formatLine(plot, dsMovingAverage, COLOR2); formatLine(plot, dsMovingMedian, GraphicsUtils.deriveDarker(COLOR2)); // Add plot to Swing component add(new InteractivePanel(plot), BorderLayout.CENTER); } private static void formatLine(XYPlot plot, DataSeries series, Color color) { plot.setPointRenderers(series, null); DefaultLineRenderer2D line = new DefaultLineRenderer2D(); line.setColor(color); plot.setLineRenderers(series, line); } @Override public String getTitle() { return "Convolution filtering"; } @Override public String getDescription() { return "Line plot showing various ways of filtering data with convolution"; } public static void main(String[] args) { new ConvolutionExample().showInFrame(); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/xyplot/MemoryUsage.java000066400000000000000000000202341267060725100320320ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.xyplot; import java.awt.BorderLayout; import java.awt.Color; import java.awt.LinearGradientPaint; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.DateFormat; import java.text.DecimalFormat; import javax.swing.JComponent; import javax.swing.Timer; import de.erichseifert.gral.data.Column; import de.erichseifert.gral.data.DataSeries; import de.erichseifert.gral.data.DataSource; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.data.statistics.Statistics; import de.erichseifert.gral.examples.ExamplePanel; import de.erichseifert.gral.graphics.Insets2D; import de.erichseifert.gral.graphics.Orientation; import de.erichseifert.gral.plots.Plot; import de.erichseifert.gral.plots.XYPlot; import de.erichseifert.gral.plots.XYPlot.XYPlotArea2D; import de.erichseifert.gral.plots.areas.AreaRenderer; import de.erichseifert.gral.plots.areas.DefaultAreaRenderer2D; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.lines.DefaultLineRenderer2D; import de.erichseifert.gral.plots.lines.LineRenderer; import de.erichseifert.gral.ui.InteractivePanel; import de.erichseifert.gral.util.GraphicsUtils; final class UpdateTask implements ActionListener { private final DataTable data; private final Plot plot; private final JComponent component; private Method getTotalPhysicalMemorySize; private Method getFreePhysicalMemorySize; public UpdateTask(DataTable data, XYPlot plot, JComponent comp) { this.data = data; this.plot = plot; this.component = comp; // Check for VM specific methods getTotalPhysicalMemorySize() and // getFreePhysicalMemorySize() OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); try { getTotalPhysicalMemorySize = osBean.getClass() .getMethod("getTotalPhysicalMemorySize"); getTotalPhysicalMemorySize.setAccessible(true); getFreePhysicalMemorySize = osBean.getClass() .getMethod("getFreePhysicalMemorySize"); getFreePhysicalMemorySize.setAccessible(true); } catch (SecurityException ex) { } catch (NoSuchMethodException ex) { } } public void actionPerformed(ActionEvent e) { if (!component.isVisible()) { return; } double time = System.currentTimeMillis(); // Physical system memory long memSysTotal = 0L; long memSysFree = 0L; long memSysUsed = 0L; // We can only display system memory if there are the corresponding // methods if ((getTotalPhysicalMemorySize != null) && (getFreePhysicalMemorySize != null)) { OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); try { memSysTotal = (Long) getTotalPhysicalMemorySize.invoke(osBean); memSysFree = (Long) getFreePhysicalMemorySize.invoke(osBean); memSysUsed = memSysTotal - memSysFree; } catch (IllegalArgumentException ex) { } catch (IllegalAccessException ex) { } catch (InvocationTargetException ex) { } } // JVM memory long memVmTotal = Runtime.getRuntime().totalMemory(); long memVmFree = Runtime.getRuntime().freeMemory(); long memVmUsed = memVmTotal - memVmFree; data.add(time, memSysUsed/1024L/1024L, memVmTotal/1024L/1024L, memVmUsed/1024L/1024L); data.remove(0); Column col1 = data.getColumn(0); plot.getAxis(XYPlot.AXIS_X).setRange( col1.getStatistics(Statistics.MIN), col1.getStatistics(Statistics.MAX) ); Column col3 = data.getColumn(2); plot.getAxis(XYPlot.AXIS_Y).setRange( 0, Math.max( memSysTotal/1024L/1024L, col3.getStatistics(Statistics.MAX) ) ); component.repaint(); } } public class MemoryUsage extends ExamplePanel { /** Version id for serialization. */ private static final long serialVersionUID = 5914124874301980251L; /** Size of the data buffer in no. of element. */ private static final int BUFFER_SIZE = 400; /** Update interval in milliseconds */ private static final int INTERVAL = 100; @SuppressWarnings("unchecked") public MemoryUsage() { DataTable data = new DataTable(Double.class, Long.class, Long.class, Long.class); double time = System.currentTimeMillis(); for (int i=BUFFER_SIZE - 1; i>=0; i--) { data.add(time - i*INTERVAL, null, null, null); } // Use columns 0 and 1 for physical system memory DataSource memSysUsage = new DataSeries("Used by system", data, 0, 1); // Use columns 0 and 2 for JVM memory DataSource memVm = new DataSeries("Allocated by Java VM", data, 0, 2); // Use columns 0 and 2 for JVM memory usage DataSource memVmUsage = new DataSeries("Used by Java VM", data, 0, 3); // Create new xy-plot XYPlot plot = new XYPlot(memSysUsage, memVm, memVmUsage); // Format plot plot.setInsets(new Insets2D.Double(20.0, 90.0, 40.0, 20.0)); plot.getTitle().setText("Memory Usage"); plot.setLegendVisible(true); // Format legend plot.getLegend().setOrientation(Orientation.HORIZONTAL); // Format plot area ((XYPlotArea2D) plot.getPlotArea()).setMajorGridX(false); ((XYPlotArea2D) plot.getPlotArea()).setMinorGridY(true); // Format axes (set scale and spacings) plot.getAxis(XYPlot.AXIS_Y).setRange(0.0, 1.0); AxisRenderer axisRendererX = plot.getAxisRenderer(XYPlot.AXIS_X); axisRendererX.setTickSpacing(BUFFER_SIZE*INTERVAL/10.0); axisRendererX.setTickLabelFormat(DateFormat.getTimeInstance()); AxisRenderer axisRendererY = plot.getAxisRenderer(XYPlot.AXIS_Y); axisRendererY.setMinorTicksCount(4); axisRendererY.setTickLabelFormat(new DecimalFormat("0 MiB")); Color color1Dark = GraphicsUtils.deriveDarker(COLOR1); // Format first data series plot.setPointRenderers(memSysUsage, null); AreaRenderer area1 = new DefaultAreaRenderer2D(); area1.setColor(new LinearGradientPaint( 0f, 0f, 0f, 1f, new float[] {0f, 1f}, new Color[] { GraphicsUtils.deriveWithAlpha(COLOR1, 128), GraphicsUtils.deriveWithAlpha(COLOR1, 24) } )); plot.setAreaRenderers(memSysUsage, area1); // Format second data series plot.setPointRenderers(memVm, null); LineRenderer line2 = new DefaultLineRenderer2D(); line2.setColor(GraphicsUtils.deriveWithAlpha(color1Dark, 128)); plot.setLineRenderers(memVm, line2); // Format third data series plot.setPointRenderers(memVmUsage, null); AreaRenderer area3 = new DefaultAreaRenderer2D(); area3.setColor(new LinearGradientPaint( 0f, 0f, 0f, 1f, new float[] {0f, 1f}, new Color[] { GraphicsUtils.deriveWithAlpha(COLOR2, 128), GraphicsUtils.deriveWithAlpha(COLOR2, 24) } )); plot.setAreaRenderers(memVmUsage, area3); // Add plot to frame InteractivePanel plotPanel = new InteractivePanel(plot); plotPanel.setPannable(false); plotPanel.setZoomable(false); add(plotPanel, BorderLayout.CENTER); // Start watching memory UpdateTask updateTask = new UpdateTask(data, plot, plotPanel); Timer updateTimer = new Timer(INTERVAL, updateTask); updateTimer.setCoalesce(false); updateTimer.start(); } @Override public String getTitle() { return "Memory usage"; } @Override public String getDescription() { return "Area plot of the system's current memory usage. This example " + "works best with Oracle VM, but it can show VM memory usage on " + "other VMs too."; } public static void main(String[] args) { new MemoryUsage().showInFrame(); } } MultiplePointRenderers.java000066400000000000000000000102221267060725100341710ustar00rootroot00000000000000gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/xyplot/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.xyplot; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.geom.AffineTransform; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.examples.ExamplePanel; import de.erichseifert.gral.graphics.AbstractDrawable; import de.erichseifert.gral.graphics.Drawable; import de.erichseifert.gral.graphics.DrawingContext; import de.erichseifert.gral.graphics.Insets2D; import de.erichseifert.gral.plots.XYPlot; import de.erichseifert.gral.plots.lines.DefaultLineRenderer2D; import de.erichseifert.gral.plots.lines.LineRenderer; import de.erichseifert.gral.plots.points.AbstractPointRenderer; import de.erichseifert.gral.plots.points.DefaultPointRenderer2D; import de.erichseifert.gral.plots.points.PointData; import de.erichseifert.gral.plots.points.PointRenderer; import de.erichseifert.gral.ui.InteractivePanel; import de.erichseifert.gral.util.GraphicsUtils; public class MultiplePointRenderers extends ExamplePanel { /** Version id for serialization. */ private static final long serialVersionUID = -5263057758564264677L; private static class ShadowPointRenderer extends AbstractPointRenderer { private final PointRenderer pointRenderer; public ShadowPointRenderer(PointRenderer pointRenderer) { this.pointRenderer = pointRenderer; } @Override public Shape getPointShape(PointData data) { return pointRenderer.getPointShape(data); } @Override public Drawable getPoint(final PointData data, final Shape shape) { Drawable drawable = new AbstractDrawable() { @Override public void draw(DrawingContext context) { Graphics2D graphics2D = context.getGraphics(); AffineTransform txOld = graphics2D.getTransform(); graphics2D.translate(2.0, 1.0); GraphicsUtils.fillPaintedShape( graphics2D, shape, new Color(0.0f, 0.0f, 0.0f, 0.2f), null); graphics2D.setTransform(txOld); } }; return drawable; } @Override public Drawable getValue(PointData data, Shape shape) { return pointRenderer.getValue(data, shape); } } @SuppressWarnings("unchecked") public MultiplePointRenderers() { // Generate data DataTable data = new DataTable(Double.class, Double.class); for (double x = 1.0; x <= 20.0; x += 1.0) { data.add(x, x*x); } // Create new xy-plot XYPlot plot = new XYPlot(data); // Format plot plot.setInsets(new Insets2D.Double(20.0, 60.0, 40.0, 40.0)); plot.setBackground(Color.WHITE); plot.getTitle().setText(getDescription()); // Format rendering of data points PointRenderer defaultPointRenderer = new DefaultPointRenderer2D(); defaultPointRenderer.setColor(GraphicsUtils.deriveDarker(COLOR1)); plot.setPointRenderers(data, defaultPointRenderer); PointRenderer shadowRenderer = new ShadowPointRenderer(defaultPointRenderer); plot.addPointRenderer(data, shadowRenderer); LineRenderer lineRenderer = new DefaultLineRenderer2D(); lineRenderer.setGap(2.0); plot.setLineRenderers(data, lineRenderer); // Add plot to Swing component add(new InteractivePanel(plot), BorderLayout.CENTER); } @Override public String getTitle() { return "Multiple renderers"; } @Override public String getDescription() { return "Plot with point shadows"; } public static void main(String[] args) { new MultiplePointRenderers().showInFrame(); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/xyplot/ScatterPlot.java000066400000000000000000000045241267060725100320450ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.xyplot; import java.awt.BorderLayout; import java.util.Random; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.examples.ExamplePanel; import de.erichseifert.gral.plots.XYPlot; import de.erichseifert.gral.ui.InteractivePanel; import de.erichseifert.gral.graphics.Insets2D; public class ScatterPlot extends ExamplePanel { /** Version id for serialization. */ private static final long serialVersionUID = -412699430625953887L; private static final int SAMPLE_COUNT = 100000; /** Instance to generate random data values. */ private static final Random random = new Random(); @SuppressWarnings("unchecked") public ScatterPlot() { // Generate 100,000 data points DataTable data = new DataTable(Double.class, Double.class); for (int i = 0; i <= SAMPLE_COUNT; i++) { data.add(random.nextGaussian()*2.0, random.nextGaussian()*2.0); } // Create a new xy-plot XYPlot plot = new XYPlot(data); // Format plot plot.setInsets(new Insets2D.Double(20.0, 40.0, 40.0, 40.0)); plot.getTitle().setText(getDescription()); // Format points plot.getPointRenderers(data).get(0).setColor(COLOR1); // Add plot to Swing component add(new InteractivePanel(plot), BorderLayout.CENTER); } @Override public String getTitle() { return "Scatter plot"; } @Override public String getDescription() { return String.format("Scatter plot with %d data points", SAMPLE_COUNT); } public static void main(String[] args) { new ScatterPlot().showInFrame(); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/xyplot/SimpleXYPlot.java000066400000000000000000000126111267060725100321460ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.xyplot; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.RadialGradientPaint; import java.awt.geom.Point2D; import java.util.HashMap; import java.util.Map; import java.util.Random; import de.erichseifert.gral.data.DataSeries; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.examples.ExamplePanel; import de.erichseifert.gral.graphics.Label; import de.erichseifert.gral.plots.XYPlot; import de.erichseifert.gral.plots.axes.AxisRenderer; import de.erichseifert.gral.plots.axes.LogarithmicRenderer2D; import de.erichseifert.gral.plots.lines.DiscreteLineRenderer2D; import de.erichseifert.gral.plots.points.DefaultPointRenderer2D; import de.erichseifert.gral.plots.points.PointRenderer; import de.erichseifert.gral.plots.points.SizeablePointRenderer; import de.erichseifert.gral.ui.InteractivePanel; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.graphics.Insets2D; import de.erichseifert.gral.graphics.Orientation; public class SimpleXYPlot extends ExamplePanel { /** Version id for serialization. */ private static final long serialVersionUID = -5263057758564264676L; /** Instance to generate random data values. */ private static final Random random = new Random(); @SuppressWarnings("unchecked") public SimpleXYPlot() { // Generate data DataTable data = new DataTable(Double.class, Double.class, Double.class, Double.class, Double.class, Double.class); for (double x = 1.0; x <= 400.0; x *= 1.5) { double x2 = x/5.0; data.add(x2, -Math.sqrt(x2) + 5.0, 5.0*Math.log10(x2), random.nextDouble() + 1.0, random.nextDouble() + 0.5, 1.0 + 2.0*random.nextDouble()); } // Create data series DataSeries seriesLog = new DataSeries(data, 0, 2, 3, 4); DataSeries seriesLin = new DataSeries(data, 0, 1, 5); // Create new xy-plot XYPlot plot = new XYPlot(seriesLog, seriesLin); // Format plot plot.setInsets(new Insets2D.Double(20.0, 40.0, 40.0, 40.0)); plot.setBackground(Color.WHITE); plot.getTitle().setText(getDescription()); // Format plot area plot.getPlotArea().setBackground(new RadialGradientPaint( new Point2D.Double(0.5, 0.5), 0.75f, new float[] { 0.6f, 0.8f, 1.0f }, new Color[] { new Color(0, 0, 0, 0), new Color(0, 0, 0, 32), new Color(0, 0, 0, 128) } )); plot.getPlotArea().setBorderStroke(null); // Format axes AxisRenderer axisRendererX = new LogarithmicRenderer2D(); AxisRenderer axisRendererY = plot.getAxisRenderer(XYPlot.AXIS_Y); axisRendererX.setLabel(new Label("Logarithmic axis")); plot.setAxisRenderer(XYPlot.AXIS_X, axisRendererX); // Custom tick labels Map labels = new HashMap(); labels.put(2.0, "Two"); labels.put(1.5, "OnePointFive"); axisRendererX.setCustomTicks(labels); // Custom stroke for the x-axis BasicStroke stroke = new BasicStroke(2f); axisRendererX.setShapeStroke(stroke); Label linearAxisLabel = new Label("Linear axis"); linearAxisLabel.setRotation(90); axisRendererY.setLabel(linearAxisLabel); // Change intersection point of Y axis axisRendererY.setIntersection(1.0); // Change tick spacing axisRendererX.setTickSpacing(2.0); // Format rendering of data points PointRenderer sizeablePointRenderer = new SizeablePointRenderer(); sizeablePointRenderer.setColor(GraphicsUtils.deriveDarker(COLOR1)); plot.setPointRenderers(seriesLin, sizeablePointRenderer); PointRenderer defaultPointRenderer = new DefaultPointRenderer2D(); defaultPointRenderer.setColor(GraphicsUtils.deriveDarker(COLOR2)); defaultPointRenderer.setErrorVisible(true); defaultPointRenderer.setErrorColor(COLOR2); plot.setPointRenderers(seriesLog, defaultPointRenderer); // Format data lines DiscreteLineRenderer2D discreteRenderer = new DiscreteLineRenderer2D(); discreteRenderer.setColor(COLOR1); discreteRenderer.setStroke(new BasicStroke( 3.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f, new float[] {3f, 6f}, 0.0f)); plot.setLineRenderers(seriesLin, discreteRenderer); // Custom gaps for points discreteRenderer.setGap(2.0); discreteRenderer.setGapRounded(true); // Custom ascending discreteRenderer.setAscentDirection(Orientation.VERTICAL); discreteRenderer.setAscendingPoint(0.5); // Add plot to Swing component add(new InteractivePanel(plot), BorderLayout.CENTER); } @Override public String getTitle() { return "x-y plot"; } @Override public String getDescription() { return "Styled x-y plot with example data"; } public static void main(String[] args) { new SimpleXYPlot().showInFrame(); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/xyplot/SpiralPlot.java000066400000000000000000000077051267060725100316760ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.xyplot; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.geom.Ellipse2D; import de.erichseifert.gral.data.DataSeries; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.examples.ExamplePanel; import de.erichseifert.gral.plots.XYPlot; import de.erichseifert.gral.plots.XYPlot.XYPlotArea2D; import de.erichseifert.gral.plots.points.SizeablePointRenderer; import de.erichseifert.gral.ui.InteractivePanel; import de.erichseifert.gral.util.GraphicsUtils; import de.erichseifert.gral.graphics.Insets2D; public class SpiralPlot extends ExamplePanel { /** Version id for serialization. */ private static final long serialVersionUID = 995084910079463763L; @SuppressWarnings("unchecked") public SpiralPlot() { setPreferredSize(new Dimension(600, 600)); // Generate data DataTable data = new DataTable(Double.class, Double.class, Double.class); for (double alpha = 0.0, r = 0.0; r <= 10.0; alpha -= 1.0, r += 0.05) { double x = r*Math.cos(alpha); double y = r*Math.sin(alpha); double z = 3.0 + 4.0*r; data.add(x, y, z); } // Create a new data series (optional) DataSeries series = new DataSeries("Spiral", data); // Create a new xy-plot XYPlot plot = new XYPlot(series); // Format plot plot.setInsets(new Insets2D.Double(40.0)); // Add a margin to the plot plot.setBackground(new Color(0.75f, 0.75f, 0.75f)); // Format plot area XYPlotArea2D plotArea = (XYPlotArea2D) plot.getPlotArea(); plotArea.setBorderColor(null); // Remove border of plot area plotArea.setMajorGridX(false); // Disable vertical grid plotArea.setMajorGridY(false); // Disable horizontal grid plotArea.setClippingArea(null); // Disable clipping // Format axes plot.getAxisRenderer(XYPlot.AXIS_X).setShapeVisible(false); // Disable x axis plot.getAxisRenderer(XYPlot.AXIS_X).setTicksVisible(false); // Disable tick marks on x axis plot.getAxisRenderer(XYPlot.AXIS_Y).setShapeVisible(false); // Disable y axis plot.getAxisRenderer(XYPlot.AXIS_Y).setTicksVisible(false); // Disable tick marks on y axis plot.getAxis(XYPlot.AXIS_X).setRange(-10.0, 10.0); // Scale x axis from -10 to 10 plot.getAxis(XYPlot.AXIS_Y).setRange(-10.0, 10.0); // Scale y axis from -10 to 10 // Format data series Color color = GraphicsUtils.deriveWithAlpha(COLOR1, 96); SizeablePointRenderer pointRenderer = new SizeablePointRenderer(); pointRenderer.setShape(new Ellipse2D.Double(-0.5, -0.5, 1.0, 1.0)); // shape of data points pointRenderer.setColor(color); // color of data points pointRenderer.setColumn(2); // data column which determines the scaling of data point shapes plot.setPointRenderers(series, pointRenderer); // Assign the point renderer to the data series add(new InteractivePanel(plot), BorderLayout.CENTER); // Add the plot to the Swing component } @Override public String getTitle() { return "Spiral bubble plot"; } @Override public String getDescription() { return "Bubble plot showing data points in a spiral-like shape"; } public static void main(String[] args) { new SpiralPlot().showInFrame(); } } gral-0.11/gral-examples/src/main/java/de/erichseifert/gral/examples/xyplot/StackedPlots.java000066400000000000000000000074361267060725100322060ustar00rootroot00000000000000/* * GRAL: GRAphing Library for Java(R) * * (C) Copyright 2009-2015 Erich Seifert , * Michael Seifert * * This file is part of GRAL. * * GRAL is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GRAL. If not, see . */ package de.erichseifert.gral.examples.xyplot; import java.awt.BasicStroke; import java.awt.Color; import java.awt.geom.Ellipse2D; import java.util.Random; import de.erichseifert.gral.data.DataTable; import de.erichseifert.gral.examples.ExamplePanel; import de.erichseifert.gral.graphics.DrawableContainer; import de.erichseifert.gral.graphics.Insets2D; import de.erichseifert.gral.graphics.layout.TableLayout; import de.erichseifert.gral.plots.XYPlot; import de.erichseifert.gral.plots.areas.AreaRenderer; import de.erichseifert.gral.plots.areas.DefaultAreaRenderer2D; import de.erichseifert.gral.plots.lines.DefaultLineRenderer2D; import de.erichseifert.gral.plots.lines.LineRenderer; import de.erichseifert.gral.plots.points.PointRenderer; import de.erichseifert.gral.ui.InteractivePanel; import de.erichseifert.gral.util.GraphicsUtils; public class StackedPlots extends ExamplePanel { /** Version id for serialization. */ private static final long serialVersionUID = 6832343098989019088L; /** Instance to generate random data values. */ private static final Random random = new Random(); @SuppressWarnings("unchecked") public StackedPlots() { // Generate data DataTable data = new DataTable(Double.class, Double.class); double x=0.0, y=0.0; for (x=0.0; x<100.0; x+=2.0) { y += 10.0*random.nextGaussian(); data.add(x, Math.abs(y)); } // Create and format upper plot XYPlot plotUpper = new XYPlot(data); Color colorUpper = COLOR1; plotUpper.setPointRenderers(data, null); LineRenderer lineUpper = new DefaultLineRenderer2D(); lineUpper.setColor(colorUpper); plotUpper.setLineRenderers(data, lineUpper); AreaRenderer areaUpper = new DefaultAreaRenderer2D(); areaUpper.setColor(GraphicsUtils.deriveWithAlpha(colorUpper, 64)); plotUpper.setAreaRenderers(data, areaUpper); plotUpper.setInsets(new Insets2D.Double(20.0, 50.0, 40.0, 20.0)); // Create and format lower plot XYPlot plotLower = new XYPlot(data); Color colorLower = COLOR1; PointRenderer pointsLower = plotLower.getPointRenderers(data).get(0); pointsLower.setColor(colorLower); pointsLower.setShape(new Ellipse2D.Double(-3, -3, 6, 6)); LineRenderer lineLower = new DefaultLineRenderer2D(); lineLower.setStroke(new BasicStroke(2f)); lineLower.setGap(1.0); lineLower.setColor(colorLower); plotLower.setLineRenderers(data, lineLower); plotLower.setInsets(new Insets2D.Double(20.0, 50.0, 40.0, 20.0)); DrawableContainer plots = new DrawableContainer(new TableLayout(1)); plots.add(plotUpper); plots.add(plotLower); // Connect the two plots, i.e. user (mouse) actions affect both plots plotUpper.getNavigator().connect(plotLower.getNavigator()); InteractivePanel panel = new InteractivePanel(plots); add(panel); } @Override public String getTitle() { return "Stacked plots"; } @Override public String getDescription() { return "An area and a line plot with synchronized actions."; } public static void main(String[] args) { new StackedPlots().showInFrame(); } } gral-0.11/settings.gradle000066400000000000000000000003111267060725100154010ustar00rootroot00000000000000rootProject.name = 'GRAL' include ':gral-core', ':gral-examples' project(':gral-core').projectDir = "$rootDir/gral-core" as File project(':gral-examples').projectDir = "$rootDir/gral-examples" as File