[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/watsonryan/gnuplotpp/main/include/gnuplotpp/plot.hpp [Back]  [Original]

#pragma once

#include 
#include 
#include 
#include 
#include 
#include 
#include 

/**
 * @namespace gnuplotpp
 * @brief Pure C++ plotting API that renders through a gnuplot backend.
 */
namespace gnuplotpp {

/** @brief Output file formats supported by the renderer. */
enum class OutputFormat { Pdf, Svg, Eps, Png };

/** @brief Figure-wide palette selection for automatic series colors. */
enum class ColorPalette { Default, Tab10, Viridis, Grayscale };

/** @brief Heatmap colormap palette selection. */
enum class ColorMap { Viridis, Cividis, Turbo, Magma, CoolWarm, Gray };

/** @brief Color normalization mode for color-mapped plots. */
enum class ColorNorm { Linear, Log };

/** @brief Text rendering mode used by terminal setup. */
enum class TextMode { Enhanced, Plain, LaTeX };

/** @brief Coordinate system used by typed annotations. */
enum class CoordSystem { Data, Graph, Screen };

/** @brief Built-in publication presets for size and style defaults. */
enum class Preset {
  IEEE_SingleColumn,
  IEEE_DoubleColumn,
  AIAA_Column,
  AIAA_Page,
  IEEE_Tran,
  Nature_1Col,
  Elsevier_1Col,
  Custom
};

/** @brief Figure dimensions in inches. */
struct FigureSizeInches {
  double w = 3.5;
  double h = 2.5;
};

/** @brief Shared style defaults applied at figure scope. */
struct Style {
  std::string font = "Times-New-Roman";
  double font_pt = 9.0;
  double line_width_pt = 1.0;
  double point_size = 0.6;
  bool grid = false;
  double tick_font_scale = 1.0;
  double label_font_scale = 1.0;
  double title_font_scale = 1.0;
  bool title_bold = false;
};

/** @brief Export behavior knobs for format-specific rendering policy. */
struct ExportPolicy {
  bool drop_line_alpha_for_vector = true;
  bool warn_line_alpha_on_vector = true;
};

/** @brief High-level figure configuration. */
struct FigureSpec {
  Preset preset = Preset::IEEE_SingleColumn;
  FigureSizeInches size{};
  Style style{};
  ColorPalette palette = ColorPalette::Default;
  TextMode text_mode = TextMode::Enhanced;
  int rows = 1;
  int cols = 1;
  std::vector formats{OutputFormat::Pdf};
  std::string title;
  std::string caption;
  bool panel_labels = false;
  bool write_manifest = false;
  bool share_x = false;
  bool share_y = false;
  bool hide_inner_tick_labels = false;
  bool auto_layout = true;
  bool interactive_preview = false;
  std::vector font_fallbacks{"Helvetica", "Arial", "Times"};
  ExportPolicy export_policy{};
};

/** @brief Legend placement presets. */
enum class LegendPosition {
  TopRight,
  TopLeft,
  BottomRight,
  BottomLeft,
  OutsideRight,
  OutsideBottom
};

/** @brief Legend configuration for one axes. */
struct LegendSpec {
  bool enabled = true;
  LegendPosition position = LegendPosition::TopRight;
  int columns = 1;
  bool boxed = false;
  bool opaque = false;
  bool has_font_pt = false;
  double font_pt = 8.0;
};

/** @brief Typed label annotation. */
struct LabelAnnotation {
  std::string text;
  std::string at = "graph 0.05,0.95";
  std::string font;
  bool front = true;
};

/** @brief Typed arrow annotation. */
struct ArrowAnnotation {
  std::string from = "graph 0.1,0.9";
  std::string to = "graph 0.2,0.8";
  bool heads = true;
  double line_width_pt = 1.0;
  std::string color = "#000000";
  bool front = true;
};

/** @brief Typed rectangle object for highlights/masks. */
struct RectObject {
  std::string from = "graph 0.1,0.1";
  std::string to = "graph 0.2,0.2";
  bool has_fill_opacity = false;
  double fill_opacity = 0.15;
  std::string fill_color = "#000000";
  bool border = false;
  std::string border_color = "#000000";
  bool front = false;
};

/** @brief Typed coordinate pair for annotation placement. */
struct Coord2D {
  CoordSystem system = CoordSystem::Data;
  double x = 0.0;
  double y = 0.0;
};

/** @brief Typed equation label annotation. */
struct EquationAnnotation {
  std::string expression;
  Coord2D at{};
  bool boxed = false;
  bool front = true;
};

/** @brief Typed callout with arrow and attached text. */
struct CalloutAnnotation {
  std::string text;
  Coord2D from{};
  Coord2D to{};
  bool heads = true;
  double line_width_pt = 1.0;
  std::string color = "#000000";
  bool front = true;
};

/** @brief Axes typography overrides (optional). */
struct TypographySpec {
  bool has_tick_font_pt = false;
  double tick_font_pt = 8.0;
  bool has_label_font_pt = false;
  double label_font_pt = 9.0;
  bool has_title_font_pt = false;
  double title_font_pt = 9.0;
  bool has_title_bold = false;
  bool title_bold = false;
};

/** @brief Axes frame/tick style overrides (optional). */
struct AxisFrameSpec {
  bool has_border_mask = false;
  int border_mask = 15;
  bool has_border_line_width_pt = false;
  double border_line_width_pt = 0.9;
  bool has_border_color = false;
  std::string border_color = "#222222";
  bool has_ticks_out = false;
  bool ticks_out = false;
  bool has_ticks_mirror = false;
  bool ticks_mirror = false;
};

/** @brief Axes-level labels, limits, and grid/log controls. */
struct AxesSpec {
  std::string title;
  std::string xlabel;
  std::string ylabel;
  std::string y2label;
  bool grid = false;
  bool legend = true;
  LegendSpec legend_spec{};
  bool enable_crosshair = false;
  ColorMap color_map = ColorMap::Viridis;
  ColorNorm color_norm = ColorNorm::Linear;
  std::string colorbar_label;
  bool has_cbrange = false;
  double cbmin = 0.0;
  double cbmax = 1.0;
  bool has_cbtick_step = false;
  double cbtick_step = 0.1;

  bool has_xlim = false;
  double xmin = 0.0;
  double xmax = 0.0;

  bool has_ylim = false;
  double ymin = 0.0;
  double ymax = 0.0;

  bool xlog = false;
  bool ylog = false;
  bool y2log = false;

  bool has_y2lim = false;
  double y2min = 0.0;
  double y2max = 0.0;

  bool has_xtick_step = false;
  double xtick_step = 1.0;
  bool has_ytick_step = false;
  double ytick_step = 1.0;
  bool has_xminor_count = false;
  int xminor_count = 2;
  bool has_yminor_count = false;
  int yminor_count = 2;
  std::string xformat;
  std::string yformat;

  TypographySpec typography{};
  AxisFrameSpec frame{};

  /**
   * @deprecated Use `typography.has_tick_font_pt` and `typography.tick_font_pt`.
   * Legacy fields are normalized in `Axes::set()` for compatibility only.
   */
  bool has_tick_font_pt = false;
  /**
   * @deprecated Use `typography.tick_font_pt`.
   */
  double tick_font_pt = 8.0;
  /**
   * @deprecated Use `typography.has_label_font_pt` and `typography.label_font_pt`.
   * Legacy fields are normalized in `Axes::set()` for compatibility only.
   */
  bool has_label_font_pt = false;
  /**
   * @deprecated Use `typography.label_font_pt`.
   */
  double label_font_pt = 9.0;
  /**
   * @deprecated Use `typography.has_title_font_pt` and `typography.title_font_pt`.
   * Legacy fields are normalized in `Axes::set()` for compatibility only.
   */
  bool has_title_font_pt = false;
  /**
   * @deprecated Use `typography.title_font_pt`.
   */
  double title_font_pt = 9.0;
  /**
   * @deprecated Use `typography.has_title_bold` and `typography.title_bold`.
   * Legacy fields are normalized in `Axes::set()` for compatibility only.
   */
  bool has_title_bold = false;
  /**
   * @deprecated Use `typography.title_bold`.
   */
  bool title_bold = false;

  std::vector labels;
  std::vector arrows;
  std::vector rectangles;
  std::vector equations;
  std::vector callouts;

  // Optional raw gnuplot commands for advanced annotations (arrows/labels/etc).
  std::vector gnuplot_commands;
};

/** @brief Supported series drawing types. */
enum class SeriesType { Line, Scatter, ErrorBars, Band, Histogram, Heatmap };

/** @brief Series metadata and optional per-series style override. */
struct SeriesSpec {
  SeriesType type = SeriesType::Line;
  std::string label;
  bool has_line_width = false;
  double line_width_pt = 1.0;
  /** @brief Optional explicit line/point color (e.g., "#112233"). */
  bool has_color = false;
  std::string color = "#000000";
  /**
   * @brief Optional opacity in [0, 1].
   * @note Backends map this to gnuplot ARGB color strings when possible.
   */
  bool has_opacity = false;
  double opacity = 1.0;
  bool use_y2 = false;
};

/** @brief In-memory series samples used by backends for emission/rendering. */
struct SeriesData {
  SeriesSpec spec;
  std::vector x;
  std::vector y;
  std::vector y2;
  std::vector yerr_low;
  std::vector yerr_high;
  std::vector z;
};

/**
 * @brief One subplot in a figure layout.
 */
class Axes {
public:
  /**
   * @brief Set axes configuration.
   * @param spec Axes settings to store.
   */
  void set(AxesSpec spec);

  /**
   * @brief Add one x/y series to this axes.
   * @param spec Series metadata and styling.
   * @param x X samples.
   * @param y Y samples; must match x length.
   * @throws std::invalid_argument if x and y lengths differ.
   */
  void add_series(const SeriesSpec& spec,
                  std::span x,
                  std::span y);

  /**
   * @brief Add a confidence band from lower/upper curves.
   * @param spec Series style metadata.
   * @param x X samples.
   * @param y_low Lower bound values.
   * @param y_high Upper bound values.
   * @throws std::invalid_argument if lengths differ.
   */
  void add_band(const SeriesSpec& spec,
                std::span x,
                std::span y_low,
                std::span y_high);

  /**
   * @brief Add a histogram-style series from bin centers and counts.
   * @param spec Series metadata.
   * @param bin_centers Histogram bin centers.
   * @param counts Histogram values.
   * @throws std::invalid_argument if lengths differ.
   */
  void add_histogram(const SeriesSpec& spec,
                     std::span bin_centers,
                     std::span counts);

  /**
   * @brief Add heatmap samples as x/y/z triplets.
   * @param spec Series metadata.
   * @param x X coordinates.
   * @param y Y coordinates.
   * @param z Intensity values.
   * @throws std::invalid_argument if lengths differ.
   */
  void add_heatmap(const SeriesSpec& spec,
                   std::span x,
                   std::span y,
                   std::span z);

  /**
   * @brief Add asymmetric y-errorbar series.
   * @param spec Series metadata.
   * @param x X samples.
   * @param y Central values.
   * @param y_low Absolute lower errors.
   * @param y_high Absolute upper errors.
   */
  void add_errorbars_asymmetric(const SeriesSpec& spec,
                                std::span x,
                                std::span y,
                                std::span y_low,
                                std::span y_high);

  /** @return Current axes configuration. */
  const AxesSpec& spec() const { return spec_; }

  /** @return All series added to this axes. */
  const std::vector& series() const { return series_; }

private:
  AxesSpec spec_{};
  std::vector series_{};
};

class Figure;

/** @brief Backend render status and generated output paths. */
enum class RenderStatus {
  Success,
  InvalidInput,
  IoError,
  ExternalToolMissing,
  ExternalToolFailure,
  UnsupportedFormat
};

/** @brief Backend render status and generated output paths. */
struct RenderResult {
  bool ok = true;
  RenderStatus status = RenderStatus::Success;
  std::string message;
  std::filesystem::path script_path;
  std::vector outputs;
};

/**
 * @brief Renderer backend abstraction.
 */
class IPlotBackend {
public:
  virtual ~IPlotBackend() = default;

  /**
   * @brief Render a figure to output files.
   * @param fig Figure and series data.
   * @param out_dir Output directory for artifacts.
   * @return Render status and paths.
   */
  virtual RenderResult render(const Figure& fig,
                              const std::filesystem::path& out_dir) = 0;
};

/**
 * @brief Validate figure/series invariants before backend rendering.
 * @param fig Figure to validate.
 * @return `ok=true` when valid, otherwise InvalidInput with message.
 */
RenderResult validate_figure_for_render(const Figure& fig);

/**
 * @brief Figure container with a fixed subplot grid and backend delegation.
 */
class Figure {
public:
  /**
   * @brief Construct a figure from specification.
   * @param spec Figure spec including layout.
   * @throws std::invalid_argument if rows or cols are not positive.
   */
  explicit Figure(FigureSpec spec);

  /**
   * @brief Access axes by row/column index.
   * @param r Zero-based row.
   * @param c Zero-based column.
   * @return Mutable axes reference.
   * @throws std::out_of_range when indices are invalid.
   */
  Axes& axes(int r, int c);

  /**
   * @brief Access axes by flattened index.
   * @param idx Zero-based index in row-major order.
   * @return Mutable axes reference.
   * @throws std::out_of_range when index is invalid.
   */
  Axes& axes(int idx);

  /** @return Figure specification. */
  const FigureSpec& spec() const { return spec_; }

  /** @return All axes in row-major order. */
  const std::vector& all_axes() const { return axes_; }

  /**
   * @brief Save the figure by invoking the configured backend.
   * @param out_dir Output directory.
   * @return Render status and output paths.
   * @note Returns ok=false when no backend is set.
   */
  RenderResult save(const std::filesystem::path& out_dir) const;

  /**
   * @brief Attach a backend used by save().
   * @param backend Backend implementation.
   */
  void set_backend(std::shared_ptr backend);

private:
  FigureSpec spec_{};
  std::vector axes_{};
  std::shared_ptr backend_{};
};

}  // namespace gnuplotpp

Web Proxy Viewer  |  New URL  |  Original Page