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

add support for categorical scales to the chart geometry elements

parent 07217a99
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
@@ -220,5 +220,44 @@ ReturnCode data_load(
  return expr_to_measures(expr, values);
}

ReturnCode data_to_measures(
    std::vector<std::string>& src,
    const ScaleConfig& scale,
    std::vector<Measure>* dst) {
  for (auto v = src.begin(); v != src.end(); ++v) {
    Measure m;
    switch (scale.kind) {
      case ScaleKind::CATEGORICAL: {
        auto v_iter = scale.categories_map.find(*v);
        if (v_iter == scale.categories_map.end()) {
          return errorf(
              ERROR,
              "error while parsing data: value '{}' is not part of the categories list",
              *v);
        }

        auto n = scale.categories.size();
        m = from_rel(double(v_iter->second + 1) / (n + 1));
        break;
      }
      default:
        if (auto rc = parse_measure(*v, &m); !rc) {
          return errorf(
              ERROR,
              "error while parsing data: '{}': {} -- "
              "if this is intentional, set 'scale-[x,y] to (categorical ...)'",
              *v,
              rc.message);
        }
        break;
    }

    dst->push_back(m);
  }

  return OK;
}


} // namespace fviz
+5 −0
Original line number Diff line number Diff line
@@ -65,5 +65,10 @@ ReturnCode data_load(
    const Expr* expr,
    std::vector<Measure>* values);

ReturnCode data_to_measures(
    std::vector<std::string>& src,
    const ScaleConfig& scale,
    std::vector<Measure>* dst);

} // namespace fviz
+6 −1
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "data.h"
#include "core/scale.h"
#include "core/sexpr_conv.h"
#include "core/sexpr_util.h"
@@ -199,10 +200,14 @@ ReturnCode scale_configure_kind(
      domain->kind = ScaleKind::CATEGORICAL;

      expr = expr_next(expr);
      if (auto rc = expr_to_strings(expr, &domain->categories); !rc) {
      if (auto rc = data_load_strings(expr, &domain->categories); !rc) {
        return rc;
      }

      for (size_t i = 0; i < domain->categories.size(); ++i) {
        domain->categories_map[domain->categories[i]] = i;
      }

      continue;
    }

+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ struct ScaleConfig {
  double padding;
  std::shared_ptr<ScaleLimitHints> limit_hints;
  std::vector<std::string> categories;
  std::unordered_map<std::string, size_t> categories_map;
};

struct ScaleLayout {
+38 −16
Original line number Diff line number Diff line
@@ -219,6 +219,11 @@ ReturnCode build(
  auto c = std::make_shared<PlotAreaConfig>();

  /* parse properties */
  std::vector<std::string> data_x;
  std::vector<std::string> data_y;
  std::vector<std::string> data_xoffset;
  std::vector<std::string> data_yoffset;

  auto config_rc = expr_walk_map(expr_next(expr), {
    {"data-x", bind(&data_load, _1, &c->x)},
    {"data-y", bind(&data_load, _1, &c->y)},
@@ -251,28 +256,23 @@ ReturnCode build(
    return config_rc;
  }

  /* check configuraton */
  if (c->x.size() != c->y.size()) {
    return error(
        ERROR,
        "the length of the 'data-x' and 'data-y' properties must be equal");
  /* scale configuration */
  if (auto rc = data_to_measures(data_x, c->scale_x, &c->x); !rc){
    return rc;
  }

  if (!c->xoffset.empty() &&
      c->xoffset.size() != c->x.size()) {
    return error(
        ERROR,
        "the length of the 'data-x' and 'data-x2' properties must be equal");
  if (auto rc = data_to_measures(data_xoffset, c->scale_x, &c->xoffset); !rc){
    return rc;
  }

  if (!c->yoffset.empty() &&
      c->yoffset.size() != c->y.size()) {
    return error(
        ERROR,
        "the length of the 'data-y' and 'data-y2' properties must be equal");
  if (auto rc = data_to_measures(data_y, c->scale_y, &c->y); !rc){
    return rc;
  }

  if (auto rc = data_to_measures(data_yoffset, c->scale_y, &c->yoffset); !rc){
    return rc;
  }

  /* scale autoconfig */
  for (const auto& v : c->x) {
    if (v.unit == Unit::USER) {
      scale_fit(v.value, &c->scale_x);
@@ -297,6 +297,28 @@ ReturnCode build(
    }
  }

  /* check configuraton */
  if (c->x.size() != c->y.size()) {
    return error(
        ERROR,
        "the length of the 'data-x' and 'data-y' properties must be equal");
  }

  if (!c->xoffset.empty() &&
      c->xoffset.size() != c->x.size()) {
    return error(
        ERROR,
        "the length of the 'data-x' and 'data-x2' properties must be equal");
  }

  if (!c->yoffset.empty() &&
      c->yoffset.size() != c->y.size()) {
    return error(
        ERROR,
        "the length of the 'data-y' and 'data-y2' properties must be equal");
  }

  /* return element */
  *elem = std::make_shared<Element>();
  (*elem)->draw = bind(&draw, c, _1, _2);
  return OK;
Loading