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

[FEATURE] Histograms #3900

Open
mrjv opened this issue Feb 12, 2017 · 25 comments
Open

[FEATURE] Histograms #3900

mrjv opened this issue Feb 12, 2017 · 25 comments

Comments

@mrjv
Copy link

mrjv commented Feb 12, 2017

A nice feature would be to support histogram charts, or alternatively, update the bar chart so that a histogram can be manually created given the right data. At the moment it seems like a bar chart only can represent value-category pairs, while a histogram would require the bars to be drawn at the right positions on a numerical/linear axis.

@etimberg
Copy link
Member

You're correct about the current limitations of the bar graph. If you pre-process your data into bins then you can easily create the histogram using the current bar chart.

Some thoughts on bar sizing in this case:

  1. Bars have a fixed width and gaps may appear between the bars
  2. Bars width is determined by the distance between bars and calculated so that bars touch

I think option 2 is better here since it produces a better result

In terms of data processing, I think this would be best as a new chart type that extends from the bar chart. The calculateBarX and calculateBarWidth methods would need to be overridden
https://github.com/chartjs/Chart.js/blob/master/src/controllers/controller.bar.js#L196
https://github.com/chartjs/Chart.js/blob/master/src/controllers/controller.bar.js#L165

@mrjv
Copy link
Author

mrjv commented Feb 22, 2017

Thanks for the tips! I will try that out.

@xnakos
Copy link

xnakos commented May 3, 2017

As long as one can get away with:

  1. bins of equal width, e.g., [0, 2), [2, 4), [4, 6), [6, 8], in contrast to bins of variable width,
  2. labels under bars that denote the bar's range, e.g., "[0, 2)", "[2, 4)", "[4, 6)", "[6, 8]", or "0-2", "2-4", "4-6", "6-8", in contrast to having a numerical axis (whose ticks may or may not align with the bars' vertical sides),
  3. manually calculating each bar's height, that is counting the value for each bin,

then the current bar chart may be used, just making sure that:

barPercentage : 1.0,
categoryPercentage : 1.0,

are used as axis options, so that the bars touch. I have used the bar chart this way myself where a histogram was needed and it was nice.

But if the histogram was to be fully supported, then points (1) and (2) should be dealt with, as shown in:

I am not sure about point (3). I think that this cannot and should not be avoided. If thousands of values fell into one bin, should the chart "know" all those values? I guess not. I many cases the dev would not "know" all those values either.

So, one way or another, one should define something like the following as data for the histogram:

[
  [0, 2, 15],
  [2, 4, 29],
  [4, 6, 32],
  [6, 8, 15],
]

or (irregular histogram):

[
  [0, 1, 15],
  [1, 4, 29],
  [4, 7, 32],
  [7, 8, 15],
]

I am not familiar with the source code, so feedback is needed. My question is this: Is extending the bar chart the way to go? Because the numerical axis is definitely needed.

EDIT:

Scatter chart builds on line chart, but uses a numerical scale as well as a different data representation. Following this approach, maybe histogram could build on bar chart and a representation such as the following could be used (here width is added as a parameter, another option would be to have xLeft and xRight - this depends on library conventions):

data: [
  {
    x: 0,
    width: 1,
    y: 15,
  }, {
    x: 1,
    width: 3,
    y: 29,
  }, {
    x: 4,
    width: 3,
    y: 32,
  },
  {
    x: 7,
    width: 1,
    y: 15,
  },
]

@szaydel
Copy link

szaydel commented Jul 8, 2017

I feel like extending the bar graph is the way to go. Bins should be equal-sized, at least as the first cut. You can easily fit data into buckets by doing something along these lines with integer values, assuming a bucket size is 10.

In [20]: [(i/10)*10 for i in [1023, 1025, 1021, 1033, 1039, 1037, 1033]]
Out[20]: [1020, 1020, 1020, 1030, 1030, 1030, 1030]

This is simple enough to implement to group values into containers. The only tricky part is determining proper number of bins. Some people prefer fairly blocky histograms, some like the more hairy ones, where bins are smaller and you get more of them. Ideally one should be able to pick a number of bins to display, but you could probably make this value fixed for first, just to see how it works out with a bar graph. You could say stick with 30 to 50 graphs and then divide the range of data by that number to get a rough size of each bucket, perhaps.

I wish I had more free time to help with this, but have been slammed as of late. I am happy to test and offer constructive feedback. :)

@ldemailly
Copy link

ldemailly commented Nov 8, 2017

I'm trying to plot histograms but I have variable bins sizes (semi log) so I'd really like the option to set a [start, end[ for each bar - and overlay some cumulative % at the mid point

For now I'm trying to do this by hand using scatter but being completely new to chartjs I still haven't found how to draw lines between points (X,Y line graph instead of X,Y scatter point graph) - hint/pointer for that would be welcome

Edit: found that I can just use "line" as the mode and style have X,Y in the data - when also using type: 'linear' xAxes

@spitzbubchen
Copy link

spitzbubchen commented Feb 7, 2018

Here is a jsfiddle that I cobbled together over lunch using a bar chart to make a histogram. Just a rough draft to help people get started.

https://jsfiddle.net/s8qas3km/17/

@ldemailly
Copy link

if you want to see you can see fortio's line based implementation on
https://istio.fortio.org/

source code: https://github.com/istio/fortio/blob/master/ui/static/js/fortio_chart.js

@rupsaijna
Copy link

Any way to position the xAxis labels to align 'with' the gridlines instead of below the bar? So as to give more of that "bucket" feel...

@baus
Copy link

baus commented May 16, 2018

I'm using bar charts with fair results to plot histograms. I would like to see a feature to label edges rather than bars, and may look into implementing. I've implemented an NPM module to calculate the bin sizes here: https://www.npmjs.com/package/compute-histogram.

Here's an example of it in use: https://yield.io

@etimberg
Copy link
Member

Testing this in v2.9,3, setting gridLines.offsetGridLines to false on the x axis gets a bit closer

v2.1.3 https://jsfiddle.net/z136gkL4/
v2.9.3 https://jsfiddle.net/3ehp4L58/1/
v3.0.0-alpha https://jsfiddle.net/8cothjzs/

@benmccann @kurkle one thought on how we could support this:

  • Keep offsetGridLines for the bar location in it's current form
  • Introduce a new option (name TBD) for controlling the tick label alignment. Values: 'start' and 'center'. We'd default to 'center' for bar charts and this would put mimic the current v2 behaviour. If the user overrides to 'start' we place it on the grid line.

@benmccann
Copy link
Contributor

If I do a Google images search for histogram none of the results have vertical gridlines. I think I'd just turn off the gridlines in the fiddle and call it a day 😄

@bnisevic
Copy link

Any progress on this issue?

@etimberg
Copy link
Member

@bnisevic no specific progress has been made, but if I use chart.js v3.0.0-beta.13 I can make a very nice histogram. I started with https://en.wikipedia.org/wiki/Histogram#/media/File:Histogram_of_arrivals_per_minute.svg from the wikipedia article on histograms.

What I made was https://jsfiddle.net/swg4y1at/ which i think is very close

@leeoniya
Copy link

leeoniya commented Mar 15, 2021

that wikipedia image is terrible - the colors literally mean nothing in that chart, not even correlated to the bar height. the only time that's appropriate is when the x axis represents the visible color spectrum and the bars are colored by the portion of the spectrum they represent, while the labels are in nanometers of wavelength 🌈

the key parts are (vs a bar chart):

  • continuous x range instead of category
  • tightly packed, since x dimension now has semantic meaning (no gaps between bars)
  • tick marks usually at the bar boundaries (usually leading edge)

most are pretty good: https://www.google.com/search?q=histogram&source=lnms&tbm=isch&biw=2560&bih=1299

https://www.mathsisfun.com/data/histograms.html

@etimberg
Copy link
Member

Agreed @leeoniya that it's not the best example. Getting the tight packing and ticks well align required 4 key settings:

  • barPercentage: 1
  • categoryPercentage: 1
  • X scale offset: false
  • X scale gridLines.offsetGridLines: false

The first two direct the bars to take all available width, eliminating the spacing between. The last two put the ticks back on the grid lines.

I think the other keys were the linear X axis and computing the X locations to be in the center of the bucket range. I don't think Chart.js should be doing all of that itself, but writing a custom chart type plugin would be very easy. It'd need some defaults and maybe something to preprocess the data into buckets.

@bnisevic
Copy link

Thanks guys for the explanation! I am starting to understand what is purpose of these 4 key settings when it comes to a histogram.
But, how I can achieve different bar width based on given data as ranges? For example, if I have [1, 2, 3, 5, 8, 13, 21, ...] on the x axis and I want to plot one bar from 1 to 2, then next bar is from 2 to 3, the next one is from to 3 to 5, the next one 5 to 8 and so on. On the y axis I also have custom values which determine height of each bar.

thdadsa

@etimberg
Copy link
Member

The variable width bars might be possible using the scriptable options added in v3.0.0-beta.12. You'd have to supply. a function for the barThickness prop and use that to compute the width based on the X scale values.

@vaasu070
Copy link

I am using version 2.9.3. I cannot downgrade or upgrade this.
Here is example using 2.9.3 https://codepen.io/vaasu070/pen/bGgKdML?editors=1111

is it not possible to align ticks with labels using plugins or something? Help me out on this, it is crucial for our project

@mortalapeman
Copy link

mortalapeman commented May 17, 2021

I got some bad news for you @vaasu070. I was trying to do something similar using 2.9.3 as you can see in this SO post. I ended up having to upgrade to ChartJS 3 and I was able to accomplish my goal using a combination of the suggestions here.

Link to JSFiddle

The final key was setting the axis max of each non visible axis to the length of the data array minus 1.

@EwoutH
Copy link

EwoutH commented Dec 1, 2021

Thanks for the examples @etimberg and @mortalapeman!

I think a native histogram feature would be a great addition to Chart.js.

@aentwist
Copy link

Does a histogram feature have to be native (long term, it should be), or can it somehow simply wrap a bar chart implementation?

@stephanebouget
Copy link

The variable width bars might be possible using the scriptable options added in v3.0.0-beta.12. You'd have to supply. a function for the barThickness prop and use that to compute the width based on the X scale values.

Hello @etimberg , how do you make that ?
barThickness is a setting of a dataset, so if i set a callback to this, for instance like that :

 barThickness: (e) => {
     return randomIntFromInterval(1, 100);
 }

=> the callback is just called once so all bars will take the same width,
is not it ?

@EwoutH
Copy link

EwoutH commented Oct 19, 2022

Does a histogram feature have to be native (long term, it should be), or can it somehow simply wrap a bar chart implementation?

Yeah I might have worded that badly: I meant an user-exposed histogram feature, it could be both native, a wrap of the bar chart or even something else.

For an user, it's just way nicer than having to modify a bar plot to look like a histogram.

@stephanebouget
Copy link

For those who are interested, i made a quick fork based on 3.9 branch to manage dynamic width :
https://github.com/stephanebouget/Chart.js/tree/3.9

For example :

image

Live demo

https://codepen.io/stephanebouget/pen/PoerxPP

@uglow
Copy link

uglow commented Nov 7, 2022

@stephanebouget & ChartJS contributors, would you accept a PR for this feature if someone put it together?

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

No branches or pull requests