diff --git a/.drone.yml b/.drone.yml index f0d70649..85da3560 100644 --- a/.drone.yml +++ b/.drone.yml @@ -45,8 +45,7 @@ steps: image: python:3.9 commands: - git fetch --tags - - pip install . - - pip install coverage sphinx sphinx-rtd-theme + - pip install .[doc,test] - cd ./script - coverage run --source plot_data ci_tests.py --path="/drone/src/cypress/data_src" - coverage report diff --git a/CHANGELOG.md b/CHANGELOG.md index acd31850..965ad839 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.26.1] +### Add +- Sphinx documentation + ## [0.26.0] ### Add - RemoteFigure.setFeatureFilter to directly edit rubberbands' value from external requests @@ -12,7 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Emit rubberband changes ### Fix -- Labels: +- Labels: - fix wide text - remove shape hovering - RubberBand: fix rubberband deletion when putting it outside view point diff --git a/doc/source/_static/htmls/section2_1_2_angle_time.html b/doc/source/_static/htmls/section2_1_2_angle_time.html new file mode 100644 index 00000000..693a9dc9 --- /dev/null +++ b/doc/source/_static/htmls/section2_1_2_angle_time.html @@ -0,0 +1,8338 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_1_2_x_time.html b/doc/source/_static/htmls/section2_1_2_x_time.html new file mode 100644 index 00000000..3f618c5c --- /dev/null +++ b/doc/source/_static/htmls/section2_1_2_x_time.html @@ -0,0 +1,8158 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_1_2_x_y.html b/doc/source/_static/htmls/section2_1_2_x_y.html new file mode 100644 index 00000000..08b30ba9 --- /dev/null +++ b/doc/source/_static/htmls/section2_1_2_x_y.html @@ -0,0 +1,8158 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_1_2_y_time.html b/doc/source/_static/htmls/section2_1_2_y_time.html new file mode 100644 index 00000000..ef9260a8 --- /dev/null +++ b/doc/source/_static/htmls/section2_1_2_y_time.html @@ -0,0 +1,8158 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_1_plot_graph.html b/doc/source/_static/htmls/section2_1_plot_graph.html new file mode 100644 index 00000000..7f028cdc --- /dev/null +++ b/doc/source/_static/htmls/section2_1_plot_graph.html @@ -0,0 +1,747 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_2_1_alone_multi_graph.html b/doc/source/_static/htmls/section2_2_1_alone_multi_graph.html new file mode 100644 index 00000000..00b75455 --- /dev/null +++ b/doc/source/_static/htmls/section2_2_1_alone_multi_graph.html @@ -0,0 +1,1767 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_2_1_x_and_y.html b/doc/source/_static/htmls/section2_2_1_x_and_y.html new file mode 100644 index 00000000..03f6c178 --- /dev/null +++ b/doc/source/_static/htmls/section2_2_1_x_and_y.html @@ -0,0 +1,16957 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_2_2_y_vs_time.html b/doc/source/_static/htmls/section2_2_2_y_vs_time.html new file mode 100644 index 00000000..aff0b1a9 --- /dev/null +++ b/doc/source/_static/htmls/section2_2_2_y_vs_time.html @@ -0,0 +1,162249 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_2_2_y_vs_x.html b/doc/source/_static/htmls/section2_2_2_y_vs_x.html new file mode 100644 index 00000000..ea9bd298 --- /dev/null +++ b/doc/source/_static/htmls/section2_2_2_y_vs_x.html @@ -0,0 +1,162258 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_3_1_rand_scatter.html b/doc/source/_static/htmls/section2_3_1_rand_scatter.html new file mode 100644 index 00000000..9cdc8012 --- /dev/null +++ b/doc/source/_static/htmls/section2_3_1_rand_scatter.html @@ -0,0 +1,6701 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_3_2_speed_period.html b/doc/source/_static/htmls/section2_3_2_speed_period.html new file mode 100644 index 00000000..d08d35b9 --- /dev/null +++ b/doc/source/_static/htmls/section2_3_2_speed_period.html @@ -0,0 +1,1683 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_3_3_speed_period_self.html b/doc/source/_static/htmls/section2_3_3_speed_period_self.html new file mode 100644 index 00000000..b6456c8f --- /dev/null +++ b/doc/source/_static/htmls/section2_3_3_speed_period_self.html @@ -0,0 +1,1660 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_3_speed_period.html b/doc/source/_static/htmls/section2_3_speed_period.html new file mode 100644 index 00000000..e83468ba --- /dev/null +++ b/doc/source/_static/htmls/section2_3_speed_period.html @@ -0,0 +1,1683 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_3_speed_period_self.html b/doc/source/_static/htmls/section2_3_speed_period_self.html new file mode 100644 index 00000000..99b2aa80 --- /dev/null +++ b/doc/source/_static/htmls/section2_3_speed_period_self.html @@ -0,0 +1,1660 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_4_1_rand_parallelplot.html b/doc/source/_static/htmls/section2_4_1_rand_parallelplot.html new file mode 100644 index 00000000..2d1ab103 --- /dev/null +++ b/doc/source/_static/htmls/section2_4_1_rand_parallelplot.html @@ -0,0 +1,8648 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_4_2_parallel_plot.html b/doc/source/_static/htmls/section2_4_2_parallel_plot.html new file mode 100644 index 00000000..8a9c00a4 --- /dev/null +++ b/doc/source/_static/htmls/section2_4_2_parallel_plot.html @@ -0,0 +1,1642 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_5_1_rand_histogram.html b/doc/source/_static/htmls/section2_5_1_rand_histogram.html new file mode 100644 index 00000000..c6c643a4 --- /dev/null +++ b/doc/source/_static/htmls/section2_5_1_rand_histogram.html @@ -0,0 +1,3656 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_5_2_histogram.html b/doc/source/_static/htmls/section2_5_2_histogram.html new file mode 100644 index 00000000..3944ef61 --- /dev/null +++ b/doc/source/_static/htmls/section2_5_2_histogram.html @@ -0,0 +1,1643 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_6_2_draw.html b/doc/source/_static/htmls/section2_6_2_draw.html new file mode 100644 index 00000000..ed2cb1e2 --- /dev/null +++ b/doc/source/_static/htmls/section2_6_2_draw.html @@ -0,0 +1,761 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_6_3_draw.html b/doc/source/_static/htmls/section2_6_3_draw.html new file mode 100644 index 00000000..e552b804 --- /dev/null +++ b/doc/source/_static/htmls/section2_6_3_draw.html @@ -0,0 +1,1192 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_7_1_multiplot.html b/doc/source/_static/htmls/section2_7_1_multiplot.html new file mode 100644 index 00000000..98b058ed --- /dev/null +++ b/doc/source/_static/htmls/section2_7_1_multiplot.html @@ -0,0 +1,9741 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/section2_7_2_multiplot.html b/doc/source/_static/htmls/section2_7_2_multiplot.html new file mode 100644 index 00000000..4438b75a --- /dev/null +++ b/doc/source/_static/htmls/section2_7_2_multiplot.html @@ -0,0 +1,198955 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/htmls/speed_period.html b/doc/source/_static/htmls/speed_period.html new file mode 100644 index 00000000..e83468ba --- /dev/null +++ b/doc/source/_static/htmls/speed_period.html @@ -0,0 +1,1683 @@ + + + + + + +
+ +    + + + +    Cluster:  + + +    + +    + + + + + +
+
+
+ + + +
+ diff --git a/doc/source/_static/index-images/draw_with_plotdata.svg b/doc/source/_static/index-images/draw_with_plotdata.svg new file mode 100644 index 00000000..825e1e97 --- /dev/null +++ b/doc/source/_static/index-images/draw_with_plotdata.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/doc/source/_static/index-images/graph2d_1.png b/doc/source/_static/index-images/graph2d_1.png new file mode 100644 index 00000000..a087210f --- /dev/null +++ b/doc/source/_static/index-images/graph2d_1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b0d9a8636d6f607a31f2a3f1a6bdf6813d82588a4c7ee62b25c1b002493e4da8 +size 12928 diff --git a/doc/source/_static/index-images/graph2d_2.png b/doc/source/_static/index-images/graph2d_2.png new file mode 100644 index 00000000..43c8f579 --- /dev/null +++ b/doc/source/_static/index-images/graph2d_2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e5997a78d66ecfa9e031943746ede0c9d14c0e2c7c5c542b3577e69668cade69 +size 38360 diff --git a/doc/source/_static/index-images/histogram.png b/doc/source/_static/index-images/histogram.png new file mode 100644 index 00000000..0af829c1 --- /dev/null +++ b/doc/source/_static/index-images/histogram.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a596f35db1f62b66ca0c2ae6642f508becee96707196a3e6b734ba96357204e8 +size 21954 diff --git a/doc/source/_static/index-images/multiplot.png b/doc/source/_static/index-images/multiplot.png new file mode 100644 index 00000000..b5e6aae3 --- /dev/null +++ b/doc/source/_static/index-images/multiplot.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e3648a4dee59e1bee5aa3ad7130a5ebce8846864873deee7f3345deb2ef6277a +size 445116 diff --git a/doc/source/_static/index-images/object.png b/doc/source/_static/index-images/object.png new file mode 100644 index 00000000..d9590ec7 --- /dev/null +++ b/doc/source/_static/index-images/object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a89758188abc960fe327f6779f988599f1342c4ee7381920ad4a33d8a625c002 +size 21254 diff --git a/doc/source/_static/index-images/parallel.png b/doc/source/_static/index-images/parallel.png new file mode 100644 index 00000000..dcb48886 --- /dev/null +++ b/doc/source/_static/index-images/parallel.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:177446e31ab5d163ea62548f3c3a9814600d4db607d9067ee232b33ef56c3f31 +size 366900 diff --git a/doc/source/_static/index-images/platform.svg b/doc/source/_static/index-images/platform.svg new file mode 100644 index 00000000..22565a64 --- /dev/null +++ b/doc/source/_static/index-images/platform.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/doc/source/_static/index-images/scatter.png b/doc/source/_static/index-images/scatter.png new file mode 100644 index 00000000..a36cb3be --- /dev/null +++ b/doc/source/_static/index-images/scatter.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:666d6c762c1257b9a6dc0e8eb80d92033b1d90c4d1f0be0741b438b4550056f5 +size 37899 diff --git a/doc/source/_static/plot_data-dark.png b/doc/source/_static/plot_data-dark.png new file mode 100644 index 00000000..28e8bc0c --- /dev/null +++ b/doc/source/_static/plot_data-dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9da9432b07699c2eb831e5dc25c54d6bcc68e5e5e228608c28353385458e70b9 +size 197745 diff --git a/doc/source/_static/plot_data.css b/doc/source/_static/plot_data.css new file mode 100644 index 00000000..c8253e4d --- /dev/null +++ b/doc/source/_static/plot_data.css @@ -0,0 +1,130 @@ +@import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;0,900;1,400;1,700;1,900&family=Open+Sans:ital,wght@0,400;0,600;1,400;1,600&display=swap'); + +.navbar-brand img { + height: 75px; +} +.navbar-brand { + height: 75px; +} + +body { + font-family: 'Open Sans', sans-serif; +} + +pre, code { + font-size: 100%; + line-height: 155%; +} + +h1 { + font-family: "Lato", sans-serif; + color: #013243; /* warm black */ +} + +h2 { + color: #4d77cf; /* han blue */ + letter-spacing: -.03em; +} + +h3 { + color: #013243; /* warm black */ + letter-spacing: -.03em; +} + +/* If the active version has the name "dev", style it orange */ +#version_switcher_button[data-active-version-name*="dev"] { + background-color: #E69F00; + border-color: #E69F00; + color:#000000; +} + +/* green for `stable` */ +#version_switcher_button[data-active-version-name*="stable"] { + background-color: #009E73; + border-color: #009E73; +} + +/* red for `old` */ +#version_switcher_button:not([data-active-version-name*="stable"], [data-active-version-name*="dev"], [data-active-version-name=""]) { + background-color: #980F0F; + border-color: #980F0F; +} + +/* Main page overview cards */ + +.sd-card { + background: #fff; + border-radius: 40; + padding: 30px 10px 20px 10px; + margin: 10px 0px; +} + +.sd-card .sd-card-header { + text-align: center; +} + +.sd-card .sd-card-text{ + text-align: center; +} + +.sd-card .sd-card-header .sd-card-text { + margin: 0px; +} + +.sd-card .sd-card-img-top { + height: 60px; + width: 60px; + margin-left: auto; + margin-right: auto; +} + +.sd-card .sd-card-header { + border: none; + background-color: white; + color: #5599ad !important; + font-size: var(--pst-font-size-h5); + font-weight: bold; + padding: 2.5rem 0rem 0.5rem 0rem; +} + +.sd-card .sd-card-footer { + border: none; + background-color: white; +} + +.sd-card .sd-card-footer .sd-card-text { + max-width: 220px; + margin-left: auto; + margin-right: auto; +} + +/* Dark theme tweaking */ +html[data-theme=dark] .sd-card img[src*='.svg'] { + filter: invert(0.82) brightness(0.8) contrast(1.2); +} + +/* Main index page overview cards */ +html[data-theme=dark] .sd-card { + background-color:var(--pst-color-background); +} + +html[data-theme=dark] .sd-shadow-sm { + box-shadow: 0 .1rem 1rem rgba(250, 250, 250, .6) !important +} + +html[data-theme=dark] .sd-card .sd-card-header { + background-color:var(--pst-color-background); + color: #5599ad !important; +} + +html[data-theme=dark] .sd-card .sd-card-footer { + background-color:var(--pst-color-background); +} + +html[data-theme=dark] h1 { + color: var(--pst-color-primary); +} + +html[data-theme=dark] h3 { + color: #0a6774; +} diff --git a/doc/source/_static/plot_data.png b/doc/source/_static/plot_data.png new file mode 100644 index 00000000..28e8bc0c --- /dev/null +++ b/doc/source/_static/plot_data.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9da9432b07699c2eb831e5dc25c54d6bcc68e5e5e228608c28353385458e70b9 +size 197745 diff --git a/doc/source/about_dessia.rst b/doc/source/about_dessia.rst new file mode 100644 index 00000000..77f2a09e --- /dev/null +++ b/doc/source/about_dessia.rst @@ -0,0 +1,26 @@ +About Dessia +============ + +Objective +--------- + +Dessia aims to provide a platform that enables engineers to organize and utilize +their expertise through bots. This solution offers significant advantages for +engineers, allowing them to generate a multitude of solutions to facilitate +well-informed decision-making. Our platform provides a low-code Python-based +SDK that empowers method engineers to express the expertise of engineers. +Additionally, we offer a web-based platform that allows users to execute these +bots without needing extensive Python knowledge. + +History +------- + +In 2017, Steven Masfaraud and Pierre-Emmanuel Dumouchel, two former engineers +from Peugeot-Citroen, founded Dessia. Initially, their goal was to develop a +generic engineering language for gearbox design. Subsequently, they expanded +their vision and developed a generic platform capable of collecting diverse +engineering expertise and implementing it through bots. + +Today, Dessia employs 25 people primarily based in Antony, +Île-de-France. Since 2021, Dessia has been supported by three specialized +software investment funds focused on the engineering domain. diff --git a/doc/source/about_the_package.rst b/doc/source/about_the_package.rst new file mode 100644 index 00000000..69b71ffe --- /dev/null +++ b/doc/source/about_the_package.rst @@ -0,0 +1,85 @@ +About the package +================= + +Contribute to the package +------------------------- + +First off, thanks for taking the time to contribute! + +All types of contributions are encouraged and valued. The community looks +forward to your contributions. + +And if you like the project, but just don't have time to contribute, that's +fine. There are other easy ways to support the project and show your +appreciation, which we would also be very happy about: + +- Use the package in your projects! +- Star the project +- Talk about it +- Refer this project in your project's readme +- Mention the project at local meetups and tell your friends/colleagues + +If you would like to contribute to the project, please go to our +`GitHub page `_ +and submit a pull request or an issue. You can contribute in many ways: by +improving the existing code, adding new features or changing the documentation. +Documentation improvements are crucial to us to make this package as user +friendly as possible. If you find a typo in the documentation, or have made +improvements, please consider sending us an email or preferably submit a +GitHub pull request. Full documentation can be found under the doc/ directory. + +Ask before coding +~~~~~~~~~~~~~~~~~ + +If you are not sure about your contribution you can ask the question on the +issues or MP the project leader. But before asking, it is best to search for +existing Issues that might help you. In case you have found a suitable issue +and still need clarification, you can write your question in this issue. It +is also advisable to search the internet for answers first. + +If you then still feel the need to ask a question and need clarification, we +recommend the following: + +- Open an issue. +- Provide as much context as you can about what you're running into. +- Provide project and platform versions , depending on what seems relevant. +- Put the label "Question" to your issue + +Process +~~~~~~~ + +We have a process based on three branches and the process goes as follows: + +- dev that receive the features and impacting changes pull requests +- testing that is regularly a freeze of testing. Release candidate (RC) + can be made on testing +- master that receive the code from testing before the release. Release are +made on master + +Before coding, think of where to start from. You should start your branch +for pull request where the pull request will point at: + + +- if your contribution is trivial or has low risk of negative impact, start + from master branch: simple and urgent bug fixes, docs, build... +- in most other case, start from dev and submit your pull request to dev + +Continuous integration +~~~~~~~~~~~~~~~~~~~~~~ + +About continuous integration, your contribution may be refused by our CI. In +this case: + +- lowering the coverage: add some tests +- introducing pylint errors +- triggering pydocstyle errors +- non-respect of PEP8 +- no CHANGELOG.md edit + +Correct the CI errors to get approval from our team! + +License +------- + +100% open source on LGPL license. See the package's LICENSE.md file for more +details. diff --git a/doc/source/authors.rst b/doc/source/authors.rst new file mode 100644 index 00000000..e2d1433d --- /dev/null +++ b/doc/source/authors.rst @@ -0,0 +1,18 @@ +Authors +======= + +The people cited here are core contributors to this package's development and +maintenance: + +|tanguy loreau| Tanguy Loreau + +|axel ringhausen| Axel Ringhausen + + +.. |tanguy loreau| image:: https://github.com/Tanguylo.png + :width: 100 + :target: https://github.com/Tanguylo + +.. |axel ringhausen| image:: https://github.com/AxelRinghausen.png + :width: 100 + :target: https://github.com/AxelRinghausen diff --git a/doc/source/conf.py b/doc/source/conf.py index 632dac65..e84aca30 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -1,8 +1,10 @@ +# -*- coding: utf-8 -*- +# # Configuration file for the Sphinx documentation builder. # -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config # -- Path setup -------------------------------------------------------------- @@ -10,25 +12,31 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) +import os +import sys +sys.path.insert(0, os.path.abspath('../../plot_data')) # -- Project information ----------------------------------------------------- +import datetime -project = 'plot data' -copyright = '2021, DessiA Technologies SAS' -author = 'DessiA Technologies SAS' +project = 'plot_data' +copyright = f'2018-{datetime.datetime.now().year} DessIA Technologies' +author = 'DessIA Technologies' -# The full version, including alpha/beta/rc tags import plot_data +version = plot_data.__version__ +# The full version, including alpha/beta/rc tags release = plot_data.__version__ # -- General configuration --------------------------------------------------- +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. @@ -38,25 +46,151 @@ 'sphinx.ext.coverage', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', + 'sphinx_design', + 'matplotlib.sphinxext.plot_directive', + 'sphinx_copybutton', + 'nbsphinx', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = "en" + # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. +# This pattern also affects html_static_path and html_extra_path . exclude_patterns = [] +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' +# html_theme = 'sphinx_rtd_theme' +html_theme = "pydata_sphinx_theme" +# html_theme = "furo" + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. + +html_theme_options = { + "logo": { + "image_light": "plot_data.png", + "image_dark": "plot_data-dark.png", + }, + "github_url": "https://github.com/Dessia-tech/plot_data", + # "twitter_url": "https://twitter.com/numpy_team", + "collapse_navigation": True, + # "external_links": [ + # {"name": "Learn", "url": "https://numpy.org/numpy-tutorials/"}, + # {"name": "NEPs", "url": "https://numpy.org/neps"} + # ], + "header_links_before_dropdown": 6, + # Add light/dark mode and documentation version switcher: + "navbar_end": ["theme-switcher", "navbar-icon-links"], + # "switcher": { + # "version_match": switcher_version, + # "json_url": "https://numpy.org/doc/_static/versions.json", + # }, +} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] +html_css_files = ["plot_data.css"] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'plot_datadoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'plot_data.tex', 'plot_data Documentation', + 'DessIA Technologies', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'plot_data', 'plot_data Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'plot_data', 'plot_data Documentation', + author, 'plot_data', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Extension configuration ------------------------------------------------- + +# -- Options for todo extension ---------------------------------------------- + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True diff --git a/doc/source/draw_multiple_curves.rst b/doc/source/draw_multiple_curves.rst new file mode 100644 index 00000000..a66d13aa --- /dev/null +++ b/doc/source/draw_multiple_curves.rst @@ -0,0 +1,184 @@ +Display several curves in a Graph2D object +========================================== + +Graph2D objects also allows to draw several curves on only one figure. + +How to create a Graph2D with several curves ? +--------------------------------------------- + +Several datasets can be used to create a Graph2D. This allows to draw several curves on only one figure. The following code lines show how to specify it to draw `x` and `y` values of a circle with `radius = 1`. + +.. code-block:: python + + import numpy + + import plot_data.core as pld + from plot_data.colors import BLUE, RED + + time = npy.arange(100) + x_coord = npy.cos(0.1 * time) + y_coord = npy.sin(0.1 * time) + x_vector = [] + y_vector = [] + for t, x, y in zip(time, x_coord, y_coord): + x_vector.append({"time": t, "amplitude": x}) + y_vector.append({"time": t, "amplitude": y}) + + x_dataset = pld.Dataset(elements=x_vector, edge_style=pld.EdgeStyle(color_stroke=BLUE)) + y_dataset = pld.Dataset(elements=y_vector, edge_style=pld.EdgeStyle(color_stroke=RED)) + graph2d = pld.Graph2D(graphs=[x_dataset, y_dataset], x_variable="time", y_variable="amplitude",) + pld.plot_canvas(plot_data_object=graph2d, filepath="section2_2_1_alone_multi_graph") + +In the case of the pendulum, one can draw both x and y on the same Graph2D. + +In order to do it, a function that takes a pendulum as argument and draws a Graph2D with both the curves on the same plot can be written. + +.. code-block:: python + + # Function definition + def pendulum_draw_x_y_vs_time(pendulum): + x_amplitude = [] + y_amplitude = [] + # Create vector elements with same name for x and y values + for t, coord in zip(pendulum.time, pendulum.coords): + x_amplitude.append({"time": t, "amplitude": coord[0]}) + y_amplitude.append({"time": t, "amplitude": coord[1]}) + + # Create the two datasets + x_dataset = pld.Dataset( + elements=x_amplitude, + name="x_amplitude", + edge_style=pld.EdgeStyle(color_stroke=Color(1, 0, 0)) + ) + y_dataset = pld.Dataset( + elements=y_amplitude, + name="y_amplitude", + edge_style=pld.EdgeStyle(color_stroke=Color(0, 0, 1)) + ) + + # Draw the Graph2D + graphs2d = pld.Graph2D( + graphs=[x_dataset, y_dataset], + x_variable="time", + y_variable="amplitude" + ) + pld.plot_canvas(plot_data_object=graphs2d, canvas_id='my_graph2d') + + # Instantiate a pendulum + pendulum = Pendulum(math.pi / 3, 1, 9.81, 10, 0.01) + + # Draw Graph2D + pendulum_draw_x_y_vs_time(pendulum) + +.. raw:: html + + + +How to design a class for getting a Graph2D with several curves ? +----------------------------------------------------------------- + +For the pendulum example, a Design Of Experiment (DOE) can be built to generate several pendulums with different masses, lengths, initial angles or even on different planets. + +Firstly, Dataset to store all generated pendulums have been designed. Then the `from_boundaries` method has been written to generate sets of pendulum thanks to a sampling. It has been set to produce several solutions in a closed parameter space which is, in this example, constituted of the planet’s gravity `g` and the pendulum’s `length`. + +.. code-block:: python + + import math + from matplotlib import colormaps + import numpy as npy + from typing import List + + from dessia_common.core import DessiaObject + from dessia_common.optimization import BoundedAttributeValue, FixedAttributeValue + from dessia_common.datatools.dataset import Dataset + from dessia_common.datatools.sampling import ClassSampler + from dessia_common.decorators import plot_data_view + + import plot_data.core as pld + from plot_data.colors import Color, DARK_BLUE, BLUE + + class PendulumDOE(Dataset): + def __init__(self, dessia_objects: List[DessiaObject] = None, name: str = ''): + super().__init__(dessia_objects=dessia_objects, name=name) + + @classmethod + def from_boundaries(cls, planet_sampling: BoundedAttributeValue, + length_sampling: BoundedAttributeValue, + duration: float, time_step: float, method: str = 'lhs', + n_samples: int = 1000, name: str = ''): + sampled_attributes = [planet_sampling, length_sampling] + fixed_attributes = [ + FixedAttributeValue("init_angle", math.pi / 3), + FixedAttributeValue("duration", 10), + FixedAttributeValue("time_step", 0.05) + ] + sampler = ClassSampler(Pendulum, sampled_attributes, fixed_attributes) + return cls(sampler.make_doe(n_samples, method).dessia_objects, name=name) + +Finally, to draw all curves in a unique Graph2D figure, write specific methods for creating a curve for each pendulum. Here the code is duplicated for the sake of simplicity but every duplicated line should be in a factored method (e.g. colors, for loop,…). Some colors have been added for a better viewing and curves’ name have been set so that the corresponding pendulum’s parameters are shown when clicking on its curve. + +.. code-block:: python + + # To add to PendulumDOE class + @plot_data_view("all_y") + def all_y_vs_time(self, reference_path: str = "#"): + datasets = [] + cmap = colormaps["jet"](npy.linspace(0, 1, len(self.dessia_objects))) + for i, pendulum in enumerate(self.dessia_objects): + color = Color(*cmap[i][:-1]) + edge_style = pld.EdgeStyle(line_width = 0.8, color_stroke=color) + elements = [{"time": time, "y": coord[0]} for time, coord in zip(pendulum.time, pendulum.coords)] + name = f"length: {round(pendulum.length, 2)}, planet: {round(pendulum.g, 2)}" + dataset = pld.Dataset(elements, name=name, edge_style=edge_style) + datasets.append(dataset) + + graphs2d = pld.Graph2D(graphs=datasets, x_variable="time", y_variable="y") + return graphs2d + + @plot_data_view("all_x_y") + def all_y_vs_x(self, reference_path: str = "#"): + datasets = [] + cmap = colormaps["jet"](npy.linspace(0, 1, len(self.dessia_objects))) + for i, pendulum in enumerate(self.dessia_objects): + color = Color(*cmap[i][:-1]) + edge_style = pld.EdgeStyle(line_width = 0.8, color_stroke=color) + elements = [{"x": x, "y": y} for x, y in pendulum.coords] + name = f"length: {round(pendulum.length, 2)}, planet: {round(pendulum.g, 2)}" + dataset = pld.Dataset(elements, name=name, edge_style=edge_style) + datasets.append(dataset) + + graphs2d = pld.Graph2D(graphs=datasets, x_variable="x", y_variable="y") + return graphs2d + +Once done, the DOE can be generated and the pendulum behavior curves can be displayed with the following command lines: + +.. code-block:: python + + # Parameters sampling definition + planet_sampling = BoundedAttributeValue('g', 1, 11, 10) + length_sampling = BoundedAttributeValue('length', 0.1, 3, 10) + + # DOE instantiation + pendulum_doe = PendulumDOE.from_boundaries( + planet_sampling, + length_sampling, + 10, + 0.01, + method = 'fullfact' + ) + + # Graph2D creation + y_vs_t_curves = pendulum_doe.all_y_vs_time() + y_vs_x_curves = pendulum_doe.all_y_vs_x() + + # Plot + pld.plot_canvas(plot_data_object=y_vs_t_curves, canvas_id='my_graph2d') + pld.plot_canvas(plot_data_object=y_vs_x_curves, canvas_id='my_graph2d') + +.. raw:: html + + + +.. raw:: html + + diff --git a/doc/source/draw_single_curve.rst b/doc/source/draw_single_curve.rst new file mode 100644 index 00000000..651cda34 --- /dev/null +++ b/doc/source/draw_single_curve.rst @@ -0,0 +1,277 @@ +Graph2D: draw curves on a Figure +================================ + +With `Graph2D`, time series or any curve function that can be written `y = f(x)` can be displayed on a figure with axes such as x values are drawn on x axis and y values are drawn on y axis, in an orthogonal frame. + +How to draw a curve in a Graph2D ? +---------------------------------- + +1. **Import the required packages** + +.. code-block:: python + + # Required packages + import math + import plot_data.core as pld + from plot_data.colors import BLUE, DARK_BLUE, RED, BLACK + + +2. **Create Data** + +In order to display a Graph2D, create a vector of x values and their associated y values. + +Values then have to be added in a list of samples, where each sample is a `dict` which keys are names of samples’ features. + +Here, we create a sinusoidal function. + +.. code-block:: python + + # Inputs + amplitude = 2 + n_samples = 50 + x_name = "angle" + y_name = "amplitude" + + # Vectors creation + X = [i / (2 * math.pi) for i in range(n_samples)] + Y = [amplitude * math.sin(i) for i in X] + + # Build PlotData vector of samples + samples = [] + for k in range(len(X)): + samples.append({x_name: X[k], y_name: Y[k]}) + + # Create the dataset + dataset = pld.Dataset(elements=samples, name='y = A.sin(x)',) + +3. **Add meta-data on samples** + +Some additional information can be added on data thanks to tooltips, that can be displayed by clicking on the shape that carries the designed tootlip. + +Here, the tooltip is directly created as an independent object that will be used in next steps, while creating the figure to draw the previously built data. + +.. code-block:: python + + # Attributes to show in tooltip + shown_attributes = [x_name, y_name] + + # Tooltip creation + tooltip = pld.Tooltip(attributes=shown_attributes) + +4. **Set styles for points, curves and axes** + +Styles for points, curves and axes can be customized with the user’s preferences. + +.. code-block:: python + + # Points style + point_style = pld.PointStyle(color_fill=RED, color_stroke=BLACK) + + # Curves style + edge_style = pld.EdgeStyle(color_stroke=BLUE, dashline=[10, 5]) + + # Dataset style + custom_dataset = pld.Dataset( + elements=samples, + name='y = A.sin(x)', + tooltip=tooltip, + point_style=point_style, + edge_style=edge_style + ) + + # Axis style + ## Text style + graduation_style = pld.TextStyle( + font_size=10, + font_style='Arial' + ) + + ## Axis edge style + axis_style = pld.EdgeStyle( + line_width=0.5, + color_stroke=DARK_BLUE, + dashline=[] + ) + + # Axes ticks number and styles + axis = pld.Axis( + nb_points_x=7, + nb_points_y=5, + graduation_style=graduation_style, + axis_style=axis_style + ) + +5. **Create the Graph2D object and draw it in a web browser** + +.. code-block:: python + + graph2d = pld.Graph2D( + graphs=[custom_dataset], + x_variable=x_name, + y_variable=y_name, + axis=axis + ) + +Once done, the figure can be displayed with the following command line : + +.. code-block:: python + + pld.plot_canvas(plot_data_object=graph2d, canvas_id='my_graph2d') + +.. raw:: html + + + + +Graph2D features +---------------- + +- Points used to build the curve can be displayed by clicking on `Show Points` button, +- The figure can be scaled with mouse wheel or by clicking on `Zoom Box`, `Zoom+` and `Zoom-` buttons, +- Curves can be displayed with log scales by clicking on `Log Scale` button, +- One can select points with a selection window by keeping pressed the `Shift` key, +- One can select several points with several mouse click by keeping pressed `Ctrl` key, +- One can reset the view by pressing `Ctrl + Space`, +- One can reset the whole figure by pressing `Ctrl + Shift + Left Click.` + +How to add a method to draw a Graph2D within a DessiaObject ? +------------------------------------------------------------- + +A Graph2D (or any kind of figure that can be drawn with PlotData) can be added to any DessiaObject to depict its behavior. + +In the following example, a free pendulum with no friction as been designed as a DessiaObject. + +Firstly, import all the required packages. + +.. code-block:: python + + import math + import numpy as npy + + from dessia_common.core import DessiaObject + from dessia_common.decorators import plot_data_view + + import plot_data.core as pld + from plot_data.colors import Color + +Then create a pendulum object with no friction. Required attributes to get the pendulum movement are its `initial angle`, its `length`, its `mass` and the gravity acceleration constant (declared as a variable `g`). `duration` and `time_step` have been added to simulate the pendulum over time. + +In order to get the pendulum state evolving with time, a method to compute its `angle` over `time` and a method to compute its Cartesian coordinates (`coords`) over time have also been added. + +.. code-block:: python + + class Pendulum(DessiaObject): + _standalone_in_db = True + + def __init__(self, init_angle: float, length: float, g: float, + duration: float, time_step: float, name: str = ''): + self.length = length + self.g = g + self.duration = duration + self.time_step = time_step + self.init_angle = init_angle + self.period = self._compute_period(length) + self.time = self._get_time_vector(duration, time_step) + self.angle = self._compute_angle() + self.coords = self._compute_coords() + super().__init__(name) + + def _compute_period(self, length: float): + return (self.g / length) ** 0.5 + + def _get_time_vector(self, duration: float, time_step: float): + return npy.arange(0, duration + time_step, time_step).tolist() + + def _compute_angle(self): + return [self.init_angle * math.cos(self.period * t) for t in self.time] + + def _compute_coords(self): + return [ + [self.length * math.sin(angle), self.length * (1 - math.cos(angle))] + for angle in self.angle + ] + +To plot the pendulum state variables over time, write methods with `@plot_data_view` decorator for platform usages. Each of the written method defines a `Graph2D` to draw data of interest. + +.. code-block:: python + + # To add to Pendulum class + @plot_data_view("angle_vs_time") + def angle_vs_time(self, reference_path: str = "#"): + elements = [ + {"time": t, "angle": angle} + for t, angle in zip(self.time, self.angle) + ] + dataset = pld.Dataset(elements, name="angle vs time") + graphs2d = pld.Graph2D( + graphs=[dataset], + x_variable="time", + y_variable="angle" + ) + return graphs2d + + @plot_data_view("x_vs_time") + def x_vs_time(self, reference_path: str = "#"): + elements = [ + {"time": t, "x": coord[0]} + for t, coord in zip(self.time, self.coords) + ] + dataset = pld.Dataset(elements, name="x vs time") + graphs2d = pld.Graph2D( + graphs=[dataset], + x_variable="time", + y_variable="x" + ) + return graphs2d + + @plot_data_view("y_vs_time") + def y_vs_time(self, reference_path: str = "#"): + elements = [ + {"time": t, "y": coord[1]} + for t, coord in zip(self.time, self.coords) + ] + dataset = pld.Dataset(elements, name="y vs time") + graphs2d = pld.Graph2D( + graphs=[dataset], + x_variable="time", + y_variable="y" + ) + return graphs2d + + @plot_data_view("y_vs_time") + def y_vs_x(self, reference_path: str = "#"): + elements = [{"x": x, "y": y} for x, y in self.coords] + dataset = pld.Dataset(elements, name="y vs x") + graphs2d = pld.Graph2D(graphs=[dataset], x_variable="x", y_variable="y") + return graphs2d + +In these methods, a vector of elements is firstly created and added to a `Dataset`. It is then declared as the only dataset drawn in a `Graph2D` object that plots `x_variable` against `y_variable` of vector `elements`. + +The results of graph drawings are available on the next 4 html pages in the present document. They have generated with the following code: + +.. code-block:: python + + # Instantiate a pendulum + pendulum = Pendulum(math.pi / 3, 1, 9.81, 10, 0.01) + + # Draw its graphs with specific files name + pld.plot_canvas(plot_data_object=pendulum.angle_vs_time(), canvas_id='my_graph2d', filepath="section2_1_2_angle_time") + pld.plot_canvas(plot_data_object=pendulum.x_vs_time(), canvas_id='my_graph2d', filepath="section2_1_2_x_time") + pld.plot_canvas(plot_data_object=pendulum.y_vs_time(), canvas_id='my_graph2d', filepath="section2_1_2_y_time") + pld.plot_canvas(plot_data_object=pendulum.y_vs_x(), canvas_id='my_graph2d', filepath="section2_1_2_x_y") + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + diff --git a/doc/source/draw_with_plotdata.rst b/doc/source/draw_with_plotdata.rst new file mode 100644 index 00000000..04f4b20e --- /dev/null +++ b/doc/source/draw_with_plotdata.rst @@ -0,0 +1,141 @@ +Draw graphs +=========== + +.. grid:: 3 + + .. grid-item-card:: + :img-top: ../source/_static/index-images/graph2d_1.png + + ^^^^^^^^^^^^^^ + + Draw single curves + + +++ + + .. button-ref:: draw_single_curve + :expand: + :color: primary + :click-parent: + + To single curve + + .. grid-item-card:: + :img-top: ../source/_static/index-images/graph2d_2.png + + + ^^^^^^^^^^^^^^ + + Draw multiple curves + + +++ + + .. button-ref:: draw_multiple_curves + :expand: + :color: primary + :click-parent: + + To multiple curves + + .. grid-item-card:: + :img-top: ../source/_static/index-images/scatter.png + + + ^^^^^^^^^^^^^^ + + Draw scatter plots + + +++ + + .. button-ref:: scatter + :expand: + :color: primary + :click-parent: + + To scatter plots + + .. grid-item-card:: + :img-top: ../source/_static/index-images/parallel.png + + + ^^^^^^^^^^^^^^ + + Draw parallel plots + + +++ + + .. button-ref:: parallel + :expand: + :color: primary + :click-parent: + + To parallel plots + + .. grid-item-card:: + :img-top: ../source/_static/index-images/histogram.png + + + ^^^^^^^^^^^^^^ + + Draw histograms + + +++ + + .. button-ref:: histogram + :expand: + :color: primary + :click-parent: + + To histograms + + .. grid-item-card:: + :img-top: ../source/_static/index-images/object.png + + + ^^^^^^^^^^^^^^ + + 2D representation of objects + + +++ + + .. button-ref:: object + :expand: + :color: primary + :click-parent: + + To object representation + + .. grid-item-card:: + :img-top: ../source/_static/index-images/multiplot.png + + + ^^^^^^^^^^^^^^ + + Draw multiplots + + +++ + + .. button-ref:: multiplot + :expand: + :color: primary + :click-parent: + + To multiplots + + +The plot_data library is structured using a modular approach as follows: + + +* :ref:`core`: provides fundamental data structures and algorithms; +* :ref:`graph`: converts networkx graph into a 2D PlotData graph; +* :ref:`colors`: defines an exhaustive list of colors; +* :ref:`template`: templates of html files built for PlotDataObject; + + +:ref:`modules` +-------------- + + +Q&A +--- + +No questions yet. diff --git a/doc/source/glossary.rst b/doc/source/glossary.rst new file mode 100644 index 00000000..a3a6e615 --- /dev/null +++ b/doc/source/glossary.rst @@ -0,0 +1,20 @@ +Glossary +======== + +Bot +--- + +Digitalization of a process including the writing of generic knowledge and a +workflow to describe the Know-How + +SDK +--- + +Set of Python libraries allowing to write in low-code the Know-That bricks +(generic knowledge) + +Platform +-------- + +Dessia's software solution based on a Web interface and a backend that emulates +Python diff --git a/doc/source/histogram.rst b/doc/source/histogram.rst new file mode 100644 index 00000000..6cfe3053 --- /dev/null +++ b/doc/source/histogram.rst @@ -0,0 +1,109 @@ +Histogram: draw the amount of samples in ranges of values +========================================================= + +A histogram is a visual representation of the distribution of quantitative data. In other words, it allows to represent the amount of samples for which a chosen attribute is contained in a range of values. + +How to draw a Histogram ? +------------------------- + +1. **Import the required packages** + +.. code-block:: python + + # Required packages + import random + import plot_data as pld + from plot_data.colors import BLUE, GREEN + +2. **Create data** + +In order to draw a Histogram of a variable sampled randomly, build a random vector of samples (stored as Python `dict`) with one attribute. Here we chose to build a vector of length sampled within a Gaussian distribution. + +.. code-block:: python + + # Vector construction + elements = [{'length': random.gauss(0, 3)} for _ in range(500)] + +3. **Set styles for bars and axes** + +Styles for bars and axes can be customized with the user’s preferences: + +.. code-block:: python + + # Surface Style + surface_style = pld.SurfaceStyle(color_fill=BLUE) + + # Edge Style + edge_style = pld.EdgeStyle(line_width=1, color_stroke=GREEN, dashline=[5, 3]) + +4. **Build the Histogram object and draw it in a web browser** + +When building the histogram, ticks number on x axis can be specified with the `graduation_nb` attribute. + +.. code-block:: python + + histogram = pld.Histogram(x_variable='length', + elements=elements, + graduation_nb=20, + surface_style=surface_style, + edge_style=edge_style) + +Once done, the figure can be displayed with the following command line: + +.. code-block:: python + + pld.plot_canvas(plot_data_object=histogram, canvas_id='my_histogram') + +.. raw:: html + + + + +Histogram Features +------------------ + +- **Rubberbands can be drawn on axes by clicking and dragging on it with mouse. Rubberbands allow to select range of values on each axis,** +- Bars tooltips give information on how samples are distributed within a clicked bar, +- The view can be adjusted with mouse interactions (click, drag and wheel), +- One can select several bars with several mouse click by keeping pressed `Ctrl` key, +- One can reset the view by pressing `Ctrl + Space`, +- One can reset the whole figure by pressing `Ctrl + Shift + Left Click`. + +How to write a method to draw a Histogram in a DessiaObject ? +------------------------------------------------------------- + +For the previously designed PendulumDOE ([section 2.2.2](https://www.notion.so/Using-data-display-with-PlotData-30f86e58db6240788cf4f3b543b0ae51?pvs=21)), an interesting plot may be to draw the distribution of pendulums speeds within the previously designed PendulumDOE class. + +To do it, add a method to draw a Histogram to the PendulumDOE class: + +.. code-block:: python + + class PendulumDOE(Dataset): + : + : + : + @plot_data_view("histogram") + def histogram(self, reference_path: str = "#"): + elements = [{"speed": pendulum.max_speed} for pendulum in self.dessia_objects] + return pld.Histogram(x_variable="speed", elements=elements, graduation_nb=20) + +And draw the Histogram with the function `plot_canvas`: + +.. code-block:: python + + # Parameters sampling definition + planet_sampling = BoundedAttributeValue('g', 1, 11, 10) + length_sampling = BoundedAttributeValue('length', 0.1, 3, 10) + + # DOE instantiation + pendulum_doe = PendulumDOE.from_boundaries(planet_sampling, length_sampling, 10, 0.01, method = 'fullfact') + + # Parallel Plot construction + histogram = pendulum_doe.histogram() + + # Draw the figure in a web browser + pld.plot_canvas(plot_data_object=histogram, filepath="section_2_5_2_histogram") + +.. raw:: html + + diff --git a/doc/source/images/add_plot.png b/doc/source/images/add_plot.png new file mode 100644 index 00000000..7770996c --- /dev/null +++ b/doc/source/images/add_plot.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1dd88cf0061101e6d380bbd18c7e5fb64de428cb93438236d161d68b9f5a0d7 +size 1028931 diff --git a/doc/source/images/change_disposition.png b/doc/source/images/change_disposition.png new file mode 100644 index 00000000..36c7f4fe --- /dev/null +++ b/doc/source/images/change_disposition.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:563f78497cd782829af8123c395e0b156bfe16ab84621c0538caef52c4f4d4f1 +size 391715 diff --git a/doc/source/images/merge_button.png b/doc/source/images/merge_button.png new file mode 100644 index 00000000..39a4e0b1 --- /dev/null +++ b/doc/source/images/merge_button.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4bf93f284018c3df092d9fa4fcbcdd75b503b23d2a700f8fd63805195635be6 +size 149450 diff --git a/doc/source/images/multiplot_layout.png b/doc/source/images/multiplot_layout.png new file mode 100644 index 00000000..47756d60 --- /dev/null +++ b/doc/source/images/multiplot_layout.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:23b2734430ec1a48652306b0906d5ac06c78d9a0067e22c2c943edeeec6b01c0 +size 616438 diff --git a/doc/source/images/multiplot_table.png b/doc/source/images/multiplot_table.png new file mode 100644 index 00000000..e11b3d07 --- /dev/null +++ b/doc/source/images/multiplot_table.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:51e6497c15f2be4daf436e5563fa1a1ef0df3c6690a944048385bc5a364fb51f +size 447328 diff --git a/doc/source/images/order_plots.png b/doc/source/images/order_plots.png new file mode 100644 index 00000000..3324bef2 --- /dev/null +++ b/doc/source/images/order_plots.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f47a26eb407743ea620e49ea7460cfffa6557d69cce164c26d7dcd12180126a1 +size 6561 diff --git a/doc/source/images/points_sets.png b/doc/source/images/points_sets.png new file mode 100644 index 00000000..66da78cc --- /dev/null +++ b/doc/source/images/points_sets.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cc46390e67790474e63d4b4e01bb5c00d4f8e75c2cd9f2d1d289823c079bc33e +size 1047550 diff --git a/doc/source/images/rubberband_selection.png b/doc/source/images/rubberband_selection.png new file mode 100644 index 00000000..727e4463 --- /dev/null +++ b/doc/source/images/rubberband_selection.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:71c6f943521dcf104ae6e933611c982927e7a1313ca4bf7e3322bfbe9a859691 +size 465303 diff --git a/doc/source/images/selection_button.png b/doc/source/images/selection_button.png new file mode 100644 index 00000000..859c894f --- /dev/null +++ b/doc/source/images/selection_button.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3751a0967e9f71fad29773ab9ff2ec16213307ed4f2e5dc566ad73cf1569ce9a +size 47724 diff --git a/doc/source/images/zoom_buttons.png b/doc/source/images/zoom_buttons.png new file mode 100644 index 00000000..7caec0fc --- /dev/null +++ b/doc/source/images/zoom_buttons.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6cd0a245c5036e22f2efbf1cc65396567f2bab8c3e1ad6e27d1106848f112331 +size 2785 diff --git a/doc/source/index.rst b/doc/source/index.rst index eb8a20e3..58d608fd 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -1,112 +1,61 @@ -.. plot data documentation master file, created by - sphinx-quickstart on Wed Feb 17 14:40:42 2021. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Plot_data python API documentation -================================== - -plot data is a language to draw in a web browser some awesome plots and graphs. Its rendering engine is written in typescript. This doc is for the python package to create the data structure to give to typescript lib for rendering. - -For the typescript doc see: https://documentation.dessia.tech/plot_data/typescript +###################### +PlotData Documentation +###################### .. toctree:: - :maxdepth: 2 - :caption: Contents: - -.. autofunction:: plot_data.delete_none_from_dict - -.. autoclass:: plot_data.PlotDataObject - :members: - -.. autoclass:: plot_data.HatchingSet - :members: - -.. autoclass:: plot_data.EdgeStyle - :members: - -.. autoclass:: plot_data.PointStyle - :members: - -.. autoclass:: plot_data.TextStyle - :members: - -.. autoclass:: plot_data.SurfaceStyle - :members: - -.. autoclass:: plot_data.Text - :members: - -.. autoclass:: plot_data.Line2D - :members: - -.. autoclass:: plot_data.LineSegment2D - :members: - -.. autoclass:: plot_data.Circle2D - :members: - -.. autoclass:: plot_data.Point2D - :members: - -.. autoclass:: plot_data.Axis - :members: + :maxdepth: 1 + :hidden: -.. autoclass:: plot_data.Tooltip - :members: + About Dessia + Authors + About the Package + Roadmap + Tutorials -.. autoclass:: plot_data.Dataset - :members: -.. autoclass:: plot_data.Graph2D - :members: +PlotData is a Python web library that allows to draw data with several kinds of layouts such as scatters, histograms, graphs,… -.. autoclass:: plot_data.Scatter - :members: +This tutorial teaches how to use it for working with Dessia framework, to draw insightful figures to take well informed decisions. -.. autoclass:: plot_data.Arc2D - :members: +In this tutorial, all available features are explained and presented in simple examples, exhibited both on standalone mode and in Dessia Platform context: -.. autoclass:: plot_data.Contour2D - :members: +- If the reader is interested in how to use PlotData in Python IDE, please refer to 2 - Draw data with PlotData. +- If the reader is interested in how to post treat workflow results in Dessia platform, please refer to 3 - PlotData on Dessia’s Platform. -.. autoclass:: plot_data.Label - :members: -.. autoclass:: plot_data.MultipleLabels - :members: -.. autoclass:: plot_data.PrimitiveGroup - :members: +.. grid:: 2 -.. autoclass:: plot_data.PrimitiveGroupsContainer - :members: + .. grid-item-card:: + :img-top: ../source/_static/index-images/draw_with_plotdata.svg -.. autoclass:: plot_data.ParallelPlot - :members: + Getting Started + ^^^^^^^^^^^^^^^ -.. autoclass:: plot_data.Attribute - :members: + New to PlotData? Learn here about drawing graph. -.. autoclass:: plot_data.PointFamily - :members: + +++ -.. autoclass:: plot_data.MultiplePlots - :members: + .. button-ref:: draw_with_plotdata + :expand: + :color: primary + :click-parent: -.. autofunction:: plot_data.plot_canvas + Start drawing graphs -.. autofunction:: plot_data.get_csv_vectors + .. grid-item-card:: + :img-top: ../source/_static/index-images/platform.svg -.. autofunction:: plot_data.bounding_box + Using PlotData with Dessia's platform + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. autoclass:: plot_data.colors.Color - :members: + Integrate your PlotData drawings to the platform. + +++ -Indices and tables -================== + .. button-ref:: platform + :expand: + :color: primary + :click-parent: -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` + To platform integration diff --git a/doc/source/modules.rst b/doc/source/modules.rst new file mode 100644 index 00000000..861315f8 --- /dev/null +++ b/doc/source/modules.rst @@ -0,0 +1,9 @@ +PlotData Modules +---------------- + +.. toctree:: + :maxdepth: 1 + + modules/core.rst + modules/graph.rst + modules/colors.rst diff --git a/doc/source/modules/colors.rst b/doc/source/modules/colors.rst new file mode 100644 index 00000000..b2fca549 --- /dev/null +++ b/doc/source/modules/colors.rst @@ -0,0 +1,8 @@ +.. _colors: +Colors +------ + +.. automodule:: plot_data.colors + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/modules/core.rst b/doc/source/modules/core.rst new file mode 100644 index 00000000..e3d69eb4 --- /dev/null +++ b/doc/source/modules/core.rst @@ -0,0 +1,8 @@ +.. _core: +Core +---- + +.. automodule:: plot_data.core + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/modules/graph.rst b/doc/source/modules/graph.rst new file mode 100644 index 00000000..64ca20c4 --- /dev/null +++ b/doc/source/modules/graph.rst @@ -0,0 +1,8 @@ +.. _graph: +Graph +----- + +.. automodule:: plot_data.graph + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/modules/template.rst b/doc/source/modules/template.rst new file mode 100644 index 00000000..d6534218 --- /dev/null +++ b/doc/source/modules/template.rst @@ -0,0 +1,8 @@ +.. _template: +template +-------- + +.. automodule:: plot_data.template + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/multiplot.rst b/doc/source/multiplot.rst new file mode 100644 index 00000000..b7833525 --- /dev/null +++ b/doc/source/multiplot.rst @@ -0,0 +1,173 @@ +Multiplot: drawing several plots on one page +============================================ + +The `Multiplot` object is basically a layout of several figures where all drawn elements are linked together so that selecting an object in one plot selects this object on all plots, except for 2D representations (`PrimitiveGroup`) and `Graph2D` objects. + +How to draw a Multiplot ? +------------------------- + +1. **Import the required packages** + +.. code-block:: python + + # Required packages + import random + import plot_data + +2. **Create Data** + +In order to draw a Multiplot with random values, build a random vector of samples (stored as Python `dict`) with different attributes. Here 4 float attributes (`mass`, `length`, `speed` and `power`), 1 integer attribute (`rank`) and 1 discrete attribute (`shape`) are chosen to describe each sample. + +.. code-block:: python + + # Vector construction + elements = [] + SHAPES = ['round', 'square', 'triangle', 'ellipse'] + for i in range(500): + elements.append({"mass": random.uniform(0, 10), + "length": random.uniform(0, 100), + "speed": random.uniform(0, 3.6), + "shape": random.choice(SHAPES), + "rank": random.randint(1, 20), + 'power': random.gauss(0, 3)}) + +3. **Build all plots to draw in the Multiplot** + +.. code-block:: python + + # ParallelPlot + parallelplot = pld.ParallelPlot(axes=['mass', 'length', 'speed', 'shape', 'rank', 'power']) + + # Scatterplots + mass_vs_length = pld.Scatter(x_variable='mass', y_variable='length') + shape_vs_rank = pld.Scatter(x_variable='shape', y_variable='rank') + + # 2D representation + drawing_2d = pld.PrimitiveGroup(primitives=[pld.Rectangle(0, 0, 12, 24), pld.Circle2D(12, 24, 5)]) + + histogram_power = pld.Histogram(x_variable='power') + histogram_speed = pld.Histogram(x_variable='speed') + + # Creating the multiplot + plots = [parallelplot, mass_vs_length, shape_vs_rank, drawing_2d, histogram_power, histogram_speed] + +4. **Build a Multiplot with all these plots** + +.. code-block:: python + + # Points sets creation as an example + point_families=[ + pld.PointFamily('rgb(25, 178, 200)', [1,2,3,4,5,6,7]), + pld.PointFamily('rgb(225, 13, 200)', [10,20,30,41,45,46,47]), + pld.PointFamily('rgb(146, 178, 78)', [11,21,31,41,25,26,27]) + ] + + multiplot = pld.MultiplePlots( + plots=plots, + elements=elements, + initial_view_on=True + ) + +Once done, the figure can be displayed with the following command line : + +.. code-block:: python + + pld.plot_canvas(plot_data_object=multiplot, canvas_id='my_mulitplot') + +.. raw:: html + + + +Multiplot Features +------------------ + +- All features available in alone figures are available in the Multiplot layout, +- Cross selection between figures is available, +- One can reorder figures by clicking on `Resize Figures` , +- One can select several lines with several mouse click by keeping pressed `Ctrl` key, +- One can reset the view of the mouse hovered plot by pressing `Ctrl + Space`, +- One can reset the whole figure by pressing `Ctrl + Shift + Left Click`. + +How to write a method to draw a Multiplot in a DessiaObject ? +------------------------------------------------------------- + +For the pendulum example, a Multiplot can be designed for the `PendulumDOE` class to draw all relevant figures in one html page. As for other plots, a decorator `@plot_data_view` is added for a future platform usage. + +1. **Before coding the Multiplot method, some re-arrangements need to be done in PendulumDOE class for minimizing the amount of produced data** + +.. code-block:: python + + class PendulumDOE(Dataset): + : + : + : + # To build only one vector elements + def _to_sample(self): + return [{ + "length": pendulum.length, + "g": pendulum.g, + "speed": pendulum.max_speed, + "period": pendulum.period, + } for pendulum in self.dessia_objects] + + # To draw all pendulums + def _to_drawings(self): + cmap = colormaps["jet"](npy.linspace(0, 1, len(self.dessia_objects))) + return sum([pendulum.draw(Color(*(cmap[i][:-1]))).primitives + for i, pendulum in enumerate(self.dessia_objects)], []) + + def _scatter_speed_period(self, elements = None): + tooltip = pld.Tooltip(["length", "g"]) + return pld.Scatter(x_variable="period", y_variable="speed", tooltip=tooltip, elements=elements) + + def _parallel_plot(self, elements = None): + return pld.ParallelPlot(axes=["g", "length", "period", "speed"], elements=elements) + + def _histogram(self, elements = None): + return pld.Histogram(x_variable="speed", graduation_nb=20, elements=elements) + + @plot_data_view("max_speed") + def scatter_speed_period(self, reference_path: str = "#"): + return self._scatter_speed_period(elements=self._to_sample()) + + @plot_data_view("parallelplot") + def parallel_plot(self, reference_path: str = "#"): + return self._parallel_plot(elements=self._to_sample()) + + @plot_data_view("histogram") + def histogram(self, reference_path: str = "#"): + return self._histogram(elements=self._to_sample()) + + @plot_data_view("draw") + def draw(self): + return pld.PrimitiveGroup(primitives=self._to_drawings()) + +2. Write the **Mutliplot** method + +.. code-block:: python + + class PendulumDOE(Dataset): + : + : + : + @plot_data_view("Multiplot") + def multiplot(self, reference_path: str = "#"): + scatter_plot = self._scatter_speed_period() + y_vs_t_curves = self.all_y_vs_time() + parallel_plot = self._parallel_plot() + histogram = self._histogram() + draw = self.draw() + plots = [scatter_plot, parallel_plot, histogram, draw, y_vs_t_curves] + elements = self._to_sample() + return pld.MultiplePlots(elements=elements, plots=plots, name="Multiple Plot") + +Once done, the figure can be displayed with the following command line : + +.. code-block:: python + + multiplot = pendulum_doe.multiplot() + pld.plot_canvas(plot_data_object=multiplot, canvas_id='my_multiplot') + +.. raw:: html + + diff --git a/doc/source/object.rst b/doc/source/object.rst new file mode 100644 index 00000000..505735d9 --- /dev/null +++ b/doc/source/object.rst @@ -0,0 +1,308 @@ +Draw a 2D representation of an object +===================================== + +PlotData allows to draw complex shapes and to associate them with a DessiaObject. + +Available shapes +---------------- + +The following bullet point lists all available shapes in PlotData and how to instantiate and draw them. For the sake of simplicity, imports are given just below and used for all the following shapes. + +.. code-block:: python + + import math + import plot_data as pld + from plot_data.colors import ORANGE, BLACK, BLUE, LIGHTGREEN + +- **Point**: draw a point at the given 2D coordinates `(cx, cy)`. To create a `Point2D` which drawing parameters are customized, write the following lines: + +.. code-block:: python + + point_style = pld.PointStyle( + color_fill=ORANGE, + color_stroke=BLACK, + stroke_width=2, + shape="circle", + size = 20 + ) + + point = pld.Point2D( + cx = 1, + cy=12, + point_style=point_style, + tooltip="Circle point" + ) + +- **Line segment**: draw a line segment between two given points. To create a `LineSegment2D` which drawing parameters are customized, write the following lines: + +.. code-block:: python + + edge_style = pld.EdgeStyle( + line_width=3, + color_stroke=BLUE, + dashline=[5, 2] + ) + + line_segment = pld.LineSegment2D( + point1=[0, 0], + point2=[20, 16], + edge_style=edge_style, + tooltip="LineSegment2D" + ) + +- **Line**: draw an infinite line crossing two given points. To create a `Line2D` (same style customization as `LineSegment2D`) write the following lines: + +.. code-block:: python + + pld.Line2D( + point1=[-10, 24.5], + point2=[22, 24.5], + edge_style=edge_style, + tooltip="Line2D" + ) + +- **Rectangle**: draw a rectangle with given origin coordinates, width and height. To create a Rectangle which drawing parameters are customized, write the following lines: + +.. code-block:: python + + # Surface hatching + hatching = pld.HatchingSet(1, 10) + + surface_style = pld.SurfaceStyle( + color_fill=LIGHTGREEN, + opacity=0.8, + hatching=hatching + ) + + edge_style = pld.EdgeStyle( + line_width=3, + color_stroke=BLUE, + dashline=[5, 2] + ) + + rectangle = pld.Rectangle( + x_coord=-6, y_coord=16, width=15, height=10, + surface_style=surface_style, + edge_style=edge_style, + tooltip="rectangle" + ) + +- **Round rectangle**: draw a rectangle with given origin coordinates, width, height and radius. To create a `RoundRectangle`(same style customization as `Rectangle`) write the following lines: + +.. code-block:: python + + round_rect = pld.RoundRectangle( + x_coord=24, y_coord=0, width=60, height=37, radius=1, + edge_style=edge_style, + surface_style=surface_style, + tooltip="round_rectangle" + ) + +- **Circle**: draw a circle with given origin coordinates and radius. To create a `Circle` (same style customization as `Rectangle`) write the following lines: + +.. code-block:: python + + circle = pld.Circle2D( + cx=15, + cy=35, + r=5, + edge_style=edge_style, + surface_style=surface_style, + tooltip="Circle" + ) + +- **Arc**: draw an arc with given origin coordinates, radius and start and end angles. To create an `Arc2D` (same style customization as `Line`) write the following lines: + +.. code-block:: python + + arc = pld.Arc2D( + cx=0, + cy=30, + r=5, + start_angle=math.pi/4, + end_angle=2*math.pi/3, + edge_style=edge_style, + clockwise=False, # Specify the turning sense for drawing the arc + tooltip="arc_anticlockwise" + ) + +- **Wire**: draw a 2D polygon connecting the given points. It can be closed or open. To create a `Wire` (same customization as `Line`) write the following lines: + +.. code-block:: python + + # Point series ([x1, y1],...,[xn, yn]) to link with lines + lines = [ + [25, 35], [28, 26], [29, 30], [30, 26], + [33, 35], [34, 35], [34, 26], [35, 26], + [35, 35], [40, 35], [35, 30], [40, 26], + [44, 26], [41, 26], [41, 30.5], [43, 30.5], + [41, 30.5], [41, 35], [44, 35] + ] + + wire = pld.Wire( + lines=lines, + tooltip="Wire", + edge_style=edge_style + ) + +- **Contour**: draw a 2D polygon with arcs and lines. It can be closed or open. To get a transparent filling for the Contour, do not specify any `SurfaceStyle` when building it. To create a `Contour` (same style customization as `Rectangle`) write the following lines: + +.. code-block:: python + + heart_lines = [ + pld.LineSegment2D([51, 26], [47, 33]), + pld.Arc2D(cx=49, cy=33, r=2, start_angle=math.pi, end_angle=0, clockwise=True), + pld.Arc2D(cx=53, cy=33, r=2, start_angle=math.pi, end_angle=0, clockwise=True), + pld.LineSegment2D([55, 33], [51, 26]) + ] + + contour = pld.Contour2D( + plot_data_primitives=heart_lines, + edge_style=pld.EdgeStyle(line_width=2, color_stroke=BORDEAUX), + surface_style=pld.SurfaceStyle(color_fill=RED), + tooltip="Heart shaped contour.") + +- **Text**: write text at the specified coordinates with the given text properties. To create a `Text` write the following lines and specify the following attribute for it to fit with its requirements: + + - `text_style` attribute allows to specify a `TextStyle`to custom text font, size and align + - `text_scaling` attribute allows to scale the text with mouse wheel or not + - `max_width` attribute allows to resize the text’s font automatically to be smaller than the specified length + - `height` attribute allows to resize the text’s font automatically to be smaller than the specified height + - `multi_lines` attribute allows to specify if the text shall automatically create a new line when it is longer than the specified `max_width` + +.. code-block:: python + + # Unscaled text + unscaled = pld.Text( + comment='This text never changes its size because text_scaling is False.', + position_x=-14, + position_y=28, + text_scaling=False, + multi_lines=True + text_style=pld.TextStyle( + font_size=16, + text_align_y="top" + ) + ) + + # Scaled text + scaled = pld.Text( + comment='Dessia', + position_x=70, + position_y=35, + text_scaling=True, + multi_lines=False, + text_style=pld.TextStyle( + font_size=8, + text_color=BLUE, + text_align_x="right", + text_align_y="bottom", + bold=True + ) + ) + +- **Label**: draw a label with the given text **or** for the given shape. To create a `Label` create a shape and associate it to a `Label` or write a text and set a style to show anything else. The following lines give the procedure to build labels: + +.. code-block:: python + + # Standalone Label + text_style = pld.TextStyle( + text_color=ORANGE, + font_size=14, + italic=True, + bold=True + ) + + edge_style = pld.EdgeStyle( + line_width=1, + color_stroke=BLUE, + dashline=[5, 5] + ) + + label_1 = pld.Label( + title='Standalone Label 1', + text_style=text_style, + rectangle_surface_style=surface_style, + rectangle_edge_style=edge_style) + + # Automatic labels + ## Set a shape list + shapes = [ + point, line_segment, line, rectangle, round_rectangle, circle, + arc, wire, contour] + + ## Create a label for each shape + labels = [ + pld.Label(title=type(shape).__name__, shape=shape) for shape in shapes + ] + +Drawing shapes in a Figure +-------------------------- + +The previously presented shapes can all be drawn in a `PrimitiveGroup` (soon renamed as `Draw`). To do it, store all these shapes in a list and draw a `PrimitiveGroup` : + +.. code-block:: python + + primitives=[point, line_segment, line, rectangle, round_rectangle, + circle, arc, wire, contour, unscaled, scaled, label_1] + labels + + draw = pld.PrimitiveGroup(primitives=primitives) + +Once done, the figure can be displayed with the following command line: + +.. code-block:: python + + pld.plot_canvas(plot_data_object=draw, filepath="section2_6_2_draw") + +.. raw:: html + + + + +How to add a 2D representation to a DessiaObject ? +-------------------------------------------------- + +For the previously designed Pendulum ([section 2.1.2](https://www.notion.so/Using-data-display-with-PlotData-30f86e58db6240788cf4f3b543b0ae51?pvs=21)), an interesting 2D representation may be to represent the pendulum with its course over x and y coordinates. + +To do it, add a method to build the 2D representation to the `Pendulum` class: + +.. code-block:: python + + class Pendulum(DessiaObject): + : + : + : + @plot_data_view("2d_drawing") + def draw(self, reference_path: str = "#"): + # Pendulum's pivot + origin = pld.Point2D(0, 3.1, pld.PointStyle(color_fill=BLACK, color_stroke=BLACK, size=20, shape="circle")) + + # Pendulum's mass object + mass_origin = [ + self.length * math.sin(self.init_angle), + origin.cy - self.length *math.cos(self.init_angle) + ] + mass_circle = pld.Circle2D( + cx=mass_origin[0], cy=mass_origin[1], r=0.25, + surface_style = pld.SurfaceStyle(color_fill=BLUE) + ) + + # Pendulum's link + bar = pld.LineSegment2D( + [origin.cx, origin.cy], mass_origin, + edge_style=pld.EdgeStyle(line_width=5, color_stroke=BLACK)) + + # Pendulum's course + shifted_coords = (npy.array(self.coords) + npy.array([[0, origin.cy - self.length]])).tolist() + course = pld.Wire(shifted_coords, edge_style=pld.EdgeStyle(line_width=1, color_stroke=BLUE, dashline=[7,3])) + return pld.PrimitiveGroup([origin, mass_circle, bar, course]) + +Once done, the figure can be displayed with the following command line: + +.. code-block:: python + + pld.plot_canvas(plot_data_object=pendulum.draw(), canvas_id='my_draw', filepath="section2_6_3_draw") + +.. raw:: html + + diff --git a/doc/source/parallel.rst b/doc/source/parallel.rst new file mode 100644 index 00000000..414013b1 --- /dev/null +++ b/doc/source/parallel.rst @@ -0,0 +1,110 @@ +Parallel Plot: draw all features on one Figure +============================================== + +Parallel plot or parallel coordinates plot allows to compare features of several individual observations (series) on a set of numeric variables. + +Each vertical bar represents a variable or an objective value and has its own scale (units can even be different). Values are then plotted as series of lines connected across each axis. + +**Thanks to Parallel Plot, correlations between variables and objectives can be globally visually studied**. + +How to draw a Parallel Plot ? +----------------------------- + +1. **Import the required packages** + +.. code-block:: python + + # Required packages + import random + import plot_data.core as pld + from plot_data.colors import BLUE, RED, GREEN, BLACK + +2. **Create Data** + +In order to draw a Parallel plot with random values, build a random vector of samples (stored as Python `dict`) with different attributes. Here 3 float attributes (`mass`, `length` and `speed`), 1 integer attribute (`rank`) and 1 discrete attribute (`shape`) are chosen to describe each sample. + +.. code-block:: python + + # Vector construction + elements = [] + SHAPES = ['round', 'square', 'triangle', 'ellipse'] + for i in range(500): + elements.append({"mass": random.uniform(0, 10), + "length": random.uniform(0, 100), + "speed": random.uniform(0, 3.6), + "shape": random.choice(SHAPES), + "rank": random.randint(1, 20)}) + +3. **Build the Parallel Plot object and draw it in a web browser** + +.. code-block:: python + + parallel_plot = pld.ParallelPlot( + elements=elements, + axes=["mass", "length", "speed", "shape", "rank"], + edge_style=edge_style + ) + +Once done, the figure can be displayed with the following command line : + +.. code-block:: python + + pld.plot_canvas(plot_data_object=parallel_plot, canvas_id='my_parallel_plot') + +.. raw:: html + + + +Parallel Plot Features +---------------------- + +- **Rubberbands can be drawn on axes by clicking and dragging on it with mouse. Rubberbands allow to select range of values on each axis,** +- Axes layout can be changed from vertical to horizontal with the `Change Disposition` button, +- Values order on axes can be changed from ascending to descending by clicking on its title, +- Each axis can be scrolled and scaled with mouse click and wheel, +- Each axis can be moved by clicking on its title and dragging it with mouse, +- Values can be displayed in log scales by clicking on `Log Scale` button, +- One can select several lines with several mouse click by keeping pressed `Ctrl` key, +- One can reset the view by pressing `Ctrl + Space`, +- One can reset the whole figure by pressing `Ctrl + Shift + Left Click`. + +How to write a method to draw a Parallel Plot in a DessiaObject ? +----------------------------------------------------------------- + +For the previously designed PendulumDOE ([section 2.2.2](https://www.notion.so/Using-data-display-with-PlotData-30f86e58db6240788cf4f3b543b0ae51?pvs=21)), an interesting plot may be to draw all pendulum variables and objective values (`length`, `gravity`, `speed` and `period`). + +To do it, add a method to draw a Parallel Plot to the PendulumDOE class: + +.. code-block:: python + + class PendulumDOE(Dataset): + : + : + : + @plot_data_view("parallelplot") + def parallel_plot(self, reference_path: str = "#"): + elements = [ + {"period": pendulum.period, "speed": pendulum.max_speed, "length": pendulum.length, "g": pendulum.g} + for pendulum in self.dessia_objects] + return pld.ParallelPlot(axes=["g", "length", "period", "speed"], elements=elements) + +And draw the Parallel Plot with the function `plot_canvas` : + +.. code-block:: python + + # Parameters sampling definition + planet_sampling = BoundedAttributeValue('g', 1, 11, 10) + length_sampling = BoundedAttributeValue('length', 0.1, 3, 10) + + # DOE instantiation + pendulum_doe = PendulumDOE.from_boundaries(planet_sampling, length_sampling, 10, 0.01, method = 'fullfact') + + # Parallel Plot construction + parallel_plot = pendulum_doe.parallel_plot() + + # Draw the figure in a web browser + pld.plot_canvas(plot_data_object=parallel_plot, filepath="section2_4_2_parallel_plotod") + +.. raw:: html + + diff --git a/doc/source/platform.rst b/doc/source/platform.rst new file mode 100644 index 00000000..0ba4f593 --- /dev/null +++ b/doc/source/platform.rst @@ -0,0 +1,107 @@ +Using PlotData with Dessia's platform +===================================== + +Select objects +-------------- + +When drawing multiple objects on one figure, one feature of interest can be to select these objects on the plot and to get them downloaded from the database and displayed on a table below the figure. + +The DessiaObject `Dataset` implements it by default by adding an attribute `reference_path` to each displayed element in the object container: + +.. code-block:: python + + # self is an object container where objects are stored in the attribute "dessia_objects" + def _object_to_sample(self, dessia_object: DessiaObject, row: int, reference_path: str = '#'): + sample_values = {attr: self.matrix[row][col] for col, attr in enumerate(self.common_attributes)} + reference_path = f"{reference_path}/dessia_objects/{row}" + name = dessia_object.name if dessia_object.name else f"Sample {row}" + return pld.Sample(values=sample_values, reference_path=reference_path, name=name) + + # The vector of elements (or Samples) is built with an additional key attribute: + # reference_path, which is '#/dessia_objects/i' where # is the path of the Dataset + # and i is the DessiaObject index. + def _to_samples(self, reference_path: str = '#'): + return [self._object_to_sample(dessia_object=dessia_object, row=row, reference_path=reference_path) + for row, dessia_object in enumerate(self.dessia_objects)] + + # The Scatter draws the previously built samples + @plot_data_view("Scatter", load_by_default=True) + def scatter(self, reference_path: str = "#"): + samples = self._to_samples(reference_path) + return pld.Scatter(elements=samples, x_variable="period", y_variable="speed") + +From the platform view, selecting referenced objects (i.e. with a specified `reference_path`) on a plot will make a table appearing below the figure (warning: data are not from the pendulum example): + +.. image:: images/multiplot_table.png + :width: 600 + +To select several objects on a figure, several features are available: + +- **Ctrl + click**: Press `Ctrl` and click on several points. + +**WARNING: Points selected this way can not be added to a Point Set (see below)** + +- **Selection box**: Press Shift and draw a **Selection Box** by clicking and dragging mouse on a Frame plot (Scatter, Histogram) +- **Buttons**: Click on the `Selection` button and draw a **Selection Box** by clicking and dragging mouse on a Frame plot (Scatter, Histogram) + +.. image:: images/selection_button.png + :width: 600 + +- **Filters with rubberbands**: Click and drag mouse on any axis of Scatter, Histogram or ParallelPlot to create a `Rubberband` that allows to select range of values: + +.. image:: images/rubberband_selection.png + :width: 600 + +Handle view +----------- + +The view on figures can be handled by user’s manipulations. Available methods are: + +- **Mouse buttons**: Click and drag or wheel mouse to handle the view box and the zoom level, +- **Zoom box**: Click on the `Zoom Window` button to activate the Zoom window tool to define new minimums and maximums on displayed axes of Frame figures (Draw, Scatter, Histogram) thanks to a Zoom window that is drawn with mouse click and drag, + +.. image:: images/zoom_buttons.png + :width: 600 + +- **Buttons (vertical / horizontal , merge points)**: + +- **Merge points on Scatter with `Merge Points` button:** Activate this option for performances when drawing a Scatter plot. It will merge some points to down scale the number of drawn points, for performance reasons, + +.. image:: images/merge_button.png + :width: 600 + +- **Switch from Vertical axes to Horizontal axes on Parallel Plots:** Click on `Change disposition` button to switch from vertical to horizontal layout (and inverse) on parallel plots + +.. image:: images/change_disposition.png + :width: 600 + +Add figures on Multiplot +------------------------ + +The Multiplot figure allows to dynamically add new Scatters or Parallel Plots on the existing view. **WARNING: The added figures on Multiplot are not persistent. This means they won’t remain after a refresh or after leaving the current page.** + +.. image:: images/add_plot.png + :width: 600 + +Change Multiplot Layout +----------------------- + +The Multiplot figure allows to dynamically change figures layout on the existing view. **WARNING: The custom layout of Multiplot is not persistent. This means it won’t remain after a refresh or after leaving the current page.** + +.. image:: images/multiplot_layout.png + :width: 600 + +To cancel changes on the Multiplot layout, click on the `Order Plots` button + +.. image:: images/order_plots.png + :width: 600 + +Create Points Sets +------------------ + +PlotData allows to dynamically add points to subsets for giving them a new color to get a better view of clusters in figures. To do it, select some points with the selection tools detailed before and add them to a `PointFamily` + +**WARNING: The custom points sets are not persistent. This means they won’t remain after a refresh or after leaving the current page.** + +.. image:: images/points_sets.png + :width: 600 diff --git a/doc/source/plot_data.rst b/doc/source/plot_data.rst new file mode 100644 index 00000000..d2fec25d --- /dev/null +++ b/doc/source/plot_data.rst @@ -0,0 +1,11 @@ +.. _modules: +ALL MODULES +=========== + +Submodules +---------- + +.. toctree:: + :maxdepth: 3 + + modules diff --git a/doc/source/road_map_and_current_limitations.rst b/doc/source/road_map_and_current_limitations.rst new file mode 100644 index 00000000..095e2f1e --- /dev/null +++ b/doc/source/road_map_and_current_limitations.rst @@ -0,0 +1,21 @@ +Roadmap and current limitations +=============================== + +What's new +---------- + +The version 0.1.0 released on April 4, 2023 includes: + +- a documentation +- method names follow the pep8 instructions, with possible backward + compatibility + +Current limitations +------------------- + +No limitations have been discovered. + +Roadmap +------- + +No future improvements are planned. diff --git a/doc/source/scatter.rst b/doc/source/scatter.rst new file mode 100644 index 00000000..3ab43bdb --- /dev/null +++ b/doc/source/scatter.rst @@ -0,0 +1,213 @@ +Scatter: draw points on a Figure +================================ + +A Scatter draw is a figure that plots points in an orthogonal frame, without any curve to link them. As an example a transparent curve from the previous Graph2D where points are shown is like a Scatter drawing. + +How to draw a Scatter ? +----------------------- + +1. **Import the required packages** + +.. code-block:: python + + # Required packages + import random + import plot_data.core as pld + from plot_data.colors import BLUE, RED, GREEN, BLACK + +1. **Create Data** + +In order to draw a Scatter plot with random values, build a random vector of samples (stored as Python `dict`) with different attributes. Here three attributes (`mass`, `length` and `speed`) have been set for the samples to carry more information than just their coordinates in the Scatter plot: + +.. code-block:: python + + # Vector construction + elements = [] + for i in range(500): + elements.append({'mass': random.uniform(0, 10), + 'length': random.uniform(0, 100), + 'speed': random.uniform(0, 3.6)}) + +1. **Add meta-data on samples** + +Some additional information can be added on points thanks to tooltips. They can be displayed by clicking on the point of interest. Here, the tooltip is directly created as an independent object that will be used in next steps, while creating the figure to draw the previously built data. + +For the scatter example, some point sets are defined (`PointFamily` object, where a sample is in a set if this set contains its index in vector `elements`). + +.. code-block:: python + + # Attributes to show in tooltip + shown_attributes = ["mass", "length", "speed"] + + # Tooltip creation + tooltip = pld.Tooltip(attributes=shown_attributes) + + # Points sets declaration + points_sets = [ + pld.PointFamily(RED, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + pld.PointFamily(BLUE, [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]) + ] + +1. **Set styles for points, curves and axes** + +Styles for points and axes can be customized with the user’s preferences. + +.. code-block:: python + + # Points style + point_style = pld.PointStyle(color_fill=GREEN, + color_stroke=BLUE, + stroke_width=2, + size=8, + shape='square') + # Axis style + ## Text style + graduation_style = pld.TextStyle( + text_color=BLUE, + font_size=10, + font_style='Arial' + ) + + ## Axis edge style + axis_style = pld.EdgeStyle( + line_width=0.5, + color_stroke=DARK_BLUE, + dashline=[] + ) + + # Axes ticks number and styles + axis = pld.Axis( + nb_points_x=7, nb_points_y=5, + graduation_style=graduation_style, + axis_style=axis_style + ) + +1. **Build the Scatter object and draw it in a web browser** + +.. code-block:: python + + scatter = pld.Scatter( + elements=elements, + x_variable="mass", + y_variable="length", + point_style=point_style, + points_sets=points_sets, + axis=axis, + tooltip=tooltip + ) + +Once done, the figure can be displayed with the following command line : + +.. code-block:: python + + pld.plot_canvas(plot_data_object=scatter, canvas_id='my_scatter') + +.. raw:: html + + + +Scatter features +---------------- + +- Points used to build the curve can be merged by clicking on `Merge Points` button, +- The figure can be scaled with mouse wheel or by clicking on `Zoom Box`, `Zoom+` and `Zoom-` buttons, +- Points can be displayed in log scales by clicking on `Log Scale` button, +- One can select points with a selection window by keeping pressed the `Shift` key, +- One can select several points with several mouse click by keeping pressed `Ctrl` key, +- One can reset the view by pressing `Ctrl + Space`, +- One can reset the whole figure by pressing `Ctrl + Shift + Left Click`. + +How to write a function to draw a Scatter for an object ? +--------------------------------------------------------- + +As a concrete example, the influence of the pendulum’s period on its maximum speed can be studied by drawing a scatter plot of the pendulum’s maximum speed against its period. + +1. **First, add methods to pendulum to compute some insightful values to draw on a scatter plot. Here, we compute the speed over time and its maximum value.** + +.. code-block:: python + + # To add to the pendulum class + def get_speed(self): + speed = npy.array(self.coords)[1:, :] - npy.array(self.coords)[:-1, :] + return npy.linalg.norm(speed, ord=2, axis=1) / self.time_step + + @property + def max_speed(self): + return npy.max(self.get_speed()) + +1. **Then write a function to draw speed against period in a Scatter plot** + +In the following code lines, `point_style` , `axis_style` and `axis` properties are customized and tooltip is specified so that only relevant information are drawn in tooltips when points are clicked. + +.. code-block:: python + + def scatter_speed_period(pendulum_doe: PendulumDOE, reference_path: str = "#"): + tooltip = pld.Tooltip(["length", "g"]) + elements = [ + {"period": pendulum.period, + "speed": pendulum.max_speed, + "length": pendulum.length, + "g": pendulum.g} for pendulum in pendulum_doe.dessia_objects] + + # Point Style + point_style = pld.PointStyle( + color_fill=Color(0, 1, 1), + color_stroke=Color(0, 0, 0), + size=6, + shape="triangle", # square, circle, mark, cross, halfline + orientation="down" # up, left, right + ) + + # Axis edge style + axis_style = pld.EdgeStyle( + line_width=0.5, + color_stroke=DARK_BLUE, + dashline=[] + ) + axis = pld.Axis( + nb_points_x=10, nb_points_y=15, + axis_style=axis_style + ) + return pld.Scatter(x_variable="period", y_variable="speed", + elements=elements, tooltip=tooltip, + point_style=point_style, axis=axis) + +1. **Run the function to draw the Scatter plot in a web browser** + +With such plot the user can pick the best solutions considering its performances criteria. + +.. code-block:: python + + scatter = scatter_speed_period(pendulum_doe) + pld.plot_canvas(plot_data_object=scatter, filepath="section_2_3_speed_period") + +.. raw:: html + + + +How to add a method to draw a Scatter within a DessiaObject ? +------------------------------------------------------------- + +For the pendulum example, the previous Scatter plot can be added to the `PendulumDOE` class by simply changing the previous function into a `PendulumDOE` method. As for Graph2D, a decorator `@plot_data_view` is added for a future platform usage. Furthermore, for the sake of simplicity, plot customization is removed: + +.. code-block:: python + + # To add to PendulumDOE class + @plot_data_view("max_speed") + def scatter_speed_period(self, reference_path: str = "#"): + tooltip = pld.Tooltip(["length", "g"]) + elements = [ + {"period": pendulum.period, "speed": pendulum.max_speed, "length": pendulum.length, "g": pendulum.g} + for pendulum in self.dessia_objects] + return pld.Scatter(x_variable="period", y_variable="speed", elements=elements, tooltip=tooltip) + +To draw this scatter in a web browser, run the following code lines: + +.. code-block:: python + + scatter_self = pendulum_doe.scatter_speed_period() + pld.plot_canvas(plot_data_object=scatter_self, canvas_id='my_scatter') + +.. raw:: html + + diff --git a/doc/source/tutorials.rst b/doc/source/tutorials.rst new file mode 100644 index 00000000..476a3944 --- /dev/null +++ b/doc/source/tutorials.rst @@ -0,0 +1,85 @@ +Tutorials +========= + +In this example, a regular decision tree with next_unique_node is implemented +to find the bast solution for a Knapsack Problem. A selection of items among a +collection of 10 items, having a mass and a value, have to be made to yield +the highest value while fitting in a knapsack of maximum 30kg. To solve this +problem the regular decision tree will be composed of 10 levels (a selection of +maximum 10 items) and each node will have 10 possibilities, one for each item. +However an item can't be picked twice so this example uses next_unique_node. :: + + from dectree import RegularDecisionTree + + + # Creating a class for the items + class Item: + def __init__(self, mass, value, name): + self.mass, self.value, self.name = mass, value, name + + def __repr__(self): + return f'{self.name} : value = {self.value} ; mass = {self.mass}' + + + # Knapsack maximum weight + max_mass = 30 + + # List of all the items + items = [Item(4, 10, 'item1'), + Item(5, 11, 'item2'), + Item(6, 14, 'item3'), + Item(7, 18, 'item4'), + Item(8, 20, 'item5'), + Item(9, 24, 'item6'), + Item(10, 27, 'item7'), + Item(11, 28, 'item8'), + Item(12, 30, 'item9'), + Item(13, 33, 'item10')] + + # Creating a regular decision tree + tree = RegularDecisionTree(np=[len(items)] * len(items)) + + result = None + max_value = 0 + while not tree.finished: + # Stocking information about current node + current_mass = sum(items[i].mass for i in tree.current_node) + current_value = sum(items[i].value for i in tree.current_node) + current_items = [items[i] for i in tree.current_node] + + # Checking viability of current node + valid = False if current_mass > max_mass else True + + if valid and current_value > max_value: + result = current_items + max_value = current_value + + # Going to next node + tree.next_unique_node(current_node_viability=valid) + +However, knowing that order of the items inside a solution doesn't matter, +the algorithm can be improved using next_sorted_unique_node instead of +next_unique_node. It is then equivalent to a regular decision tree with +10 levels, on for each item, and only 2 possibilities for each node : take +the corresponding item or not. :: + + # Creating a regular decision tree + tree = RegularDecisionTree(np=[2] * len(items)) + + result = None + max_value = 0 + while not tree.finished: + # Stocking information about current node + current_mass = sum(items[item_i].mass * i for item_i, i in enumerate(tree.current_node)) + current_value = sum(items[item_i].value * i for item_i, i in enumerate(tree.current_node)) + current_items = [items[item_i] for item_i, i in enumerate(tree.current_node) if i] + + # Checking viability of current node + valid = False if current_mass > max_mass else True + + if valid and current_value > max_value: + result = current_items + max_value = current_value + + # Going to next node + tree.next_node(current_node_viability=valid) diff --git a/setup.py b/setup.py index b3ce06d5..c30db43f 100644 --- a/setup.py +++ b/setup.py @@ -117,4 +117,8 @@ def get_version(): package_dir={}, include_package_data=True, install_requires=['matplotlib', 'dessia_common'], + extras_require={"test": ["coverage"], + "doc": ["sphinx", "nbsphinx", "pydata_sphinx_theme", "nbformat", "nbconvert", + "sphinx_copybutton", "sphinx_design"]}, + classifiers=['Topic :: Scientific/Engineering :: Visualization', 'Development Status :: 3 - Alpha'])