Chartjs export chart without html - node.js

I'm trying to export a chart created with chartjs without an actual site it's just a node backend app that creates the chart, I then need to export it and send it to slack api.
I figured I would try to create a virtual dom and then export from there but is it not working. I'm open to other approaches or fixes to this code. I'm getting an error that says window is undefined, but if I console.log(window) it says it's a window object, and everything looks normal.
const JSDOM = require("jsdom");
const Chart = require("chart.js");
const dom = new JSDOM.JSDOM(`<!DOCTYPE html><canvas id="myChart" width="400" height="400"></canvas>`);
const canvas = dom.window.document.getElementById('myChart');
const ctx = canvas.getContext('2d');
const chart = new Chart(ctx, {
type: 'line',
data: {
labels: ['Standing costs', 'Running costs'],
datasets: [{
label: 'Washing and cleaning',
data: [0, 8],
backgroundColor: '#22aa99'
}, {
label: 'Traffic tickets',
data: [0, 2],
backgroundColor: '#994499'
}, {
label: 'Tolls',
data: [0, 1],
backgroundColor: '#316395'
}, {
label: 'Parking',
data: [5, 2],
backgroundColor: '#b82e2e'
}, {
label: 'Car tax',
data: [0, 1],
backgroundColor: '#66aa00'
}, {
label: 'Repairs and improvements',
data: [0, 2],
backgroundColor: '#dd4477'
}, {
label: 'Maintenance',
data: [6, 1],
backgroundColor: '#0099c6'
}, {
label: 'Inspection',
data: [0, 2],
backgroundColor: '#990099'
}, {
label: 'Loan interest',
data: [0, 3],
backgroundColor: '#109618'
}, {
label: 'Depreciation of the vehicle',
data: [0, 2],
backgroundColor: '#109618'
}, {
label: 'Fuel',
data: [0, 1],
backgroundColor: '#dc3912'
}, {
label: 'Insurance and Breakdown cover',
data: [4, 0],
backgroundColor: '#3366cc'
}]
},
options: {
onAnimationComplete: animationDone,
responsive: false,
legend: {
position: 'right'
},
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: true
}]
}
}
});
function animationDone() {
return canvas.toDataUrl("image/jpg");
}
I just want an image file or url that I can send to slack api.

Use chartjs-node-canvas, this is a Node JS renderer for Chart.js using canvas.
It provides and alternative to chartjs-node that does not require jsdom (or the global variables that this requires) and allows chartJS as a peer dependency, so you can manage its version yourself.
This is how it will work with your code:
const { CanvasRenderService } = require('chartjs-node-canvas');
const width = 400;
const height = 400;
const chartCallback = (ChartJS) => {
// Global config example: https://www.chartjs.org/docs/latest/configuration/
ChartJS.defaults.global.elements.rectangle.borderWidth = 2;
// Global plugin example: https://www.chartjs.org/docs/latest/developers/plugins.html
ChartJS.plugins.register({
// plugin implementation
});
// New chart type example: https://www.chartjs.org/docs/latest/developers/charts.html
ChartJS.controllers.MyType = ChartJS.DatasetController.extend({
// chart implementation
});
};
const canvasRenderService = new CanvasRenderService(width, height, chartCallback);
(async () => {
const configuration = {
type: 'line',
data: {
labels: ['Standing costs', 'Running costs'],
datasets: [{
label: 'Washing and cleaning',
data: [0, 8],
backgroundColor: '#22aa99'
}, {
label: 'Traffic tickets',
data: [0, 2],
backgroundColor: '#994499'
}, {
label: 'Tolls',
data: [0, 1],
backgroundColor: '#316395'
}, {
label: 'Parking',
data: [5, 2],
backgroundColor: '#b82e2e'
}, {
label: 'Car tax',
data: [0, 1],
backgroundColor: '#66aa00'
}, {
label: 'Repairs and improvements',
data: [0, 2],
backgroundColor: '#dd4477'
}, {
label: 'Maintenance',
data: [6, 1],
backgroundColor: '#0099c6'
}, {
label: 'Inspection',
data: [0, 2],
backgroundColor: '#990099'
}, {
label: 'Loan interest',
data: [0, 3],
backgroundColor: '#109618'
}, {
label: 'Depreciation of the vehicle',
data: [0, 2],
backgroundColor: '#109618'
}, {
label: 'Fuel',
data: [0, 1],
backgroundColor: '#dc3912'
}, {
label: 'Insurance and Breakdown cover',
data: [4, 0],
backgroundColor: '#3366cc'
}]
},
options: {
responsive: false,
legend: {
position: 'right'
},
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: true
}]
}
}
};
const dataUrl = await canvasRenderService.renderToDataURL(configuration);
})();
dataUrl variable will contain the image you can pass to Slack API

Related

I want to create a Weibull probability Plot in Angular

This is the chart i am trying to create in Angular. This comes from the reliability package in python.
https://github.com/MatthewReid854/reliability/tree/master/reliability
I am using Highchart - Area-Range + scatter. I am able to fix the x-axis as it is just logarithmic scale. But I am unable to fix the y -axis
For Weibull analysis, formula for Y-Axis Scale is as: ln(-ln(1-p))
where p=(i-0.3)/(n+0.4) and i is the rank of the observation. This scale is chosen in order to linearize the resulting plot for Weibull data.
weibullHighcharts(weibullresp:any,statDataresp:any){
const chart = Highcharts.chart('chart-gauge', {
chart: {
marginTop: 5,
height: 380,
inverted: true,
zoomType: 'xy',
credits: false,
events: {
load() {
let chart = this;
},
},
},
title: {
credits: false,
text: '',
},
xAxis: {
gridLineWidth: 1,
labels: {
format: '{value}%'
},
type: 'logarithmic',
reversed: false,
min: 0.1,
max:90,
title: {
enabled: true,
text: 'Fraction Failure'
},
startOnTick: true,
endOnTick: true,
showLastLabel: true
},
yAxis: {
gridLineWidth: 1,
max: 999,
min: 10,
type: 'logarithmic',
title: {
text: 'Days to Failure'
}
},
legend: {
credits: false,
layout: 'vertical',
align: 'left',
verticalAlign: 'top',
floating: true,
borderWidth: 1
},
series: [
{
color:'#0000FF',
showInLegend:false,
type: 'line',
data: weibullresp.averages,
zIndex: 1,
marker: {
lineWidth: 2,
}},
{
showInLegend:false,
data: weibullresp.ranges,
type: 'arearange',
lineWidth: 0,
linkedTo: ':previous',
fillOpacity: 0.3,
zIndex: 0,
marker: {
enabled: false
}},
{
showInLegend:false,
type:'scatter',
data: weibullresp.scatterData,
color:'#343434',
marker: {
radius: 2,
symbol: 'circle'
}
}
],
credits: {
enabled: false,
},
} as any);
}
Is there a package for python where Weibull plot can be created?
How to fix the y-axis in Highchart?
Kindly help me fix the y-axis in Highchart or Let me know how can i achieve the the python image shared in front end -Angular. I need exactly same image in Python
Try to change tickInterval, minorTickInterval on axis.
On logarithmic axes, the unit is the power of the value. For example, setting the minorTickInterval to 1 puts one tick on each of 0.1, 1, 10, 100 etc. Setting the minorTickInterval to 0.1 produces 9 ticks between 1 and 10, 10 and 100 etc.
Highcharts.chart('container', {
title: {
text: 'Logarithmic axis demo'
},
xAxis: {
tickInterval: 1,
type: 'logarithmic',
},
yAxis: {
type: 'logarithmic',
minorTickInterval: 0.1,
},
tooltip: {
headerFormat: '<b>{series.name}</b><br />',
pointFormat: 'x = {point.x}, y = {point.y}'
},
series: [{
data: [1, 2, 4, 8, 16, 32, 64, 128, 256, 512],
pointStart: 1
}]
});
Demo: https://jsfiddle.net/BlackLabel/x21uc5sd/

My data array has null values in chart.js. Is there a way to draw a line between the two segments to maintain visual progress?

As shown in the screenshot, there are days where I have a null value... I would like to connect the dataset with a line regardless of a particular day being null. Is this possible in chart.js 2.x?
You can set spangaps to true:
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, null, 2, 3],
borderColor: 'pink',
fill: false,
spanGaps: true
},
{
label: '# of Points',
data: [7, null, null, 8, 3, 7],
borderColor: 'orange',
fill: false,
spanGaps: true
}
]
},
options: {}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
</body>

Aligning labels in highchart donut

I'm trying to make a highchart donut with a legend on the side,
I'm really struggling to get the data labels to be more centered. At the moment each of them are in a different place,
an image of intended result:
https://codepen.io/mattdavidson/pen/qgqZyV
Highcharts.chart('container', {
credits: { enabled: false },
chart: { height: 300, width: 500, animation: false },
title: {
align: 'center',
verticalAlign: 'middle',
text: 10,
y: 25,
x: 55,
style: { color: '#333333', fontSize: '72px', fontWeight:'bold'},
},
plotOptions: {
pie: {
dataLabels: {
enabled: true,
format: '{point.y}',
distance: -25,
style: { fontSize: '32px', textOutline: 0 },
},
animation: false,
showInLegend: true,
},
},
legend: {
layout: 'vertical',
verticalAlign: 'middle',
align: 'left',
symbolHeight: 25,
symbolRadius: 5,
itemMarginTop: 10,
itemMarginBottom: 10,
},
series: [
{
type: 'pie',
innerSize: '55%',
colors: ['rgb(212,33,71)', 'rgb(250,189,43)', 'rgb(60,168,74)'],
data: [['Category 1', 4], ['Category 2', 5], ['Category 3', 1]],
},
],
});
There is an issue reported on Highcharts github about donut labels position. Check it here: https://github.com/highcharts/highcharts/issues/9005.
I've changed some options and added custom text using Highcharts.SVGRenderer#text (dynamic sum of all values) on the donut center. Perhaps it will help you: https://jsfiddle.net/BlackLabel/2jmqext9/.
Code:
Highcharts.chart('container', {
credits: {
enabled: false
},
chart: {
height: 300,
width: 500,
animation: false,
events: {
load: function() {
var chart = this,
offsetLeft = -20,
offsetTop = 10,
x = chart.plotLeft + chart.plotWidth / 2 + offsetLeft,
y = chart.plotTop + chart.plotHeight / 2 + offsetTop,
value = 0;
chart.series[0].yData.forEach(function(point) {
value += point;
});
chart.renderer.text(value, x, y).add().css({
fontSize: '30px'
}).toFront();
}
}
},
plotOptions: {
pie: {
dataLabels: {
enabled: true,
color: '#fff',
format: '{point.y}',
distance: -25,
style: {
fontSize: '20px',
textOutline: 0
},
},
animation: false,
showInLegend: true,
},
},
legend: {
layout: 'vertical',
verticalAlign: 'middle',
align: 'left',
symbolHeight: 15,
symbolRadius: 5,
symbolPadding: 10,
itemMarginTop: 10,
itemMarginBottom: 10,
itemStyle: {
fontSize: '15px'
}
},
series: [{
type: 'pie',
innerSize: '55%',
colors: ['rgb(212,33,71)', 'rgb(250,189,43)', 'rgb(60,168,74)'],
data: [
['Category 1', 4],
['Category 2', 2],
['Category 3', 12]
],
}, ],
});

Flot chart with Threshold and Fillbetween

I'm looking for advice on how I should/can configure Flotcharts using the Fillbetween and Threshold pluggins to create a chart that accomplishes the following:
Plot a line chart. (done)
Set some threshold values. (done)
Set and fill values that are outside of the threshold values. (not quite done)
Here's what I've accomplished so far,
https://jsfiddle.net/gstoa/utv4kvw2/
$(function() {
var values = {
'avgBottom': [
[1, -2],
[2, -2],
[3, -2],
[4, -2],
[5, -2]
],
'avgTop': [
[1, 3],
[2, 3],
[3, 3],
[4, 3],
[5, 3]
],
'values': [
[1, .5],
[2, -3],
[3, .8],
[4, 4.5],
[5, 6.6]
]
};
var dataset = [{
data: values['values'],
lines: {
show: true
},
color: "rgb(50,50,255)"
}, {
id: 'avgBottom',
data: values['avgBottom'],
lines: {
show: true,
lineWidth: 0,
fill: false
},
color: "rgb(50,50,255)"
}, {
id: 'values',
data: values['values'],
lines: {
show: true,
lineWidth: 0.5,
fill: 0.2,
shadowSize: 0
},
color: "rgb(50,50,255)",
fillBetween: 'avgBottom'
}, {
id: 'avgTop',
data: values['avgTop'],
lines: {
show: true,
lineWidth: 0,
fill: 0.2
},
color: "rgb(50,50,255)",
fillBetween: 'values'
}];
$.plot($("#placeholder"), dataset, {
xaxis: {
tickDecimals: 0
},
series: {
lines: {
show: true,
fill: true
},
points: {
show: false,
radius: 4
},
color: "#62CB31",
// threshold: {
// below: -2,
// color: "rgb(255,0,0)"
// }
},
yaxis: {
tickFormatter: function(v) {
return v;
}
}
});
$.plot($("#placeholder"), [d1, d2, d3]);
});
I'd like this line chart to look like the following:
Any advice is greatly appreciated.
To do this, I had to switch from the fillbetween to the fillbelow flot plugin. I then had to modify the source of the fillbelow plugin to look at a new fillColor property of the series (I've got a pull request to merge these changes back into the main branch).
All in all, your new data set looks like the code snippet below (this JSFiddle demonstrates how to get the chart to look like your example image).
var dataset = [{
id: 'topValues',
data: values['values'],
lines: {
show: true,
},
color: "rgb(50,50,255)",
fillBelowTo: 'avgTop',
fillBelowUseSeriesObjectFillColor: false,
fillColor: "#FF0000"
}, {
id: 'avgTop',
data: values['avgTop'],
lines: {
show: true,
lineWidth: 0,
fill: true
},
color: "rgb(50,50,255)"
}, {
id: 'bottomValues',
data: values['values'],
lines: {
show: true,
lineWidth: 0,
shadowSize: 0
},
color: "rgb(50,50,255)"
}, {
id: 'avgBottom',
data: values['avgBottom'],
lines: {
show: true,
lineWidth: 0,
fill: true,
},
fillBelowTo: 'bottomValues',
fillBelowUseSeriesObjectFillColor: false,
fillColor: "#FF0000",
color: "rgb(50,50,255)"
}];
The fillBelowTo property acts similarly to the fillBetween
property of the fillbetween plugin - it denotes to which series you'd
like to fill below to.
The fillBelowUseSeriesObjectFillColor
property (set to false) tells us to not use the lines.fillColor
color and instead use the fillColor value. If fillBelowUseSeriesObjectFillColor was true, the lines.fillColor color would be used (which in this case would be blue).

Getting extra color while drawing two charts using flot js

Here my code
<div id="chart-revenue3" style="width:1100px; height:480px;" > </div>
var series = [{
data: [
[0, 100],
[1, 150],
[2, 125],
[3, 160],
[4, 95]
],
label: "Generes",
color:"#4598AE"
},
{
data: [
[0, 104],
[1, 157],
[2, 178],
[3, 145],
[4, 78]],
label: "Playlists",
color:"#8AA453"
}, {
data: [
[0, 55],
[1, 40],
[2, 60],
[3, 10],
[4, 20]
],
label: "Home",
color:"#A84745"
}, {
data: [
[0, 55],
[1, 40],
[2, 60],
[3, 10],
[4, 20]
],
label: "Search",
color:"#D98445"
}, {
data: [
[0, 55],
[1, 40],
[2, 60],
[3, 10],
[4, 20]
],
label: "New and Hot",
color:"#71598E"
},
{
data: [
[0,150],
[1, 200],
[2, 250],
[3, 120],
[4, 90]
],
label: "# Venues",
points: { show: false },
lines: { show: true,fill: false},
yaxis: 2,
color:"#81A0C1"
}];
var options = {
xaxis: {
minTickSize: 1,
ticks: [[0,'Dafault'],[1,'Alternative'],[2,'Country'],[3,'Latin'],[4,'Rock']]
}, yaxes: [
{
},
{
position: "right" , min:0, max: 1200, tickSize: 200
}
],
series: {
bars: {
show: true,
barWidth: .3,
align: "center",fillColor: {
colors: [{ opacity: 1 }, { opacity: 1 } ]
}
},
stack: true,
shadowSize:1
},
legend: { show: true, container: '#chart-revenue3-table' }
};
$.plot("#chart-revenue3", series, options);
so if i run this code am getting some extra color on bar chart..please give any idea
Ok, now I understand what you are trying to do. What you are missing is that you need to tell flot not to plot the # Venues series as a bar:
{
data: [
[0, 150],
[1, 200],
[2, 250],
[3, 120],
[4, 90]
],
label: "# Venues",
points: {
show: false
},
lines: {
show: true,
fill: false
},
yaxis: 2,
bars: {
show: false // <-- this is the bit you were missing
},
color: "#81A0C1"
}
http://jsfiddle.net/BrEJm/6/
The reason you need to do this is because in your options you set:
series: {
bars: {
show: true,
//...
}
}
And the way flot works is that it will merge those default set of series options with whatever explicit options you set for each series. So, even if you don't specify, all your series inherit bars.show = true.

Resources