1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
//! This is a plotting util for rust which uses ascii/unicode art to display graphs, plots, and images in the standard output, in a string, or saved to a file.
//!
//! Check out the documentation for more information on each of the plot types and options.
//!
//! # Basic Syntax / Example Usage
//!
//! Each plot file contains a public function by the name of that plot. For example,
//! `pub fn array_plot<T>(data: &Vec<Vec<T>>) -> ArrayPlotBuilder<T>`
//! creates an ArrayPlotBuilder instance.
//!
//! You can then set options for it such as title, axes, output size, and more (depending on the type of plot). Finally, you can call .print() or .as_string() or .pyplot() to print it to the standard output, or return the plot as a string, or display an interactive window with matplotlib, respectively.
//!
//! For example:
//! ```
//! use cgrustplot::{
//! plots::array_plot::{array_plot, bin_arr},
//! helper::charset::gradient_chars::shade_chars,
//! };
//!
//! // table of sin(x + y)
//! let my_data: Vec<Vec<f64>> = (0..10).map(|x| {(0..30).map(|y| (x as f64 + y as f64).sin()).collect()}).collect();
//!
//! array_plot(&bin_arr(&my_data, 4)) // Bins the array to have four values
//! .set_title("A Plot of my Data:") // Sets the title of the plot
//! .set_axes(true) // Turns on the axes for the plot
//! .set_chars(shade_chars()) // uses unicode shade characters
//! .print() // Displays the plot
//! ```
//!
//! And the output of the above code is this plot:
//!
//! *NOTE: some plots may not display correctly without a monowidth font, such as on github*
//!
//! ```text
//! A Plot of my Data:
//! │▓██▓ ░██▓ ▓██░ ▓██░ ░██▓
//! 8.500 ┼██▓ ░██▓ ▓██░ ▓██░ ░██▓
//! │█▓ ░██▓ ▓██░ ▓██░ ░██▓ ░
//! 6.500 ┼▓ ░██▓ ▓██░ ▓██░ ░██▓ ░█
//! │ ░██▓ ▓██░ ▓██░ ░██▓ ░██
//! 4.500 ┼ ░██▓ ▓██░ ▓██░ ░██▓ ░███
//! │░██▓ ▓██░ ▓██░ ░██▓ ░███░
//! 2.500 ┼██▓ ▓██░ ▓██░ ░██▓ ░███░
//! │█▓ ▓██░ ▓██░ ░██▓ ░███░
//! 0.500 ┼▓ ▓██░ ▓██░ ░██▓ ░███░ ▓
//! └┼──────┼──────┼──────┼────────
//! 0.5000 7.5000 14.500 21.500
//! ```
//! # Plot Types
//! In no particular order, here are some of the various types of plots that can be used
//! (more plots than listed here may already be available. Check the /src/plots/ for a full list while in development).
//!
//! ## Array Plot
//! Filename: array_plot.rs
//!
//! Displays a table with varying brightness across it's characters.
//! Takes in a `&Vec<Vec<T>>`, representing the brightness value at each point.
//!
//! The dimensions of the output string are equal to the dimensions of the input table, so if you give a 15x12 grid of values, the output will be about 15x12 characters in size. (Note that axes and title will change this).
//!
//! ### Options
//! `title: Option<&str>` Sets the title to be displayed above the output. Default is None, which has no displayed title.
//!
//! `axes: bool` Selects whether to turn on or off the axes. Axes display in units of the number of characters. Default is true
//!
//! `chars: Vec<String>` The character set to be used. Defaults are based on `rustplot::helper::charset::gradient_chars`, depending on the number of distinct values in the table.
//!
//! `bins: Option<u32>` Only for plots of f64. It bins close-together datapoints and plots based on those. Not so much a plot option as much as a transformation, as it actually creates a new struct of `<u32>` instead of `<f64>`.
//!
//! ### Example
//!
//! Code:
//! ```
//! use cgrustplot::plots::array_plot::array_plot;
//!
//! let data: Vec<Vec<i32>> = (-5..=5)
//! .map(|i: i32|
//! (-15..=15).map(|j: i32|
//! i.pow(2) + j.pow(2)
//! ).collect()
//! ).collect();
//!
//! array_plot(&data)
//! .print()
//! ```
//!
//! Output:
//! ```text
//! 10.50 ┼@%%#**++=---:::::::---=++**#%%@
//! │@%##**+==--::.....::--==+**##%@
//! 8.500 ┼@%##*++=--::.......::--=++*##%@
//! │@%##*+==-::... ...::-==+*##%@
//! 6.500 ┼@%#**+==-::.. ..::-==+**#%@
//! │%%#**+=--::.. ..::--=+**#%%
//! 4.500 ┼@%#**+==-::.. ..::-==+**#%@
//! │@%##*+==-::... ...::-==+*##%@
//! 2.500 ┼@%##*++=--::.......::--=++*##%@
//! │@%##**+==--::.....::--==+**##%@
//! 0.500 ┼@%%#**++=---:::::::---=++**#%%@
//! └┼──────┼──────┼──────┼─────────
//! 0.5000 7.5000 14.500 21.500
//! ```
//!
//! ## Function Plot
//! Filename: func_plot.rs
//!
//! Displays the output of a numerically-valued function over a domain.
//! Takes in a `Fn(U) -> V` for types which can be cast to and from f64, respectively.
//!
//! ### Options
//! `domain: (f64, f64)` Sets the domain (i.e. min and max x values) over which to plot the function. If no domain is selected, `rustplot::helper::func_plot_domain::determine_plot_domain` will be used as a default. By a variety of heuristic methods, it is usually able to determine a domain over which some useful behavior can be observed.
//!
//! `range: (f64, f64)` Sets the range (i.e. min and max y values) over which to plot the function. Default comes from the min and max values of the function within it's domain.
//!
//! `domain_padding: f64` Pads the domain by some percentage. For example, with padding of 0.01, the domain (0, 10) gets turned into (-0.1, 10.1).
//!
//! `range_padding: f64` Pads the range by some percentage.
//!
//! `size: (u32, u32)` Sets the size of the output of the plot, measured in number of characters.
//!
//! `title: Option<&str>`
//!
//! `axes: bool`
//!
//! ### Example
//!
//! Code:
//! ```
//! use cgrustplot::plots::function_plot::function_plot;
//!
//! let f = |x: f64| x.powi(3);
//!
//! function_plot(&f)
//! .set_size((30, 10))
//! .print();
//! ```
//!
//! Output:
//! ```text
//! │ _‾
//! 1.293 ┼ /
//! │ _‾
//! 0.554 ┼ _―‾
//! │ _――――――――――‾
//! -0.18 ┼ _―‾
//! │ _‾
//! -0.92 ┼ /
//! │ /
//! -1.66 ┼ /
//! └┼──────┼──────┼──────┼────────
//! -1.339 -0.692 -0.046 0.6004
//! ```
//!
//! ## Scatter Plot
//! Filename: scatter_plot.rs
//!
//! Displays a scatter plot from a given set of points `Vec<(f64, f64)>`.
//!
//! ### Options
//! `range: ((f64, f64), (f64, f64))` Sets the domain as well as range (i.e. min and max x and values) over which to plot the function. Sorry about the inconsistency between range here and in other places. It may be fixed in the future.
//!
//! `padding: f64` Pads both the domain and range by some percentage.
//!
//! `size: (u32, u32)`
//!
//! `title: Option<&str>`
//!
//! `axes: bool`
//!
//! `chars: (Vec<char>, (u32, u32))` The character set to be used. Defaults are based on `rustplot::helper::charset::subdiv_chars`, depending on the number of unique points that would be overwritten at each size. (i.e. it tries not to show two points in only a single character). You must specify the dimension of each character. For example, braille characters allow you to plot a grid of 2x4 dots for each character, so you must pass in (2, 4) in addition to the character set.
//!
//! ### Example
//! Code:
//! ```
//! use cgrustplot::plots::scatter_plot::scatter_plot;
//! use cgrustplot::helper::charset::subdiv_chars::dots_two_by_four;
//! use rand::{Rng, SeedableRng, rngs::StdRng};
//!
//! // Generate some random data points within ((0, 60), (0, 30))
//! let mut rng: StdRng = SeedableRng::seed_from_u64(0);
//! let data: Vec<(f64, f64)> = (0..100).map(|_|
//! (rng.gen_range(0.0..60.0), rng.gen_range(0.0..30.0))
//! ).collect();
//!
//! scatter_plot(&data)
//! .set_size((30, 10))
//! .set_chars((dots_two_by_four(), (2, 4)))
//! .set_range(((0., 60.), (0., 30.)))
//! .set_padding(0.)
//! .print();
//! ```
//!
//! Output:
//! ```text
//! │⠔⡈⢀⠀⠂⠀⠀⠂⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠂⢁⠀⠀⠂⠀⠀⠀⡀⠀⠀⠄
//! 25.50 ┼⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⢀⠀⠀⠁⠐⠀⠁⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐
//! │⠀⠀⠀⠄⠀⠄⠀⠠⠀⠀⡀⠈⠀⠈⠀⠀⠀⠀⠠⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀
//! 19.50 ┼⠄⠀⠁⠀⠀⠀⠁⠀⠡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠈⠀⠀⠐⠀⠀
//! │⠀⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠂⠀⠀
//! 13.50 ┼⢀⠀⠀⠀⠀⠁⠣⠀⠀⠀⠠⠄⠀⠀⠰⠀⠀⢂⠀⠀⠀⠀⠀⠁⠀⠀⣀⠀⠀⠀
//! │⠠⢀⠀⠀⠅⠠⠀⠀⠐⠀⠀⠀⠀⠀⠀⠀⠀⠁⠈⠀⠀⠀⠀⠠⠀⠐⠀⣀⠠⠠
//! 7.500 ┼⠀⠀⠈⠂⠀⠀⢀⠡⠀⠀⠀⠀⠀⠀⠀⠠⠀⠀⠀⠀⡀⠠⠀⠀⠀⠀⠀⠀⠀⠀
//! │⠀⠐⠀⠀⠐⠀⠀⠀⠀⠀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠀⠀⢀⠄⠁⠄⠄⠀⠀⠀
//! 1.500 ┼⠀⢀⡀⠄⠁⠀⢀⠀⠀⠀⠀⠀⠀⠈⠀⢀⠀⠀⠀⠀⠀⢀⠄⠀⠀⠁⠀⠀⠀⠀
//! └┼──────┼──────┼──────┼────────
//! 1.0000 15.000 29.000 43.000
//! ```
//!
//!
//! ## Region Plot
//! Filename: Region_plot.rs
//!
//! Displays the region over which a predicate `pred: Fn(f64, f64) -> bool` is true.
//!
//! ### Options
//! `range: ((f64, f64), (f64, f64))` Sets the domain as well as range (i.e. min and max x and values) over which to plot the predicate
//!
//! `padding: f64`
//!
//! `size: (u32, u32)`
//!
//! `title: Option<&str>`
//!
//! `axes: bool`
//!
//! ### Example
//! Code:
//! ```
//! use cgrustplot::plots::region_plot::region_plot;
//!
//! let p = |x: f64, y: f64| (x.powi(2) + y.powi(2)).sqrt() <= 0.7;
//!
//! region_plot(&p)
//! .set_domain_and_range(((-1., 1.), (-1., 1.)))
//! .set_size((30, 10))
//! .print();
//! ```
//!
//! Output:
//! ```text
//! │
//! 0.840 ┼
//! │ ▄▄▄▄▖
//! 0.360 ┼ ▗▟█████████▄
//! │ ▗████████████▙
//! -0.12 ┼ ▜█████████████▘
//! │ ▜███████████▘
//! -0.60 ┼ ▝▀▀████▛▀▀
//! │
//! -1.08 ┼
//! └┼─────┼─────┼─────┼──────
//! -1.15 -0.57 0.000 0.576
//! ```
//! # Structure
//!
//! This crate is structured into plots, helper functions, and tests.
//!
//! The `plots` module contains all the plot types.
//!
//! The `helper` module contains extra functions used throughout the crate.
//!
//! The 'tests` module (private) implemenents unit tests and full tests for plots and helpers.
//!
//! # Contribution and Development
//!
//! So far, this has been a completely solo project. If you have anything to add, or would like to
//! help out in any way, just reach out or submit your changes with a pull request.
//!
//! In order to properly run tests involving saving files, create a directory called "testoutput"
//! in the workspace folder.
//!