#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DataPoint {
pub x: f64,
pub y: f64,
}
impl DataPoint {
pub fn new(x: f64, y: f64) -> Self {
Self { x, y }
}
}
#[derive(Debug, Clone)]
pub struct Series<T> {
pub name: String,
pub data: Vec<T>,
pub visible: bool,
}
impl<T> Series<T> {
pub fn new(name: impl Into<String>, data: Vec<T>) -> Self {
Self {
name: name.into(),
data,
visible: true,
}
}
}
#[derive(Debug, Clone)]
pub struct Dataset {
pub series: Vec<Series<DataPoint>>,
}
impl Dataset {
pub fn new() -> Self {
Self { series: Vec::new() }
}
pub fn add_series(&mut self, series: Series<DataPoint>) {
self.series.push(series);
}
pub fn from_series(series: Series<DataPoint>) -> Self {
Self {
series: vec![series],
}
}
}
impl Default for Dataset {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct OhlcBar {
pub timestamp: f64,
pub open: f64,
pub high: f64,
pub low: f64,
pub close: f64,
}
impl OhlcBar {
pub fn new(timestamp: f64, open: f64, high: f64, low: f64, close: f64) -> Self {
Self {
timestamp,
open,
high,
low,
close,
}
}
pub fn is_bullish(&self) -> bool {
self.close >= self.open
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WaterfallKind {
Start,
Delta,
Total,
}
#[derive(Debug, Clone)]
pub struct WaterfallBar {
pub label: String,
pub value: f64,
pub kind: WaterfallKind,
}
impl WaterfallBar {
pub fn delta(label: impl Into<String>, value: f64) -> Self {
Self {
label: label.into(),
value,
kind: WaterfallKind::Delta,
}
}
pub fn start(label: impl Into<String>, value: f64) -> Self {
Self {
label: label.into(),
value,
kind: WaterfallKind::Start,
}
}
pub fn total(label: impl Into<String>, value: f64) -> Self {
Self {
label: label.into(),
value,
kind: WaterfallKind::Total,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct BarDataset {
pub categories: Vec<String>,
pub series: Vec<BarSeries>,
}
impl BarDataset {
pub fn new(categories: Vec<String>) -> Self {
Self {
categories,
series: Vec::new(),
}
}
pub fn add_series(&mut self, name: impl Into<String>, values: Vec<f64>) {
self.series.push(BarSeries {
name: name.into(),
values,
});
}
}
#[derive(Debug, Clone)]
pub struct BarSeries {
pub name: String,
pub values: Vec<f64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum DataType {
Quantitative,
Temporal,
Nominal,
Ordinal,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FieldRole {
Dimension,
Measure,
}
impl FieldRole {
pub fn from_data_type(dt: DataType) -> Self {
match dt {
DataType::Quantitative => Self::Measure,
DataType::Temporal => Self::Dimension, DataType::Nominal | DataType::Ordinal => Self::Dimension,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct GridData {
pub values: Vec<Vec<f64>>,
pub row_labels: Option<Vec<String>>,
pub col_labels: Option<Vec<String>>,
}
impl GridData {
pub fn min(&self) -> f64 {
self.values
.iter()
.flatten()
.cloned()
.fold(f64::INFINITY, f64::min)
.clamp(0.0, f64::MAX)
}
pub fn max(&self) -> f64 {
self.values
.iter()
.flatten()
.cloned()
.fold(f64::NEG_INFINITY, f64::max)
}
}
#[derive(Debug, Clone)]
pub struct StripGroup {
pub name: String,
pub values: Vec<f64>,
}
#[derive(Debug, Clone)]
pub struct SankeyNode {
pub label: String,
pub color: Option<String>,
}
#[derive(Debug, Clone)]
pub struct SankeyLink {
pub source: usize,
pub target: usize,
pub value: f64,
pub color: Option<String>,
}
#[derive(Debug, Clone, Default)]
pub struct SankeyData {
pub nodes: Vec<SankeyNode>,
pub links: Vec<SankeyLink>,
}
#[derive(Debug, Clone, Default)]
pub struct ChordData {
pub matrix: Vec<Vec<f64>>,
pub labels: Vec<String>,
pub colors: Option<Vec<String>>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_data_point_creation() {
let point = DataPoint::new(1.0, 2.0);
assert_eq!(point.x, 1.0);
assert_eq!(point.y, 2.0);
}
#[test]
fn test_series_creation() {
let data = vec![DataPoint::new(1.0, 2.0), DataPoint::new(3.0, 4.0)];
let series = Series::new("test", data.clone());
assert_eq!(series.name, "test");
assert_eq!(series.data.len(), 2);
}
#[test]
fn test_dataset_creation() {
let mut dataset = Dataset::new();
assert_eq!(dataset.series.len(), 0);
let series = Series::new("s1", vec![DataPoint::new(1.0, 2.0)]);
dataset.add_series(series);
assert_eq!(dataset.series.len(), 1);
}
#[test]
fn test_dataset_from_series() {
let series = Series::new("s1", vec![DataPoint::new(1.0, 2.0)]);
let dataset = Dataset::from_series(series);
assert_eq!(dataset.series.len(), 1);
assert_eq!(dataset.series[0].name, "s1");
}
}