Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
8696877
Defining axis serializer function
yasuomaidana Aug 2, 2024
d45f901
Defining axes as vector instead of filed items values
yasuomaidana Aug 2, 2024
b39bd4e
Updating layout test to use the new vector axis instead of filed acce…
yasuomaidana Aug 2, 2024
1fc5ab2
Updating themes layout usage signature
yasuomaidana Aug 2, 2024
badc5ad
Merge branch 'main' of https://github.com/plotly/plotly.rs into multi…
yasuomaidana Aug 2, 2024
d3e3ef2
Updating test to new axis definition
yasuomaidana Aug 2, 2024
df4759b
Updating statistical charts example
yasuomaidana Aug 6, 2024
3e910b2
Creating axis builders
yasuomaidana Aug 11, 2024
52e687b
Adding x,y,z add axis to api
yasuomaidana Aug 22, 2024
e53cead
Defining axis serializer function
yasuomaidana Aug 2, 2024
14721ac
Defining axes as vector instead of filed items values
yasuomaidana Aug 2, 2024
8f39f9b
Updating layout test to use the new vector axis instead of filed acce…
yasuomaidana Aug 2, 2024
da083f2
Updating themes layout usage signature
yasuomaidana Aug 2, 2024
b93a5d4
Updating test to new axis definition
yasuomaidana Aug 2, 2024
92fc89c
Updating statistical charts example
yasuomaidana Aug 6, 2024
73657bd
Creating axis builders
yasuomaidana Aug 11, 2024
bb2dfb1
Reducing code complexity
yasuomaidana Oct 23, 2024
99db7dc
Implementing axis and axes setters
yasuomaidana Oct 23, 2024
c0d81e7
Formatting code
yasuomaidana Oct 23, 2024
324111c
Merge remote-tracking branch 'origin/multiples-axis' into multiples-axis
yasuomaidana Oct 23, 2024
eb04201
Merge remote-tracking branch 'origin/main'
yasuomaidana Jul 30, 2025
7193865
Merge branch 'main' into multiples-axis
yasuomaidana Sep 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions examples/statistical_charts/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,9 @@ fn grouped_box_plot(show: bool, file_name: &str) {
plot.add_trace(trace2);
plot.add_trace(trace3);

let y_axis = Vec::from([Some(Box::new(Axis::new().title("normalized moisture").zero_line(false)))]);
let layout = Layout::new()
.y_axis(Axis::new().title("normalized moisture").zero_line(false))
.y_axis(y_axis)
.box_mode(BoxMode::Group);

plot.set_layout(layout);
Expand Down Expand Up @@ -390,9 +391,10 @@ fn grouped_horizontal_box_plot(show: bool, file_name: &str) {
plot.add_trace(trace2);
plot.add_trace(trace3);

let x_axis = Vec::from([Some(Box::new(Axis::new().title("normalized moisture").zero_line(false)))]);
let layout = Layout::new()
.title("Grouped Horizontal Box Plot")
.x_axis(Axis::new().title("normalized moisture").zero_line(false))
.x_axis(x_axis)
.box_mode(BoxMode::Group);

plot.set_layout(layout);
Expand Down Expand Up @@ -440,19 +442,21 @@ fn fully_styled_box_plot(show: bool, file_name: &str) {
];

let mut plot = Plot::new();
let layout = Layout::new()
.title("Points Scored by the Top 9 Scoring NBA Players in 2012")
.y_axis(
Axis::new()

let y_axis = Vec::from([Some(
Box::new(Axis::new()
.auto_range(true)
.show_grid(true)
.zero_line(true)
.dtick(5.0)
.grid_color(Rgb::new(255, 255, 255))
.grid_width(1)
.zero_line_color(Rgb::new(255, 255, 255))
.zero_line_width(2),
)
.zero_line_width(2)
))]);
let layout = Layout::new()
.title("Points Scored by the Top 9 Scoring NBA Players in 2012")
.y_axis(y_axis )
.margin(Margin::new().left(40).right(30).bottom(80).top(100))
.paper_background_color(Rgb::new(243, 243, 243))
.plot_background_color(Rgb::new(243, 243, 243))
Expand Down Expand Up @@ -615,10 +619,13 @@ fn colored_and_styled_histograms(show: bool, file_name: &str) {
.opacity(0.75)
.auto_bin_x(false)
.x_bins(Bins::new(-3.2, 4.0, 0.06));

let x_axis = Vec::from([Some(Box::new(Axis::new().title("Value")))]);
let y_axis = Vec::from([Some(Box::new(Axis::new().title("Count")))]);
let layout = Layout::new()
.title("Colored and Styled Histograms")
.x_axis(Axis::new().title("Value"))
.y_axis(Axis::new().title("Count"))
.x_axis(x_axis)
.y_axis(y_axis)
.bar_mode(BarMode::Overlay)
.bar_gap(0.05)
.bar_group_gap(0.2);
Expand Down
11 changes: 3 additions & 8 deletions examples/subplots/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,8 @@ fn simple_subplot_matches_x_axis(show: bool, file_name: &str) {
plot.show_html(path);
}
}
// ANCHOR_END: simple_subplot_matches_x_axis

// ANCHOR: simple_subplot_matches_y_axis
fn simple_subplot_matches_y_axis(show: bool, file_name: &str) {
fn simple_subplot_matches_y_axis() {
let trace1 = Scatter::new(vec![1, 2, 3], vec![4, 5, 6]).name("trace1");
let trace2 = Scatter::new(vec![20, 30, 40], vec![50, 60, 70])
.name("trace2")
Expand All @@ -88,10 +86,8 @@ fn simple_subplot_matches_y_axis(show: bool, file_name: &str) {
plot.show_html(path);
}
}
// ANCHOR_END: simple_subplot_matches_y_axis

// ANCHOR: custom_sized_subplot
fn custom_sized_subplot(show: bool, file_name: &str) {
fn custom_sized_subplot() {
let trace1 = Scatter::new(vec![1, 2, 3], vec![4, 5, 6]).name("trace1");
let trace2 = Scatter::new(vec![20, 30, 40], vec![50, 60, 70])
.name("trace2")
Expand Down Expand Up @@ -251,8 +247,7 @@ fn multiple_custom_sized_subplots(show: bool, file_name: &str) {
// ANCHOR_END: multiple_custom_sized_subplots

// Multiple Axes
// ANCHOR: two_y_axes
fn two_y_axes(show: bool, file_name: &str) {
fn two_y_axes() {
let trace1 = Scatter::new(vec![1, 2, 3], vec![40, 50, 60]).name("trace1");
let trace2 = Scatter::new(vec![2, 3, 4], vec![4, 5, 6])
.name("trace2")
Expand Down
162 changes: 67 additions & 95 deletions plotly/src/layout/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
use std::borrow::Cow;

use plotly_derive::layout_structs;
use plotly_derive::FieldSetter;
use serde::Serialize;
use serde::{Serialize, Serializer};
use std::borrow::Cow;
use std::collections::HashMap;
use update_menu::UpdateMenu;

use crate::color::Color;
use crate::common::{Calendar, ColorScale, Font, Label, Orientation, Title};
use crate::common::Domain;
use crate::{
color::Color,
common::{
Anchor, AxisSide, Calendar, ColorBar, ColorScale, DashType, ExponentFormat, Font, Label,
Orientation, TickFormatStop, TickMode, Title,
},
private::{NumOrString, NumOrStringCollection},
};

pub mod themes;
pub mod update_menu;
Expand All @@ -24,6 +30,48 @@ mod scene;
mod shape;
mod slider;

fn serialize_axes<S>(axes: &Option<Vec<Option<Box<Axis>>>>, serializer: S, axis_prefix: &str) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = HashMap::new();
let axes = axes.as_ref().unwrap();

for (i, axis) in axes.iter().enumerate() {
let axe = axis.as_ref().unwrap();
let key = if i == 0 {
axis_prefix.to_string()
} else {
format!("{}{}", axis_prefix, i + 1)
};
map.insert(key, axe);
}

map.serialize(serializer)
}

fn serialize_x_axes<S>(axes: &Option<Vec<Option<Box<Axis>>>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serialize_axes(axes, serializer, "xaxis")
}

fn serialize_y_axes<S>(axes: &Option<Vec<Option<Box<Axis>>>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serialize_axes(axes, serializer, "yaxis")
}


fn serialize_z_axes<S>(axes: &Option<Vec<Option<Box<Axis>>>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serialize_axes(axes, serializer, "zaxis")
}

// Re-export layout sub-module types
pub use self::animation::{
Animation, AnimationDirection, AnimationEasing, AnimationMode, AnimationOptions, Frame,
Expand Down Expand Up @@ -279,54 +327,14 @@ pub struct LayoutFields {
hover_label: Option<Label>,
grid: Option<LayoutGrid>,
calendar: Option<Calendar>,
#[serde(rename = "xaxis")]
x_axis: Option<Box<Axis>>,
#[serde(rename = "yaxis")]
y_axis: Option<Box<Axis>>,
#[serde(rename = "zaxis")]
z_axis: Option<Box<Axis>>,
#[serde(rename = "xaxis2")]
x_axis2: Option<Box<Axis>>,
#[serde(rename = "yaxis2")]
y_axis2: Option<Box<Axis>>,
#[serde(rename = "zaxis2")]
z_axis2: Option<Box<Axis>>,
#[serde(rename = "xaxis3")]
x_axis3: Option<Box<Axis>>,
#[serde(rename = "yaxis3")]
y_axis3: Option<Box<Axis>>,
#[serde(rename = "zaxis3")]
z_axis3: Option<Box<Axis>>,
#[serde(rename = "xaxis4")]
x_axis4: Option<Box<Axis>>,
#[serde(rename = "yaxis4")]
y_axis4: Option<Box<Axis>>,
#[serde(rename = "zaxis4")]
z_axis4: Option<Box<Axis>>,
#[serde(rename = "xaxis5")]
x_axis5: Option<Box<Axis>>,
#[serde(rename = "yaxis5")]
y_axis5: Option<Box<Axis>>,
#[serde(rename = "zaxis5")]
z_axis5: Option<Box<Axis>>,
#[serde(rename = "xaxis6")]
x_axis6: Option<Box<Axis>>,
#[serde(rename = "yaxis6")]
y_axis6: Option<Box<Axis>>,
#[serde(rename = "zaxis6")]
z_axis6: Option<Box<Axis>>,
#[serde(rename = "xaxis7")]
x_axis7: Option<Box<Axis>>,
#[serde(rename = "yaxis7")]
y_axis7: Option<Box<Axis>>,
#[serde(rename = "zaxis7")]
z_axis7: Option<Box<Axis>>,
#[serde(rename = "xaxis8")]
x_axis8: Option<Box<Axis>>,
#[serde(rename = "yaxis8")]
y_axis8: Option<Box<Axis>>,
#[serde(rename = "zaxis8")]
z_axis8: Option<Box<Axis>>,

#[serde(flatten, serialize_with = "serialize_x_axes")]
x_axis: Option<Vec<Option<Box<Axis>>>>,
#[serde(flatten, serialize_with = "serialize_y_axes")]
y_axis: Option<Vec<Option<Box<Axis>>>>,
#[serde(flatten, serialize_with = "serialize_z_axes")]
z_axis: Option<Vec<Option<Box<Axis>>>>,

// ternary: Option<LayoutTernary>,
scene: Option<LayoutScene>,
geo: Option<LayoutGeo>,
Expand Down Expand Up @@ -494,30 +502,8 @@ mod tests {
.hover_label(Label::new())
.grid(LayoutGrid::new())
.calendar(Calendar::Jalali)
.x_axis(Axis::new())
.x_axis2(Axis::new())
.x_axis3(Axis::new())
.x_axis4(Axis::new())
.x_axis5(Axis::new())
.x_axis6(Axis::new())
.x_axis7(Axis::new())
.x_axis8(Axis::new())
.y_axis(Axis::new())
.y_axis2(Axis::new())
.y_axis3(Axis::new())
.y_axis4(Axis::new())
.y_axis5(Axis::new())
.y_axis6(Axis::new())
.y_axis7(Axis::new())
.y_axis8(Axis::new())
.z_axis(Axis::new())
.z_axis2(Axis::new())
.z_axis3(Axis::new())
.z_axis4(Axis::new())
.z_axis5(Axis::new())
.z_axis6(Axis::new())
.z_axis7(Axis::new())
.z_axis8(Axis::new())
.x_axis(xaxis)
.y_axis(yaxis)
.annotations(vec![Annotation::new()])
.shapes(vec![Shape::new()])
.new_shape(NewShape::new())
Expand Down Expand Up @@ -661,22 +647,8 @@ mod tests {
.template(Template::new())
.grid(LayoutGrid::new())
.calendar(Calendar::Jalali)
.x_axis(Axis::new())
.x_axis2(Axis::new())
.x_axis3(Axis::new())
.x_axis4(Axis::new())
.x_axis5(Axis::new())
.x_axis6(Axis::new())
.x_axis7(Axis::new())
.x_axis8(Axis::new())
.y_axis(Axis::new())
.y_axis2(Axis::new())
.y_axis3(Axis::new())
.y_axis4(Axis::new())
.y_axis5(Axis::new())
.y_axis6(Axis::new())
.y_axis7(Axis::new())
.y_axis8(Axis::new())
.x_axis(xaxis)
.y_axis(yaxis)
.annotations(vec![Annotation::new()])
.shapes(vec![Shape::new()])
.new_shape(NewShape::new())
Expand All @@ -698,7 +670,7 @@ mod tests {
.extend_pie_colors(true)
.sunburst_colorway(vec!["#654654"])
.extend_sunburst_colors(false)
.z_axis(Axis::new())
.z_axis(Vec::from([Some(Box::new(Axis::new()))]))
.scene(LayoutScene::new());

let expected = json!({
Expand Down
40 changes: 22 additions & 18 deletions plotly/src/layout/themes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,22 +66,22 @@ pub static PLOTLY_WHITE: Lazy<Template> = Lazy::new(|| {
.plot_background_color("#FFFFFF")
.title(Title::new().x(0.05))
.x_axis(
Axis::new()
Vec::from([Some(Box::new(Axis::new()
.auto_margin(true)
.grid_color("#EBF0F8")
.line_color("#EBF0F8")
// missing title.standoff = 15
.zero_line_color("#EBF0F8")
.zero_line_width(2),
.zero_line_width(2)))])
)
.y_axis(
Axis::new()
Vec::from([Some(Box::new(Axis::new()
.auto_margin(true)
.grid_color("#EBF0F8")
.line_color("#EBF0F8")
// missing title.standoff = 15
.zero_line_color("#EBF0F8")
.zero_line_width(2),
.zero_line_width(2)))])
);
Template::new().layout(layout_template)
});
Expand Down Expand Up @@ -142,22 +142,26 @@ pub static PLOTLY_DARK: Lazy<Template> = Lazy::new(|| {
.plot_background_color("#111111")
.title(Title::new().x(0.05))
.x_axis(
Axis::new()
.auto_margin(true)
.grid_color("#283442")
.line_color("#506784")
// missing title.standoff = 15
.zero_line_color("#283442")
.zero_line_width(2),
Vec::from(
[Some(Box::new(Axis::new()
.auto_margin(true)
.grid_color("#283442")
.line_color("#506784")
// missing title.standoff = 15
.zero_line_color("#283442")
.zero_line_width(2)))]
)
)
.y_axis(
Axis::new()
.auto_margin(true)
.grid_color("#283442")
.line_color("#506784")
// missing title.standoff = 15
.zero_line_color("#283442")
.zero_line_width(2),
Vec::from(
[Some(Box::new(Axis::new()
.auto_margin(true)
.grid_color("#283442")
.line_color("#506784")
// missing title.standoff = 15
.zero_line_color("#283442")
.zero_line_width(2)))]
)
);
Template::new().layout(layout_template)
});
Expand Down