Combine two line charts into one in ChartJS - javascript

What I have
I've created 2 graphs like shown in the first image below. I need these 2 graphs to be perfectly aligned on the 0 axis (which is shown in the section below).
Wanted result
In the image below, the graphs are perfectly aligned and should therefore contain 2 different datasets. One should be placed on the left grid and the other one on the right grid.
The options I thought of
I have not seen a way to implement this in ChartJS. Therefore, I thought of some possible solutions that could solve this issue in a different way.
Because both datasets don't have negative values, I could convert the left dataset to negative values (on the x-axis). The downside is that the range would be incorrect. Also, this would give issues with the popup message if you hover your mouse on a value.
Maybe, two canvas objects can be combined that could result in the wanted result
Question
Is there a way to achieve the wanted result within ChartJS? Or can I perform some wizardry to combine two charts nicely into one? Or should I move to the D3.js library for this particular graph?

I did not find a way to "nicely" implement this. I've changed the source code of the ChartJS library to implement this.
This method uses 2 different graphs that render in 2 different canvas objects. These canvas objects are placed side-by-side to let it look like one graph.
This is my result (The code in here is not exactly like the graph in the picture because I changed it to my specific needs).
I've added a custom variable in the options.layout category named sidePadding.
The code of creating the graph:
new Chart(document.getElementById(this.element), {
type: 'scatter',
data: {
datasets: [{
borderColor: this.lineColor,
borderWidth: 1,
pointBackgroundColor: '#000',
pointBorderColor: '#000',
pointRadius: 0,
fill: false,
tension: 0,
showLine: true,
data: [],
}],
},
options: {
aspectRatio: 0.3,
maintainAspectRatio: false,
responsive: true,
layout: {
sidePadding: {
left: 3,
right: -3,
}
}
}
});
The padding on the sides is by default 3 so it does not touch the border of the canvas. I wanted it to touch the border of the canvas, and therefore set it to -3.
Two different graphs need to be created, one for the left side and one for the right side.
The left graph should have the sidePadding.right set to -3. The right graph should have the sidePadding.left set to -3.
Changes in the ChartJS library
I've worked with ChartJS version v2.9.3. This method will possibly not work anymore in a new version.
I've changed the following in the Chart.js file:
Replace (line number around 11800):
// Adjust padding taking into account changes in offsets
// and add 3 px to move away from canvas edges
me.paddingLeft = Math.max((paddingLeft - offsetLeft) * me.width / (me.width - offsetLeft), 0) + 3;
me.paddingRight = Math.max((paddingRight - offsetRight) * me.width / (me.width - offsetRight), 0) + 3;
to:
// Adjust padding taking into account changes in offsets
// and add 3 px to move away from canvas edges
var layoutOptions = chart.options.layout || {};
var sidePadding = helpers$1.options.toPadding(layoutOptions.sidePadding);
me.paddingLeft = Math.max((paddingLeft - offsetLeft) * me.width / (me.width - offsetLeft), 0) + sidePadding.left;
me.paddingRight = Math.max((paddingRight - offsetRight) * me.width / (me.width - offsetRight), 0) + sidePadding.right;
Also you must add the sidePadding.left and sidePadding.right parameter to ChartJS.
This can be done by changing (line number around 7180):
core_defaults._set('global', {
layout: {
padding: {
top: 0,
right: 0,
bottom: 0,
left: 0
},
// Custom added parameter
sidePadding: {
left: 3,
right: 3,
}
}
});
to:
core_defaults._set('global', {
layout: {
padding: {
top: 0,
right: 0,
bottom: 0,
left: 0
},
// Custom added parameter
sidePadding: {
left: 3,
right: 3,
}
}
});
Note
This is probably not the best way to achieve this. Changing the ChartJS library is bad-practice and updating the library could revert these changes.
If someone has a better way to achieve this, please post your methods or comment below.

Related

Where do chart.js positioners go for tooltips to move downward

I am wanting to move the tooltip downwards a few pixels instead of always at the top of each stack (on stacked bar chart).
I found this in the docs about positioners, but I cannot understand the structure of code and where it should actually go.
Chart.Tooltip.positioners.custom = function(elements, eventPosition) {
var tooltip = this;
return {
x: 0,
y: -50
};
}
For reference, you can see where I've tried to place it here ( not much wonder why its not working )
Config seems to have a position and yPadding, neither of which seem to have effect I want when I put them in the tooltips options:
tooltips: {
yAlign: 'top',
position: 'nearest',
yPadding: 50
}
yPadding distorts the tooltip, I'm not sure why but it muddles up the caret and box.

Set ECG paper-like grid intervals (highcharts.js)

I need to show an ECG result with highcharts which is basically a simple line/spline diagram but with a little tweak. The ECG paper looks like this: https://cdn.printablepaper.net/samples/ECG_Paper.png
And this is what I want to achieve with hightcharts too. One little square means 0.1 mV and 0.04 s, so one big square is 0.5 mV and 0.2 s. I know there is a tickInterval setting, but that just does not work in this scenario, I think the intervals are too small for it, because it randomly hides grid lines.
The optimal solution would be that if there is a need for hiding grid lines (too broad data), it only hides the small squares. To try not to confuse the users with this, we also would like to colorize grid lines differently, so every fifth line should be red, others gray.
Is this possible with highcharts?
minorTicks functionality seems to be ideal for this case. Use this option along with minorTickInterval. Configuration for both axes will look like this:
var axesOptions = {
tickInterval: 0.5,
minorTicks: true,
minorTickInterval: 0.1,
gridLineWidth: 1,
gridLineColor: 'red'
};
Live demo: http://jsfiddle.net/kkulig/6dbnmyxf/
If minor ticks are not visible on any axis this code will hide them on all axes (and restore them when needed):
chart: {
events: {
render: function() {
var axes = this.axes,
showMinorTicks = true;
// find if minor ticks are present on both axes
axes.forEach(function(a) {
console.log(a.minorTicks);
if (Object.keys(a.minorTicks).length === 0) {
showMinorTicks = false;
}
});
// hide/show ticks
axes.forEach(function(a) {
for (var key in a.minorTicks) {
var mt = a.minorTicks[key].gridLine;
showMinorTicks ? mt.show() : mt.hide();
}
});
}
}
},
API references:
https://api.highcharts.com/highcharts/xAxis.minorTickInterval
https://api.highcharts.com/highcharts/xAxis.minorTicks

How to disable Stacking on an individual series using Primefaces jQplot implementation

I am using Primefaces 6 for my companys charting needs, which relies on jQplot.
For a project, I am trying to overlay a line chart on a stacked bar chart with negative values, to obtain something like this:
The problem is that when I try to add a linechartseries to the same model as the two barchartseries , the linechart becomes a part of the stack when setting setStacked(true); on the model, because Primefaces seems to not allow individual disabling of stacking on series, only per model. So I end up with this when rendering the chart with
<p:chart type="bar" model="#{backingBean.cartesianChartModel}"/>
After some investigation I have notoced that jQplot is capable of disabling Stacking on individual series by passing disableStack : true in the JS options, so the question is if it's posssible to override this in some way on the rendered page,either via PF or via some JS hack? I feel that using the extender only apples to the entire model?
Related issues: Disable individual stacking
By pouring through the documentation I found a solution to the problem, if not the question:
It seems that Primefaces allows for individual series to be excempt from the stack in the series creation in this version, by passing
LineChartSeries.setDisableStack(true);
Simple as that.
I guess it may be possible. I used the extender functionality for some jqPlot hacks in the past.
In my case, for example, I had a Donut Chart defined with an extender function as follows:
private void createDonutModel() {
donutModel = new DonutChartModel();
donutModel.setLegendPosition("s");
donutModel.setLegendPlacement(LegendPlacement.OUTSIDE);
donutModel.setSliceMargin(4);
donutModel.setDataFormat("value");
donutModel.setShadow(false);
donutModel.setExtender("donutExtender");
donutModel.setSeriesColors("B81C40, FFA600, 79B54A");
}
The corresponding javascript was doing some changes to the jqPlot:
/**
* Customized jqPlot JQuery layout of the Donut Chart for Status Dashboard.
*/
function donutExtender() {
this.cfg.seriesDefaults = {
// make this a donut chart.
renderer:$.jqplot.DonutRenderer,
rendererOptions:{
thickness: 26,
ringMargin: 0,
fill: true,
padding: 0,
sliceMargin: 4,
// Pies and donuts can start at any arbitrary angle.
startAngle: -90,
showDataLabels: false,
// By default, data labels show the percentage of the donut/pie.
// You can show the data 'value' or data 'label' instead, or 'percent'
dataLabels: 'value',
shadow: false
}
}
this.cfg.gridPadding = {
top: 0, right: 0, bottom: 0, left: 0
}
this.cfg.legend = {
show: false
}
this.cfg.grid = { drawBorder: false,
shadow: false,
background: "transparent"
};
}
So you may try something like this in your case ?
Leave the extension configuration of your series empty, except for the one you are interested in...
function chartExtender() {
this.cfg.series = [
{ //...
},
{ // ...
},
{
disableStack: true
}
]
}
Worth having a shot ...

Data graph labels cut off on c3.js chart

I'm graphing some lines on a c3.js line chart, but the data label of the leftmost point is being cut off:
I've tried adding padding to the chart, but this just adds padding to the overall chart. What I need is some way to add some sort of padding to just the bar graph ticks.
Something that I've considered:
I've considered using the "transform" property:
.c3-texts .c3-text text {
transform: translate(10px, 0);
}
But moving the position of all the data labels to the right would end up causing the data labels on the right-hand side of the graph to get cut off.
Here's a simple example of labels getting cut off:
fiddle
var chart = c3.generate({
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250]
],
labels: {
format: function(x){
return "Test Label"
}
}
}
});
Any help would be appreciated. Thanks!
#ksav pointed me in the right direction. I remember trying this before, but foolishly, I didn't think of putting decimal numbers. I had tried putting in the value 1, and it gave way too much padding, but doing the following worked perfectly:
axis: {
x: {
padding: {
left: 0,
right: 0,
}
}
}

Issues with dojox.charting and xDomain reference to dojo/dojox library

I have a web HTML page with some client-side JS codes based on dojox.charting. I don't have dojo library in my local web site (actually no web server). I use dojos' xDomain reference feature with src to google's hosting site like this:
<head>
...
<script type="text/javascript"
djConfig1="isDebug:true"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojo/dojo.xd.js">
</script>
<script type="text/javascript"
dojo.require("dojox.gfx");
dojo.require("dojox.gfx.move");
dojo.require("dojo.html");
dojo.require("dojox.charting.Chart2D");
dojo.require("dojox.charting.themes.PlotKit.green");
dojo.require("dojox.charting.action2d.Highlight");
dojo.require("dojox.charting.action2d.Magnify");
dojo.require("dojox.charting.action2d.MoveSlice");
dojo.require("dojox.charting.action2d.Shake");
dojo.require("dojox.charting.action2d.Tooltip");
dojo.require("dojox.charting.themes.MiamiNice");
dojo.require("dojox.charting.widget.Legend");
</script>
....
</head>
Here is the function to create curve chart, based on the codes in Dojo: Now With Drawing Tools.
function drawCurve(nodeChart, nodeLegend) {
var chart1 = new dc.Chart2D(nodeChart)
.setTheme(dc.themes.PlotKit.green)
.addPlot("default", {
type: "Default",
lines: true,
markers: true,
tension: 2
})
.addAxis("x", {
min: 0,
max: 6,
majorTick: { stroke: "black", length: 3 },
minorTick: { stroke: "gray", length: 3 }
})
.addAxis("y", {
vertical: true,
min: 0,
max: 10,
fixLower: "major",
fixUpper: "major",
majorTick: { stroke: "black", length: 3 },
minorTick: { stroke: "gray", length: 3 }
})
.addSeries("Series A", [
{ x: 0.5, y: 5 },
{ x: 1.5, y: 1.5 },
{ x: 2, y: 9 },
{ x: 5, y: 0.3 }
])
.addSeries("Series B", [
{ x: 0.3, y: 8 },
{ x: 4, y: 6, tooltip: "Custom tooltip"},
{ x: 5.5, y: 2 }
]);
var series = chart1.series;
var anim_a = new dc.action2d.Tooltip(chart1, "default");
var anim_c = new dc.action2d.Magnify(chart1, "default"); // not working
chart1.render();
var legendChart = new dc.widget.Legend(
{chart: chart1, horizontal: false}, nodeLegend.id);
}
My first question is that for the curve chart, the numbers along the y axis only displays 0 and 10. All the middle numbers 1 to 9 are not displayed. The values for x axis from 1 to 6 are visible. The original chart snapshot in the article does show y axis values as well, but the one on DojoToolKit Demos does show values along y axis. I am not sure what I missed in my codes. How can I enable displaying y axis values?
The next question is about the Magnify(). The DojoToolKit demo site's curve chart works fine but my chart's magnify feature does not work. I think this may be caused by xDomain reference. I may need to specify some specified js file from xDomain's dojox library. I am not sure which one I have to specify.
One thing I noticed is that my FireBug displays following errors after curve chart is drawn:
_4.fx.combine is not a function http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojox/charting/action2d/Magnify.xd.js Line 8
_11.action is undefined http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojox/charting/action2d/Magnify.xd.js Line 8
I think those undefined errors may indicate I miss loading some dojox library files in my head section.
By the way, I dont' have a web server and I prefer to use dojo's xDomain reference option. In this way, I can edit a html file in any place and send it to other people. No need to download and install dojo source library.
I think I got the missing part:
dojo.require("dojo.fx");
When I added this line to my HTML's head setction see above, the animation part set by Mangify() is working. This is only for the case you set xDomain reference to dojox for dojox.charting library.
What I found this is by using Firebug to look at DojoToolKit's Event 2D web page. In the head section there is code:
<script src="http://../action2/Magnify.js" type="text/javascript"></script>
That page has debug enabled. As a result, in FireBug window, you will see the source codes of js in a nice layout. I saw three requirements, and one is for "dojo.fx". I tried to add this one in. Then no more errors and I can see animation of magnify effect when I move mouse over points in the curve of the chart.
One thing interesting about <script src=".."> is that if the js is xDomain referenced, the js source codes are displayed partially in one long long time. If you hav the dojo library installed on your web page, ie same domain, the dojo's source codes are displayed nicely.
Regarding the y axis values, I also find out easy way to display them (0 to 9):
.addAxis("y", {
vertical: true,
//min: 0
//max: 10
....
You can also comment out min only and leave max with 10 (0, 1, ... to 10). See DojoCampus.org for more detail information about axis settings.

Categories