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
//! This module provides all functionality for creating and drawing customizable charts.
//!
//! Each chart that can drawn has its own structure which can be created with data provided to it and a name.
//!
//! All charts can be drawn using the draw() method provided by the Chart trait that each chart implements.
//!
//! All charts are composed of the ChartProp structure allowing manipulation of functionality common to all charts.
//!
//! Charts that require axis are composed of the AxisProp structure allowing manipulation of axis.
//!
//! # Example of General Use
//!
//! ```
//! // Imports for libary use.
//! use rustplot::chart_builder;
//! use rustplot::chart_builder::Chart;
//!
//! // Data used to build chart (data_parser can be used to fetch this data from a csv file).
//! let x_data = vec![vec![38.0, 67.0, 80.0],     // x data of first series
//!                   vec![29.0, 48.0, 94.0]];    // x data of second series
//! let y_data = vec![vec![27.0, 50.0, 80.0],     // y data of first series
//!                   vec![45.0, 55.0, 78.0]];    // y data of second series
//! let mag_data = vec![vec![2.0, 8.0, 15.0],     // magnitude data of first series
//!                   vec![6.0, 10.0, 18.0]];     // magnitude data of second series
//!
//! // Create instance of a chart with data.
//! let mut example_chart = chart_builder::BubbleChart::new(String::from("Example Bubble Chart"),
//!     x_data,
//!     y_data,
//!     mag_data
//!     );
//!
//! // Add legend data and show ledgend (optional)
//! let legend_values = vec![String::from("Series 1"), String::from("Series 2")];
//! example_chart.chart_prop.set_legend_values(legend_values);
//! example_chart.chart_prop.set_show_legend(true);
//!
//! // Draw the chart displayed in a window.
//! example_chart.draw();
//! ```

use std::env::args;

// Imports from gtk-rs for drawing
extern crate cairo;
extern crate gio;
extern crate gtk;

// warning suppressed as gio::prelude::* is used but a warning is still thrown.
#[allow(unused_imports)]
use self::gio::prelude::*;

use self::gtk::prelude::*;
use self::gtk::DrawingArea;

use self::cairo::Context;
use self::cairo::enums::{FontSlant, FontWeight};
#[allow(unused_imports)]
use self::cairo::MatrixTrait;

/*
 * Defining general Chart component structures and thier constructors.
 */

mod chart_prop;
pub use self::chart_prop::ChartProp;

mod axis_prop;
pub use self::axis_prop::AxisProp;

/*
 * Generic Chart Trait specified.
 */

mod chart;
pub use self::chart::Chart;

/*
 * Window drawing functionality
 */

mod window;

/*
 * Seperated functionality for readability
 */

mod axis_drawer;

/*
 * Defining specific Chart structures.
 */

mod charts;
pub use self::charts::histogram::Histogram;
pub use self::charts::box_whisker_plot::BoxWhiskerPlot;
// pub use self::charts::tree_map::TreeMap;
pub use self::charts::doughnut_chart::DoughnutChart;
pub use self::charts::pie_chart::PieChart;
pub use self::charts::vertical_bar_chart::VerticalBarChart;
pub use self::charts::radar_chart::RadarChart;
pub use self::charts::area_chart::AreaChart;
pub use self::charts::stacked_area_chart::StackedAreaChart;
pub use self::charts::line_chart::LineChart;
pub use self::charts::xy_scatter_plot::XYScatterPlot;
pub use self::charts::bubble_chart::BubbleChart;

/*
 * Helper functions
 */

pub(in chart_builder) fn get_percentage_in_bounds(value: f64, min: f64, max: f64) -> f64 {
    (value - min) / (max - min)
}

/*
 * Public helper functions
 */

 /// Removes possible outliers from a Vector of numbers.
 ///
 /// ```data``` is a ```Vec<f64>``` for which the possible outliers will be removed.
pub fn remove_outliers(data: &Vec<f64>) -> Vec<f64> {
    // Sort data for determing percentile
    let mut sorted_data =  data.clone();
    sorted_data.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());

    use chart_builder::axis_prop::percentile;

    // Lower quartile is the (n + 1) ÷ 4 th value.
    let lq = percentile(&sorted_data, 0.25);
    // Upper quartile is the 3 (n + 1) ÷ 4 th value.
    let uq = percentile(&sorted_data, 0.75);
    // uq - lq
    let iqr = uq - lq;

    // set limits for outliers
    let lower_limit = lq - iqr * 1.5;
    let upper_limit = uq + iqr * 1.5;

    // remove outliers vaules from data
    sorted_data.retain(|&i|i >= lower_limit && i <= upper_limit);

    sorted_data
}


#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn get_percentage_in_bounds_tests() {
        assert_eq!(get_percentage_in_bounds(0.0, 0.0, 10.0), 0.0);
        assert_eq!(get_percentage_in_bounds(10.0, 0.0, 10.0), 1.0);
        assert_eq!(get_percentage_in_bounds(5.0, 0.0, 10.0), 0.5);
        assert_eq!(get_percentage_in_bounds(2.0, 0.0, 10.0), 0.2);
        assert_eq!(get_percentage_in_bounds(7.0, 0.0, 10.0), 0.7);
        assert_eq!(get_percentage_in_bounds(-2.0, 0.0, 10.0), -0.2);
        assert_eq!(get_percentage_in_bounds(12.0, 0.0, 10.0), 1.2);
    }
    #[test]
    fn remove_outliers_tests() {
        // No outlier
        let vec_1: Vec<f64> = vec![1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0];
        let result_1 = vec![1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0];
        let outlier_res_1 = remove_outliers(&vec_1);
        assert_eq!(outlier_res_1, result_1);

        // Outlier outside upper limit
        let vec_2: Vec<f64> = vec![1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,40.0];
        let result_2 = vec![1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0];
        let outlier_res_2 = remove_outliers(&vec_2);
        assert_eq!(outlier_res_2, result_2);

        // Outlier outside lower limit
        let vec_3: Vec<f64> = vec![1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,-40.0];
        let result_3= vec![1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0];
        let outlier_res_3 = remove_outliers(&vec_3);
        assert_eq!(outlier_res_3, result_3);
    }
}