Skip to content

Commit 8713ad2

Browse files
naijimandrei-ngbaiguonamekylemello
authored
Add Table trace (#207)
* Add `Table` trace * update changelog --------- Signed-off-by: Andrei Gherghescu <[email protected]> Co-authored-by: Andrei Gherghescu <[email protected]> Co-authored-by: baiguoname <[email protected]> Co-authored-by: kylemello <[email protected]>
1 parent 4815df7 commit 8713ad2

File tree

6 files changed

+196
-2
lines changed

6 files changed

+196
-2
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
55

66
## [0.9.0] - 2024-xx-xx
77
### Added
8+
- [[#207](https://github.com/plotly/plotly,rs/pull/207)] Add `Table` trace.
89
- [[#181](https://github.com/plotly/plotly,rs/pull/181)] Fix compilation error when mixing the crate with `askama/with-axum` by adding `with-axum` feature.
910
- [[#180](https://github.com/plotly/plotly.rs/pull/180)] Add setter for `Mapbox::domain`.
11+
- [[#178](https://github.com/plotly/plotly.rs/pull/178)] Fix setter for `Axis::matches` to take string arg.
1012
- [[#166](https://github.com/plotly/plotly.rs/pull/166)] Added subplot example with multiple titles.
1113
- [[#163](https://github.com/plotly/plotly.rs/pull/163)] Added `DensityMapbox`.
1214
- [[#161](https://github.com/plotly/plotly.rs/pull/161)] Added `Axis` `scaleanchor` settter.

examples/basic_charts/src/main.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ use plotly::{
99
},
1010
layout::{Axis, BarMode, Layout, Legend, TicksDirection, TraceOrder},
1111
sankey::{Line as SankeyLine, Link, Node},
12-
Bar, Plot, Sankey, Scatter, ScatterPolar,
12+
traces::table::{Cells, Header},
13+
Bar, Plot, Sankey, Scatter, ScatterPolar, Table,
1314
};
1415
use rand_distr::{Distribution, Normal, Uniform};
1516

@@ -604,6 +605,16 @@ fn basic_sankey_diagram() {
604605
plot.show();
605606
}
606607

608+
fn table_chart() {
609+
let trace = Table::new(
610+
Header::new(vec![String::from("col1"), String::from("col2")]),
611+
Cells::new(vec![vec![1, 2], vec![2, 3]]),
612+
);
613+
let mut plot = Plot::new();
614+
plot.add_trace(trace);
615+
plot.show();
616+
}
617+
607618
fn main() {
608619
// Uncomment any of these lines to display the example.
609620

@@ -629,6 +640,7 @@ fn main() {
629640
// basic_bar_chart();
630641
// grouped_bar_chart();
631642
// stacked_bar_chart();
643+
// table_chart();
632644

633645
// Sankey Diagrams
634646
// basic_sankey_diagram();

plotly/src/common/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ pub enum PlotType {
202202
Sankey,
203203
Surface,
204204
DensityMapbox,
205+
Table,
205206
}
206207

207208
#[derive(Serialize, Clone, Debug)]

plotly/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub use traces::{
3636
// Bring the different trace types into the top-level scope
3737
pub use traces::{
3838
Bar, BoxPlot, Candlestick, Contour, DensityMapbox, HeatMap, Histogram, Image, Mesh3D, Ohlc,
39-
Sankey, Scatter, Scatter3D, ScatterMapbox, ScatterPolar, Surface,
39+
Sankey, Scatter, Scatter3D, ScatterMapbox, ScatterPolar, Surface, Table,
4040
};
4141

4242
pub trait Restyle: serde::Serialize {}

plotly/src/traces/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ mod scatter3d;
1616
pub mod scatter_mapbox;
1717
mod scatter_polar;
1818
pub mod surface;
19+
pub mod table;
1920

2021
pub use bar::Bar;
2122
pub use box_plot::BoxPlot;
@@ -32,5 +33,6 @@ pub use scatter3d::Scatter3D;
3233
pub use scatter_mapbox::ScatterMapbox;
3334
pub use scatter_polar::ScatterPolar;
3435
pub use surface::Surface;
36+
pub use table::Table;
3537

3638
pub use self::image::Image;

plotly/src/traces/table.rs

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
//! Table trace
2+
3+
use plotly_derive::FieldSetter;
4+
use serde::Serialize;
5+
6+
use crate::{
7+
color::Color,
8+
common::{Font, Line, PlotType, Visible},
9+
Trace,
10+
};
11+
12+
#[serde_with::skip_serializing_none]
13+
#[derive(Serialize, Clone, Debug, FieldSetter)]
14+
#[field_setter(box_self, kind = "trace")]
15+
pub struct Table<T, N>
16+
where
17+
T: Serialize + Clone + 'static,
18+
N: Serialize + Clone + 'static,
19+
{
20+
#[field_setter(default = "PlotType::Table")]
21+
r#type: PlotType,
22+
/// Sets the trace name. The trace name appear as the legend item and on
23+
/// hover.
24+
name: Option<String>,
25+
#[serde(rename = "columnorder")]
26+
/// Determines whether or not this trace is visible. If
27+
/// `Visible::LegendOnly`, the trace is not drawn, but can appear as a
28+
/// legend item (provided that the legend itself is visible).
29+
visible: Option<Visible>,
30+
///Specifies the rendered order of the data columns; for example, a value
31+
/// `2` at position `0`, means that column index `0` in the data will be
32+
/// rendered as the, third column, as columns have an index base of
33+
/// zero.
34+
column_order: Option<Vec<usize>>,
35+
#[serde(rename = "columnwidth")]
36+
///The width of columns expressed as a ratio. Columns fill the available
37+
/// width, in proportion of their specified column widths.
38+
column_width: Option<f64>,
39+
///Header cell values. `values[m][n]` represents the value of the `n`th
40+
/// point in column `m`,, therefore the `values[m]` vector length for
41+
/// all columns must be the same (longer vectors, will be truncated).
42+
/// Each value must be a finite number or a string.
43+
header: Option<Header<T>>,
44+
///Cell values. `values[m][n]` represents the value of the `n`th point in
45+
/// column `m`,, therefore the `values[m]` vector length for all columns
46+
/// must be the same (longer vectors, will be truncated). Each value
47+
/// must be a finite number or a string.
48+
cells: Option<Cells<N>>,
49+
}
50+
51+
impl<T, N> Table<T, N>
52+
where
53+
T: Serialize + Clone + Default + 'static,
54+
N: Serialize + Clone + Default + 'static,
55+
{
56+
pub fn new(header: Header<T>, cells: Cells<N>) -> Box<Self> {
57+
Box::new(Table {
58+
header: Some(header),
59+
cells: Some(cells),
60+
..Default::default()
61+
})
62+
}
63+
}
64+
65+
impl<T, N> Trace for Table<T, N>
66+
where
67+
T: Serialize + Clone + 'static,
68+
N: Serialize + Clone + 'static,
69+
{
70+
fn to_json(&self) -> String {
71+
serde_json::to_string(self).unwrap()
72+
}
73+
}
74+
75+
#[serde_with::skip_serializing_none]
76+
#[derive(Serialize, Clone, Debug, FieldSetter)]
77+
pub struct Cells<N> {
78+
///Cell values. `values[m][n]` represents the value of the `n`th point in
79+
/// column `m`, therefore the `values[m]` vector length for all columns
80+
/// must be the same (longer vectors, will be truncated). Each value
81+
/// must be a finite number or a string
82+
values: Option<Vec<Vec<N>>>,
83+
///Prefix for cell values.
84+
prefix: Option<String>,
85+
///Suffix for cell values.
86+
suffix: Option<String>,
87+
height: Option<f64>,
88+
align: Option<String>,
89+
line: Option<Line>,
90+
///Sets the cell fill color. It accepts either a specific color,
91+
///or an array of colors or a 2D array of colors
92+
fill: Option<Fill>,
93+
font: Option<Font>,
94+
}
95+
96+
impl<N> Cells<N>
97+
where
98+
N: Serialize + Clone + Default + 'static,
99+
{
100+
pub fn new(values: Vec<Vec<N>>) -> Self {
101+
Cells {
102+
values: Some(values),
103+
..Default::default()
104+
}
105+
}
106+
}
107+
108+
#[serde_with::skip_serializing_none]
109+
#[derive(Serialize, Clone, Debug, FieldSetter)]
110+
pub struct Header<T> {
111+
///Header cell values. `values[m][n]` represents the value of the `n`th
112+
/// point in column `m`, therefore the `values[m]` vector length for all
113+
/// columns must be the same (longer vectors, will be truncated). Each
114+
/// value must be a finite number or a string.
115+
values: Option<Vec<T>>,
116+
///Prefix for cell values.
117+
prefix: Option<String>,
118+
///Suffix for cell values.
119+
suffix: Option<String>,
120+
height: Option<f64>,
121+
align: Option<String>,
122+
line: Option<Line>,
123+
///Sets the cell fill color. It accepts either a specific color,
124+
///or an array of colors or a 2D array of colors
125+
fill: Option<Fill>,
126+
font: Option<Font>,
127+
}
128+
129+
impl<T> Header<T>
130+
where
131+
T: Serialize + Clone + Default + 'static,
132+
{
133+
pub fn new(values: Vec<T>) -> Self {
134+
Header {
135+
values: Some(values),
136+
..Default::default()
137+
}
138+
}
139+
}
140+
141+
#[serde_with::skip_serializing_none]
142+
#[derive(Serialize, Clone, Debug, FieldSetter)]
143+
pub struct Fill {
144+
color: Option<Box<dyn Color>>,
145+
}
146+
147+
impl Fill {
148+
pub fn new() -> Self {
149+
Default::default()
150+
}
151+
}
152+
153+
#[cfg(test)]
154+
mod tests {
155+
use serde_json::{json, to_value};
156+
157+
use super::*;
158+
159+
#[test]
160+
fn test_serialize_table() {
161+
let columns = Header::new(vec![String::from("col1"), String::from("col2")]);
162+
let values = Cells::new(vec![vec![1, 2], vec![2, 3]]);
163+
let trace = Table::new(columns, values);
164+
165+
let expected = json!({
166+
"type": "table",
167+
"cells": {
168+
"values": [[1, 2], [2, 3]],
169+
},
170+
"header": {
171+
"values": ["col1", "col2"],
172+
},
173+
});
174+
175+
assert_eq!(to_value(trace).unwrap(), expected);
176+
}
177+
}

0 commit comments

Comments
 (0)