Plotters-rs PathElement borrow problem

Hello folks,

I'm new to Rust, but I enjoy it much. Now trying to write a data visualisation program with plotters-rs, where I need to visualize several sets on the same graph. The problem I have is with the legend - I cannot put a variable which would track the graph offset for each iteration (and, correspondingly, set with its color), this fails because of the borrow rules violation.

use plotters::prelude::*;
fn main() {
    let mut _counter = 0;
    for _ in 1..5
    {
        let root_drawing_area = SVGBackend::new("output/out.svg", (500, 500)).into_drawing_area();
        let mut chart_builder = ChartBuilder::on(&root_drawing_area) ;
        let mut chart_context = 
            chart_builder
            .build_cartesian_2d(0..100, 0..100).unwrap();
        chart_context.configure_mesh().draw().unwrap();

        chart_context.draw_series(
            vec![(10, 20), (30, 40), (50, 60)]
            .iter()
            .map(|(x, y)| Circle::new((*x, *y), 5, BLACK)), 
            ).unwrap()
            .label("label1")
            .legend(|(x,y)|  // <-borrow occurs here
                    PathElement::new(vec![( x, ( y + _counter)), ( x + 20, ( y + _counter ))], RED));
        _counter += 1; // Error! `_counter` is assigned to here but it was already borrowed

        chart_context.configure_series_labels()
            .border_style(&BLACK)
            .draw().unwrap();
    }
}

Tried to isolate the plotters things in a block ({}), the workaround didn't work, the library draws the legend canvas only as if there is a single legend element. Usual fix with .clone() / .to_owned() didn't work too.

Any help would be greatly appreciated, thank you!

A simple fix for the compiler error is to make _counter into a loop variable:

 fn main() {
-    let mut _counter = 0;
-    for _ in 1..5
+    for _counter in 0..4
     {

so you don’t need to increment it in the loop body:

-        _counter += 1; // Error! `_counter` is assigned to here but it was already borrowed

But an alternate fix is to use a move closure so that the closure has its own independent copy of the _counter variable:

-            .legend(|(x,y)|  // <-borrow occurs here
+            .legend(move |(x,y)|
                     PathElement::new(vec![( x, ( y + _counter)), ( x + 20, ( y + _counter ))], RED));

You probably need the latter fix if you want to move the other code out of the loop, like this: Playground

If you are exploring plotting, there is also gnuplot - which can do both simple and fancy plots very well.

Gnuplot is not tied to rust - but there is a rust crate that can control it.

http://www.gnuplot.info/

1 Like

Thank you so much for all the answers! Solved with

.legend(move |(x,y)|