use crate::error::Result;
#[cfg(feature = "visualization")]
use crate::vis::backward_compat::plotters_ext::PlotSettings;
use crate::vis::config::PlotKind;
use crate::DataFrame;
use crate::Series;
use std::path::Path;
pub trait SeriesPlotExt<T> {
fn plot_to<P: AsRef<Path>>(&self, path: P, title: Option<&str>) -> Result<()>;
fn line_plot<P: AsRef<Path>>(&self, path: P, title: Option<&str>) -> Result<()>;
fn scatter_plot<P: AsRef<Path>>(&self, path: P, title: Option<&str>) -> Result<()>;
fn bar_plot<P: AsRef<Path>>(&self, path: P, title: Option<&str>) -> Result<()>;
fn histogram<P: AsRef<Path>>(
&self,
path: P,
bins: Option<usize>,
title: Option<&str>,
) -> Result<()>;
fn area_plot<P: AsRef<Path>>(&self, path: P, title: Option<&str>) -> Result<()>;
fn plot_svg<P: AsRef<Path>>(
&self,
path: P,
plot_kind: PlotKind,
title: Option<&str>,
) -> Result<()>;
}
pub trait DataFramePlotExt {
fn plot_column<P: AsRef<Path>>(&self, column: &str, path: P, title: Option<&str>)
-> Result<()>;
fn line_plot<P: AsRef<Path>>(&self, column: &str, path: P, title: Option<&str>) -> Result<()>;
fn scatter_plot<P: AsRef<Path>>(
&self,
column: &str,
path: P,
title: Option<&str>,
) -> Result<()>;
fn bar_plot<P: AsRef<Path>>(&self, column: &str, path: P, title: Option<&str>) -> Result<()>;
fn area_plot<P: AsRef<Path>>(&self, column: &str, path: P, title: Option<&str>) -> Result<()>;
fn box_plot<P: AsRef<Path>>(
&self,
value_column: &str,
category_column: &str,
path: P,
title: Option<&str>,
) -> Result<()>;
fn scatter_xy<P: AsRef<Path>>(
&self,
x_column: &str,
y_column: &str,
path: P,
title: Option<&str>,
) -> Result<()>;
fn multi_line_plot<P: AsRef<Path>>(
&self,
columns: &[&str],
path: P,
title: Option<&str>,
) -> Result<()>;
fn plot_svg<P: AsRef<Path>>(
&self,
column: &str,
path: P,
plot_kind: PlotKind,
title: Option<&str>,
) -> Result<()>;
}
#[cfg(feature = "visualization")]
impl<T> SeriesPlotExt<T> for Series<T>
where
T: Clone + Copy + Into<f64> + std::fmt::Debug,
{
fn plot_to<P: AsRef<Path>>(&self, path: P, title: Option<&str>) -> Result<()> {
let mut settings = PlotSettings::default();
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else if let Some(name) = self.name() {
settings.title = format!("{} Plot", name);
}
self.plotters_plot(path, settings)
}
fn line_plot<P: AsRef<Path>>(&self, path: P, title: Option<&str>) -> Result<()> {
let mut settings = PlotSettings::default();
settings.plot_kind = crate::vis::backward_compat::plotters_ext::PlotKind::Line;
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else if let Some(name) = self.name() {
settings.title = format!("{} Line Plot", name);
}
self.plotters_plot(path, settings)
}
fn scatter_plot<P: AsRef<Path>>(&self, path: P, title: Option<&str>) -> Result<()> {
let mut settings = PlotSettings::default();
settings.plot_kind = crate::vis::backward_compat::plotters_ext::PlotKind::Scatter;
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else if let Some(name) = self.name() {
settings.title = format!("{} Scatter Plot", name);
}
self.plotters_plot(path, settings)
}
fn bar_plot<P: AsRef<Path>>(&self, path: P, title: Option<&str>) -> Result<()> {
let mut settings = PlotSettings::default();
settings.plot_kind = crate::vis::backward_compat::plotters_ext::PlotKind::Bar;
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else if let Some(name) = self.name() {
settings.title = format!("{} Bar Plot", name);
}
self.plotters_plot(path, settings)
}
fn histogram<P: AsRef<Path>>(
&self,
path: P,
bins: Option<usize>,
title: Option<&str>,
) -> Result<()> {
let mut settings = PlotSettings::default();
settings.plot_kind = crate::vis::backward_compat::plotters_ext::PlotKind::Histogram;
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else if let Some(name) = self.name() {
settings.title = format!("{} Histogram", name);
}
self.plotters_histogram(path, bins.unwrap_or(10), settings)
}
fn area_plot<P: AsRef<Path>>(&self, path: P, title: Option<&str>) -> Result<()> {
let mut settings = PlotSettings::default();
settings.plot_kind = crate::vis::backward_compat::plotters_ext::PlotKind::Area;
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else if let Some(name) = self.name() {
settings.title = format!("{} Area Plot", name);
}
self.plotters_plot(path, settings)
}
fn plot_svg<P: AsRef<Path>>(
&self,
path: P,
plot_kind: PlotKind,
title: Option<&str>,
) -> Result<()> {
let mut settings = PlotSettings::default();
settings.plot_kind = match plot_kind {
crate::vis::config::PlotKind::Line => {
crate::vis::backward_compat::plotters_ext::PlotKind::Line
}
crate::vis::config::PlotKind::Scatter => {
crate::vis::backward_compat::plotters_ext::PlotKind::Scatter
}
crate::vis::config::PlotKind::Bar => {
crate::vis::backward_compat::plotters_ext::PlotKind::Bar
}
crate::vis::config::PlotKind::Histogram => {
crate::vis::backward_compat::plotters_ext::PlotKind::Histogram
}
crate::vis::config::PlotKind::BoxPlot => {
crate::vis::backward_compat::plotters_ext::PlotKind::BoxPlot
}
crate::vis::config::PlotKind::Area => {
crate::vis::backward_compat::plotters_ext::PlotKind::Area
}
};
settings.output_type = crate::vis::backward_compat::plotters_ext::OutputType::SVG;
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else if let Some(name) = self.name() {
settings.title = format!("{} Plot", name);
}
self.plotters_plot(path, settings)
}
}
#[cfg(feature = "visualization")]
impl DataFramePlotExt for DataFrame {
fn plot_column<P: AsRef<Path>>(
&self,
column: &str,
path: P,
title: Option<&str>,
) -> Result<()> {
let mut settings = PlotSettings::default();
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else {
settings.title = format!("{} Plot", column);
}
settings.y_label = column.to_string();
self.plotters_plot_column(column, path, settings)
}
fn line_plot<P: AsRef<Path>>(&self, column: &str, path: P, title: Option<&str>) -> Result<()> {
let mut settings = PlotSettings::default();
settings.plot_kind = crate::vis::backward_compat::plotters_ext::PlotKind::Line;
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else {
settings.title = format!("{} Line Plot", column);
}
settings.y_label = column.to_string();
self.plotters_plot_column(column, path, settings)
}
fn scatter_plot<P: AsRef<Path>>(
&self,
column: &str,
path: P,
title: Option<&str>,
) -> Result<()> {
let mut settings = PlotSettings::default();
settings.plot_kind = crate::vis::backward_compat::plotters_ext::PlotKind::Scatter;
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else {
settings.title = format!("{} Scatter Plot", column);
}
settings.y_label = column.to_string();
self.plotters_plot_column(column, path, settings)
}
fn bar_plot<P: AsRef<Path>>(&self, column: &str, path: P, title: Option<&str>) -> Result<()> {
let mut settings = PlotSettings::default();
settings.plot_kind = crate::vis::backward_compat::plotters_ext::PlotKind::Bar;
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else {
settings.title = format!("{} Bar Plot", column);
}
settings.y_label = column.to_string();
self.plotters_plot_column(column, path, settings)
}
fn area_plot<P: AsRef<Path>>(&self, column: &str, path: P, title: Option<&str>) -> Result<()> {
let mut settings = PlotSettings::default();
settings.plot_kind = crate::vis::backward_compat::plotters_ext::PlotKind::Area;
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else {
settings.title = format!("{} Area Plot", column);
}
settings.y_label = column.to_string();
self.plotters_plot_column(column, path, settings)
}
fn box_plot<P: AsRef<Path>>(
&self,
value_column: &str,
category_column: &str,
path: P,
title: Option<&str>,
) -> Result<()> {
let mut settings = PlotSettings::default();
settings.plot_kind = crate::vis::backward_compat::plotters_ext::PlotKind::BoxPlot;
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else {
settings.title = format!("{} by {}", value_column, category_column);
}
settings.x_label = category_column.to_string();
settings.y_label = value_column.to_string();
self.plotters_boxplot(category_column, value_column, path, settings)
}
fn scatter_xy<P: AsRef<Path>>(
&self,
x_column: &str,
y_column: &str,
path: P,
title: Option<&str>,
) -> Result<()> {
let mut settings = PlotSettings::default();
settings.plot_kind = crate::vis::backward_compat::plotters_ext::PlotKind::Scatter;
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else {
settings.title = format!("{} vs {}", y_column, x_column);
}
settings.x_label = x_column.to_string();
settings.y_label = y_column.to_string();
self.plotters_scatter(x_column, y_column, path, settings)
}
fn multi_line_plot<P: AsRef<Path>>(
&self,
columns: &[&str],
path: P,
title: Option<&str>,
) -> Result<()> {
let mut settings = PlotSettings::default();
settings.plot_kind = crate::vis::backward_compat::plotters_ext::PlotKind::Line;
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else {
settings.title = "Multi Column Plot".to_string();
}
self.plotters_plot_columns(columns, path, settings)
}
fn plot_svg<P: AsRef<Path>>(
&self,
column: &str,
path: P,
plot_kind: PlotKind,
title: Option<&str>,
) -> Result<()> {
let mut settings = PlotSettings::default();
settings.plot_kind = match plot_kind {
crate::vis::config::PlotKind::Line => {
crate::vis::backward_compat::plotters_ext::PlotKind::Line
}
crate::vis::config::PlotKind::Scatter => {
crate::vis::backward_compat::plotters_ext::PlotKind::Scatter
}
crate::vis::config::PlotKind::Bar => {
crate::vis::backward_compat::plotters_ext::PlotKind::Bar
}
crate::vis::config::PlotKind::Histogram => {
crate::vis::backward_compat::plotters_ext::PlotKind::Histogram
}
crate::vis::config::PlotKind::BoxPlot => {
crate::vis::backward_compat::plotters_ext::PlotKind::BoxPlot
}
crate::vis::config::PlotKind::Area => {
crate::vis::backward_compat::plotters_ext::PlotKind::Area
}
};
settings.output_type = crate::vis::backward_compat::plotters_ext::OutputType::SVG;
if let Some(title_str) = title {
settings.title = title_str.to_string();
} else {
settings.title = format!("{} Plot", column);
}
settings.y_label = column.to_string();
self.plotters_plot_column(column, path, settings)
}
}
#[cfg(feature = "visualization")]
impl DataFramePlotExt for crate::optimized::dataframe::OptimizedDataFrame {
fn plot_column<P: AsRef<Path>>(
&self,
column: &str,
path: P,
title: Option<&str>,
) -> Result<()> {
let df = crate::optimized::convert::standard_dataframe(self)?;
df.plot_column(column, path, title)
}
fn line_plot<P: AsRef<Path>>(&self, column: &str, path: P, title: Option<&str>) -> Result<()> {
let df = crate::optimized::convert::standard_dataframe(self)?;
df.line_plot(column, path, title)
}
fn scatter_plot<P: AsRef<Path>>(
&self,
column: &str,
path: P,
title: Option<&str>,
) -> Result<()> {
let df = crate::optimized::convert::standard_dataframe(self)?;
df.scatter_plot(column, path, title)
}
fn bar_plot<P: AsRef<Path>>(&self, column: &str, path: P, title: Option<&str>) -> Result<()> {
let df = crate::optimized::convert::standard_dataframe(self)?;
df.bar_plot(column, path, title)
}
fn area_plot<P: AsRef<Path>>(&self, column: &str, path: P, title: Option<&str>) -> Result<()> {
let df = crate::optimized::convert::standard_dataframe(self)?;
df.area_plot(column, path, title)
}
fn box_plot<P: AsRef<Path>>(
&self,
value_column: &str,
category_column: &str,
path: P,
title: Option<&str>,
) -> Result<()> {
let df = crate::optimized::convert::standard_dataframe(self)?;
df.box_plot(value_column, category_column, path, title)
}
fn scatter_xy<P: AsRef<Path>>(
&self,
x_column: &str,
y_column: &str,
path: P,
title: Option<&str>,
) -> Result<()> {
let df = crate::optimized::convert::standard_dataframe(self)?;
df.scatter_xy(x_column, y_column, path, title)
}
fn multi_line_plot<P: AsRef<Path>>(
&self,
columns: &[&str],
path: P,
title: Option<&str>,
) -> Result<()> {
let df = crate::optimized::convert::standard_dataframe(self)?;
df.multi_line_plot(columns, path, title)
}
fn plot_svg<P: AsRef<Path>>(
&self,
column: &str,
path: P,
plot_kind: PlotKind,
title: Option<&str>,
) -> Result<()> {
let df = crate::optimized::convert::standard_dataframe(self)?;
let compat_kind = match plot_kind {
crate::vis::config::PlotKind::Line => {
crate::vis::backward_compat::plotters_ext::PlotKind::Line
}
crate::vis::config::PlotKind::Scatter => {
crate::vis::backward_compat::plotters_ext::PlotKind::Scatter
}
crate::vis::config::PlotKind::Bar => {
crate::vis::backward_compat::plotters_ext::PlotKind::Bar
}
crate::vis::config::PlotKind::Histogram => {
crate::vis::backward_compat::plotters_ext::PlotKind::Histogram
}
crate::vis::config::PlotKind::BoxPlot => {
crate::vis::backward_compat::plotters_ext::PlotKind::BoxPlot
}
crate::vis::config::PlotKind::Area => {
crate::vis::backward_compat::plotters_ext::PlotKind::Area
}
};
df.plot_svg(column, path, compat_kind, title)
}
}
#[cfg(not(feature = "visualization"))]
impl<T> SeriesPlotExt<T> for Series<T>
where
T: Clone + Copy + Into<f64> + std::fmt::Debug,
{
fn plot_to<P: AsRef<Path>>(&self, _path: P, _title: Option<&str>) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn line_plot<P: AsRef<Path>>(&self, _path: P, _title: Option<&str>) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn scatter_plot<P: AsRef<Path>>(&self, _path: P, _title: Option<&str>) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn bar_plot<P: AsRef<Path>>(&self, _path: P, _title: Option<&str>) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn histogram<P: AsRef<Path>>(
&self,
_path: P,
_bins: Option<usize>,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn area_plot<P: AsRef<Path>>(&self, _path: P, _title: Option<&str>) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn plot_svg<P: AsRef<Path>>(
&self,
_path: P,
_plot_kind: crate::vis::config::PlotKind,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
}
#[cfg(not(feature = "visualization"))]
impl DataFramePlotExt for DataFrame {
fn plot_column<P: AsRef<Path>>(
&self,
_column: &str,
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn line_plot<P: AsRef<Path>>(
&self,
_column: &str,
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn scatter_plot<P: AsRef<Path>>(
&self,
_column: &str,
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn bar_plot<P: AsRef<Path>>(
&self,
_column: &str,
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn area_plot<P: AsRef<Path>>(
&self,
_column: &str,
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn box_plot<P: AsRef<Path>>(
&self,
_value_column: &str,
_category_column: &str,
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn scatter_xy<P: AsRef<Path>>(
&self,
_x_column: &str,
_y_column: &str,
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn multi_line_plot<P: AsRef<Path>>(
&self,
_columns: &[&str],
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn plot_svg<P: AsRef<Path>>(
&self,
_column: &str,
_path: P,
_plot_kind: crate::vis::config::PlotKind,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
}
#[cfg(not(feature = "visualization"))]
impl DataFramePlotExt for crate::optimized::dataframe::OptimizedDataFrame {
fn plot_column<P: AsRef<Path>>(
&self,
_column: &str,
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn line_plot<P: AsRef<Path>>(
&self,
_column: &str,
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn scatter_plot<P: AsRef<Path>>(
&self,
_column: &str,
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn bar_plot<P: AsRef<Path>>(
&self,
_column: &str,
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn area_plot<P: AsRef<Path>>(
&self,
_column: &str,
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn box_plot<P: AsRef<Path>>(
&self,
_value_column: &str,
_category_column: &str,
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn scatter_xy<P: AsRef<Path>>(
&self,
_x_column: &str,
_y_column: &str,
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn multi_line_plot<P: AsRef<Path>>(
&self,
_columns: &[&str],
_path: P,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
fn plot_svg<P: AsRef<Path>>(
&self,
_column: &str,
_path: P,
_plot_kind: crate::vis::config::PlotKind,
_title: Option<&str>,
) -> Result<()> {
Err(crate::error::PandRSError::FeatureNotAvailable(
"Visualization feature is not enabled. Recompile with --feature visualization"
.to_string(),
))
}
}
#[cfg(all(test, feature = "visualization"))]
mod tests {
#[allow(unused_imports)]
use super::*;
use crate::column::{Column, Float64Column};
use crate::optimized::dataframe::OptimizedDataFrame;
#[test]
fn test_optimized_dataframe_plot_ext_line_plot() {
let mut opt_df = OptimizedDataFrame::new();
let values = vec![1.0_f64, 2.0, 3.0, 4.0, 5.0];
opt_df
.add_column(
"values".to_string(),
Column::Float64(Float64Column::new(values)),
)
.expect("Failed to add column");
let tmp_dir = std::env::temp_dir();
let path = tmp_dir.join("test_opt_df_line_plot.png");
let result = opt_df.line_plot("values", &path, Some("Test Line Plot"));
assert!(
result.is_ok(),
"line_plot should succeed: {:?}",
result.err()
);
}
#[test]
fn test_optimized_dataframe_plot_ext_scatter_plot() {
let mut opt_df = OptimizedDataFrame::new();
let values = vec![10.0_f64, 20.0, 30.0, 40.0, 50.0];
opt_df
.add_column(
"data".to_string(),
Column::Float64(Float64Column::new(values)),
)
.expect("Failed to add column");
let tmp_dir = std::env::temp_dir();
let path = tmp_dir.join("test_opt_df_scatter_plot.png");
let result = opt_df.scatter_plot("data", &path, Some("Test Scatter Plot"));
assert!(
result.is_ok(),
"scatter_plot should succeed: {:?}",
result.err()
);
}
#[test]
fn test_optimized_dataframe_plot_ext_plot_column() {
let mut opt_df = OptimizedDataFrame::new();
let values = vec![5.0_f64, 10.0, 15.0, 20.0];
opt_df
.add_column(
"metrics".to_string(),
Column::Float64(Float64Column::new(values)),
)
.expect("Failed to add column");
let tmp_dir = std::env::temp_dir();
let path = tmp_dir.join("test_opt_df_plot_column.png");
let result = opt_df.plot_column("metrics", &path, None);
assert!(
result.is_ok(),
"plot_column should succeed: {:?}",
result.err()
);
}
}