Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 6 additions & 1 deletion include/roboptim/core/visualization/matplotlib-commands.hh
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,20 @@ namespace roboptim
{
public:
/// \brief Make a command from a string.
explicit Command (const std::string& cmd);
explicit Command (const std::string& cmd, bool isPlot = false);

~Command ();

/// \brief Retrieve the command as a string.
const std::string& command () const;

const bool& isPlot() const;

protected:
/// \brief Store matplotlib command.
std::string command_;
/// \brief Whether the command is a plot or not
bool isPlot_;
};

/// \brief Make a matplotlib comment.
Expand Down Expand Up @@ -127,6 +131,7 @@ namespace roboptim

ROBOPTIM_DLLAPI Command show ();
ROBOPTIM_DLLAPI Command figure ();
ROBOPTIM_DLLAPI Command title (const char* argument);

/// @}

Expand Down
2 changes: 1 addition & 1 deletion include/roboptim/core/visualization/matplotlib-function.hh
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ namespace roboptim
% i).str () << std::endl;
}

return Command (ss.str ());
return Command (ss.str (), true);
}

/// @}
Expand Down
16 changes: 13 additions & 3 deletions include/roboptim/core/visualization/matplotlib.hh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
# include <roboptim/core/debug.hh>
# include <roboptim/core/function.hh>

# include <utility>
# include <vector>

# define EIGEN_YES_I_KNOW_SPARE_MODULE_IS_NOT_STABLE_YET
Expand Down Expand Up @@ -54,9 +55,9 @@ namespace roboptim
/// \brief Instanciate a matplotlib without setting a term.
/// \param with_header whether to print the header or not
/// \return matplotlib instance
static Matplotlib make_matplotlib (bool with_header = true)
static Matplotlib make_matplotlib (std::pair<int, int> multiplot = std::make_pair(1, 1), bool with_header = true)
{
return Matplotlib (with_header);
return Matplotlib (multiplot, with_header);
}

/// \brief Add a new matplotlib command to the script.
Expand Down Expand Up @@ -86,12 +87,18 @@ namespace roboptim
/// \brief Whether to print the header (imports).
bool withHeader () const;

/// \brief Plots layout. {1,1} if unspecified.
/// \return Reference to multiplot_
std::pair<int, int>& multiplot ();

/// \brief Plots layout. {1,1} if unspecified.
std::pair<int, int> multiplot () const;
protected:
/// \brief Default constructor can not be called directly.
///
/// Use of the named constructor (see static methods) to
/// instantiate this class.
explicit Matplotlib (bool with_header = true);
explicit Matplotlib (std::pair<int, int> multiplot = std::make_pair(1, 1), bool with_header = true);

/// \brief Reset imports to initial values.
void resetImports ();
Expand All @@ -105,6 +112,9 @@ namespace roboptim

/// \brief Whether to export the header (imports etc.).
bool withHeader_;

/// \brief Whether to expect multiple plots or not.
std::pair<int, int> multiplot_;
};

/// Example shows simple matplotlib visualization.
Expand Down
20 changes: 18 additions & 2 deletions src/visualization/matplotlib-commands.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,20 @@ namespace roboptim
return Import (from, packages);
}

Command::Command (const std::string& cmd)
: command_ (cmd)
Command::Command (const std::string& cmd, bool isPlot)
: command_ (cmd),
isPlot_ (isPlot)
{}

Command::~Command ()
{}

const bool&
Command::isPlot () const
{
return isPlot_;
}

const std::string&
Command::command () const
{
Expand All @@ -81,6 +88,14 @@ namespace roboptim
return Command (BOOST_PP_STRINGIZE(VAR) " = plt." BOOST_PP_STRINGIZE(NAME) " ()"); \
}

# define MATPLOTLIB_UNARY_COMMAND_ARG(NAME, ARG) \
Command \
NAME (const char* ARG) \
{ \
return Command ((boost::format("plt." BOOST_PP_STRINGIZE(NAME) "(\"%1%\")") \
% ARG).str()); \
}

Command
comment (const char* content)
{
Expand Down Expand Up @@ -119,6 +134,7 @@ namespace roboptim

MATPLOTLIB_UNARY_COMMAND (show)
MATPLOTLIB_UNARY_COMMAND_VAR (fig, figure)
MATPLOTLIB_UNARY_COMMAND_ARG (title, argument)

# undef MATPLOTLIB_UNARY_COMMAND

Expand Down
48 changes: 39 additions & 9 deletions src/visualization/matplotlib.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ namespace roboptim
{
namespace visualization
{
Matplotlib::Matplotlib (bool with_header)
: withHeader_ (with_header)
Matplotlib::Matplotlib (std::pair<int, int> multiplot, bool with_header)
: withHeader_ (with_header),
multiplot_ (multiplot)
{
resetImports ();
}
Expand All @@ -48,6 +49,16 @@ namespace roboptim
return withHeader_;
}

std::pair<int, int>& Matplotlib::multiplot ()
{
return multiplot_;
}

std::pair<int, int> Matplotlib::multiplot () const
{
return multiplot_;
}

void
Matplotlib::resetImports ()
{
Expand All @@ -73,6 +84,7 @@ namespace roboptim
{
typedef std::vector<matplotlib::Import>::const_iterator citer_imp_t;
typedef std::vector<matplotlib::Command>::const_iterator citer_cmd_t;
int n = 1; // number of the plot

if (withHeader_)
{
Expand All @@ -84,21 +96,39 @@ namespace roboptim

o << std::endl;
o << "fig = plt.figure ()" << std::endl;
o << "ax = plt.subplot(111)" << std::endl;
if (multiplot().first == 1 && multiplot().second == 1)
o << "ax = plt.subplot(111)" << std::endl;
o << std::endl;
}

for (citer_cmd_t it = commands_.begin (); it != commands_.end (); ++it)
o << it->command () << std::endl;
{
if (!it->isPlot() || (multiplot().first == 1 && multiplot().second == 1))
o << it->command () << std::endl;
else
{
assert (multiplot().first > 0 && multiplot().second > 0);
o << "ax" << n << " = plt.subplot(" << multiplot().first
<< ", " << multiplot().second << ", " << n << ")" << std::endl;
o << it->command () << std::endl;
o << "box = ax" << n << ".get_position()" << std::endl;
o << "ax" << n << ".set_position([box.x0, box.y0, box.width * 0.8, box.height])" << std::endl;
o << "ax" << n << ".legend(loc='center left', bbox_to_anchor=(1, 0.5))" << std::endl;
++n;
}
}

o << std::endl;

if (withHeader_)
if (withHeader())
{
// Display legend on the right of the image
o << "box = ax.get_position()" << std::endl;
o << "ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])" << std::endl;
o << "ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))" << std::endl;
if (multiplot().first == 1 && multiplot().second == 1)
{
// Display legend on the right of the image
o << "box = ax.get_position()" << std::endl;
o << "ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])" << std::endl;
o << "ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))" << std::endl;
}

// Show image
o << "plt.show ()" << std::endl;
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,4 @@ ROBOPTIM_CORE_TEST(visualization-gnuplot-function)
ROBOPTIM_CORE_TEST(visualization-gnuplot-differentiable-function)
ROBOPTIM_CORE_TEST(visualization-matplotlib-simple)
ROBOPTIM_CORE_TEST(visualization-matplotlib-function)
ROBOPTIM_CORE_TEST(visualization-matplotlib-multiplot)
117 changes: 117 additions & 0 deletions tests/visualization-matplotlib-multiplot.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright (C) 2015 by Félix Darricau, AIST, CNRS, EPITA
//
// This file is part of the roboptim.
//
// roboptim is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// roboptim is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with roboptim. If not, see <http://www.gnu.org/licenses/>.

#include "shared-tests/fixture.hh"

#include <iostream>

#include <roboptim/core/io.hh>

#include <roboptim/core/visualization/matplotlib.hh>
#include <roboptim/core/visualization/matplotlib-commands.hh>
#include <roboptim/core/visualization/matplotlib-function.hh>

using namespace roboptim;
using namespace roboptim::visualization;


// Define f(x) = x * x
struct Square : public Function
{
explicit Square ()
: Function (1, 1, "x * x")
{
}

void impl_compute (result_ref result,
const_argument_ref argument) const
{
result[0] = argument[0] * argument[0];
}
};

// Define a function that displays a circle.
struct Circle : public Function
{
explicit Circle (double r = 1.)
: Function (1, 2, "{sin (x) * r; cos (x) * r}"),
r_ (r)
{
}

void impl_compute (result_ref result,
const_argument_ref argument) const
{
result[0] = sin (argument[0]) * r_;
result[1] = cos (argument[0]) * r_;
}

double r_;
};

// Define a function that displays a cubic and a quartic monomial.
struct Poly : public Function
{
explicit Poly ()
: Function (1, 2, "{x^3; x^4}")
{
}

void impl_compute (result_ref result,
const_argument_ref argument) const
{
result[0] = argument[0] * argument[0] * argument[0];
result[1] = result[0] * argument[0];
}
};

BOOST_FIXTURE_TEST_SUITE (core, TestSuiteConfiguration)

BOOST_AUTO_TEST_CASE (visualization_matplotlib_multiplot)
{
boost::shared_ptr<boost::test_tools::output_test_stream>
output = retrievePattern ("visualization-matplotlib-multiplot");

using namespace roboptim::visualization::matplotlib;
Matplotlib matplotlib = Matplotlib::make_matplotlib (std::make_pair(2, 2));

Square square;
discreteInterval_t intervalS (-10., 10., 0.01);

Circle circle;
discreteInterval_t intervalC (0., 2 * M_PI, 0.01);

Poly poly;
discreteInterval_t intervalP (-1., 1., 0.01);

(*output)
<< (matplotlib
<< plot (square, intervalS)
<< title ("Such a beautiful square") // Beware, you should always call the
// title of your plot after the actual
// plot. That's how matplotlib works.
<< plot (circle, intervalC)
<< title ("Such a beautiful circle")
<< plot (poly, intervalP)
<< title ("Such beautiful monomials")
);

std::cout << output->str () << std::endl;
BOOST_CHECK (output->match_pattern ());
}

BOOST_AUTO_TEST_SUITE_END ()
35 changes: 35 additions & 0 deletions tests/visualization-matplotlib-multiplot.stdout

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion tests/visualization-matplotlib-simple.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ BOOST_AUTO_TEST_CASE (visualization_matplotlib_simple)
output = retrievePattern ("visualization-matplotlib-simple");

using namespace roboptim::visualization::matplotlib;
Matplotlib matplotlib = Matplotlib::make_matplotlib (false);
Matplotlib matplotlib = Matplotlib::make_matplotlib (std::make_pair(1, 1), false);

// Display nothing, generate just some valid matplotlib commands.
(*output)
Expand Down