diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6c3eb9e..877040f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,6 +17,5 @@ repos: - repo: https://github.com/doublify/pre-commit-rust rev: v1.0 hooks: - - id: fmt - id: cargo-check - - id: clippy \ No newline at end of file + - id: clippy diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a8977d..aa34051 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,43 @@ All notable changes to this project will be documented in this file. +## [0.9.0] - 2025-04-27 + +### 🚀 Features + +- Add Contour plot +- Add Sankey diagram +- Add surface plot +- Add the secondary y axis + +### 🚜 Refactor + +- Remove contours struct + +### 📚 Documentation + +- Add implemented plots overview with examples to README + +### ⚙️ Miscellaneous Tasks + +- Bump plotlars version to 0.8.1 in Cargo files +- Update CHANGELOG for version 0.8.1 with new features and documentation +- Update Rust version and edition and bon crate +- Remove fmt hook +- Add fmt +- Format imports +- Refactor dataframe from documentation +- Format code +- Remove empty line +- Update with the new plots +- Update bon +- Update documentation +- Update + +### Feat + +- Additional trait methods to provide html string + ## [0.8.0] - 2025-01-05 ### 🚀 Features @@ -21,6 +58,7 @@ All notable changes to this project will be documented in this file. - Update dependencies to latest versions - Add image - Clean up comments in PieChart builder example for clarity +- Bump plotlars version to 0.8.0 in Cargo files ## [0.7.0] - 2024-11-06 diff --git a/Cargo.lock b/Cargo.lock index fe234a4..8747c21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -24,10 +24,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", + "getrandom 0.2.15", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -47,9 +47,9 @@ checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android-tzdata" @@ -68,9 +68,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "arbitrary" @@ -86,7 +86,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn", ] [[package]] @@ -100,9 +100,9 @@ dependencies = [ [[package]] name = "array-init-cursor" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7d0a018de4f6aa429b9d33d69edf69072b1c5b1cb8d3e4a5f7ef898fc3eb76" +checksum = "ed51fe0f224d1d4ea768be38c51f9f831dee9d05c163c11fba0b8c44387b1fc3" [[package]] name = "arrayvec" @@ -129,27 +129,18 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn", ] [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", -] - -[[package]] -name = "atoi" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" -dependencies = [ - "num-traits", + "syn", ] [[package]] @@ -166,9 +157,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "av1-grain" @@ -186,9 +177,9 @@ dependencies = [ [[package]] name = "avif-serialize" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e335041290c43101ca215eed6f43ec437eb5a42125573f600fc3fa42b9bddd62" +checksum = "98922d6a4cfbcb08820c69d8eeccc05bb1f29bfa06b4f5b1dbfe9a868bd7608e" dependencies = [ "arrayvec", ] @@ -216,9 +207,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "basic-toml" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" dependencies = [ "serde", ] @@ -237,9 +228,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "bitstream-io" @@ -249,9 +240,9 @@ checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" [[package]] name = "bon" -version = "3.3.2" +version = "3.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7acc34ff59877422326db7d6f2d845a582b16396b6b08194942bf34c6528ab" +checksum = "ced38439e7a86a4761f7f7d5ded5ff009135939ecb464a24452eaa4c1696af7d" dependencies = [ "bon-macros", "rustversion", @@ -259,9 +250,9 @@ dependencies = [ [[package]] name = "bon-macros" -version = "3.3.2" +version = "3.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4159dd617a7fbc9be6a692fe69dc2954f8e6bb6bb5e4d7578467441390d77fd0" +checksum = "0ce61d2d3844c6b8d31b2353d9f66cf5e632b3e9549583fe3cac2f4f6136725e" dependencies = [ "darling", "ident_case", @@ -269,47 +260,41 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.87", + "syn", ] [[package]] name = "built" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytemuck" -version = "1.18.0" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" +checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.7.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" +checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn", ] -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "byteorder-lite" version = "0.1.0" @@ -318,9 +303,12 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.7.1" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +dependencies = [ + "serde", +] [[package]] name = "castaway" @@ -333,9 +321,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.19" +version = "1.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" +checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" dependencies = [ "jobserver", "libc", @@ -360,22 +348,22 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "serde", - "windows-targets", + "windows-link", ] [[package]] name = "chrono-tz" -version = "0.10.0" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6dd8046d00723a59a2f8c5f295c515b9bb9a331ee4f8f3d4dd49e428acd3b6" +checksum = "efdce149c370f133a071ca8ef6ea340b7b88748ab0810097a9e2976eaa34b4f3" dependencies = [ "chrono", "chrono-tz-build", @@ -384,9 +372,9 @@ dependencies = [ [[package]] name = "chrono-tz-build" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7" +checksum = "8f10f8c9340e31fc120ff885fcdb54a0b48e474bbd77cab557f0c30a3e569402" dependencies = [ "parse-zoneinfo", "phf_codegen", @@ -400,21 +388,20 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "comfy-table" -version = "7.1.1" +version = "7.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b34115915337defe99b2aff5c2ce6771e5fbc4079f4b506301f5cf394c8452f7" +checksum = "4a65ebfec4fb190b6f90e944a817d60499ee0744e582530e2c9900a22e591d9a" dependencies = [ "crossterm", - "strum", - "strum_macros", + "unicode-segmentation", "unicode-width", ] [[package]] name = "compact_str" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6050c3a16ddab2e412160b31f2c871015704239bca62f72f6e5f0be631d3f644" +checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" dependencies = [ "castaway", "cfg-if", @@ -442,18 +429,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -470,29 +457,29 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossterm" -version = "0.27.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "crossterm_winapi", - "libc", "parking_lot", + "rustix", "winapi", ] @@ -507,15 +494,15 @@ dependencies = [ [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "darling" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ "darling_core", "darling_macro", @@ -523,34 +510,34 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.87", + "syn", ] [[package]] name = "darling_macro" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.87", + "syn", ] [[package]] name = "deranged" -version = "0.3.11" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058" dependencies = [ "powerfmt", "serde", @@ -558,15 +545,15 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.17" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "enum_dispatch" @@ -577,25 +564,35 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" dependencies = [ "serde", "typeid", ] +[[package]] +name = "errno" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "ethnum" version = "1.5.0" @@ -640,9 +637,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.35" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", "miniz_oxide", @@ -656,9 +653,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "futures" @@ -716,7 +713,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn", ] [[package]] @@ -758,10 +755,22 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + [[package]] name = "gif" version = "0.13.1" @@ -780,15 +789,15 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "half" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" dependencies = [ "cfg-if", "crunchy", @@ -814,9 +823,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "allocator-api2", "equivalent", @@ -831,12 +840,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "hex" version = "0.4.3" @@ -845,11 +848,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -863,16 +866,17 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", - "windows-core 0.52.0", + "windows-core 0.61.0", ] [[package]] @@ -892,9 +896,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "image" -version = "0.25.5" +version = "0.25.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" dependencies = [ "bytemuck", "byteorder-lite", @@ -915,9 +919,9 @@ dependencies = [ [[package]] name = "image-webp" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f" +checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" dependencies = [ "byteorder-lite", "quick-error", @@ -942,12 +946,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.2", "serde", ] @@ -959,7 +963,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn", ] [[package]] @@ -973,22 +977,17 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "itoap" -version = "1.0.1" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.2", "libc", ] @@ -1000,10 +999,11 @@ checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1015,15 +1015,15 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libfuzzer-sys" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b9569d2f74e257076d8c6bfa73fb505b46b851e51ddaecc825944aa3bed17fa" +checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75" dependencies = [ "arbitrary", "cc", @@ -1031,9 +1031,15 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "lock_api" @@ -1047,9 +1053,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "loop9" @@ -1062,18 +1068,18 @@ dependencies = [ [[package]] name = "lz4" -version = "1.27.0" +version = "1.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a231296ca742e418c43660cb68e082486ff2538e8db432bc818580f3965025ed" +checksum = "a20b523e860d03443e98350ceaac5e71c6ba89aea7d960769ec3ce37f4de5af4" dependencies = [ "lz4-sys", ] [[package]] name = "lz4-sys" -version = "1.11.0" +version = "1.11.1+lz4-1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb44a01837a858d47e5a630d2ccf304c8efcc4b83b8f9f75b7a9ee4fcc6e57d" +checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" dependencies = [ "cc", "libc", @@ -1128,9 +1134,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" dependencies = [ "adler2", "simd-adler32", @@ -1138,38 +1144,15 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] -[[package]] -name = "multiversion" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4851161a11d3ad0bf9402d90ffc3967bf231768bfd7aeb61755ad06dbf1a142" -dependencies = [ - "multiversion-macros", - "target-features", -] - -[[package]] -name = "multiversion-macros" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79a74ddee9e0c27d2578323c13905793e91622148f138ba29738f9dddb835e90" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "target-features", -] - [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -1234,7 +1217,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn", ] [[package]] @@ -1269,29 +1252,26 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] -name = "once_map" -version = "0.4.19" +name = "ordered-float" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30c7f82d6d446dd295845094f3a76bcdc5e6183b66667334e169f019cd05e5a0" +checksum = "e2c1f9f56e534ac6a9b8a4600bdf0f530fb393b5f393e7b4d03489c3cf0c3f01" dependencies = [ - "ahash", - "hashbrown 0.14.5", - "parking_lot", - "stable_deref_trait", + "num-traits", ] [[package]] @@ -1340,18 +1320,18 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "phf" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ "phf_shared", ] [[package]] name = "phf_codegen" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ "phf_generator", "phf_shared", @@ -1359,9 +1339,9 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", "rand", @@ -1369,18 +1349,18 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ "siphasher", ] [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -1390,9 +1370,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "planus" @@ -1405,10 +1385,12 @@ dependencies = [ [[package]] name = "plotlars" -version = "0.8.0" +version = "0.9.0" dependencies = [ "bon", "image", + "indexmap 2.9.0", + "ordered-float", "plotly", "polars", "serde", @@ -1442,7 +1424,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.87", + "syn", ] [[package]] @@ -1460,11 +1442,11 @@ dependencies = [ [[package]] name = "polars" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0af18ae021b0396c42f39396146332957ebc4d4d25d931b4fe73509948f348" +checksum = "72571dde488ecccbe799798bf99ab7308ebdb7cf5d95bcc498dbd5a132f0da4d" dependencies = [ - "getrandom", + "getrandom 0.2.15", "polars-arrow", "polars-core", "polars-error", @@ -1480,23 +1462,22 @@ dependencies = [ [[package]] name = "polars-arrow" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1fd3c64d50b7f5f328e1566cab9979d4bc1ba2ff22114b301ed2ee0e518dbca" +checksum = "6611c758d52e799761cc25900666b71552e6c929d88052811bc9daad4b3321a8" dependencies = [ "ahash", - "atoi", + "atoi_simd", "bytemuck", "chrono", "chrono-tz", "dyn-clone", "either", "ethnum", - "getrandom", - "hashbrown 0.15.1", - "itoap", + "getrandom 0.2.15", + "hashbrown 0.15.2", + "itoa", "lz4", - "multiversion", "num-traits", "parking_lot", "polars-arrow-format", @@ -1523,9 +1504,9 @@ dependencies = [ [[package]] name = "polars-compute" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e60822c245a870113df5a88fb184039501eda0a56bcd0c3f866406ff659df340" +checksum = "332f2547dbb27599a8ffe68e56159f5996ba03d1dad0382ccb62c109ceacdeb6" dependencies = [ "atoi_simd", "bytemuck", @@ -1533,7 +1514,6 @@ dependencies = [ "either", "fast-float2", "itoa", - "itoap", "num-traits", "polars-arrow", "polars-error", @@ -1545,20 +1525,20 @@ dependencies = [ [[package]] name = "polars-core" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4794a9e38ef2faf7e47a6f736c7f156c6fbb66cd529f82593b2d48348e422c8d" +checksum = "796d06eae7e6e74ed28ea54a8fccc584ebac84e6cf0e1e9ba41ffc807b169a01" dependencies = [ "ahash", - "bitflags 2.6.0", + "bitflags 2.9.0", "bytemuck", "chrono", "chrono-tz", "comfy-table", "either", "hashbrown 0.14.5", - "hashbrown 0.15.1", - "indexmap 2.5.0", + "hashbrown 0.15.2", + "indexmap 2.9.0", "itoa", "num-traits", "once_cell", @@ -1573,32 +1553,32 @@ dependencies = [ "rayon", "regex", "strum_macros", - "thiserror 2.0.9", + "thiserror 2.0.12", "version_check", "xxhash-rust", ] [[package]] name = "polars-error" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "100093a164bf6c001487ea528b7504f4be1a6881bcffe279bd6133e8f4b4e4f7" +checksum = "19d6529cae0d1db5ed690e47de41fac9b35ae0c26d476830c2079f130887b847" dependencies = [ "polars-arrow-format", "regex", "simdutf8", - "thiserror 2.0.9", + "thiserror 2.0.12", ] [[package]] name = "polars-expr" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad56c5ea4d6e0546fbc3fa35918a537b76587600a5118770ed331136249d50d8" +checksum = "c8e639991a8ad4fb12880ab44bcc3cf44a5703df003142334d9caf86d77d77e7" dependencies = [ "ahash", - "bitflags 2.6.0", - "hashbrown 0.15.1", + "bitflags 2.9.0", + "hashbrown 0.15.2", "num-traits", "once_cell", "polars-arrow", @@ -1616,9 +1596,9 @@ dependencies = [ [[package]] name = "polars-io" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95d774d5971d2092f0588e89d2f0be524dff35ea368272c0810ba54a860e4411" +checksum = "719a77e94480f6be090512da196e378cbcbeb3584c6fe1134c600aee906e38ab" dependencies = [ "ahash", "async-trait", @@ -1628,7 +1608,7 @@ dependencies = [ "fast-float2", "futures", "glob", - "hashbrown 0.15.1", + "hashbrown 0.15.2", "home", "itoa", "memchr", @@ -1653,12 +1633,13 @@ dependencies = [ [[package]] name = "polars-lazy" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa457bfa96f45cf14c33507eaa3ebcec6a8d52e7f7fc60cd23f338631369d417" +checksum = "a0a731a672dfc8ac38c1f73c9a4b2ae38d2fc8ac363bfb64c5f3a3e072ffc5ad" dependencies = [ "ahash", - "bitflags 2.6.0", + "bitflags 2.9.0", + "chrono", "memchr", "once_cell", "polars-arrow", @@ -1678,9 +1659,9 @@ dependencies = [ [[package]] name = "polars-mem-engine" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73aa56fc0a4c1e9d56b4a4485800f4780ca214030d32d0150eccc44f71d6dab" +checksum = "33442189bcbf2e2559aa7914db3835429030a13f4f18e43af5fba9d1b018cf12" dependencies = [ "memmap2", "polars-arrow", @@ -1697,9 +1678,9 @@ dependencies = [ [[package]] name = "polars-ops" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b267480495ffe382dab63318e3c6bf4073bb82971c8b80294d079293fece458b" +checksum = "cbb83218b0c216104f0076cd1a005128be078f958125f3d59b094ee73d78c18e" dependencies = [ "ahash", "argminmax", @@ -1708,11 +1689,12 @@ dependencies = [ "chrono", "chrono-tz", "either", - "hashbrown 0.15.1", + "hashbrown 0.15.2", "hex", - "indexmap 2.5.0", + "indexmap 2.9.0", "memchr", "num-traits", + "once_cell", "polars-arrow", "polars-compute", "polars-core", @@ -1723,15 +1705,16 @@ dependencies = [ "regex", "regex-syntax", "strum_macros", + "unicode-normalization", "unicode-reverse", "version_check", ] [[package]] name = "polars-parquet" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20237f232b1a74b1fae6b5c9bea8c440f2e5d3b5506601b038f0a7a34b84b710" +checksum = "5c60ee85535590a38db6c703a21be4cb25342e40f573f070d1e16f9d84a53ac7" dependencies = [ "ahash", "async-stream", @@ -1739,7 +1722,7 @@ dependencies = [ "bytemuck", "ethnum", "futures", - "hashbrown 0.15.1", + "hashbrown 0.15.2", "num-traits", "polars-arrow", "polars-compute", @@ -1762,15 +1745,16 @@ dependencies = [ [[package]] name = "polars-pipe" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e3066f4fea8e55e72eba54ffe20ebdf08f63b9691aba8ea1135c3aeb9c2c7e" +checksum = "42d238fb76698f56e51ddfa89b135e4eda56a4767c6e8859eed0ab78386fcd52" dependencies = [ "crossbeam-channel", "crossbeam-queue", "enum_dispatch", - "hashbrown 0.15.1", + "hashbrown 0.15.2", "num-traits", + "once_cell", "polars-arrow", "polars-compute", "polars-core", @@ -1787,18 +1771,18 @@ dependencies = [ [[package]] name = "polars-plan" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99a3832887671df1eb326df52cbfcc47789d3d58454c1084a154b48b240175e2" +checksum = "4f03533a93aa66127fcb909a87153a3c7cfee6f0ae59f497e73d7736208da54c" dependencies = [ "ahash", - "bitflags 2.6.0", + "bitflags 2.9.0", "bytemuck", "bytes", "chrono", "chrono-tz", "either", - "hashbrown 0.15.1", + "hashbrown 0.15.2", "memmap2", "num-traits", "once_cell", @@ -1819,11 +1803,11 @@ dependencies = [ [[package]] name = "polars-row" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e36350fb8a90238e02c8ece0f0c4c24f3374197e9c08c1c22cc8b9c526e6c25" +checksum = "6bf47f7409f8e75328d7d034be390842924eb276716d0458607be0bddb8cc839" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "bytemuck", "polars-arrow", "polars-compute", @@ -1833,11 +1817,11 @@ dependencies = [ [[package]] name = "polars-schema" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6aa4913cffc522cea3ccbc0cafb350bec18fed0a1ef8d417ac88ea320d7749" +checksum = "416621ae82b84466cf4ff36838a9b0aeb4a67e76bd3065edc8c9cb7da19b1bc7" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.9.0", "polars-error", "polars-utils", "version_check", @@ -1845,13 +1829,11 @@ dependencies = [ [[package]] name = "polars-sql" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a2247028629b1db384437a9f2792488f0ddb539ec16fb46a5e2bceeba6dbc" +checksum = "edaab553b90aa4d6743bb538978e1982368acb58a94408d7dd3299cad49c7083" dependencies = [ "hex", - "once_cell", - "polars-arrow", "polars-core", "polars-error", "polars-lazy", @@ -1860,16 +1842,16 @@ dependencies = [ "polars-time", "polars-utils", "rand", + "regex", "serde", - "serde_json", "sqlparser", ] [[package]] name = "polars-stream" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8cd9da4b063146c3ab7c08678a52eb9d466ade4f4c8617605a5a3ea063002c6" +checksum = "498997b656c779610c1496b3d96a59fe569ef22a5b81ccfe5325cb3df8dff2fd" dependencies = [ "atomic-waker", "crossbeam-deque", @@ -1897,15 +1879,16 @@ dependencies = [ [[package]] name = "polars-time" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f005c3441eed1a96464305f73e197813cbae7894ff6712726a1182e31f52b4" +checksum = "d192efbdab516d28b3fab1709a969e3385bd5cda050b7c9aa9e2502a01fda879" dependencies = [ - "atoi", + "atoi_simd", "bytemuck", "chrono", "chrono-tz", "now", + "num-traits", "once_cell", "polars-arrow", "polars-compute", @@ -1913,22 +1896,23 @@ dependencies = [ "polars-error", "polars-ops", "polars-utils", + "rayon", "regex", "strum_macros", ] [[package]] name = "polars-utils" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0fc010eea42ad113b641aa53106e4d6e474650c73573d959a546eed0ce6d479" +checksum = "a8f6c8166a4a7fbc15b87c81645ed9e1f0651ff2e8c96cafc40ac5bf43441a10" dependencies = [ "ahash", "bytemuck", "bytes", "compact_str", - "hashbrown 0.15.1", - "indexmap 2.5.0", + "hashbrown 0.15.2", + "indexmap 2.9.0", "libc", "memmap2", "num-traits", @@ -1950,28 +1934,28 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy", + "zerocopy 0.8.24", ] [[package]] name = "prettyplease" -version = "0.2.25" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" dependencies = [ "proc-macro2", - "syn 2.0.87", + "syn", ] [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] @@ -1992,14 +1976,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" dependencies = [ "quote", - "syn 2.0.87", + "syn", ] [[package]] name = "psm" -version = "0.1.23" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205" +checksum = "f58e5423e24c18cc840e1c98370b3993c6649cd1678b4d24318bcf0a083cbe88" dependencies = [ "cc", ] @@ -2021,13 +2005,19 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "rand" version = "0.8.5" @@ -2055,7 +2045,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -2120,11 +2110,11 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "11.1.0" +version = "11.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb9ee317cfe3fbd54b36a511efc1edd42e216903c9cd575e686dd68a2ba90d8d" +checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", ] [[package]] @@ -2164,23 +2154,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76009fbe0614077fc1a2ce255e3a1881a2e3a3527097d5dc6d8212c585e7e38b" dependencies = [ "quote", - "syn 2.0.87", + "syn", ] [[package]] name = "redox_syscall" -version = "0.5.4" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", ] [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -2190,9 +2180,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -2213,13 +2203,12 @@ checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" [[package]] name = "rinja" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a73141aab0b35b30bb993f5c832b8c9211709563b8b95517713b7d00ebb063e" +checksum = "3dc4940d00595430b3d7d5a01f6222b5e5b51395d1120bdb28d854bb8abb17a5" dependencies = [ "humansize", "itoa", - "num-traits", "percent-encoding", "rinja_derive", "serde", @@ -2228,28 +2217,27 @@ dependencies = [ [[package]] name = "rinja_derive" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b0baa0b963e94a919d0dcad5be1e2d30dcc0fdab93d9803ab4a019e188647c" +checksum = "08d9ed0146aef6e2825f1b1515f074510549efba38d71f4554eec32eb36ba18b" dependencies = [ "basic-toml", "memchr", "mime", "mime_guess", - "once_map", "proc-macro2", "quote", "rinja_parser", "rustc-hash", "serde", - "syn 2.0.87", + "syn", ] [[package]] name = "rinja_parser" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27303ef1ee98bb4240e3dd417f26459061e068d331b7ad05576167da3ae59a4e" +checksum = "93f9a866e2e00a7a1fb27e46e9e324a6f7c0e7edc4543cae1d38f4e4a100c610" dependencies = [ "memchr", "nom", @@ -2264,21 +2252,34 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "scopeguard" @@ -2288,29 +2289,29 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn", ] [[package]] name = "serde_json" -version = "1.0.134" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -2320,13 +2321,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn", ] [[package]] @@ -2340,15 +2341,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.9.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ "base64", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.5.0", + "indexmap 2.9.0", "serde", "serde_derive", "serde_json", @@ -2358,14 +2359,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.9.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.87", + "syn", ] [[package]] @@ -2391,15 +2392,15 @@ dependencies = [ [[package]] name = "simdutf8" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "siphasher" -version = "0.3.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" @@ -2421,15 +2422,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" dependencies = [ "libc", "windows-sys 0.52.0", @@ -2437,24 +2438,18 @@ dependencies = [ [[package]] name = "sqlparser" -version = "0.52.0" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a875d8cd437cc8a97e9aeaeea352ec9a19aea99c23e9effb17757291de80b08" +checksum = "05a528114c392209b3264855ad491fcce534b94a38771b0a0b97a79379275ce8" dependencies = [ "log", ] -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "stacker" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799c883d55abdb5e98af1a7b3f23b9b6de8ecada0ecac058672d7635eb48ca7b" +checksum = "601f9201feb9b09c00266478bf459952b9ef9a6b94edb2f21eba14ab681a60a9" dependencies = [ "cc", "cfg-if", @@ -2496,12 +2491,6 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" - [[package]] name = "strum_macros" version = "0.26.4" @@ -2512,25 +2501,14 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.87", + "syn", ] [[package]] name = "syn" -version = "1.0.109" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -2539,9 +2517,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.32.1" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c33cd241af0f2e9e3b5c32163b873b29956890b5342e6745b917ce9d490f4af" +checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01" dependencies = [ "core-foundation-sys", "libc", @@ -2563,12 +2541,6 @@ dependencies = [ "version-compare", ] -[[package]] -name = "target-features" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1bbb9f3c5c463a01705937a24fdabc5047929ac764b2d5b9cf681c1f5041ed5" - [[package]] name = "target-lexicon" version = "0.12.16" @@ -2586,11 +2558,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.9" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.9", + "thiserror-impl 2.0.12", ] [[package]] @@ -2601,18 +2573,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn", ] [[package]] name = "thiserror-impl" -version = "2.0.9" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn", ] [[package]] @@ -2628,9 +2600,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", @@ -2643,25 +2615,40 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", ] +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" -version = "1.41.0" +version = "1.44.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" +checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" dependencies = [ "backtrace", "bytes", @@ -2674,9 +2661,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" dependencies = [ "bytes", "futures-core", @@ -2687,9 +2674,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" dependencies = [ "serde", "serde_spanned", @@ -2708,11 +2695,11 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.9.0", "serde", "serde_spanned", "toml_datetime", @@ -2721,24 +2708,30 @@ dependencies = [ [[package]] name = "typeid" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-normalization" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] [[package]] name = "unicode-reverse" @@ -2757,17 +2750,17 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "uuid" -version = "1.10.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" dependencies = [ - "getrandom", + "getrandom 0.3.2", ] [[package]] @@ -2799,37 +2792,46 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2837,22 +2839,25 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "weezl" @@ -2894,23 +2899,27 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.52.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ + "windows-implement 0.57.0", + "windows-interface 0.57.0", + "windows-result 0.1.2", "windows-targets", ] [[package]] name = "windows-core" -version = "0.57.0" +version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-targets", + "windows-implement 0.60.0", + "windows-interface 0.59.1", + "windows-link", + "windows-result 0.3.2", + "windows-strings", ] [[package]] @@ -2921,7 +2930,18 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -2932,9 +2952,26 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn", ] +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + [[package]] name = "windows-result" version = "0.1.2" @@ -2944,6 +2981,24 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -3028,18 +3083,27 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.22" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980" +checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" dependencies = [ "memchr", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.0", +] + [[package]] name = "xxhash-rust" -version = "0.8.12" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" [[package]] name = "zerocopy" @@ -3047,8 +3111,16 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +dependencies = [ + "zerocopy-derive 0.8.24", ] [[package]] @@ -3059,32 +3131,43 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "zstd" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.2.1" +version = "7.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" +version = "2.0.15+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index 3083fe4..e415c49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "plotlars" -version = "0.8.0" +version = "0.9.0" authors = ["Alberto Cebada Aleu "] -edition = "2021" -rust-version = "1.80.1" +edition = "2024" +rust-version = "1.86.0" description = "Plotlars is a Rust library designed to facilitate the integration between the Polars data analysis library and visualization libraries." documentation = "https://docs.rs/plotlars/latest/plotlars/" readme = "README.md" @@ -14,9 +14,11 @@ keywords = ["chart", "plot", "plotly", "polars", "visualization"] categories = ["visualization"] [dependencies] -bon = "3.3.2" -image = "0.25.5" +bon = "3.6.3" +image = "0.25.6" +indexmap = "2.9.0" +ordered-float = "5.0.0" plotly = "0.12.1" -polars = { version = "0.45.1", features = ["lazy", "strings"] } -serde = "1.0.217" -serde_json = "1.0.134" +polars = { version = "0.46.0", features = ["lazy", "strings"] } +serde = "1.0.219" +serde_json = "1.0.140" diff --git a/README.md b/README.md index f22aa95..439fa13 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,16 @@ Plotly. It simplifies the process of creating visualizations from data frames, allowing developers to focus on data insights rather than the intricacies of plot creation. +## Implemented Plots Overview + +| Plot | Example | Plot | Example | Plot | Example | +|------|:---------:|------|:---------:|------|:---------:| +| [Array 2D](https://docs.rs/plotlars/latest/plotlars/struct.Array2dPlot.html) | | [Bar Plot](https://docs.rs/plotlars/latest/plotlars/struct.BarPlot.html) | | [Box Plot](https://docs.rs/plotlars/latest/plotlars/struct.BoxPlot.html) | | +| [Contour Plot](https://docs.rs/plotlars/latest/plotlars/struct.ContourPlot.html) | | [Heat Map](https://docs.rs/plotlars/latest/plotlars/struct.HeatMap.html) | | [Histogram](https://docs.rs/plotlars/latest/plotlars/struct.Histogram.html) | | +| [Image](https://docs.rs/plotlars/latest/plotlars/struct.Image.html) | | [Line Plot](https://docs.rs/plotlars/latest/plotlars/struct.LinePlot.html) | | [Pie Chart](https://docs.rs/plotlars/latest/plotlars/struct.PieChart.html) | | +| [Sankey Diagram](https://docs.rs/plotlars/latest/plotlars/struct.SankeyDiagram.html) | | [Scatter 3D Plot](https://docs.rs/plotlars/latest/plotlars/struct.Scatter3dPlot.html) | | [Scatter Map](https://docs.rs/plotlars/latest/plotlars/struct.ScatterMap.html) | | +| [Scatter Plot](https://docs.rs/plotlars/latest/plotlars/struct.ScatterPlot.html) | | [Surface Plot](https://docs.rs/plotlars/latest/plotlars/struct.SurfacePlot.html) | | [Time Series](https://docs.rs/plotlars/latest/plotlars/struct.TimeSeriesPlot.html) | | + ## Motivation The creation of Plotlars was driven by the need to simplify the process of diff --git a/src/common/layout.rs b/src/common/layout.rs index fe79b07..9de5aca 100644 --- a/src/common/layout.rs +++ b/src/common/layout.rs @@ -8,10 +8,12 @@ pub(crate) trait Layout { plot_title: Option, x_title: Option, y_title: Option, + y2_title: Option, z_title: Option, legend_title: Option, x_axis: Option<&Axis>, y_axis: Option<&Axis>, + y2_axis: Option<&Axis>, z_axis: Option<&Axis>, legend: Option<&Legend>, ) -> LayoutPlotly { @@ -21,10 +23,11 @@ pub(crate) trait Layout { layout = layout.title(title.to_plotly()); } - layout = layout.x_axis(Axis::set_axis(x_title, x_axis)); - layout = layout.y_axis(Axis::set_axis(y_title, y_axis)); - layout = layout.z_axis(Axis::set_axis(z_title, z_axis)); - layout = layout.legend(Legend::set_legend(legend_title, legend)); layout + .x_axis(Axis::set_axis(x_title, x_axis, None)) + .y_axis(Axis::set_axis(y_title, y_axis, None)) + .y_axis2(Axis::set_axis(y2_title, y2_axis, Some("y"))) + .z_axis(Axis::set_axis(z_title, z_axis, None)) + .legend(Legend::set_legend(legend_title, legend)) } } diff --git a/src/common/mod.rs b/src/common/mod.rs index 856e02a..3f1ae68 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -4,8 +4,10 @@ pub(crate) mod mark; pub(crate) mod plot; pub(crate) mod polar; -pub(crate) use layout::Layout; -pub(crate) use line::Line; -pub(crate) use mark::Marker; -pub(crate) use plot::PlotHelper; -pub(crate) use polar::Polar; +pub(crate) use { + layout::Layout, + line::Line, + mark::Marker, + plot::PlotHelper, + polar::Polar, +}; diff --git a/src/common/plot.rs b/src/common/plot.rs index 8a5212a..c9a173f 100644 --- a/src/common/plot.rs +++ b/src/common/plot.rs @@ -1,6 +1,11 @@ use std::env; -use plotly::{Layout, Plot as Plotly, Trace}; +use plotly::{ + Layout, + Plot as Plotly, + Trace, +}; + use serde::Serialize; /// A trait representing a generic plot that can be displayed or rendered. diff --git a/src/common/polar.rs b/src/common/polar.rs index 725ddf3..e5a4755 100644 --- a/src/common/polar.rs +++ b/src/common/polar.rs @@ -1,6 +1,6 @@ use polars::{ frame::DataFrame, - prelude::{col, lit, DataType, IntoLazy}, + prelude::{DataType, IntoLazy, col, lit}, }; pub(crate) trait Polar { diff --git a/src/components/arrangement.rs b/src/components/arrangement.rs new file mode 100644 index 0000000..2b5f420 --- /dev/null +++ b/src/components/arrangement.rs @@ -0,0 +1,69 @@ +use plotly::sankey::Arrangement as ArrangementPlotly; + +/// An enumeration representing node arrangement strategies for Sankey diagrams. +/// +/// The `Arrangement` enum controls how nodes are positioned relative to each other: +/// +/// * `Snap` — If value is `snap` (the default), the node arrangement is assisted by +/// automatic snapping of elements to preserve space between nodes specified via `nodepad`. +/// * `Perpendicular` — Nodes can only move along a line perpendicular to the primary flow. +/// * `Freeform` — Nodes can freely move anywhere on the plane without automatic constraints. +/// * `Fixed` — Nodes remain stationary at their specified positions and are not adjusted by the layout algorithm. +/// +/// # Example +/// +/// ```rust +/// use plotlars::{Arrangement, SankeyDiagram, Orientation, Plot, Rgb, Text}; +/// use polars::prelude::*; +/// +/// let dataset = df![ +/// "source" => &["A1", "A2", "A1", "B1", "B2", "B2"], +/// "target" => &["B1", "B2", "B2", "C1", "C1", "C2"], +/// "value" => &[8, 4, 2, 8, 4, 2], +/// ].unwrap(); +/// +/// SankeyDiagram::builder() +/// .data(&dataset) +/// .sources("source") +/// .targets("target") +/// .values("value") +/// .orientation(Orientation::Horizontal) +/// .arrangement(Arrangement::Freeform) +/// .node_colors(vec![ +/// Rgb(222, 235, 247), +/// Rgb(198, 219, 239), +/// Rgb(158, 202, 225), +/// Rgb(107, 174, 214), +/// Rgb( 66, 146, 198), +/// Rgb( 33, 113, 181), +/// ]) +/// .link_colors(vec![ +/// Rgb(222, 235, 247), +/// Rgb(198, 219, 239), +/// Rgb(158, 202, 225), +/// Rgb(107, 174, 214), +/// Rgb( 66, 146, 198), +/// Rgb( 33, 113, 181), +/// ]) +/// .build() +/// .plot(); +/// ``` +/// +/// ![Example Sankey Diagram](https://imgur.com/oCvuAZB.png) +pub enum Arrangement { + Snap, + Perpendicular, + Freeform, + Fixed, +} + +impl Arrangement { + pub(crate) fn to_plotly(&self) -> ArrangementPlotly { + match self { + Arrangement::Snap => ArrangementPlotly::Snap, + Arrangement::Perpendicular => ArrangementPlotly::Perpendicular, + Arrangement::Freeform => ArrangementPlotly::Freeform, + Arrangement::Fixed => ArrangementPlotly::Fixed, + } + } +} diff --git a/src/components/axis.rs b/src/components/axis.rs index 4411523..9d0bc69 100644 --- a/src/components/axis.rs +++ b/src/components/axis.rs @@ -1,6 +1,12 @@ use plotly::{ - common::{AxisSide as AxisSidePlotly, Font}, - layout::{Axis as AxisPlotly, AxisType as AxisTypePlotly}, + common::{ + AxisSide as AxisSidePlotly, + Font, + }, + layout::{ + Axis as AxisPlotly, + AxisType as AxisTypePlotly, + }, }; use crate::components::{Rgb, Text, TickDirection, ValueExponent}; @@ -343,7 +349,11 @@ impl Axis { self } - pub(crate) fn set_axis(title: Option, format: Option<&Axis>) -> AxisPlotly { + pub(crate) fn set_axis( + title: Option, + format: Option<&Self>, + overlaying: Option<&str>, + ) -> AxisPlotly { let mut axis = AxisPlotly::new(); if let Some(title) = title { @@ -351,13 +361,21 @@ impl Axis { } if let Some(format) = format { - axis = Self::set_format(axis, format); + axis = Self::set_format(axis, format, overlaying); } axis } - fn set_format(mut axis: AxisPlotly, format: &Axis) -> AxisPlotly { + fn set_format( + mut axis: AxisPlotly, + format: &Self, + overlaying: Option<&str>, + ) -> AxisPlotly { + if let Some(overlaying) = overlaying { + axis = axis.overlaying(overlaying); + } + if let Some(visible) = format.show_axis { axis = axis.visible(visible.to_owned()); } diff --git a/src/components/color.rs b/src/components/color.rs index 95d86cc..1602ae2 100644 --- a/src/components/color.rs +++ b/src/components/color.rs @@ -1,4 +1,8 @@ -use plotly::color::{Color, Rgb as RgbPlotly}; +use plotly::color::{ + Color, + Rgb as RgbPlotly, +}; + use serde::Serialize; /// A structure representing an RGB color with red, green, and blue components. @@ -8,15 +12,12 @@ use serde::Serialize; /// ```rust /// use plotlars::{Axis, BarPlot, Legend, Orientation, Plot, Rgb}; /// -/// let label = vec!["", "", ""]; -/// let color = vec!["red", "green", "blue"]; -/// let value = vec![1, 1, 1]; -/// -/// let df = DataFrame::new(vec![ -/// Series::new("label".into(), label), -/// Series::new("color".into(), color), -/// Series::new("value".into(), value), -/// ]).unwrap(); +/// let dataset = df![ +/// "label" => &["", "", ""], +/// "color" => &["red", "green", "blue"], +/// "value" => &[1, 1, 1], +/// ] +/// .unwrap(); /// /// let axis = Axis::new() /// .show_axis(false); @@ -26,7 +27,7 @@ use serde::Serialize; /// .x(0.3); /// /// BarPlot::builder() -/// .data(&df) +/// .data(&dataset) /// .labels("label") /// .values("value") /// .group("color") diff --git a/src/components/colorbar.rs b/src/components/colorbar.rs index dc683bf..84003f8 100644 --- a/src/components/colorbar.rs +++ b/src/components/colorbar.rs @@ -1,4 +1,7 @@ -use plotly::common::{ColorBar as ColorBarPlotly, Font}; +use plotly::common::{ + ColorBar as ColorBarPlotly, + Font, +}; use crate::components::{Orientation, Rgb, Text, TickDirection, ValueExponent}; @@ -70,6 +73,108 @@ impl ColorBar { Self::default() } + pub(crate) fn to_plotly(&self) -> ColorBarPlotly { + let mut color_bar = ColorBarPlotly::new(); + + if let Some(color) = &self.background_color { + color_bar = color_bar.background_color(color.to_plotly()); + } + + if let Some(color) = &self.border_color { + color_bar = color_bar.border_color(color.to_plotly()); + } + + if let Some(width) = self.border_width { + color_bar = color_bar.border_width(width); + } + + if let Some(step) = self.tick_step { + color_bar = color_bar.dtick(step); + } + + if let Some(value_exponent) = &self.value_exponent { + color_bar = color_bar.exponent_format(value_exponent.to_plotly()); + } + + if let Some(length) = self.length { + color_bar = color_bar + .len_mode(plotly::common::ThicknessMode::Pixels) + .len(length); + } + + if let Some(n_ticks) = self.n_ticks { + color_bar = color_bar.n_ticks(n_ticks); + } + + if let Some(orientation) = &self.orientation { + color_bar = color_bar.orientation(orientation.to_plotly()); + } + + if let Some(color) = self.outline_color { + color_bar = color_bar.outline_color(color.to_plotly()); + } + + if let Some(width) = self.outline_width { + color_bar = color_bar.outline_width(width); + } + + if let Some(separate_thousands) = self.separate_thousands { + color_bar = color_bar.separate_thousands(separate_thousands); + } + + if let Some(width) = self.width { + color_bar = color_bar + .thickness_mode(plotly::common::ThicknessMode::Pixels) + .thickness(width); + } + + if let Some(angle) = self.tick_angle { + color_bar = color_bar.tick_angle(angle); + } + + if let Some(color) = self.tick_color { + color_bar = color_bar.tick_color(color.to_plotly()); + } + + if let Some(font) = &self.tick_font { + color_bar = color_bar.tick_font(Font::new().family(font.as_str())); + } + + if let Some(length) = self.tick_length { + color_bar = color_bar.tick_len(length); + } + + if let Some(labels) = &self.tick_labels { + color_bar = color_bar.tick_text(labels.to_owned()) + } + + if let Some(values) = &self.tick_values { + color_bar = color_bar.tick_vals(values.to_owned()); + } + + if let Some(width) = self.tick_width { + color_bar = color_bar.tick_width(width); + } + + if let Some(tick_direction) = &self.tick_direction { + color_bar = color_bar.ticks(tick_direction.to_plotly_ticks()); + } + + if let Some(title) = &self.title { + color_bar = color_bar.title(title.to_plotly()); + } + + if let Some(x) = self.x { + color_bar = color_bar.x(x); + } + + if let Some(y) = self.y { + color_bar = color_bar.y(y); + } + + color_bar + } + /// Sets the background color of the color bar. /// /// # Arguments @@ -299,106 +404,4 @@ impl ColorBar { self.y = Some(y); self } - - pub(crate) fn to_plotly(&self) -> ColorBarPlotly { - let mut color_bar = ColorBarPlotly::new(); - - if let Some(color) = &self.background_color { - color_bar = color_bar.background_color(color.to_plotly()); - } - - if let Some(color) = &self.border_color { - color_bar = color_bar.border_color(color.to_plotly()); - } - - if let Some(width) = self.border_width { - color_bar = color_bar.border_width(width); - } - - if let Some(step) = self.tick_step { - color_bar = color_bar.dtick(step); - } - - if let Some(value_exponent) = &self.value_exponent { - color_bar = color_bar.exponent_format(value_exponent.to_plotly()); - } - - if let Some(length) = self.length { - color_bar = color_bar - .len_mode(plotly::common::ThicknessMode::Pixels) - .len(length); - } - - if let Some(n_ticks) = self.n_ticks { - color_bar = color_bar.n_ticks(n_ticks); - } - - if let Some(orientation) = &self.orientation { - color_bar = color_bar.orientation(orientation.to_plotly()); - } - - if let Some(color) = self.outline_color { - color_bar = color_bar.outline_color(color.to_plotly()); - } - - if let Some(width) = self.outline_width { - color_bar = color_bar.outline_width(width); - } - - if let Some(separate_thousands) = self.separate_thousands { - color_bar = color_bar.separate_thousands(separate_thousands); - } - - if let Some(width) = self.width { - color_bar = color_bar - .thickness_mode(plotly::common::ThicknessMode::Pixels) - .thickness(width); - } - - if let Some(angle) = self.tick_angle { - color_bar = color_bar.tick_angle(angle); - } - - if let Some(color) = self.tick_color { - color_bar = color_bar.tick_color(color.to_plotly()); - } - - if let Some(font) = &self.tick_font { - color_bar = color_bar.tick_font(Font::new().family(font.as_str())); - } - - if let Some(length) = self.tick_length { - color_bar = color_bar.tick_len(length); - } - - if let Some(labels) = &self.tick_labels { - color_bar = color_bar.tick_text(labels.to_owned()) - } - - if let Some(values) = &self.tick_values { - color_bar = color_bar.tick_vals(values.to_owned()); - } - - if let Some(width) = self.tick_width { - color_bar = color_bar.tick_width(width); - } - - if let Some(tick_direction) = &self.tick_direction { - color_bar = color_bar.ticks(tick_direction.to_plotly_ticks()); - } - - if let Some(title) = &self.title { - color_bar = color_bar.title(title.to_plotly()); - } - - if let Some(x) = self.x { - color_bar = color_bar.x(x); - } - - if let Some(y) = self.y { - color_bar = color_bar.y(y); - } - - color_bar - } } diff --git a/src/components/coloring.rs b/src/components/coloring.rs new file mode 100644 index 0000000..e689fa6 --- /dev/null +++ b/src/components/coloring.rs @@ -0,0 +1,46 @@ +use plotly::contour::Coloring as ColoringPlotly; + +/// Enumeration representing the coloring strategy applied to contour levels. +/// +/// # Example +/// +/// ```rust +/// use polars::prelude::*; +/// use plotlars::{ Coloring, ContourPlot, Contours, Palette, Plot }; +/// +/// let dataset = df!( +/// "x" => &[0.0, 0.0, 0.0, 2.5, 2.5, 2.5, 5.0, 5.0, 5.0], +/// "y" => &[0.0, 7.5, 15.0, 0.0, 7.5, 15.0, 0.0, 7.5, 15.0], +/// "z" => &[0.0, 5.0, 10.0, 5.0, 2.5, 5.0, 10.0, 0.0, 0.0], +/// ) +/// .unwrap(); +/// +/// ContourPlot::builder() +/// .data(&dataset) +/// .x("x") +/// .y("y") +/// .z("z") +/// .coloring(Coloring::Lines) +/// .color_scale(Palette::Viridis) +/// .build() +/// .plot(); +/// ``` +/// +/// ![Example](https://imgur.com/hFD2A82.png) +pub enum Coloring { + Fill, + HeatMap, + Lines, + None, +} + +impl Coloring { + pub(crate) fn to_plotly(&self) -> ColoringPlotly { + match self { + Coloring::Fill => ColoringPlotly::Fill, + Coloring::HeatMap => ColoringPlotly::HeatMap, + Coloring::Lines => ColoringPlotly::Lines, + Coloring::None => ColoringPlotly::None, + } + } +} diff --git a/src/components/legend.rs b/src/components/legend.rs index 8c6c057..c787b03 100644 --- a/src/components/legend.rs +++ b/src/components/legend.rs @@ -1,4 +1,7 @@ -use plotly::{common::Font, layout::Legend as LegendPlotly}; +use plotly::{ + common::Font, + layout::Legend as LegendPlotly, +}; use crate::{Orientation, Rgb, Text}; diff --git a/src/components/lighting.rs b/src/components/lighting.rs new file mode 100644 index 0000000..701b479 --- /dev/null +++ b/src/components/lighting.rs @@ -0,0 +1,184 @@ +use plotly::surface::Lighting as LightingPlotly; + +/// A structure describing the lighting model. +/// +/// # Example +/// +/// ```rust +/// use ndarray::Array; +/// use plotlars::{ColorBar, Lighting, Palette, Plot, SurfacePlot, Text}; +/// use polars::prelude::*; +/// use std::iter; +/// +/// let n: usize = 100; +/// let x_base: Vec = Array::linspace(-10.0, 10.0, n).into_raw_vec(); +/// let y_base: Vec = Array::linspace(-10.0, 10.0, n).into_raw_vec(); +/// +/// let x = x_base +/// .iter() +/// .flat_map(|&xi| iter::repeat(xi).take(n)) +/// .collect::>(); +/// +/// let y = y_base +/// .iter() +/// .cycle() +/// .take(n * n) +/// .cloned() +/// .collect::>(); +/// +/// let z = x_base +/// .iter() +/// .map(|i| { +/// y_base +/// .iter() +/// .map(|j| 1.0 / (j * j + 5.0) * j.sin() + 1.0 / (i * i + 5.0) * i.cos()) +/// .collect::>() +/// }) +/// .flatten() +/// .collect::>(); +/// +/// let dataset = df![ +/// "x" => &x, +/// "y" => &y, +/// "z" => &z, +/// ] +/// .unwrap(); +/// +/// SurfacePlot::builder() +/// .data(&dataset) +/// .x("x") +/// .y("y") +/// .z("z") +/// .plot_title( +/// Text::from("Surface Plot") +/// .font("Arial") +/// .size(18), +/// ) +/// .color_bar( +/// &ColorBar::new() +/// .border_width(1), +/// ) +/// .color_scale(Palette::Cividis) +/// .reverse_scale(true) +/// .lighting( +/// &Lighting::new() +/// .position(1, 0, 0) +/// .ambient(1.0) +/// .diffuse(1.0) +/// .fresnel(1.0) +/// .roughness(1.0) +/// .specular(1.0), +/// ) +/// .opacity(0.5) +/// .build() +/// .plot(); +/// ``` +/// +/// ![example](https://imgur.com/LEjedUE.png) +#[derive(Default, Clone)] +pub struct Lighting { + pub(crate) position: Option<[i32; 3]>, + pub(crate) ambient: Option, + pub(crate) diffuse: Option, + pub(crate) fresnel: Option, + pub(crate) roughness: Option, + pub(crate) specular: Option, +} + +impl Lighting { + /// Creates a new `Lighting` instance with default values. + pub fn new() -> Self { + Self::default() + } + + /// Sets the position of the virtual light source. + /// + /// # Arguments + /// + /// * `x` – An `i32` value representing the *x*‑coordinate of the light. + /// * `y` – An `i32` value representing the *y*‑coordinate of the light. + /// * `z` – An `i32` value representing the *z*‑coordinate of the light (positive z points toward the viewer). + pub fn position(mut self, x: i32, y:i32, z: i32) -> Self { + self.position = Some([x, y, z]); + self + } + + /// Sets the ambient light component. + /// + /// # Arguments + /// + /// * `value` – A `f64` value in the range 0.0 – 1.0 specifying the uniform tint strength. + pub fn ambient(mut self, value: f64) -> Self { + self.ambient = Some(value); + self + } + + /// Sets the diffuse light component. + /// + /// # Arguments + /// + /// * `value` – A `f64` value in the range 0.0 – 1.0 specifying the Lambertian reflection strength. + pub fn diffuse(mut self, value: f64) -> Self { + self.diffuse = Some(value); + self + } + + /// Sets the Fresnel (edge brightness) component. + /// + /// # Arguments + /// + /// * `value` – A `f64` value in the range 0.0 – 1.0 specifying the rim‑light intensity. + pub fn fresnel(mut self, value: f64) -> Self { + self.fresnel = Some(value); + self + } + + /// Sets the roughness of the material. + /// + /// # Arguments + /// + /// * `value` – A `f64` value in the range 0.0 – 1.0 that controls highlight width (0.0 = glossy, 1.0 = matte). + pub fn roughness(mut self, value: f64) -> Self { + self.roughness = Some(value); + self + } + + /// Sets the specular highlight intensity. + /// + /// # Arguments + /// + /// * `value` – A `f64` value in the range 0.0 – 1.0 specifying the mirror‑like highlight strength. + pub fn specular(mut self, value: f64) -> Self { + self.specular = Some(value); + self + } + + pub(crate) fn set_lighting(lighting: Option<&Self>) -> LightingPlotly { + let mut lighting_plotly = LightingPlotly::new(); + + if let Some(light) = lighting { + if let Some(ambient) = light.ambient { + lighting_plotly = lighting_plotly.ambient(ambient); + } + + if let Some(diffuse) = light.diffuse { + lighting_plotly = lighting_plotly.diffuse(diffuse); + } + + if let Some(fresnel) = light.fresnel { + lighting_plotly = lighting_plotly.fresnel(fresnel); + } + + if let Some(roughness) = light.roughness { + lighting_plotly = lighting_plotly.roughness(roughness); + } + + if let Some(specular) = light.specular { + lighting_plotly = lighting_plotly.specular(specular); + } + } + + lighting_plotly + } + +} diff --git a/src/components/mod.rs b/src/components/mod.rs index 301246a..9ab9758 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -1,8 +1,11 @@ +pub(crate) mod arrangement; pub(crate) mod axis; pub(crate) mod color; pub(crate) mod colorbar; +pub(crate) mod coloring; pub(crate) mod exponent; pub(crate) mod legend; +pub(crate) mod lighting; pub(crate) mod line; pub(crate) mod orientation; pub(crate) mod palette; @@ -10,12 +13,19 @@ pub(crate) mod shape; pub(crate) mod text; pub(crate) mod tick; -pub(crate) use axis::Axis; -pub(crate) use color::Rgb; -pub(crate) use exponent::ValueExponent; -pub(crate) use legend::Legend; -pub(crate) use line::Line; -pub(crate) use orientation::Orientation; -pub(crate) use shape::Shape; -pub(crate) use text::Text; -pub(crate) use tick::TickDirection; +pub(crate) use { + arrangement::Arrangement, + axis::Axis, + color::Rgb, + colorbar::ColorBar, + coloring::Coloring, + exponent::ValueExponent, + legend::Legend, + lighting::Lighting, + line::Line, + orientation::Orientation, + palette::Palette, + shape::Shape, + text::Text, + tick::TickDirection, +}; diff --git a/src/components/orientation.rs b/src/components/orientation.rs index 42a8e29..89e89fb 100644 --- a/src/components/orientation.rs +++ b/src/components/orientation.rs @@ -7,25 +7,13 @@ use plotly::common::Orientation as OrientationPlotly; /// ```rust /// use plotlars::{BarPlot, Legend, Orientation, Plot, Rgb}; /// -/// let animal = vec![ -/// "giraffe", -/// "giraffe", -/// "orangutan", -/// "orangutan", -/// "monkey", -/// "monkey", -/// ]; -/// let gender = vec!["female", "male", "female", "male", "female", "male"]; -/// let value = vec![20.0f32, 25.0, 14.0, 18.0, 23.0, 31.0]; -/// let error = vec![1.0, 0.5, 1.5, 1.0, 0.5, 1.5]; -/// -/// let dataset = DataFrame::new(vec![ -/// Series::new("animal".into(), animal), -/// Series::new("gender".into(), gender), -/// Series::new("value".into(), value), -/// Series::new("error".into(), error), -/// ]) -/// .unwrap(); +/// let dataset = df![ +/// "animal" => &["giraffe", "giraffe", "orangutan", "orangutan", "monkey", "monkey"], +/// "gender" => &vec!["female", "male", "female", "male", "female", "male"], +/// "value" => &vec![20.0f32, 25.0, 14.0, 18.0, 23.0, 31.0], +/// "error" => &vec![1.0, 0.5, 1.5, 1.0, 0.5, 1.5], +/// ] +/// .unwrap(); /// /// let legend = Legend::new() /// .orientation(Orientation::Horizontal) diff --git a/src/components/palette.rs b/src/components/palette.rs index bad6130..6c5065e 100644 --- a/src/components/palette.rs +++ b/src/components/palette.rs @@ -57,25 +57,25 @@ pub enum Palette { impl Palette { #[allow(clippy::wrong_self_convention)] pub(crate) fn to_plotly(&self) -> ColorScale { - match self { - Palette::Greys => ColorScale::Palette(ColorScalePalette::Greys), - Palette::YlGnBu => ColorScale::Palette(ColorScalePalette::YlGnBu), - Palette::Greens => ColorScale::Palette(ColorScalePalette::Greens), - Palette::YlOrRd => ColorScale::Palette(ColorScalePalette::YlOrRd), - Palette::Bluered => ColorScale::Palette(ColorScalePalette::Bluered), - Palette::RdBu => ColorScale::Palette(ColorScalePalette::RdBu), - Palette::Reds => ColorScale::Palette(ColorScalePalette::Reds), - Palette::Blues => ColorScale::Palette(ColorScalePalette::Blues), - Palette::Picnic => ColorScale::Palette(ColorScalePalette::Picnic), - Palette::Rainbow => ColorScale::Palette(ColorScalePalette::Rainbow), - Palette::Portland => ColorScale::Palette(ColorScalePalette::Portland), - Palette::Jet => ColorScale::Palette(ColorScalePalette::Jet), - Palette::Hot => ColorScale::Palette(ColorScalePalette::Hot), - Palette::Blackbody => ColorScale::Palette(ColorScalePalette::Blackbody), - Palette::Earth => ColorScale::Palette(ColorScalePalette::Earth), - Palette::Electric => ColorScale::Palette(ColorScalePalette::Electric), - Palette::Viridis => ColorScale::Palette(ColorScalePalette::Viridis), - Palette::Cividis => ColorScale::Palette(ColorScalePalette::Cividis), - } + ColorScale::Palette(match self { + Palette::Greys => ColorScalePalette::Greys, + Palette::YlGnBu => ColorScalePalette::YlGnBu, + Palette::Greens => ColorScalePalette::Greens, + Palette::YlOrRd => ColorScalePalette::YlOrRd, + Palette::Bluered => ColorScalePalette::Bluered, + Palette::RdBu => ColorScalePalette::RdBu, + Palette::Reds => ColorScalePalette::Reds, + Palette::Blues => ColorScalePalette::Blues, + Palette::Picnic => ColorScalePalette::Picnic, + Palette::Rainbow => ColorScalePalette::Rainbow, + Palette::Portland => ColorScalePalette::Portland, + Palette::Jet => ColorScalePalette::Jet, + Palette::Hot => ColorScalePalette::Hot, + Palette::Blackbody => ColorScalePalette::Blackbody, + Palette::Earth => ColorScalePalette::Earth, + Palette::Electric => ColorScalePalette::Electric, + Palette::Viridis => ColorScalePalette::Viridis, + Palette::Cividis => ColorScalePalette::Cividis, + }) } } diff --git a/src/components/text.rs b/src/components/text.rs index c0151b7..69c4870 100644 --- a/src/components/text.rs +++ b/src/components/text.rs @@ -9,13 +9,11 @@ use crate::components::Rgb; /// ```rust /// use plotlars::{Axis, BarPlot, Plot, Text, Rgb}; /// -/// let label = vec![""]; -/// let value = vec![0]; -/// -/// let dataset = DataFrame::new(vec![ -/// Series::new("label".into(), label), -/// Series::new("value".into(), value), -/// ]).unwrap(); +/// let dataset = df![ +/// "label" => &[""], +/// "value" => &[0], +/// ] +/// .unwrap(); /// /// let axis = Axis::new() /// .tick_values(vec![]); diff --git a/src/components/tick.rs b/src/components/tick.rs index 5d7efcb..4294a44 100644 --- a/src/components/tick.rs +++ b/src/components/tick.rs @@ -1,4 +1,7 @@ -use plotly::{common::Ticks, layout::TicksDirection}; +use plotly::{ + common::Ticks, + layout::TicksDirection, +}; /// Enumeration representing the direction of axis ticks. /// diff --git a/src/lib.rs b/src/lib.rs index 0c871a6..dab3390 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,27 +5,38 @@ mod common; mod components; mod plots; -pub use crate::common::plot::Plot; -pub use crate::components::axis::{Axis, AxisSide, AxisType}; -pub use crate::components::color::Rgb; -pub use crate::components::colorbar::ColorBar; -pub use crate::components::exponent::ValueExponent; -pub use crate::components::legend::Legend; -pub use crate::components::line::Line; -pub use crate::components::orientation::Orientation; -pub use crate::components::palette::Palette; -pub use crate::components::shape::Shape; -pub use crate::components::text::Text; -pub use crate::components::tick::TickDirection; -pub use crate::plots::array2dplot::Array2dPlot; -pub use crate::plots::barplot::BarPlot; -pub use crate::plots::boxplot::BoxPlot; -pub use crate::plots::heatmap::HeatMap; -pub use crate::plots::histogram::Histogram; -pub use crate::plots::image::Image; -pub use crate::plots::lineplot::LinePlot; -pub use crate::plots::piechart::PieChart; -pub use crate::plots::scatter3dplot::Scatter3dPlot; -pub use crate::plots::scattermap::ScatterMap; -pub use crate::plots::scatterplot::ScatterPlot; -pub use crate::plots::timeseriesplot::TimeSeriesPlot; +pub use crate::{ + common::plot::Plot, + components::{ + axis::{Axis, AxisSide, AxisType}, + color::Rgb, + colorbar::ColorBar, + coloring::Coloring, + exponent::ValueExponent, + legend::Legend, + lighting::Lighting, + line::Line, + orientation::Orientation, + palette::Palette, + shape::Shape, + text::Text, + tick::TickDirection, + }, + plots::{ + array2dplot::Array2dPlot, + barplot::BarPlot, + boxplot::BoxPlot, + contourplot::ContourPlot, + heatmap::HeatMap, + histogram::Histogram, + image::Image, + lineplot::LinePlot, + piechart::PieChart, + sankeydiagram::SankeyDiagram, + scatter3dplot::Scatter3dPlot, + scattermap::ScatterMap, + scatterplot::ScatterPlot, + surfaceplot::SurfacePlot, + timeseriesplot::TimeSeriesPlot, + }, +}; diff --git a/src/plots/array2dplot.rs b/src/plots/array2dplot.rs index 3a268fd..2f1e7ae 100644 --- a/src/plots/array2dplot.rs +++ b/src/plots/array2dplot.rs @@ -1,6 +1,11 @@ use bon::bon; -use plotly::{image::ColorModel, Image as ImagePlotly, Layout as LayoutPlotly, Trace}; +use plotly::{ + Image as ImagePlotly, + Layout as LayoutPlotly, + Trace, + image::ColorModel, +}; use serde::Serialize; @@ -75,10 +80,12 @@ impl Array2dPlot { plot_title, x_title, y_title, + None, // y2_title, z_title, legend_title, x_axis, y_axis, + None, // y2_axis, z_axis, legend, ); diff --git a/src/plots/barplot.rs b/src/plots/barplot.rs index 9584224..1d052c2 100644 --- a/src/plots/barplot.rs +++ b/src/plots/barplot.rs @@ -1,9 +1,15 @@ use bon::bon; use plotly::{ - common::{ErrorData, ErrorType, Marker as MarkerPlotly}, + Bar, + Layout as LayoutPlotly, + Trace, + common::{ + ErrorData, + ErrorType, + Marker as MarkerPlotly, + }, layout::BarMode, - Bar, Layout as LayoutPlotly, Trace, }; use polars::frame::DataFrame; @@ -43,26 +49,13 @@ use crate::{ /// ```rust /// use plotlars::{BarPlot, Legend, Orientation, Plot, Rgb, Text}; /// -/// let animal = vec![ -/// "giraffe", -/// "giraffe", -/// "orangutan", -/// "orangutan", -/// "monkey", -/// "monkey", -/// ]; -/// -/// let gender = vec!["female", "male", "female", "male", "female", "male"]; -/// let value = vec![20.0f32, 25.0, 14.0, 18.0, 23.0, 31.0]; -/// let error = vec![1.0, 0.5, 1.5, 1.0, 0.5, 1.5]; -/// -/// let dataset = DataFrame::new(vec![ -/// Series::new("animal".into(), animal), -/// Series::new("gender".into(), gender), -/// Series::new("value".into(), value), -/// Series::new("error".into(), error), -/// ]) -/// .unwrap(); +/// let dataset = df![ +/// "animal" => &["giraffe", "giraffe", "orangutan", "orangutan", "monkey", "monkey"], +/// "gender" => &vec!["female", "male", "female", "male", "female", "male"], +/// "value" => &vec![20.0f32, 25.0, 14.0, 18.0, 23.0, 31.0], +/// "error" => &vec![1.0, 0.5, 1.5, 1.0, 0.5, 1.5], +/// ] +/// .unwrap(); /// /// BarPlot::builder() /// .data(&dataset) @@ -139,10 +132,12 @@ impl BarPlot { plot_title, x_title, y_title, + None, // y2_title, z_title, legend_title, x_axis, y_axis, + None, // y2_axis, z_axis, legend, ); diff --git a/src/plots/boxplot.rs b/src/plots/boxplot.rs index 0afcfe8..78fcacf 100644 --- a/src/plots/boxplot.rs +++ b/src/plots/boxplot.rs @@ -1,8 +1,12 @@ use bon::bon; use plotly::{ - box_plot::BoxPoints, common::Marker as MarkerPlotly, layout::BoxMode, BoxPlot as BoxPlotly, - Layout as LayoutPlotly, Trace, + BoxPlot as BoxPlotly, + Layout as LayoutPlotly, + Trace, + box_plot::BoxPoints, + common::Marker as MarkerPlotly, + layout::BoxMode, }; use polars::frame::DataFrame; @@ -143,10 +147,12 @@ impl BoxPlot { plot_title, x_title, y_title, + None, // y2_title, z_title, legend_title, x_axis, y_axis, + None, // y2_axis, z_axis, legend, ); diff --git a/src/plots/contourplot.rs b/src/plots/contourplot.rs new file mode 100644 index 0000000..4cc5aba --- /dev/null +++ b/src/plots/contourplot.rs @@ -0,0 +1,302 @@ +use bon::bon; + +use plotly::{ + Contour, + Layout as LayoutPlotly, + Trace, + contour::Contours, +}; + +use polars::frame::DataFrame; +use serde::Serialize; + +use crate::{ + common::{Layout, PlotHelper, Polar}, + components::{Axis, ColorBar, Coloring, Palette, Text}, +}; + +/// A structure representing a contour plot. +/// +/// The `ContourPlot` struct enables the creation of contour visualizations that display level +/// curves of a three‑dimensional surface on a two‑dimensional plane. It offers extensive +/// configuration options for contour styling, color scaling, axis appearance, legends, and +/// annotations. Users can fine‑tune the contour interval, choose from predefined color palettes, +/// reverse or hide the color scale, and set custom titles for both the plot and its axes in +/// order to improve the readability of complex surfaces. +/// +/// # Arguments +/// +/// * `data` - A reference to the `DataFrame` containing the data to be plotted. +/// * `x` - A string slice specifying the column name for x‑axis values. +/// * `y` - A string slice specifying the column name for y‑axis values. +/// * `z` - A string slice specifying the column name for z‑axis values whose magnitude +/// determines each contour line. +/// * `color_bar` - An optional reference to a `ColorBar` struct for customizing the color bar +/// appearance. +/// * `color_scale` - An optional `Palette` enum for specifying the color palette (e.g., +/// `Palette::Viridis`). +/// * `reverse_scale` - An optional boolean to reverse the color scale direction. +/// * `show_scale` - An optional boolean to display the color scale on the plot. +/// * `contours` - An optional reference to a `Contours` struct for configuring the contour +/// interval, size, and coloring. +/// * `plot_title` - An optional `Text` struct for setting the title of the plot. +/// * `x_title` - An optional `Text` struct for labeling the x‑axis. +/// * `y_title` - An optional `Text` struct for labeling the y‑axis. +/// * `x_axis` - An optional reference to an `Axis` struct for customizing x‑axis appearance. +/// * `y_axis` - An optional reference to an `Axis` struct for customizing y‑axis appearance. +/// +/// # Example +/// +/// ```rust +/// use polars::prelude::*; +/// use plotlars::{Plot, Coloring, Contours, ContourPlot, Palette}; +/// +/// let dataset = df!( +/// "x" => &[0.0, 0.0, 0.0, 2.5, 2.5, 2.5, 5.0, 5.0, 5.0], +/// "y" => &[0.0, 7.5, 15.0, 0.0, 7.5, 15.0, 0.0, 7.5, 15.0], +/// "z" => &[0.0, 5.0, 10.0, 5.0, 2.5, 5.0, 10.0, 0.0, 0.0], +/// ) +/// .unwrap(); +/// +/// ContourPlot::builder() +/// .data(&dataset) +/// .x("x") +/// .y("y") +/// .z("z") +/// .color_scale(Palette::Viridis) +/// .reverse_scale(true) +/// .coloring(Coloring::Fill) +/// .show_lines(false) +/// .plot_title( +/// Text::from("Contour Plot") +/// .font("Arial") +/// .size(18) +/// ) +/// .build() +/// .plot(); +/// ``` +/// +/// ![Example](https://imgur.com/VWgxHC8.png) +#[derive(Clone, Serialize)] +pub struct ContourPlot { + traces: Vec>, + layout: LayoutPlotly, +} + +#[bon] +impl ContourPlot { + #[builder(on(String, into), on(Text, into))] + pub fn new( + data: &DataFrame, + x: &str, + y: &str, + z: &str, + color_bar: Option<&ColorBar>, + color_scale: Option, + reverse_scale: Option, + show_scale: Option, + show_lines: Option, + coloring: Option, + plot_title: Option, + x_title: Option, + y_title: Option, + x_axis: Option<&Axis>, + y_axis: Option<&Axis>, + ) -> Self { + let legend = None; + let legend_title = None; + let z_title = None; + let z_axis = None; + + let layout = Self::create_layout( + plot_title, + x_title, + y_title, + None, // y2_title, + z_title, + legend_title, + x_axis, + y_axis, + None, // y2_axis, + z_axis, + legend, + ); + + let traces = Self::create_traces( + data, + x, + y, + z, + color_bar, + color_scale, + reverse_scale, + show_scale, + show_lines, + coloring, + ); + + Self { traces, layout } + } + + #[allow(clippy::too_many_arguments)] + fn create_traces( + data: &DataFrame, + x: &str, + y: &str, + z: &str, + color_bar: Option<&ColorBar>, + color_scale: Option, + reverse_scale: Option, + show_scale: Option, + show_lines: Option, + coloring: Option, + ) -> Vec> { + let mut traces: Vec> = Vec::new(); + + let trace = Self::create_trace( + data, + x, + y, + z, + color_bar, + color_scale, + reverse_scale, + show_scale, + show_lines, + coloring, + ); + + traces.push(trace); + traces + } + + #[allow(clippy::too_many_arguments)] + fn create_trace( + data: &DataFrame, + x: &str, + y: &str, + z: &str, + color_bar: Option<&ColorBar>, + color_scale: Option, + reverse_scale: Option, + show_scale: Option, + show_lines: Option, + coloring: Option, + ) -> Box { + let x = Self::get_numeric_column(data, x); + let y = Self::get_numeric_column(data, y); + let z = Self::get_numeric_column(data, z); + + let mut trace = Contour::new(x, y, z); + + trace = Self::set_color_bar(trace, color_bar); + trace = Self::set_color_scale(trace, color_scale); + trace = Self::set_reverse_scale(trace, reverse_scale); + trace = Self::set_show_scale(trace, show_scale); + + let mut contours = Contours::new(); + + contours = Self::set_coloring(contours, coloring); + contours = Self::set_show_lines(contours, show_lines); + + trace + .contours(contours) + } + + fn set_show_lines( + mut contours: Contours, + show_lines: Option, + ) -> Contours { + if let Some(show_lines) = show_lines { + contours = contours.show_lines(show_lines) + } + + contours + } + + fn set_coloring( + mut contours: Contours, + coloring: Option, + ) -> Contours { + if let Some(coloring) = coloring { + contours = contours.coloring(coloring.to_plotly()) + } + + contours + } + + fn set_color_bar( + mut trace: Box>, + color_bar: Option<&ColorBar>, + ) -> Box> + where + X: Serialize + Clone, + Y: Serialize + Clone, + Z: Serialize + Clone, + { + if let Some(color_bar) = color_bar { + trace = trace.color_bar(color_bar.to_plotly()) + } + + trace + } + + fn set_color_scale( + mut trace: Box>, + color_scale: Option, + ) -> Box> + where + X: Serialize + Clone, + Y: Serialize + Clone, + Z: Serialize + Clone, + { + if let Some(color_scale) = color_scale { + trace = trace.color_scale(color_scale.to_plotly()); + } + + trace + } + + fn set_reverse_scale( + mut trace: Box>, + reverse_scale: Option, + ) -> Box> + where + X: Serialize + Clone, + Y: Serialize + Clone, + Z: Serialize + Clone, + { + if let Some(reverse_scale) = reverse_scale { + trace = trace.reverse_scale(reverse_scale); + } + trace + } + + fn set_show_scale( + mut trace: Box>, + show_scale: Option, + ) -> Box> + where + X: Serialize + Clone, + Y: Serialize + Clone, + Z: Serialize + Clone, + { + if let Some(show_scale) = show_scale { + trace = trace.show_scale(show_scale); + } + trace + } +} + +impl Layout for ContourPlot {} +impl Polar for ContourPlot {} + +impl PlotHelper for ContourPlot { + fn get_layout(&self) -> &LayoutPlotly { + &self.layout + } + + fn get_traces(&self) -> &Vec> { + &self.traces + } +} diff --git a/src/plots/heatmap.rs b/src/plots/heatmap.rs index 714cf7a..9dc2802 100644 --- a/src/plots/heatmap.rs +++ b/src/plots/heatmap.rs @@ -1,14 +1,17 @@ use bon::bon; -use plotly::{HeatMap as HeatMapPlotly, Layout as LayoutPlotly, Trace}; +use plotly::{ + HeatMap as HeatMapPlotly, + Layout as LayoutPlotly, + Trace, +}; use polars::frame::DataFrame; use serde::Serialize; use crate::{ common::{Layout, Marker, PlotHelper, Polar}, - components::{Axis, Text}, - ColorBar, Palette, + components::{Axis, ColorBar, Palette, Text}, }; /// A structure representing a heat map. @@ -104,10 +107,12 @@ impl HeatMap { plot_title, x_title, y_title, + None, // y2_title, z_title, legend_title, x_axis, y_axis, + None, // y2_axis, z_axis, legend, ); @@ -151,6 +156,7 @@ impl HeatMap { reverse_scale, show_scale, ); + traces.push(trace); traces } @@ -171,18 +177,18 @@ impl HeatMap { let y = Self::get_string_column(data, y); let z = Self::get_numeric_column(data, z); - let mut heat_map = HeatMapPlotly::default().x(x).y(y).z(z); + let mut trace = HeatMapPlotly::default().x(x).y(y).z(z); - heat_map = Self::set_auto_color_scale(heat_map, auto_color_scale); - heat_map = Self::set_color_bar(heat_map, color_bar); - heat_map = Self::set_color_scale(heat_map, color_scale); - heat_map = Self::set_reverse_scale(heat_map, reverse_scale); - heat_map = Self::set_show_scale(heat_map, show_scale); - heat_map + trace = Self::set_auto_color_scale(trace, auto_color_scale); + trace = Self::set_color_bar(trace, color_bar); + trace = Self::set_color_scale(trace, color_scale); + trace = Self::set_reverse_scale(trace, reverse_scale); + trace = Self::set_show_scale(trace, show_scale); + trace } fn set_auto_color_scale( - mut heat_map: Box>, + mut trace: Box>, auto_color_scale: Option, ) -> Box> where @@ -191,14 +197,14 @@ impl HeatMap { Z: Serialize + Clone, { if let Some(auto_color_scale) = auto_color_scale { - heat_map = heat_map.auto_color_scale(auto_color_scale); + trace = trace.auto_color_scale(auto_color_scale); } - heat_map + trace } fn set_color_bar( - mut heat_map: Box>, + mut trace: Box>, color_bar: Option<&ColorBar>, ) -> Box> where @@ -207,14 +213,14 @@ impl HeatMap { Z: Serialize + Clone, { if let Some(color_bar) = color_bar { - heat_map = heat_map.color_bar(color_bar.to_plotly()) + trace = trace.color_bar(color_bar.to_plotly()) } - heat_map + trace } fn set_color_scale( - mut heat_map: Box>, + mut trace: Box>, color_scale: Option, ) -> Box> where @@ -223,14 +229,14 @@ impl HeatMap { Z: Serialize + Clone, { if let Some(color_scale) = color_scale { - heat_map = heat_map.color_scale(color_scale.to_plotly()); + trace = trace.color_scale(color_scale.to_plotly()); } - heat_map + trace } fn set_reverse_scale( - mut heat_map: Box>, + mut trace: Box>, reverse_scale: Option, ) -> Box> where @@ -239,13 +245,14 @@ impl HeatMap { Z: Serialize + Clone, { if let Some(reverse_scale) = reverse_scale { - heat_map = heat_map.reverse_scale(reverse_scale); + trace = trace.reverse_scale(reverse_scale); } - heat_map + + trace } fn set_show_scale( - mut heat_map: Box>, + mut trace: Box>, show_scale: Option, ) -> Box> where @@ -254,9 +261,10 @@ impl HeatMap { Z: Serialize + Clone, { if let Some(show_scale) = show_scale { - heat_map = heat_map.show_scale(show_scale); + trace = trace.show_scale(show_scale); } - heat_map + + trace } } diff --git a/src/plots/histogram.rs b/src/plots/histogram.rs index 2b9916e..09b7cd2 100644 --- a/src/plots/histogram.rs +++ b/src/plots/histogram.rs @@ -1,8 +1,12 @@ use bon::bon; use plotly::{ - common::Marker as MarkerPlotly, histogram::HistFunc, layout::BarMode, - Histogram as HistogramPlotly, Layout as LayoutPlotly, Trace, + Histogram as HistogramPlotly, + Layout as LayoutPlotly, + Trace, + common::Marker as MarkerPlotly, + histogram::HistFunc, + layout::BarMode, }; use polars::frame::DataFrame; @@ -130,10 +134,12 @@ impl Histogram { plot_title, x_title, y_title, + None, // y2_title, z_title, legend_title, x_axis, y_axis, + None, // y2_axis, z_axis, legend, ); diff --git a/src/plots/image.rs b/src/plots/image.rs index 1cabd36..960d071 100644 --- a/src/plots/image.rs +++ b/src/plots/image.rs @@ -1,7 +1,11 @@ use bon::bon; use plotly::{ - color::Rgb as RgbPlotly, image::ColorModel, Image as ImagePlotly, Layout as LayoutPlotly, Trace, + Image as ImagePlotly, + Layout as LayoutPlotly, + Trace, + color::Rgb as RgbPlotly, + image::ColorModel, }; use serde::Serialize; @@ -70,10 +74,12 @@ impl Image { plot_title, x_title, y_title, + None, // y2_title, z_title, legend_title, x_axis, y_axis, + None, // y2_axis, z_axis, legend, ); diff --git a/src/plots/lineplot.rs b/src/plots/lineplot.rs index 22e4b26..cba5ebe 100644 --- a/src/plots/lineplot.rs +++ b/src/plots/lineplot.rs @@ -1,19 +1,32 @@ use bon::bon; use plotly::{ - common::{Line as LinePlotly, Marker as MarkerPlotly, Mode}, - Layout as LayoutPlotly, Scatter, Trace, + Layout as LayoutPlotly, + Scatter, + Trace, + common::{ + Line as LinePlotly, + Marker as MarkerPlotly, + Mode, + }, }; use polars::{ frame::DataFrame, - prelude::{col, IntoLazy}, + prelude::{IntoLazy, col}, }; use serde::Serialize; use crate::{ common::{Layout, Line, Marker, PlotHelper, Polar}, - components::{Axis, Legend, Line as LineStyle, Rgb, Shape, Text}, + components::{ + Axis, + Legend, + Line as LineStyle, + Rgb, + Shape, + Text, + }, }; /// A structure representing a line plot. @@ -136,9 +149,11 @@ impl LinePlot { plot_title: Option, x_title: Option, y_title: Option, + y2_title: Option, legend_title: Option, x_axis: Option<&Axis>, y_axis: Option<&Axis>, + y2_axis: Option<&Axis>, legend: Option<&Legend>, ) -> Self { let z_title = None; @@ -148,10 +163,12 @@ impl LinePlot { plot_title, x_title, y_title, + y2_title, z_title, legend_title, x_axis, y_axis, + y2_axis, z_axis, legend, ); diff --git a/src/plots/mod.rs b/src/plots/mod.rs index 5eed325..032e268 100644 --- a/src/plots/mod.rs +++ b/src/plots/mod.rs @@ -1,12 +1,15 @@ pub(crate) mod array2dplot; pub(crate) mod barplot; pub(crate) mod boxplot; +pub(crate) mod contourplot; pub(crate) mod heatmap; pub(crate) mod histogram; pub(crate) mod image; pub(crate) mod lineplot; pub(crate) mod piechart; +pub(crate) mod sankeydiagram; pub(crate) mod scatter3dplot; pub(crate) mod scattermap; pub(crate) mod scatterplot; +pub(crate) mod surfaceplot; pub(crate) mod timeseriesplot; diff --git a/src/plots/piechart.rs b/src/plots/piechart.rs index 3942f86..8c1605a 100644 --- a/src/plots/piechart.rs +++ b/src/plots/piechart.rs @@ -1,6 +1,10 @@ use bon::bon; -use plotly::{Layout as LayoutPlotly, Pie, Trace}; +use plotly::{ + Layout as LayoutPlotly, + Pie, + Trace, +}; use polars::frame::DataFrame; use serde::Serialize; @@ -21,7 +25,7 @@ use crate::{ /// * `data` - A reference to the `DataFrame` containing the data to be plotted. /// * `labels` - A string slice specifying the column name to be used for slice labels. /// * `hole` - An optional `f64` value specifying the size of the hole in the center of the pie chart. -/// A value of `0.0` creates a full pie chart, while a value closer to `1.0` creates a thinner ring. +/// A value of `0.0` creates a full pie chart, while a value closer to `1.0` creates a thinner ring. /// * `pull` - An optional `f64` value specifying the fraction by which each slice should be pulled out from the center. /// * `rotation` - An optional `f64` value specifying the starting angle (in degrees) of the first slice. /// * `plot_title` - An optional `Text` struct specifying the title of the plot. @@ -88,10 +92,12 @@ impl PieChart { plot_title, x_title, y_title, + None, // y2_title, z_title, legend_title, x_axis, y_axis, + None, // y2_axis, z_axis, legend, ); diff --git a/src/plots/sankeydiagram.rs b/src/plots/sankeydiagram.rs new file mode 100644 index 0000000..85c529e --- /dev/null +++ b/src/plots/sankeydiagram.rs @@ -0,0 +1,394 @@ +use bon::bon; +use std::collections::{ + HashMap, + hash_map::Entry, +}; + +use plotly::{ + sankey::{Link, Node}, Layout as LayoutPlotly, Sankey, Trace +}; + +use polars::frame::DataFrame; +use serde::Serialize; + +use crate::{ + common::{Layout, PlotHelper, Polar}, + components::{Arrangement, Orientation, Rgb, Text}, +}; + +/// A structure representing a Sankey diagram. +/// +/// The `SankeyDiagram` struct enables the creation of Sankey diagrams, which visualize flows +/// between discrete nodes with link widths proportional to the magnitude of the flow. It +/// offers extensive configuration options for flow orientation, node arrangement, spacing, +/// thickness, and coloring, as well as axis and title customization. Users can specify a +/// single uniform color or per-item colors for both nodes and links, adjust padding between +/// nodes, set node thickness, and supply custom titles and axis labels to produce clear, +/// publication-quality flow visualizations. +/// +/// # Arguments +/// +/// * `data` – A reference to the `DataFrame` containing the data to be plotted. +/// * `sources` – A string slice naming the column in `data` that contains the source node for each flow. +/// * `targets` – A string slice naming the column in `data` that contains the target node for each flow. +/// * `values` – A string slice naming the column in `data` that contains the numeric value of each flow. +/// * `orientation` – An optional `Orientation` enum to set the overall direction of the diagram +/// (e.g. `Orientation::Horizontal` or `Orientation::Vertical`). +/// * `arrangement` – An optional `Arrangement` enum to choose the node-layout algorithm +/// (e.g. `Arrangement::Snap`, `Arrangement::Perpendicular`, etc.). +/// * `pad` – An optional `usize` specifying the padding (in pixels) between adjacent nodes. +/// * `thickness` – An optional `usize` defining the uniform thickness (in pixels) of all nodes. +/// * `node_color` – An optional `Rgb` value to apply a single uniform color to every node. +/// * `node_colors` – An optional `Vec` supplying individual colors for each node in order. +/// * `link_color` – An optional `Rgb` value to apply a single uniform color to every link. +/// * `link_colors` – An optional `Vec` supplying individual colors for each link in order. +/// * `plot_title` – An optional `Text` struct for setting the overall title of the plot. +/// +/// # Example +/// +/// ```rust +/// use plotlars::{Arrangement, SankeyDiagram, Orientation, Plot, Rgb, Text}; +/// +/// let dataset = df![ +/// "source" => ["A1", "A2", "A1", "B1", "B2", "B2"], +/// "target" => &["B1", "B2", "B2", "C1", "C1", "C2"], +/// "value" => &[8, 4, 2, 8, 4, 2], +/// ] +/// .unwrap(); +/// +/// SankeyDiagram::builder() +/// .data(&dataset) +/// .sources("source") +/// .targets("target") +/// .values("value") +/// .orientation(Orientation::Horizontal) +/// .arrangement(Arrangement::Freeform) +/// .node_colors(vec![ +/// Rgb(222, 235, 247), +/// Rgb(198, 219, 239), +/// Rgb(158, 202, 225), +/// Rgb(107, 174, 214), +/// Rgb( 66, 146, 198), +/// Rgb( 33, 113, 181), +/// ]) +/// .link_colors(vec![ +/// Rgb(222, 235, 247), +/// Rgb(198, 219, 239), +/// Rgb(158, 202, 225), +/// Rgb(107, 174, 214), +/// Rgb( 66, 146, 198), +/// Rgb( 33, 113, 181), +/// ]) +/// .pad(20) +/// .thickness(30) +/// .plot_title( +/// Text::from("Sankey Diagram") +/// .font("Arial") +/// .size(18) +/// ) +/// .build() +/// .plot(); +/// ``` +/// +/// ![Example](https://imgur.com/jvAew8u.png) +#[derive(Clone, Serialize)] +pub struct SankeyDiagram { + traces: Vec>, + layout: LayoutPlotly, +} + +#[bon] +impl SankeyDiagram { + #[builder(on(String, into), on(Text, into))] + pub fn new( + data: &DataFrame, + sources: &str, + targets: &str, + values: &str, + orientation: Option, + arrangement: Option, + pad: Option, + thickness: Option, + node_color: Option, + node_colors: Option>, + link_color: Option, + link_colors: Option>, + plot_title: Option, + ) -> Self { + let legend = None; + let legend_title = None; + let x_title = None; + let y_title = None; + let z_title = None; + let x_axis = None; + let y_axis = None; + let z_axis = None; + + let layout = Self::create_layout( + plot_title, + x_title, + y_title, + None, // y2_title, + z_title, + legend_title, + x_axis, + y_axis, + None, // y2_axis, + z_axis, + legend, + ); + + let traces = Self::create_traces( + data, + sources, + targets, + values, + orientation, + arrangement, + pad, + thickness, + node_color, + node_colors, + link_color, + link_colors, + ); + + Self { traces, layout } + } + + #[allow(clippy::too_many_arguments)] + fn create_traces( + data: &DataFrame, + sources: &str, + targets: &str, + values: &str, + orientation: Option, + arrangement: Option, + pad: Option, + thickness: Option, + node_color: Option, + node_colors: Option>, + link_color: Option, + link_colors: Option>, + ) -> Vec> { + let mut traces: Vec> = Vec::new(); + + let trace = Self::create_trace( + data, + sources, + targets, + values, + orientation, + arrangement, + pad, + thickness, + node_color, + node_colors, + link_color, + link_colors, + ); + + traces.push(trace); + traces + } + + #[allow(clippy::too_many_arguments)] + fn create_trace( + data: &DataFrame, + sources: &str, + targets: &str, + values: &str, + orientation: Option, + arrangement: Option, + pad: Option, + thickness: Option, + node_color: Option, + node_colors: Option>, + link_color: Option, + link_colors: Option>, + ) -> Box { + let sources = Self::get_string_column(data, sources); + let targets = Self::get_string_column(data, targets); + let values = Self::get_numeric_column(data, values); + + let (labels_unique, label_to_idx) = Self::build_label_index(&sources, &targets); + + let sources_idx = Self::column_to_indices(&sources, &label_to_idx); + let targets_idx = Self::column_to_indices(&targets, &label_to_idx); + + let mut node = Node::new() + .label(labels_unique); + + node = Self::set_pad(node, pad); + node = Self::set_thickness(node, thickness); + node = Self::set_node_color(node, node_color); + node = Self::set_node_colors(node, node_colors); + + let mut link = Link::new() + .source(sources_idx) + .target(targets_idx) + .value(values); + + link = Self::set_link_color(link, link_color); + link = Self::set_link_colors(link, link_colors); + + let mut trace = Sankey::new() + .node(node) + .link(link); + + trace = Self::set_orientation(trace, orientation); + trace = Self::set_arrangement(trace, arrangement); + trace + } + + fn set_thickness( + mut node: Node, + thickness: Option, + ) -> Node { + if let Some(thickness) = thickness { + node = node.thickness(thickness); + } + + node + } + + fn set_pad( + mut node: Node, + pad: Option, + ) -> Node { + if let Some(pad) = pad { + node = node.pad(pad); + } + + node + } + + fn set_link_colors( + mut link: Link, + colors: Option>, + ) -> Link + where + V: Serialize + Clone, + { + if let Some(colors) = colors { + link = link.color_array( + colors + .iter() + .map(|color| color.to_plotly()) + .collect() + ); + } + + link + } + + fn set_link_color( + mut link: Link, + color: Option, + ) -> Link + where + V: Serialize + Clone, + { + if let Some(color) = color { + link = link.color(color); + } + + link + } + + fn set_node_colors( + mut node: Node, + colors: Option>, + ) -> Node { + if let Some(colors) = colors { + node = node.color_array( + colors + .iter() + .map(|color| color.to_plotly()) + .collect() + ); + } + + node + } + + fn set_node_color( + mut node: Node, + color: Option, + ) -> Node { + if let Some(color) = color { + node = node.color(color); + } + + node + } + + fn set_arrangement( + mut trace: Box>>, + arrangement: Option, + ) -> Box>> { + if let Some(arrangement) = arrangement { + trace = trace.arrangement(arrangement.to_plotly()) + } + + trace + } + + fn set_orientation( + mut trace: Box>>, + orientation: Option, + ) -> Box>> { + if let Some(orientation) = orientation { + trace = trace.orientation(orientation.to_plotly()) + } + + trace + } + + fn build_label_index<'a>( + sources: &'a [Option], + targets: &'a [Option], + ) -> (Vec<&'a str>, HashMap<&'a str, usize>) { + let mut label_to_idx: HashMap<&'a str, usize> = HashMap::new(); + let mut labels_unique: Vec<&'a str> = Vec::new(); + + let iter = sources + .iter() + .chain(targets.iter()) + .filter_map(|opt| opt.as_deref()); + + for lbl in iter { + if let Entry::Vacant(v) = label_to_idx.entry(lbl) { + let next_id = labels_unique.len(); + v.insert(next_id); + labels_unique.push(lbl); + } + } + + (labels_unique, label_to_idx) + } + + fn column_to_indices( + column: &[Option], + label_to_idx: &HashMap<&str, usize>, + ) -> Vec { + column + .iter() + .filter_map(|opt| opt.as_deref()) + .map(|lbl| *label_to_idx.get(lbl).expect("label must exist in map")) + .collect() + } +} + +impl Layout for SankeyDiagram {} +impl Polar for SankeyDiagram {} + +impl PlotHelper for SankeyDiagram { + fn get_layout(&self) -> &LayoutPlotly { + &self.layout + } + + fn get_traces(&self) -> &Vec> { + &self.traces + } +} diff --git a/src/plots/scatter3dplot.rs b/src/plots/scatter3dplot.rs index c96bc4e..e6a492e 100644 --- a/src/plots/scatter3dplot.rs +++ b/src/plots/scatter3dplot.rs @@ -1,8 +1,13 @@ use bon::bon; use plotly::{ - common::{Marker as MarkerPlotly, Mode}, - Layout as LayoutPlotly, Scatter3D, Trace, + Layout as LayoutPlotly, + Scatter3D, + Trace, + common::{ + Marker as MarkerPlotly, + Mode, + }, }; use polars::frame::DataFrame; @@ -10,8 +15,7 @@ use serde::Serialize; use crate::{ common::{Layout, Marker, PlotHelper, Polar}, - components::{Axis, Legend, Text}, - Rgb, Shape, + components::{Rgb, Shape, Text}, }; /// A structure representing a 3D scatter plot. @@ -112,23 +116,26 @@ impl Scatter3dPlot { shape: Option, shapes: Option>, plot_title: Option, - x_title: Option, - y_title: Option, - z_title: Option, - legend_title: Option, - x_axis: Option<&Axis>, - y_axis: Option<&Axis>, - z_axis: Option<&Axis>, - legend: Option<&Legend>, ) -> Self { + let legend_title = None; + let x_title = None; + let y_title = None; + let z_title = None; + let legend = None; + let x_axis = None; + let y_axis = None; + let z_axis = None; + let layout = Self::create_layout( plot_title, x_title, y_title, + None, // y2_title, z_title, legend_title, x_axis, y_axis, + None, // y2_axis, z_axis, legend, ); diff --git a/src/plots/scattermap.rs b/src/plots/scattermap.rs index 3ab572a..e92d5c9 100644 --- a/src/plots/scattermap.rs +++ b/src/plots/scattermap.rs @@ -1,9 +1,19 @@ use bon::bon; use plotly::{ - common::{Marker as MarkerPlotly, Mode}, - layout::{Center, Layout as LayoutPlotly, Mapbox, MapboxStyle, Margin}, - ScatterMapbox, Trace, + ScatterMapbox, + Trace, + common::{ + Marker as MarkerPlotly, + Mode, + }, + layout::{ + Center, + Layout as LayoutPlotly, + Mapbox, + MapboxStyle, + Margin, + }, }; use polars::frame::DataFrame; @@ -11,8 +21,7 @@ use serde::Serialize; use crate::{ common::{Layout, Marker, PlotHelper, Polar}, - components::{Legend, Text}, - Rgb, Shape, + components::{Legend, Rgb, Shape, Text}, }; /// A structure representing a scatter plot on a map. @@ -110,10 +119,12 @@ impl ScatterMap { plot_title, x_title, y_title, + None, // y2_title, z_title, legend_title, x_axis, y_axis, + None, // y2_axis, z_axis, legend, ) diff --git a/src/plots/scatterplot.rs b/src/plots/scatterplot.rs index 46f4504..68db548 100644 --- a/src/plots/scatterplot.rs +++ b/src/plots/scatterplot.rs @@ -1,8 +1,13 @@ use bon::bon; use plotly::{ - common::{Marker as MarkerPlotly, Mode}, - Layout as LayoutPlotly, Scatter, Trace, + Layout as LayoutPlotly, + Scatter, + Trace, + common::{ + Marker as MarkerPlotly, + Mode, + }, }; use polars::frame::DataFrame; @@ -141,10 +146,12 @@ impl ScatterPlot { plot_title, x_title, y_title, + None, // y2_title, z_title, legend_title, x_axis, y_axis, + None, // y2_axis, z_axis, legend, ); diff --git a/src/plots/surfaceplot.rs b/src/plots/surfaceplot.rs new file mode 100644 index 0000000..e2e1d4f --- /dev/null +++ b/src/plots/surfaceplot.rs @@ -0,0 +1,377 @@ +use bon::bon; +use indexmap::IndexSet; +use ordered_float::OrderedFloat; + +use plotly::{ + Layout as LayoutPlotly, + Surface, + Trace, + surface::Position, +}; + +use polars::frame::DataFrame; +use serde::Serialize; + +use crate::{ + common::{Layout, PlotHelper, Polar}, + components::{ColorBar, Lighting, Palette, Text}, +}; + +/// A structure representing a 3-D surface plot. +/// +/// The `SurfacePlot` struct is designed to build and customize 3-dimensional +/// surface visualizations. It supports fine-grained control over the color +/// mapping of *z* values, interactive color bars, lighting effects that enhance +/// depth perception, and global opacity settings. Layout elements such as the +/// plot title and axis labels can also be configured through the builder API, +/// allowing you to embed the surface seamlessly in complex dashboards. +/// +/// # Arguments +/// +/// * `data` – A reference to the `DataFrame` that supplies the data. +/// It must contain three numeric columns whose names are given by `x`, `y` +/// and `z`. +/// * `x` – The column name to be used for the x-axis coordinates. +/// Each distinct *x* value becomes a row in the underlying *z* grid. +/// * `y` – The column name to be used for the y-axis coordinates. +/// Each distinct *y* value becomes a column in the *z* grid. +/// * `z` – The column name that provides the z-axis heights. These values +/// are mapped to colors according to `color_scale` / `reverse_scale`. +/// * `color_bar` – An optional Reference to a `ColorBar` describing the +/// appearance of the color legend (length, tick formatting, border, etc.). +/// * `color_scale` – An optional `Palette` that defines the color gradient +/// (e.g. *Viridis*, *Cividis*). +/// * `reverse_scale` – An optional `bool` indicating whether the chosen +/// `color_scale` should run in the opposite direction. +/// * `show_scale` – An optional `bool` that toggles the visibility of the +/// color bar. Useful when you have multiple surfaces that share an external +/// legend. +/// * `lighting` – An optional Reference to a `Lighting` struct that +/// specifies *ambient*, *diffuse*, *specular* components, *roughness*, +/// *fresnel* and light position. Leaving it `None` applies Plotly’s +/// default Phong shading. +/// * `opacity` – An optional `f64` in `[0.0, 1.0]` that sets the global +/// transparency of the surface (1 = opaque, 0 = fully transparent). +/// * `plot_title` – An optional `Text` that customizes the title (content, +/// font, size, alignment). +/// +/// # Example +/// +/// ```rust +/// use ndarray::Array; +/// use plotlars::{ColorBar, Lighting, Palette, Plot, SurfacePlot, Text}; +/// use polars::prelude::*; +/// use std::iter; +/// +/// let n: usize = 100; +/// let x_base: Vec = Array::linspace(-10.0, 10.0, n).into_raw_vec(); +/// let y_base: Vec = Array::linspace(-10.0, 10.0, n).into_raw_vec(); +/// +/// let x = x_base +/// .iter() +/// .flat_map(|&xi| iter::repeat(xi).take(n)) +/// .collect::>(); +/// +/// let y = y_base +/// .iter() +/// .cycle() +/// .take(n * n) +/// .cloned() +/// .collect::>(); +/// +/// let z = x_base +/// .iter() +/// .map(|i| { +/// y_base +/// .iter() +/// .map(|j| 1.0 / (j * j + 5.0) * j.sin() + 1.0 / (i * i + 5.0) * i.cos()) +/// .collect::>() +/// }) +/// .flatten() +/// .collect::>(); +/// +/// let dataset = df![ +/// "x" => &x, +/// "y" => &y, +/// "z" => &z, +/// ] +/// .unwrap(); +/// +/// SurfacePlot::builder() +/// .data(&dataset) +/// .x("x") +/// .y("y") +/// .z("z") +/// .plot_title( +/// Text::from("Surface Plot") +/// .font("Arial") +/// .size(18), +/// ) +/// .color_bar( +/// &ColorBar::new() +/// .border_width(1), +/// ) +/// .color_scale(Palette::Cividis) +/// .reverse_scale(true) +/// .opacity(0.5) +/// .build() +/// .plot(); +/// ``` +/// +/// ![Example](https://imgur.com/tdVte4l.png) +#[derive(Clone, Serialize)] +pub struct SurfacePlot { + traces: Vec>, + layout: LayoutPlotly, +} + +#[bon] +impl SurfacePlot { + #[builder(on(String, into), on(Text, into))] + pub fn new( + data: &DataFrame, + x: &str, + y: &str, + z: &str, + color_bar: Option<&ColorBar>, + color_scale: Option, + reverse_scale: Option, + show_scale: Option, + lighting: Option<&Lighting>, + opacity: Option, + plot_title: Option, + ) -> Self { + let legend = None; + let legend_title = None; + let x_title = None; + let y_title = None; + let z_title = None; + let x_axis = None; + let y_axis = None; + let z_axis = None; + + let layout = Self::create_layout( + plot_title, + x_title, + y_title, + None, // y2_title, + z_title, + legend_title, + x_axis, + y_axis, + None, // y2_axis, + z_axis, + legend, + ); + + let traces = Self::create_traces( + data, + x, + y, + z, + color_bar, + color_scale, + reverse_scale, + show_scale, + lighting, + opacity, + ); + + Self { traces, layout } + } + + #[allow(clippy::too_many_arguments)] + fn create_traces( + data: &DataFrame, + x: &str, + y: &str, + z: &str, + color_bar: Option<&ColorBar>, + color_scale: Option, + reverse_scale: Option, + show_scale: Option, + lighting: Option<&Lighting>, + opacity: Option, + ) -> Vec> { + let mut traces: Vec> = Vec::new(); + + let trace = Self::create_trace( + data, + x, + y, + z, + color_bar, + color_scale, + reverse_scale, + show_scale, + lighting, + opacity, + ); + + traces.push(trace); + traces + } + + #[allow(clippy::too_many_arguments)] + fn create_trace( + data: &DataFrame, + x: &str, + y: &str, + z: &str, + color_bar: Option<&ColorBar>, + color_scale: Option, + reverse_scale: Option, + show_scale: Option, + lighting: Option<&Lighting>, + opacity: Option, + ) -> Box { + let x = Self::get_numeric_column(data, x); + let y = Self::get_numeric_column(data, y); + let z = Self::get_numeric_column(data, z); + + let x = Self::unique_ordered(x); + let y = Self::unique_ordered(y); + let z = z + .into_iter() + .collect::>() + .chunks(y.len()) + .map(|chunk| chunk.to_vec()) + .collect::>>>(); + + let mut trace = Surface::new(z).x(x).y(y); + + trace = Self::set_color_bar(trace, color_bar); + trace = Self::set_color_scale(trace, color_scale); + trace = Self::set_light_position(trace, lighting); + trace = trace.lighting(Lighting::set_lighting(lighting)); + trace = Self::set_opacity(trace, opacity); + trace = Self::set_reverse_scale(trace, reverse_scale); + trace = Self::set_show_scale(trace, show_scale); + + trace + } + + fn set_show_scale( + mut trace: Box>, + show_scale: Option, + ) -> Box> + where + X: Serialize + Clone, + Y: Serialize + Clone, + Z: Serialize + Clone, + { + if let Some(show_scale) = show_scale { + trace = trace.show_scale(show_scale); + } + + trace + } + + fn set_reverse_scale( + mut trace: Box>, + reverse_scale: Option, + ) -> Box> + where + X: Serialize + Clone, + Y: Serialize + Clone, + Z: Serialize + Clone, + { + if let Some(reverse_scale) = reverse_scale { + trace = trace.reverse_scale(reverse_scale); + } + + trace + } + + fn set_opacity( + mut trace: Box>, + opacity: Option, + ) -> Box> + where + X: Serialize + Clone, + Y: Serialize + Clone, + Z: Serialize + Clone, + { + if let Some(opacity) = opacity { + trace = trace.opacity(opacity); + } + + trace + } + + fn set_light_position( + mut trace: Box>, + lighting: Option<&Lighting>, + ) -> Box> + where + X: Serialize + Clone, + Y: Serialize + Clone, + Z: Serialize + Clone, + { + if let Some(light) = lighting { + if let Some(position) = light.position { + let position = Position::new(position[0], position[1], position[2]); + + trace = trace.light_position(position); + } + } + + trace + } + + fn set_color_scale( + mut trace: Box>, + color_scale: Option, + ) -> Box> + where + X: Serialize + Clone, + Y: Serialize + Clone, + Z: Serialize + Clone, + { + if let Some(color_scale) = color_scale { + trace = trace.color_scale(color_scale.to_plotly()); + } + + trace + } + + fn set_color_bar( + mut trace: Box>, + color_bar: Option<&ColorBar>, + ) -> Box> + where + X: Serialize + Clone, + Y: Serialize + Clone, + Z: Serialize + Clone, + { + if let Some(color_bar) = color_bar { + trace = trace.color_bar(color_bar.to_plotly()) + } + + trace + } + + fn unique_ordered(v: Vec>) -> Vec { + IndexSet::>::from_iter( + v.into_iter() + .flatten() + .map(OrderedFloat) + ) + .into_iter() + .map(|of| of.into_inner()) + .collect() + } +} + +impl Layout for SurfacePlot {} +impl Polar for SurfacePlot {} + +impl PlotHelper for SurfacePlot { + fn get_layout(&self) -> &LayoutPlotly { + &self.layout + } + + fn get_traces(&self) -> &Vec> { + &self.traces + } +} diff --git a/src/plots/template.rs b/src/plots/template.rs new file mode 100644 index 0000000..bed5fb7 --- /dev/null +++ b/src/plots/template.rs @@ -0,0 +1,116 @@ +use bon::bon; + +use plotly::{ + // Plot struct here, + Layout as LayoutPlotly, + Trace, +}; + +use polars::frame::DataFrame; +use serde::Serialize; + +use crate::{ + common::{Layout, PlotHelper, Polar}, + components::{Axis, Text}, +}; + +#[derive(Clone, Serialize)] +pub struct TemplatePlot { + traces: Vec>, + layout: LayoutPlotly, +} + +#[bon] +impl TemplatePlot { + #[builder(on(String, into), on(Text, into))] + pub fn new( + data: &DataFrame, + x: &str, + y: &str, + plot_title: Option, + x_title: Option, + y_title: Option, + x_axis: Option<&Axis>, + y_axis: Option<&Axis>, + ) -> Self { + let legend = None; + let legend_title = None; + let z_title = None; + let z_axis = None; + + let layout = Self::create_layout( + plot_title, + x_title, + y_title, + z_title, + legend_title, + x_axis, + y_axis, + z_axis, + legend, + ); + + let traces = Self::create_traces(data, x, y); + + Self { traces, layout } + } + + #[allow(clippy::too_many_arguments)] + fn create_traces( + data: &DataFrame, + x: &str, + y: &str, + ) -> Vec> { + let mut traces: Vec> = Vec::new(); + + let trace = Self::create_trace(data, x, y); + + traces.push(trace); + traces + } + + #[allow(clippy::too_many_arguments)] + fn create_trace( + data: &DataFrame, + x: &str, + y: &str, + ) -> Box { + let x = Self::get_string_column(data, x); + let y = Self::get_numeric_column(data, y); + + let mut trace = Plot here::new(x, y); + + trace = Self::set_something(trace, something); + + trace + } + + fn set_something( + mut trace: Box>, + something: Option<&something>, + ) -> Box> + where + X: Serialize + Clone, + Y: Serialize + Clone, + Z: Serialize + Clone, + { + if let Some(something) = something { + trace = trace.something(something.to_plotly()) + } + + trace + } +} + +impl Layout for TemplatePlot {} +impl Polar for TemplatePlot {} + +impl PlotHelper for TemplatePlot { + fn get_layout(&self) -> &LayoutPlotly { + &self.layout + } + + fn get_traces(&self) -> &Vec> { + &self.traces + } +} diff --git a/src/plots/timeseriesplot.rs b/src/plots/timeseriesplot.rs index 43cd141..32c5a46 100644 --- a/src/plots/timeseriesplot.rs +++ b/src/plots/timeseriesplot.rs @@ -1,19 +1,26 @@ use bon::bon; use plotly::{ - common::{Line as LinePlotly, Marker as MarkerPlotly, Mode}, Layout as LayoutPlotly, Scatter, Trace, + common::{Line as LinePlotly, Marker as MarkerPlotly, Mode}, }; use polars::{ frame::DataFrame, - prelude::{col, IntoLazy}, + prelude::{IntoLazy, col}, }; use serde::Serialize; use crate::{ common::{Layout, Line, Marker, PlotHelper, Polar}, - components::{Axis, Legend, Line as LineStyle, Rgb, Shape, Text}, + components::{ + Axis, + Legend, + Line as LineStyle, + Rgb, + Shape, + Text, + }, }; /// A structure representing a time series plot. @@ -44,12 +51,13 @@ use crate::{ /// * `legend_title` - An optional `Text` struct specifying the title of the legend. /// * `x_axis` - An optional reference to an `Axis` struct for customizing the x-axis. /// * `y_axis` - An optional reference to an `Axis` struct for customizing the y-axis. +/// * `y_axis2` - An optional reference to an `Axis` struct for customizing the y-axis2. /// * `legend` - An optional reference to a `Legend` struct for customizing the legend of the plot (e.g., positioning, font, etc.). /// /// # Example /// /// ```rust -/// use plotlars::{Legend, Line, Plot, Rgb, Shape, Text, TimeSeriesPlot}; +/// use plotlars::{Axis, Legend, Line, Plot, Rgb, Shape, Text, TimeSeriesPlot}; /// /// let dataset = LazyCsvReader::new("data/revenue_and_cost.csv") /// .finish() @@ -69,8 +77,8 @@ use crate::{ /// .additional_series(vec!["Cost"]) /// .size(8) /// .colors(vec![ +/// Rgb(0, 0, 255), /// Rgb(255, 0, 0), -/// Rgb(0, 255, 0), /// ]) /// .lines(vec![Line::Dash, Line::Solid]) /// .with_shape(true) @@ -85,11 +93,32 @@ use crate::{ /// .x(0.05) /// .y(0.9) /// ) +/// .x_title("x") +/// .y_title( +/// Text::from("y") +/// .color(Rgb(0, 0, 255)) +/// ) +/// .y_title2( +/// Text::from("y2") +/// .color(Rgb(255, 0, 0)) +/// ) +/// .y_axis( +/// &Axis::new() +/// .value_color(Rgb(0, 0, 255)) +/// .show_grid(false) +/// .zero_line_color(Rgb(0, 0, 0)) +/// ) +/// .y_axis2( +/// &Axis::new() +/// .axis_side(plotlars::AxisSide::Right) +/// .value_color(Rgb(255, 0, 0)) +/// .show_grid(false) +/// ) /// .build() /// .plot(); /// ``` /// -/// ![Example](https://imgur.com/1GaGFbk.png) +/// ![Example](https://imgur.com/hL27Xcn.png) #[derive(Clone, Serialize)] pub struct TimeSeriesPlot { traces: Vec>, @@ -116,9 +145,11 @@ impl TimeSeriesPlot { plot_title: Option, x_title: Option, y_title: Option, + y_title2: Option, legend_title: Option, x_axis: Option<&Axis>, y_axis: Option<&Axis>, + y_axis2: Option<&Axis>, legend: Option<&Legend>, ) -> Self { let z_title = None; @@ -128,10 +159,12 @@ impl TimeSeriesPlot { plot_title, x_title, y_title, + y_title2, z_title, legend_title, x_axis, y_axis, + y_axis2, z_axis, legend, ); @@ -189,7 +222,7 @@ impl TimeSeriesPlot { let name = Some(y_col); - let trace = Self::create_trace(data, x_col, y_col, name, with_shape, marker, line); + let trace = Self::create_trace(data, x_col, y_col, name, with_shape, marker, line, ""); traces.push(trace); @@ -218,8 +251,11 @@ impl TimeSeriesPlot { let name = Some(series); + let index = format!("y{}", i + 2); + let index = index.as_str(); + let trace = - Self::create_trace(&subset, x_col, series, name, with_shape, marker, line); + Self::create_trace(&subset, x_col, series, name, with_shape, marker, line, index); traces.push(trace); } @@ -228,6 +264,7 @@ impl TimeSeriesPlot { traces } + #[allow(clippy::too_many_arguments)] fn create_trace( data: &DataFrame, x_col: &str, @@ -236,6 +273,7 @@ impl TimeSeriesPlot { with_shape: Option, marker: MarkerPlotly, line: LinePlotly, + index: &str, ) -> Box { let x_data = Self::get_string_column(data, x_col); let y_data = Self::get_numeric_column(data, y_col); @@ -257,7 +295,7 @@ impl TimeSeriesPlot { trace = trace.name(name); } - trace + trace.y_axis(index) } }