Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abstract Data Dereferencing #82

Open
jugglinmike opened this issue Feb 20, 2014 · 2 comments
Open

Abstract Data Dereferencing #82

jugglinmike opened this issue Feb 20, 2014 · 2 comments

Comments

@jugglinmike
Copy link
Member

Some users have expressed interest in defining charts with "abstract"
requirements on the shape of input data. If this were provided by d3.chart,
charts might be considered more "reusable". Any chart could be configured to
visualize data sets defined in many different ways.

In building version 0.2 of this library, we discussed the needs of such an API
(see issue #22), built a prototype implementation, and eventually encapsulated
this solution in a JavaScript module named DataMap. We introduced the basic API
and functionality in the roadmap for the v0.2 release.

Ultimately, though, we decided not to include this solution for two reasons:

  1. General data transformation is outside of the scope of this library (see
    Miso DataSet and
    CrossFilter for existing solutions)
  2. That particular solution was not complete, and incorporating it would cause
    more confusion than it was worth.

Again, you can read the roadmap for the v0.2 release to learn more.

I'm opening this issue to create a place for further discussion on this
decision. If you disagree with #1 above and believe that data transformation
is within the purview of this data visualization plugin, let us know why. If
would like to experiment with (and possibly extend) our original solution, you'll
find a commit on the HEAD of the data-attrs branch that re-introduces the feature.

This was referenced Feb 20, 2014
@mgerring
Copy link

I have this problem, and I solved it by using the method shown in Towards Reusable Charts:

initialize: function() {
    var chart = this;

    chart.yValue = function(d){ return d[0] };
    chart.idValue = function(d){ return d[1] };
    chart.maxValue = function(data){ return d3.max(data,function(d){ return d[0] }) };

...

transform: function(data) {
    var chart = this;
    var newData = data.map( function(d,i) {
      return [chart.yValue.call(data, d, i), chart.idValue.call(data, d, i)];
    } );
    return newData;
  },

  y: function(func) {
    if (!arguments.length) return this.yValue;
    this.yValue = func;
    return this;
  },

  id: function(func) {
    if (!arguments.length) return this.idValue;
    this.idValue = func;
    return this;
  },

  max: function(func) {
    if (!arguments.length) return this.maxValue;
    this.maxValue = func;
    return this;
  }

Then, when you need to tell the chart what your data looks like, you can do this:

var myBarChart = selection
          .chart('barChart')
            .y(function(d){ return $parse(attrs.y)(d) })
            .id(function(d){ return $parse(attrs.id)(d) })
            .max(function(d){ return $parse(attrs.max)(d) });

In this case, $parse(attrs.y)(d) is using an attribute set on an angular.js directive to find a property in d, where d is raw data returned from an API.

What do people think about this approach?

@jugglinmike
Copy link
Member Author

@mgerring I think that looks pretty good! The tricky thing about solving this
problem from within d3.chart itself is that the approach has to be very
generic before it can be justified, and the trade-offs between usefulness,
performance, and simplicity are very difficult to navigate.

I'm thinking of one change that might make your approach a little better still:

     chart.yValue = function(d){ return d[0] };
     chart.idValue = function(d){ return d[1] };
-    chart.maxValue = function(data){ return d3.max(data,function(d){ return d[0] }) };
+    chart.maxValue = function(data){ return d3.max(data,function(d){ return chart.yValue(d); }) };

This way, users who override yValue can still use the "default"
implementation of maxValue. What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants