Skip to content

Commit cd7a1be

Browse files
authored
Merge branch 'main' into HeatMap_zmin_zmax_fix_pr
2 parents 771f06e + 8713ad2 commit cd7a1be

File tree

10 files changed

+256
-9
lines changed

10 files changed

+256
-9
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
components: clippy
3939
targets: wasm32-unknown-unknown
4040
# lint the main library workspace excluding the wasm feature
41-
# Rust 1.79 generates a new lint in autogenrated code:
41+
# Rust 1.79 generates a new lint in autogenerated code:
4242
# Added clippy allow at the command line until it is fixed. See: https://github.com/rust-lang/rust-clippy/issues/12643 and https://github.com/TedDriggs/darling/issues/293
4343
- run: cargo clippy --features plotly_ndarray,plotly_image,kaleido -- -D warnings -Aclippy::manual_unwrap_or_default
4444
# lint the plotly library with wasm enabled

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@ All notable changes to this project will be documented in this file.
33

44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
55

6-
## [0.8.5] - 2024-xx-xx
6+
## [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.
12+
- [[#166](https://github.com/plotly/plotly.rs/pull/166)] Added subplot example with multiple titles.
1013
- [[#163](https://github.com/plotly/plotly.rs/pull/163)] Added `DensityMapbox`.
14+
- [[#161](https://github.com/plotly/plotly.rs/pull/161)] Added `Axis` `scaleanchor` settter.
15+
- [[#159](https://github.com/plotly/plotly.rs/pull/159)] Make `heat_map` module public to expose `Smoothing enum`.
1116
- [[#153](https://github.com/plotly/plotly.rs/pull/153)] Added `LayoutScene`.
1217

1318
## [0.8.4] - 2023-07-09

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@
2929
</h4>
3030
</div>
3131

32+
<div align="center">
33+
<a href="https://dash.plotly.com/project-maintenance">
34+
<img src="https://dash.plotly.com/assets/images/maintained-by-community.png" width="400px" alt="Maintained by the Plotly Community">
35+
</a>
36+
</div>
37+
3238
# Table of Contents
3339

3440
* [Introduction](#introduction)

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();

examples/subplots/src/main.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,50 @@ fn simple_subplot() {
2929
plot.show();
3030
}
3131

32+
fn simple_subplot_matches_x_axis() {
33+
let trace1 = Scatter::new(vec![1, 2, 3], vec![4, 5, 6]).name("trace1");
34+
let trace2 = Scatter::new(vec![20, 30, 40], vec![50, 60, 70])
35+
.name("trace2")
36+
.x_axis("x2")
37+
.y_axis("y2");
38+
39+
let mut plot = Plot::new();
40+
plot.add_trace(trace1);
41+
plot.add_trace(trace2);
42+
43+
let layout = Layout::new().x_axis(Axis::new().matches("x2")).grid(
44+
LayoutGrid::new()
45+
.rows(1)
46+
.columns(2)
47+
.pattern(GridPattern::Independent),
48+
);
49+
plot.set_layout(layout);
50+
51+
plot.show();
52+
}
53+
54+
fn simple_subplot_matches_y_axis() {
55+
let trace1 = Scatter::new(vec![1, 2, 3], vec![4, 5, 6]).name("trace1");
56+
let trace2 = Scatter::new(vec![20, 30, 40], vec![50, 60, 70])
57+
.name("trace2")
58+
.x_axis("x2")
59+
.y_axis("y2");
60+
61+
let mut plot = Plot::new();
62+
plot.add_trace(trace1);
63+
plot.add_trace(trace2);
64+
65+
let layout = Layout::new().y_axis(Axis::new().matches("y2")).grid(
66+
LayoutGrid::new()
67+
.rows(1)
68+
.columns(2)
69+
.pattern(GridPattern::Independent),
70+
);
71+
plot.set_layout(layout);
72+
73+
plot.show();
74+
}
75+
3276
fn custom_sized_subplot() {
3377
let trace1 = Scatter::new(vec![1, 2, 3], vec![4, 5, 6]).name("trace1");
3478
let trace2 = Scatter::new(vec![20, 30, 40], vec![50, 60, 70])
@@ -289,6 +333,8 @@ fn main() {
289333

290334
// Subplots
291335
// simple_subplot();
336+
// simple_subplot_matches_x_axis();
337+
// simple_subplot_matches_y_axis();
292338
// custom_sized_subplot();
293339
// multiple_subplots();
294340
// stacked_subplots();

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/layout/mod.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -546,10 +546,8 @@ impl Axis {
546546
Default::default()
547547
}
548548

549-
pub fn matches(mut self, matches: bool) -> Self {
550-
if matches {
551-
self.matches = Some(String::from("x"));
552-
}
549+
pub fn matches(mut self, matches: &str) -> Self {
550+
self.matches = Some(matches.to_string());
553551
self
554552
}
555553

@@ -2444,7 +2442,7 @@ mod tests {
24442442
.n_ticks(600)
24452443
.tick0(5.0)
24462444
.dtick(10.0)
2447-
.matches(true)
2445+
.matches("x")
24482446
.tick_values(vec![1.0, 2.0])
24492447
.tick_text(vec!["one".to_string(), "two".to_string()])
24502448
.ticks(TicksDirection::Inside)

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)