Commit f64e1cfa authored by Paul Asmuth's avatar Paul Asmuth
Browse files

add basic support for categorical domains

parent 204df769
Loading
Loading
Loading
Loading
+77 −10
Original line number Diff line number Diff line
@@ -66,17 +66,39 @@ void domain_fit_linear(const Series& data_raw, DomainConfig* domain, bool snap_z
  }
}

void domain_fit_categorical(const Series& data, DomainConfig* domain) {
  std::set<std::string> cache;
  for (const auto& d : domain->categories) {
    cache.insert(d);
  }

  for (const auto& d : data) {
    if (cache.count(d) > 0) {
      continue;
    }

    domain->categories.emplace_back(d);
    cache.insert(d);
  }
}

void domain_fit(const Series& data, DomainConfig* domain, bool snap_zero) {
  switch (domain->kind) {
    case DomainKind::LINEAR:
      return domain_fit_linear(data, domain, snap_zero);
    case DomainKind::CATEGORICAL:
      return domain_fit_categorical(data, domain);
  }
}

double domain_translate_linear(const DomainConfig& domain, const Value& v) {
std::vector<double> domain_translate_linear(
    const DomainConfig& domain,
    const Series& series) {
  auto min = domain.min.value_or(0.0f);
  auto max = domain.max.value_or(0.0f);

  std::vector<double> mapped;
  for (const auto& v : series) {
    auto vf = value_to_float(v);
    auto vt = (vf - min) / (max - min);

@@ -84,16 +106,45 @@ double domain_translate_linear(const DomainConfig& domain, const Value& v) {
      vt = 1.0 - vt;
    }

  return vt;
    mapped.push_back(vt);
  }

double domain_translate(const DomainConfig& domain, const Value& v) {
  return mapped;
}

std::vector<double> domain_translate_categorical(
    const DomainConfig& domain,
    const Series& series) {
  std::unordered_map<std::string, double> cache;
  for (size_t i = 0; i < domain.categories.size(); ++i) {
    cache.emplace(domain.categories[i], double(i));
  }

  double category_count = domain.categories.size();

  std::vector<double> mapped;
  for (const auto& v : series) {
    auto vt = (cache[v] / category_count) + (0.5 / category_count);

    if (domain.inverted) {
      vt = 1.0 - vt;
    }

    mapped.push_back(vt);
  }

  return mapped;
}

std::vector<double> domain_translate(
    const DomainConfig& domain,
    const Series& series) {
  switch (domain.kind) {
    case DomainKind::LINEAR:
      return domain_translate_linear(domain, v);
      return domain_translate_linear(domain, series);
    case DomainKind::CATEGORICAL:
      return domain_translate_categorical(domain, series);
  }

  return 0;
}

double domain_untranslate(const DomainConfig& domain, double vt) {
@@ -114,6 +165,22 @@ double domain_untranslate(const DomainConfig& domain, double vt) {
  return v;
}

ReturnCode confgure_domain_kind(
    const plist::Property& prop,
    DomainKind* kind) {
  if (plist::is_value(prop, "linear")) {
    *kind = DomainKind::LINEAR;
    return OK;
  }

  if (plist::is_value(prop, "categorical")) {
    *kind = DomainKind::CATEGORICAL;
    return OK;
  }

  return ERROR_INVALID_ARGUMENT;
}

namespace chart {

/*
+11 −2
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include <vector>
#include <string>
#include <optional>
#include <unordered_map>
#include "utils/return_code.h"
#include "plist/plist.h"
#include "common/series.h"
@@ -41,7 +42,7 @@
namespace plotfx {

enum class DomainKind {
  LINEAR
  LINEAR, CATEGORICAL
};

struct DomainConfig {
@@ -50,13 +51,21 @@ struct DomainConfig {
  bool inverted;
  std::optional<double> min;
  std::optional<double> max;
  std::vector<std::string> categories;
  double padding;
};

void domain_fit(const Series& data, DomainConfig* domain, bool snap_zero);

double domain_translate(const DomainConfig& domain, const Value& v);
std::vector<double> domain_translate(
    const DomainConfig& domain,
    const Series& series);

double domain_untranslate(const DomainConfig& domain, double v);

ReturnCode confgure_domain_kind(
    const plist::Property& prop,
    DomainKind* kind);

} // namespace plotfx
+2 −0
Original line number Diff line number Diff line
@@ -140,6 +140,8 @@ ReturnCode configure(
    {"axis-bottom-format", std::bind(&confgure_format, std::placeholders::_1, &config.axis_bottom.label_formatter)},
    {"axis-left", std::bind(&parseAxisModeProp, std::placeholders::_1, &config.axis_left.mode)},
    {"axis-left-format", std::bind(&confgure_format, std::placeholders::_1, &config.axis_left.label_formatter)},
    {"xdomain", std::bind(&confgure_domain_kind, std::placeholders::_1, &config.domain_x.kind)},
    {"ydomain", std::bind(&confgure_domain_kind, std::placeholders::_1, &config.domain_y.kind)},
    {
      "xdomain-format",
      configure_multiprop({
+8 −8
Original line number Diff line number Diff line
@@ -56,14 +56,16 @@ ReturnCode draw_lines(
    return ERROR_INVALID_ARGUMENT;
  }

  auto x = domain_translate(domain_x, config.xs);
  auto y = domain_translate(domain_y, config.ys);

  // draw line
  {
    Path path;

    for (size_t i = 0; i < series_len(config.xs); ++i) {
      auto x = config.xs[i];
      auto y = config.ys[i];
      auto sx = clip.x + domain_translate(domain_x, x) * clip.w;
      auto sy = clip.y + (1.0 - domain_translate(domain_y, y)) * clip.h;
      auto sx = clip.x + x[i] * clip.w;
      auto sy = clip.y + (1.0 - y[i]) * clip.h;

      if (i == 0) {
        path.moveTo(sx, sy);
@@ -84,10 +86,8 @@ ReturnCode draw_lines(
    FillStyle style;
    style.colour = config.point_colour;
    for (size_t i = 0; i < config.xs.size(); ++i) {
      auto x = config.xs[i];
      auto y = config.ys[i];
      auto sx = clip.x + domain_translate(domain_x, x) * clip.w;
      auto sy = clip.y + (1.0 - domain_translate(domain_y, y)) * clip.h;
      auto sx = clip.x + x[i] * clip.w;
      auto sy = clip.y + (1.0 - y[i]) * clip.h;

      // FIXME point style
      Path path;
+29 −0
Original line number Diff line number Diff line
width: 1200px;
height: 480px;

plot {
  axis-top: off;
  axis-right: off;

  margin: 0px;
  margin-top: 1.1rem;
  margin-bottom: 2.6rem;
  margin-left: 5rem;
  margin-right: 3.4rem;

  ymin: -3;
  ymax: 30;
  xdomain: categorical;

  series {
    xs: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12;
    ys: -0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5;
    point-size: 3.3pt;
  }

  series {
    xs: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12;
    ys: 4.8, 6.6, 10.3, 14.2, 16.6, 17.0, 15.2, 11.9, 8.5, 5.7, 4.2, 3.9;
    point-size: 3.3pt;
  }
}
Loading