Giter Site home page Giter Site logo

d3.chart's People

Contributors

cesutherland avatar headwinds avatar iros avatar jeanlauliac avatar jugglinmike avatar knuton avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

d3.chart's Issues

API for `.extend`

As a newbie, I read the following code

d3.chart("CircleChart").extend("LabeledCircleChart", {});

as "Circle chart extends LabeledCircleChart" (when in fact the opposite is occurring). Perhaps it's because of Backbone

var Note = Backbone.Model.extend({})

where you call the extend method on the base object itself.

I'm curious why d3.chart uses d3.chart('oldChart').extend('newChart',...). This has been a small gotcha for me a few times. Not too big of a deal, but others may encounter it too. I just wanted to bring it to your guys' attention.

Update License Copyright

Currently set to Mike Pennisi - wasn't sure if it should have said "The Miso Project Team" or our names?

How to create a line path as a layer without 'insert' function

Hi Guys,
Thanks again for your great work. I really like the concept behind "layers" in d3.chart. it makes drawing with d3 more consistant and understandable. However, It becomes a bit confusing when I have to deal with simple path. Can a line path be taken as a layer ? Doing something like this, is it wrong ?

chart.layer("lineLayer", this.base.append("path"), {
            dataBind : function (data) {
                var chart = this.chart();

                var lineBuiler = d3.svg.line()
                    .x(function(d) { return chart.xScale(d.x); })
                    .y(function(d) { return chart.yScale(d.y); });

                this.attr("class", "line")
                    .attr("d", lineBuiler(data));

                return this;
            }

        });

Thanks in advance

Mixing in an axis

Is there an idiomatic way to mix an axis in with a chart?

If I make the axis a separate chart, I have to define the scales twice.

If I make the axis a layer, I can't reuse it in other charts.

Just curious what your experience has been so far.

Navigating mixins from lifecycle event handlers

While updating the examples to work with the latest version of the library, I encountered a limitation of the mixin API: lifecycle event handlers cannot access higher-level charts. See here for the motivating example.

At first glance, I think the solution is going to involve some extension to d3.selection.prototype.chart to allow for specification of which chart from a lifecycle event handler. Or maybe the introduction of a method like Chart#parent...

I am suspicious of an API that encourages dependencies in the direction of both parent-to-child (as it currently does) and child-to-parent (as both of the above solutions would).

how to resize the chart by using d3.chart?

I really like the object orient approach on d3 chart implementation. I have used this library a quiet while now and have fun doing it.

I have a question on how to handle the chart resize on window resize. When you resize the window, the d3.chart instance should resize as well by setting the new width and the new height, so the scale will change, and redraw the chart.

for example, in NVd3, nvd3, they instantiate the chart by defining a function function chart(selection), so when it resizes, it just triggered on chart.attr(width, newvalue).attr(height, newvalue).call( chart ). here chart represents function chart(selection). How could we do this easily in d3.chart since we have initialized the chart when instance has been created. a lot of attribute has been setup.

What I did now is defined redraw: function(){} to set all the changing attrs, currently, it did not work. Is there a better way to handle this case? any jsbin example on setup d3.chart?

Thanks

Invoke `:transition` events only when necessary

Because calling .transition() on a selection can effect animations queued on other selections, we should only attempt to make "transition" selections if corresponding events have been registered.

Passing a chart in the options of a mixin

I was experimenting with passing a chart to its mixin, like so:

this.xAxis = this.mixin('xAxis', this.base.select('g').append('g'), this);

Then, in the xAxis chart (really, more of a component) I could access the main chart's scale and height. The idea would be to build the xAxis component to work as a mixin with any chart that implements a scale and height method.

Do you have any comments on this approach? Would you prefer some other approach, like passing in the height and scale directly? If so, why?

Thanks!

Data transform

Hi, congrats for your work. This library seems promising.

I was wondering if asking the user of a chart to transform its data to correspond to what the chart expects was a good idea and was necessary.

For example, in the Bar Chart (http://misoproject.com/d3-chart/examples/basic.html), the chart expects d.value and d.name.

To not transform the data, I was thinking about defining getters for each property of the data the chart wants to access. These getters could by default simply return the property with the same name but could also be configurable by the user of the chart to return a specific property.

I think it will be better in term of performance and it will also self-document what the chart expect from our data.

Example of declaration of the getters for the Bar Chart:

d3.chart('BarChart', {
  dataAttributes: ["value", "name"],
  // [...]
});

d3.chart will create automatically for each element in dataAttributes a default getter that return the value of the property with the same name. But a user could replace a specific getter ("name" for example) like this:

// [...]
.chart('BarChart')
.dataAttributes({
  name: function() {
    return this.firstName; // 'this' is d
  }
});

Then, example of code that access a property via a getter in the Bar Chart code (line 146):

 .text(function(d) {
   return chart.get(d, "name");
   // or, maybe this way without a string:
   return chart.get(d).name;
 });

What do you think?

Allow passing of context to mixin components

I've been working with this library for a week or so now, and I'm really happy with the functionality so far. Thanks for all the work you guys have done!

One thing I've struggled with is modularizing graph components in a clean way.

The current mixin functionality (as far as I understand) provides a mechanism for superimposing components on top of each other, but requires them all to be stand-alone charts that don't share any attributes or properties.

This works fine until you want to abstract components that rely on the attributes of the original chart.

For example, imagine I want to provide a tooltip that displays the x and y values on chart mouseover. I'll start by defining a translucent overlay layer that records mouse movements over my chart:

chart.layer('overlay', chart.areas.overlay, {
      dataBind: function (data) {

        return this.selectAll('rect')
            .data([data]);
      },
      insert: function(){

        return this.append('rect')
          .style('fill', 'rgba(0,0,0,0.0)')
          .attr("width", chart.w - chart.margins.left)
          .attr("height", chart.h - chart.margins.bottom)
          .on("mousemove", function() {
            var mouseX = chart.x.invert(d3.mouse(this)[0]),
                 mouseY = chart.y.invert(d3.mouse(this)[1]);
           // display mouse cords in previously defined layer
            chart.areas.focus.text(mouseX +' '+ mouseY);
          })
      }
    });

I'd like to be able to abstract this functionality so I can apply it to multiple graphs across my site. The issue is that it relies on previously defined chart attributes (my x and y scales, as well as chart.h and chart.w), and therefore can't be decoupled fully from my base graph.

The other option would be extending an existing linegraph to include the overlay functionality like so:

d3.chart('Line', {
  initialize: function() {
    var chart = this;

    chart.w = chart.base.attr('width') || 960;
    chart.h = chart.base.attr('height') || 600;

    chart.x = d3.time.scale()
      .range([0, chart.w - chart.margins.left]);

    chart.y = d3.scale.linear()
      .range([chart.h - chart.margins.bottom, 0]);

    chart.areas = {};

    ...
})

d3.chart('Line').extend("LineWithOverlay", {
  initialize: function() {

     chart.layer('overlay', chart.areas.overlay, {
        dataBind: function(data) {
        ...  
        },
        insert: function() {
        ...
        }
     });
  }
});

This works, but seems kludgy as I'd have to create an new extended chart every time I want to use the overlay functionality.

Is there a better way to modularize chart components that I'm not seeing? If not, is allowing mixins with context a possibility? ex:

d3.chart('Line', {
  var chart = this; 

  initialize: function() {
    this.overlay   = this.mixin("overlay", chart, this.base.append("g"));
    this.axis = this.mixin("axis", chart, this.base.append("g"));
  }
});

Would love to hear your thoughts!

How properly update chart with new data (maybe with transitions) ?

Hello! (first of all sorry for my english)
I draw a simple pie chart - http://bl.ocks.org/rifler/7536267 (or http://jsfiddle.net/Rifler/FGmRw/)
and it looks nice till i update it with new data. On page loading data contains 4 elements, but on button click i push new random element and then call pieChart.draw(data) and pie is incorrectly drawn. Can you tell me how to properly update chart with new data? Maybe a few examples with all lifecycle events (i don't understand them fully)?

Thanks!

Specifying charts without using a name

In some cases it'd be nice to pass the chart definition directly to d3.selection.prototype.chart instead of defining a chart using d3.chart and a unique name - mostly to avoid naming collisions. For example:

d3.select('.graph')
  .append('svg')
  .chart({
    initialize: function() {
      console.log('initializing the chart')
    }
  })

Is there a way of doing this right now? If not, would you guys be open to it? I'm happy to submit a pull request if so.

Multiple bound elements in a layer

This may be a stupid question as I am just starting out with D3. I am creating a chart with an area and a line both bound to the same data.

What would be the best way to structure this? It would seem I would need one large layer that binds everything? Or could I use separate layers to bind things independently to the same data? If so is the transform function the best place to set up the axes domain so that it is only done once?

Register as bower component

I couldn't find d3.chart through bower.

It would be cool if d3.chart was registered as a bower component.

Shorthand the creation of reusable properties.

I've noticed in much of the documentation and examples the common definition of reusable properties, such as: width, height, tickFormat, etc. These functions are bulky and not particularly dry in my opinion.

The following proof of concept illustrates the concept:

d3.chart("SomeChart", {
  initialize: function(options) {
    // Configurable properties.
    this.prop("width");
    this.prop("height");

    // Configure dimensions.
    this.width(960);
    this.height(120);
  },

  // Create re-usable methods that act as getters/setters.
  prop: function(name, callback) {
    this[name] = function(val) {
      if (arguments.length === 0) {
        return this["_" + name];
      }

      // Reassign the value.
      this["_" + name] = val;

      if (callback) {
        callback.call(this, val);
      }

      return this;
    };
  }
});

Is this a common enough task to warrant a convenience method within d3.chart itself? I think it could easily cut down on a significant amount of common repeated methods.

I can't see my lineChart drawn in on part of my LayoutChart

I'm still trying to master d3.chart and I have a lot of fun using it. However, I still don't understand some unexpected behavior. It my code ( http://jsfiddle.net/lioninho11/yMg9s/1/ ) , I need to draw a line chart in the chart.zones.main part of my LayoutChart but I can't see the drawing at all. Moreover, I did suceeded in applying width and height of this part from my Layout.

Any Idea ? Again thanks for your previous feedback about my code, I tried this time to well structured my charts and don't hesitate to point out the things i'm doing wrong.

Thanks a lot

Lionel

update selection changes after .enter is called

I was reading some of Bostock's writing and came across this block:
http://bl.ocks.org/mbostock/3808218

Specifically the thing I want to point out is this sequence:

 // DATA JOIN
  // Join new data with old elements, if any.
  var text = svg.selectAll("text")
      .data(data);

  // UPDATE
  // Update old elements as needed.
  text.attr("class", "update");

  // ENTER
  // Create new elements as needed.
  text.enter().append("text")
      .attr("class", "enter")
      .attr("x", function(d, i) { return i * 32; })
      .attr("dy", ".35em");

  // ENTER + UPDATE
  // Appending to the enter selection expands the update selection to include
  // entering elements; so, operations on the update selection after appending to
  // the enter selection will apply to both entering and updating nodes.
  text.text(function(d) { return d; });

I did not know that the update selection changes after enter is called to include the elements in it. Right now our code effectively forces the update selection to always contain the entered elements. I'm not sure if that's consistant or what we want to do about it. In a sense, they are two different lifecycle events. The main issue is that we can't call .enter() until after we've executed the callback for the update + update:transition event which we currently do so that we can iterate over the selections object.

Thoughts?

select vs selectAll in dataBind

In dataBind, this.selectAll('rect') gives me a selection whose parentNode is the base selection for the layer, as I'd expect.

However, this.select('rect') returns a selection whose parentNode is html. Could somebody explain this to me? I feel like it's something in D3 I'm not understanding. I thought the only difference between select and selectAll when invoked on a selection was the data pass-through that select performs.

Groups of related elements and layers

I'm not sure what the proper approach is to render groups of related elements. For example if I consider a line with dots plotted along the line as a single entity, I'd like to include both in a single layer. Another example is a segmented line (which is actually two lines formatted differently using the d3.line.defined() function). It appears that d3.chart requires me to divide the two lines into separate layers and I'd like to avoid that. Is there a way to combine groups of related elements into a single layer? If so, what is the correct pattern?

Returning the data selection from lifecycle events

Hello everyone!

I keep seeing something like this, and I'm getting a bit confused by it:

  events: {
    enter: function() {
      var chart = this.chart();
        return this.attr("cx", function(d) {
            return chart.xScale(d)
        });
    }
  }

What specifically (if anything) needs to be returned from the lifecycle events?

Layer without data-binding

Is the chart.layer object designed to contain elements such as titles, subtitles, chart controls, etc. that are not directly bound with dataBind? If not, how should we properly add these elements to a chart?

`enter` event being erroneously triggered?

I'm extending a chart:

    d3.chart('BarChart').extend('AccountingBarChart', {
      initialize: function() {
        // this.dataLabels is a mixin
        this.dataLabels.layer('labels').on('enter', function() {
          this.text('$' + this.text());
        });
      }
    });

then rendering it multiple times

    setInterval(function() {
      barData.forEach(function(d) {
        d.value = d.value + 1;
      });
      barChart.draw(barData);
    }, 2000);

The second time the chart gets rendered, it triggers the enter event and tries to execute the above code, even though there's no entering data. Any ideas?

mixin api should reverse argument order

current api is:

mixin(selection, chartTypeName)

I think to be consistent with the layer api and chart definition api, it should take the chartTypeName first. I always mix them up.

Thoughts? +1 and I'll change it.

Rendering chart controls

I have a chart for which I need UI controls that are bound to the chart data. For example, a range slider which finds its max and min values from the data and other UI filtering controls. I'm wondering what the best practice would be for constructing the control container element (which could contain all the possible controls). Ideally, I'd want to have the option of rendering the control element(s) anywhere on the page rather than coupling it with the chart but bey default the control element could be rendered below the chart.

For now, I have added a loadControls() method to the chart and I call that method immediately after the draw(data) call. This renders the controls and binds them to the chart. Also, for each individual control, I added a bindMyControl method that configures the control with the current (filtered) data. This works for now, it would be nice to have a d3.chart design pattern/recommendation to use.

layer.base is inaccessible

Because the base is set on the layer instance, but then calling .layer returns the d3 selection, it is impossible to retrieve the base from a layer at any point. Why do we have it?

_attrs - private?

This may be a stupid question, but in the intro I see underscored attributes in the initialize function:

initialize : function() {
    this.xScale = d3.scale.linear();

    // setup some defaults
    this._width = this._width || this.base.attr("width") || 200;
    this._height = this._height || this.base.attr("height") || 100;
    this._radius = this._radius || 5;
}

Do the underscored attrs (e.g. _width) signify private variables, vs xScale being a public variable? Or is it to differentiate between the actual property and the accessor function?

Chart cleanup

We should determine & document best practices for chart cleanup upon chart removal.

allow specifying layer draw order

Sometimes I need my layers to be drawn in a certain order, because one of them will set up some scales that the others may want to use.
Do we want to allow a way to specify the order of drawing in an options parameter to the draw method, or force people to ignore the order? I feel like the former is a bit more flexible.

Why have an `insert` method?

Hello,

I'm trying to wrap my head around the insert method. In the world of vanilla D3, we typically append elements within the enter selection:

d3.select("body").selectAll("p")
    .data([4, 8, 15, 16, 23, 42])
  .enter().append("p")
    .text(function(d) { return "I’m number " + d + "!"; });

In d3.chart, we'd do something like this:

d3.chart('PChart', g, {
  ...
  insert: function() {
    return this.append('p');
  },

  events: {
    'enter': function() {
      this.text(function(d) { return "I’m number " + d + "!"; });
    }
  }
});

My question is, why not just append the elements in the enter lifecycle event? I may not be reading it right, but isn't this what the relevant code is essentially doing?

The only info I've been able to find about this was in Irene's blog post:

insert method - the method that creates the actual data-bound elements and sets any attributes that don’t have to do with the data. The reason we don’t do that here is because we want to account for our data potentially changing and thus want to delegate setting any data-driven attributes to the lifecycle events.

But isn't appending elements a data-driven operation, and therefore doesn't it belong in the enter lifecycle event?

I think I'm just missing something here - would love some clarification.

Thanks!

Generic data joiny stuff

I'm working on a simple chart has bars in one layer, and an x axis in another. Currently, I update the domain of my scales in the dataBind method of my bars layer, but since the axes are used by both layers, I'd like to extract that code out to somewhere that's not specific to one layer.

Is there a place where I have access to the chart's data and can run this shared code? In general what's a more idiomatic to accomplish this?

d3.chart js type error

When trying to include d3.chart in a larger project with many JS files I am greeted by a JS type error:

Uncaught TypeError: Cannot read property 'prototype' of undefined 

screen shot 2013-07-05 at 13 57 30

I made a reduced test case including only the relevant files. Download here:
http://cl.ly/2V012E2L2h1M

Naming case convention for charts

In http://misoproject.com/d3-chart/charts.html there is only one rule about chart naming convention:

  1. Please name your chart in the format: d3.chart.*, for example d3.chart.barchart etc.

(1) This doesn't tell which case style should be used for naming charts. For instance, if I want to create a "horizontal bar chart", it could be:

  • not separated : d3.chart.horizontalbar
  • hyphen-separated : d3.chart.horizontal-bar
  • underscore-separated : d3.chart.horizontal-bar
  • camel-cased : d3.chart.horizontalBar

(my favorite: hyphen-separated)

(2) This doesn't tell whether it should include the word "chart" or not:

  • with: d3.chart.horizontal-bar
  • without: d3.chart.horizontal-bar-chart

(my favorite: without)


I think that stating about these two question would enforce uniformity between charts and therefore add quality to this project.

add redraw method

Most of my setters have the line:

this.draw(this.data);

I feel like we can just add a redraw() that wraps that?

Nested selections

Hi,

I'm curious if there's an idiomatic way to work with nested selections with d3.chart. This is an example from a grouped barchart using vanilla d3.js:

  var state = svg.selectAll(".state")
      .data(data)
    .enter().append("g")
      .attr("class", "g")
      .attr("transform", function(d) { return "translate(" + x0(d.State) + ",0)"; });

  state.selectAll("rect")
      .data(function(d) { return d.ages; })
    .enter().append("rect")
      .attr("width", x1.rangeBand())
      .attr("x", function(d) { return x1(d.name); })
      .attr("y", function(d) { return y(d.value); })
      .attr("height", function(d) { return height - y(d.value); })
      .style("fill", function(d) { return color(d.name); });

Here we have two data bindings taking place. Initially this seems to suggest that they belong in two different layers, but I'm not sure that makes sense here.

I could "abuse" d3.chart by doing something like this

"enter": function() {
  var chart = this.chart();

  this
      .append("g")
      .attr("class", "g")
      .attr("transform", function(d) { return "translate(" + x0(d.State) + ",0)"; });
    .selectAll(".bar")
    .data(function(d) {return d.values;})
    .enter()
      .append("rect")
      .attr('class', 'bar')
      .attr("width", chart.x1Scale.rangeBand())
      ...;
},

though I'm almost certain this is not the best way to go. What's a good solution here?

Thanks!

P.S. I've been asking a lot of questions here - please let me know if there's somewhere else I should be asking (SO, google group, IRC, etc.).

Documentation: Reusable Bar Chart example on Web site

In the Reusable Bar Chart example where you determine max (lines 95-101) you call _(data), with _ not being defined when you only include d3 and d3.chart.

To make this work without additional libraries, I replaced the code with:

    chart.datamax = chart.usermax || d3.max(data, function(d) {
        return d.value;
    });
    chart.y.domain([0, chart.datamax]);

Modes

So, the modes on @iros 's d3.chart.base are awesome. And I love the api.

Any plans on putting these into d3.chart core?

pass key function to `draw` call

I realized that even though we have transform, we may still want to allow a user to pass a key function that will be used in the dataBind routine.

Given the chart:

d3.chart("MyChart", {});

For example the following calls:

chart.draw([
  { name : "a", value : 12 },
  { name : "b", value : 155 }
]);
chart.draw([
  { id : "a", value : 12 },
  { id : "b", value : 155 }
]);

It would be unfortunate to define a generic transform function on the chart that would just rename the properties id or name. In practice it would be nicer to just call:

chart.draw([
  { name : "a", value : 12 },
  { name : "b", value : 155 }
], function(d) { return d.name; });
chart.draw([
  { id : "a", value : 12 },
  { id : "b", value : 155 }
], function(d) { return d.id; });

TypeError: Cannot call method 'bind' of undefined

I'm attempting to build a simple line chart based on some of the D3 gallery examples. Basically it consists of a few steps:

  1. Standard setup, append the SVG element, etc.
  2. Set up 2 scales, x & y and set their domains and ranges
  3. Create a d3.svg.line(), with x & y set to return values from the data array, passed through the x and y scales set up in 2, above
  4. Create a path element, and set the d attribute to the line created in 3

I'm having trouble mapping steps 3-4 into a d3.chart layer (1-2 get done in initialize). Since for a line chart you only have one path element for the entire dataset, using insert and the enter event don't really make sense, but d3.chart throws errors if they are not there (from this line)

Is there a better way you can recommend doing a line chart, or if not, make layers work when no insert method is needed?

Removing layers

Should we have a way to remove a layer after it has been rendered?

Hybrid chart example is leaking

Each time new data is passed to the "Hybrid" chart example, it needlessly creates a new set of ticks. Besides visibly degrading the chart's antialiasing, this results in a crazy huge amount of markup and quickly eats up memory.

At first glance, I think it's because the underlying Chord diagram uses a d3,layout, so each call to draw looks like a new data set. Not so sure about this, though--need to look into it further.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.