I'm trying to make a particular bar chart with D3.js, and I don't find any example who could match. I would code a bar chart with two series (one negative, and one generally positive) disposed on the same line, but not stacked.
I guess that maybe it's not very clear, so I've made this on Highcharts. I want to use D3 to connect the chart with a map I did before.
So, does someone know any example that could help me? Can I sort directly the chart even if my series are unordered? And if the two series are punctually postive, does the little one appear in front of the largest?
The trick is to order your data, in order to do so, you can use the [d3.ascending()][1] functions:
with the following example data:
data = [{
name: "A",
valueRight: 1,
valueLeft: 2
}, {
name: "B",
valueRight: 4,
valueLeft: 5
}, ...]
We would have:
function leftBound(node) {
return d3.max([node.valueLeft,-node.valueRight])
}
function rightBound(node) {
return d3.max([node.valueRight,-node.valueLeft])
}
dataSort = function(a,b) {
res = d3.descending(leftBound(a),leftBound(b))
if(res==0) {
return d3.descending(rightBound(a),rightBound(b))
} else {
return res
}
}
For reusable charts, you can also use [selection.sort()][2] but you have to do this for the 2 bar categories.
JsFiddle: http://jsfiddle.net/vgZ6E/55/
ScreenShot:
The original code is from the following question: d3.js bar chart with pos & neg bars (win/loss) for each record
Related
I have a set of interconnected charts with Highcharts and callback functions. Specifically, put together a scatter plot with an x-axis range selection, which connects to a bar chart that reflects the average y-value of the points selected, by category.
It uses the 'events' key when creating the chart to call a function that edits and redraws the bar chart.
Please click on this sandbox link to see the example that I have put together: https://codesandbox.io/s/youthful-browser-mid8x?file=/index.html
I would like to know if the code can be written any better with improvements. If anyone can please review and let me know. Thanks.
You don't need to call redraw after setData:
function update_chart2(xmin, xmax) {
...
chart2.series[0].setData(new_data);
// chart2.redraw(); - redraw is called in setData
}
You can update xAxis with plot-band options instead of removing and adding it.
events: {
selection: function (event) {
...
if (event.xAxis) {
xmin = event.xAxis[0].min;
xmax = event.xAxis[0].max;
this.xAxis[0].update(
{
plotBands: [
{
from: xmin,
to: xmax
}
]
},
false
);
}
update_chart2(Math.floor(xmin) + 1, Math.floor(xmax) + 1);
},
...
}
API Reference:
https://api.highcharts.com/class-reference/Highcharts.Series#setData
https://api.highcharts.com/class-reference/Highcharts.Axis#update
I am using the Highcharts synchronized charts to display three different variables. However, in order to render cleaner graphs, I'd like to display the x-axis (which is the same for all three graphs) only for the bottom graph.
For that, I presume, I need to cycle at the end of the generation process through the charts and suppress the first two x-axis, kind like
for (i = 0; i < (Highcharts.charts.length - 1); i = i + 1)
{
chart = Highcharts.charts[i];
chart.xAxis.labels.enabled = false;
}
Here is the default fiddle.
I don't succeed in getting this to work. Can anyone help me out on this?
You can set the xAxis.visible property depending on the chart index:
success: function (activity) {
activity = JSON.parse(activity);
activity.datasets.forEach(function (dataset, i) {
...
Highcharts.chart(chartDiv, {
xAxis: {
visible: i === 2,
...
},
...
});
});
}
Live demo: https://jsfiddle.net/BlackLabel/cmdb5at0/
API Reference: https://api.highcharts.com/highcharts/xAxis.visible
This is in continued to my question here
I was having a lot of problems in creating highcharts basic charts using CSV data from my local filesystem without using a server/framework and just basic HTML/CSS/JS etc
So, finally, I got an idea to create a chart inside "d3.csv" function wherein we can add highchart functions insdie d3.csv ones
But, there seems to be something very silly wrong, I'm trying with a very basic code and table.
HTML code has only container div element,
Javascript
d3.csv("test.csv", function(data) {
data.forEach(function(d) {
name = d.name,
apples = +d.apples
});
console.log(data[2]);
dataset = data;
//display();
console.log(dataset[0]);
console.log(dataset[0].name);
function push(a)
{
var filter = [];
for (i=0; i<a.length ; i++)
{
filter.push(a[i].apples);
//console.log (filter);
}
return filter;
}
window.apples = push(dataset);
console.log(apples);
$(function () {
$('#container').highcharts({
chart: {
type : 'bar'
},
title: {
text: 'Fruit Consumption'
},
xAxis: {
categories: [dataset[0].name, dataset[1].name]
},
yAxis: {
title: {
text: 'Fruit eaten'
}
},
series: [{
data: apples
}
]
});
})
});
test.csv :
name,apples
John,8
Jane,3
My console is showing "apples" correctly as [8,3]. I'm getting an empty graph on screen with only axes shown and nothing inside and also, x axis and y axis elements are interchanged.
What am I doing wrong here? Is the global variable - apples, not being accessed inside highcharts fucntions?
UPDATE :
Found the answer, but only one number is showing up.
I have 2 more questions :
How do I show the whole series?
Is this a good method to draw highcharts or will I face many issues later?
Found the solution to this, myself, for a change.
Highcharts will expect function to be parsed in their format ( Highcharts error 14 in console)
Changed my function above to this,
for (i=0; i<a.length ; i++)
{
x = a[i].apples;
y = parseFloat(x)
filter.push(y);
}
return filter;
}
window.apples = push(dataset);
And the series part to this :
series: [{
data : [apples]
}
]
This is finally, giving me a graph with one bar (John, 8) now!!
The second number is still not being loaded, if someone wants to help with that, please comment below.
Update :
changed
data : [apples] -> data: apples (Correct format)
Credits : PawelFus
I am making a diagram that should show states in a timeline like diagram. I figured that the best fit for it would be horizontal bar diagram, I added data like this:
series: [{
data: [?],
name: 'state1'
}, {
data: [?],
name: 'state2'
}, {
data: [?],
name: 'state3'
}, {
data: [?],
name: 'state1'
}, {
....
}, {
data: [?],
name: 'state1'
}]
Here's what I'v got:
The chart looks like what I need, but I need to somehow group legends, for example this case there should be only 3 legends: state1, state2, state3.
How can I achieve something like this?
I would suggest a different approach, using the column range series type.
This way you can do this with only three series, with a data point for each time slot, rather than a series for each time slot. This saves from having to manipulate the legend or fake other series level actions.
This is an example I did for an earlier question that demonstrates the method (with only two states):
http://jsfiddle.net/jlbriggs/o9ck2zLn/0/
can easily be adapted to use a datetime axis as well, which it seems you might be going for.
Basing on the answer of #StAlex, I would recommend a similar solution, but without the ECMAScript 5 specific forEach:
var legend = {};
for (var i = 0; i < series.length; i++) {
var bar = series[i];
if (!legend[bar.name]) {
legend[bar.name] = 0;
}
legend[bar.name] += bar.data;
}
I assumed that data is a number. If this is not so, add a comment.
var legends = {};
series.forEach(function(bar){
legends[bar.name] = bar.data;
});
[
...
{
"RowID":85,
"Name":"Billy",
"B":2,
"S":2,
"S2":1,
"M":0,
"T":"0",
"H":1,
"S":0,
"W":1,
"N":2,
"Malty":1,
"Fruity":0,
"Floral":0
}
...
]
I need to create a bar chart. Just a regular bar chart.
There are a total of 86 JSON pieces of data (that is, you'll find 86 RowIDs). I only need to pick 5-10 that I want to work with. The x-axis are the "B", "S" ... "Floral" from the JSON. It does NOT include RowID or Name. So there should be "clumps" of 5 bars (colored corresponding to "Name") for each "B", ... "Floral" piece of data. The end goal is to make it easy for the user to visually compare 5 objects (distinguished by Name attribute) according to their attributes.
I've been working at least 24 hours on this problem. And I'm not making any progress. I've looked at tutorials and other posts on StackOverflow. I can't get any of them to work.
Anyone?
And no, this question does not have an answer somewhere else.
A fiddle: http://jsfiddle.net/zdy6d/3/
What you want to do is a grouped bar chart. The main thing you need to do is create 2 x-scales: one that gives the position of each group, or clump as you call it, in the screen and the other one that gives the position of each series (name in this case) inside the group.
// Where to position each clump inside svg chart
var x0 = d3.scale.ordinal();
x0.domain(d3.keys(data[0]).filter(function(key) { return key !== 'RowID' && key !== 'Name'; }));
x0.rangeRoundBands([0, width], 0.1);
// Where to position each name bar inside the clump
var x1 = d3.scale.ordinal();
x1.domain(data.map(function(d) { return d.Name; } ));
x1.rangeRoundBands([0, x0.rangeBand()]);
You then have to filter the data and maybe change its structure to a more convenient format (e.g. [{groupname: 'B', data: [{name: 'Bobby', value: 3}, {name: 'Tom', value: 5}, ... ]}, ...] should be similar to the one the example I linked uses)
Minimal working JSFiddle with example of data manipulation and rect creation: http://jsfiddle.net/LeartS/23huy/2/