text: // Mantid Repository : https://github.com/mantidproject/mantid
  //
  // Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
  //   NScD Oak Ridge National Laboratory, European Spallation Source,
  //   Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
  // SPDX - License - Identifier: GPL - 3.0 +
  #include "MantidQtWidgets/MplCpp/Figure.h"
  #include "MantidPythonInterface/core/CallMethod.h"
  #include "MantidQtWidgets/Common/Python/QHashToDict.h"
  #include "MantidQtWidgets/MplCpp/ColorConverter.h"
  
  using Mantid::PythonInterface::callMethodNoCheck;
  using Mantid::PythonInterface::GlobalInterpreterLock;
  using namespace MantidQt::Widgets::Common;
  
  namespace MantidQt {
  namespace Widgets {
  namespace MplCpp {
  
  namespace {
  Python::Object newFigure(bool tightLayout = true) {
    GlobalInterpreterLock lock;
    Python::Object figureModule{
        Python::NewRef(PyImport_ImportModule("matplotlib.figure"))};
    auto fig = figureModule.attr("Figure")();
    if (tightLayout) {
      auto tight = Python::NewRef(Py_BuildValue("{sf}", "pad", 0.5));
      fig.attr("set_tight_layout")(tight);
    }
    return fig;
  }
  } // namespace
  
  /**
   * Construct a C++ wrapper around an existing figure instance
   * @param obj An existing Figure instance
   */
  Figure::Figure(Python::Object obj)
      : Python::InstanceHolder(std::move(obj), "add_axes") {}
  
  /**
   * Construct a new default figure.
   * @param tightLayout If true set a tight layout on the matplotlib figure
   */
  Figure::Figure(bool tightLayout)
      : Python::InstanceHolder(newFigure(tightLayout)) {}
  
  /**
   * @return The facecolor of the current figure
   */
  QColor Figure::faceColor() const {
    return ColorConverter::toRGB(
        callMethodNoCheck<Python::Object>(pyobj(), "get_facecolor"));
  }
  
  /**
   * Reset the background color of the figure.
   * @param color A character string indicating the color.
   * See https://matplotlib.org/api/colors_api.html
   */
  void Figure::setFaceColor(const QColor &color) {
    callMethodNoCheck<void, const char *>(
        pyobj(), "set_facecolor",
        color.name(QColor::HexRgb).toLatin1().constData());
  }
  
  /**
   * Reset the background color of the figure.
   * @param color A character string indicating the color.
   * See https://matplotlib.org/api/colors_api.html
   */
  void Figure::setFaceColor(const char *color) {
    callMethodNoCheck<void, const char *>(pyobj(), "set_facecolor", color);
  }
  
  /**
   * Sets how tight_layout is called when drawing. ("pad", "w_pad", "h_pad",
   * "rect", etc.)
   * @param args A hash of parameters to pass to set_tight_layout
   */
  void Figure::setTightLayout(QHash<QString, QVariant> const &args) {
    pyobj().attr("set_tight_layout")(Python::qHashToDict(args));
  }
  
  /**
   * Add an Axes of the given dimensions to the current figure
   * All quantities are in fractions of figure width and height
   * @param left The X coordinate of the lower-left corner
   * @param bottom The Y coordinate of the lower-left corner
   * @param width The width of the Axes
   * @param height The heigh of the Axes
   * @return A new Axes instance
   */
  Axes Figure::addAxes(double left, double bottom, double width, double height) {
    GlobalInterpreterLock lock;
    return Axes{pyobj().attr("add_axes")(
        Python::NewRef(Py_BuildValue("(ffff)", left, bottom, width, height)))};
  }
  
  /**
   * Add a subplot Axes to the figure
   * @param subplotspec A short-form subplot specification
   * @param projection An optional string denoting the projection type
   * @return A wrapper around the Axes object
   */
  Axes Figure::addSubPlot(const int subplotspec, const QString &projection) {
    GlobalInterpreterLock lock;
    if (projection.isEmpty())
      return Axes{pyobj().attr("add_subplot")(subplotspec)};
    else {
      const auto args = Python::NewRef(Py_BuildValue("(i)", subplotspec));
      Python::Dict kwargs;
      kwargs["projection"] = projection.toLatin1().constData();
      return Axes{pyobj().attr("add_subplot")(*args, **kwargs)};
    }
  }
  
  /**
   * @brief Add a colorbar to this figure
   * @param mappable An objet providing the mapping of data to rgb colors
   * @param cax An axes instance to hold the color bar
   * @param ticks An optional array or ticker.Locator object to control tick
   * placement
   * @param format An optional object describing how to format the tick labels
   * @return A reference to the matplotlib.colorbar.Colorbar object
   */
  Python::Object Figure::colorbar(const ScalarMappable &mappable, const Axes &cax,
                                  const Python::Object &ticks,
                                  const Python::Object &format) {
    GlobalInterpreterLock lock;
    const auto args = Python::NewRef(
        Py_BuildValue("(OO)", mappable.pyobj().ptr(), cax.pyobj().ptr()));
    const auto kwargs = Python::NewRef(
        Py_BuildValue("{sOsO}", "ticks", ticks.ptr(), "format", format.ptr()));
    Python::Object attr(pyobj().attr("colorbar"));
    return Python::NewRef(PyObject_Call(attr.ptr(), args.ptr(), kwargs.ptr()));
  }
  
  } // namespace MplCpp
  } // namespace Widgets
  } // namespace MantidQt
  