message: Put gnuplot figure in Mutex to make visualizer thread-safe
diff: @@ -9,6 +9,7 @@ extern crate argmin;
  use argmin::prelude::*;
  use argmin::solver::particleswarm::*;
  use serde::{Deserialize, Serialize};
  +use std::sync::Mutex;
  use argmin_testfunctions::himmelblau;
  @@ -40,7 +41,6 @@ fn run() -> Result<(), Error> {
  let solver = ParticleSwarm::new((vec![-4.0, -4.0], vec![4.0, 4.0]), 100, 0.5, 0.0, 0.5)?;
  let res = Executor::new(cost_function, solver, init_param)
  - .add_observer(ArgminSlogLogger::term(), ObserverMode::Always)
  .add_observer(visualizer, ObserverMode::Always)
  .max_iters(15)
  .run()?;
  @@ -95,7 +95,8 @@ impl Surface {
  }
  struct ParticleSwarmVisualizer {
  - // fg: Box<gnuplot::Figure>,
  + // Need mutex because `Figure` contains `Cell`
  + fg: Mutex<gnuplot::Figure>,
  optima_x: Vec<f64>,
  optima_y: Vec<f64>,
  optima_z: Vec<f64>,
  @@ -110,7 +111,7 @@ struct ParticleSwarmVisualizer {
  impl ParticleSwarmVisualizer {
  fn new() -> Self {
  Self {
  - // fg: gnuplot::Figure::new(),
  + fg: Mutex::new(gnuplot::Figure::new()),
  optima_x: vec![],
  optima_y: vec![],
  optima_z: vec![],
  @@ -124,43 +125,43 @@ impl ParticleSwarmVisualizer {
  fn draw(&mut self) {
  use gnuplot::*;
  - // self.fg.clear_axes();
  + // TODO: unwrap evil
  + let mut figure = self.fg.lock().unwrap();
  +
  + figure.clear_axes();
  let options_optima = [Color("#ffff00"), PointSize(2.0)];
  let options_particles = [Color("#ff0000"), PointSize(2.0)];
  let window = Some(self.surface.window);
  - // self.fg
  - // .axes3d()
  - // .surface(
  - // self.surface.zvalues.iter(),
  - // self.surface.width,
  - // self.surface.height,
  - // window,
  - // &[],
  - // )
  - // .points(
  - // &self.optima_x,
  - // &self.optima_y,
  - // &self.optima_z,
  - // &options_optima,
  - // )
  - // .points(
  - // &self.particles_x,
  - // &self.particles_y,
  - // &self.particles_z,
  - // &options_particles,
  - // )
  - // // .set_size(8.0, 8.0)
  - // // .set_pos(-4.0, -4.0)
  - // .set_view(0., 0.);
  - // self.fg.show();
  + figure
  + .axes3d()
  + .surface(
  + self.surface.zvalues.iter(),
  + self.surface.width,
  + self.surface.height,
  + window,
  + &[],
  + )
  + .points(
  + &self.optima_x,
  + &self.optima_y,
  + &self.optima_z,
  + &options_optima,
  + )
  + .points(
  + &self.particles_x,
  + &self.particles_y,
  + &self.particles_z,
  + &options_particles,
  + )
  + .set_view(0., 0.);
  + println!("Show figure");
  + figure.show();
  std::thread::sleep(std::time::Duration::from_secs(1));
  }
  fn iteration(&mut self, xy: &Vec<f64>, cost: f64, particles: &Particles) {
  - // self.fg = gnuplot::Figure::new();
  -
  self.optima_x.clear();
  self.optima_y.clear();
  self.optima_z.clear();
  