animation of a graph of an equation javascript - javascript

I'm stuck on this issue and don't know where to put my hands.
I have to draw in javascript the animation of the graph of the equation y = x ^ 3
what do i mean?
knowing y (for example y = 10) I would like the graph to start from (0; 0) up to (x; 10) following the equation y = x ^ 3
also I would like to create a button which can be clicked during the animation and tells me what y is the graph at that precise moment
for now thanks to chart.js i managed to do this:
JS
var ctx = document.getElementById("myChart");
var data = {
labels: [1, 2, 3, 4, 5],
datasets: [
{
function: function(x) { return x*x*x },
borderColor: "rgba(153, 102, 255, 1)",
data: [],
fill: true
}]
};
Chart.pluginService.register({
beforeInit: function(chart) {
var data = chart.config.data;
for (var i = 0; i < data.datasets.length; i++) {
for (var j = 0; j < data.labels.length; j++) {
var fct = data.datasets[i].function,
x = data.labels[j],
y = fct(x);
data.datasets[i].data.push(y);
}
}
}
});
var myBarChart = new Chart(ctx, {
type: 'line',
data: data,
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
HTML
<canvas id="myChart"></canvas>
result
for now I only have the graph, there is no animation and I cannot select the maximum y
how can I do?

To set max amount on your y Axes you can use the max property or suggestedMax if you want to make sure that if the data goes bigger the axis adapts. For the animation you can write custom logic as in the example underneath. I only dont know how to get the value its at on the click:
const labels = [1, 2, 3, 4, 5]
const totalDuration = 5000;
const delayBetweenPoints = totalDuration / labels.length;
const previousY = (ctx) => ctx.index === 0 ? ctx.chart.scales.y.getPixelForValue(100) : ctx.chart.getDatasetMeta(ctx.datasetIndex).data[ctx.index - 1].getProps(['y'], true).y;
var options = {
type: 'line',
data: {
labels,
datasets: [{
label: '# of Votes',
data: [],
borderWidth: 1,
function: function(x) {
return x * x * x
},
borderColor: 'red',
backgroundColor: 'red'
}]
},
options: {
scales: {
y: {
max: 250
}
},
animation: {
x: {
type: 'number',
easing: 'linear',
duration: delayBetweenPoints,
from: NaN, // the point is initially skipped
delay(ctx) {
if (ctx.type !== 'data' || ctx.xStarted) {
return 0;
}
ctx.xStarted = true;
return ctx.index * delayBetweenPoints;
}
},
y: {
type: 'number',
easing: 'linear',
duration: delayBetweenPoints,
from: previousY,
delay(ctx) {
if (ctx.type !== 'data' || ctx.yStarted) {
return 0;
}
ctx.yStarted = true;
return ctx.index * delayBetweenPoints;
}
}
}
},
plugins: [{
id: 'data',
beforeInit: function(chart) {
var data = chart.config.data;
for (var i = 0; i < data.datasets.length; i++) {
for (var j = 0; j < data.labels.length; j++) {
var fct = data.datasets[i].function,
x = data.labels[j],
y = fct(x);
data.datasets[i].data.push(y);
}
}
}
}]
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
var chart = new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.0.1/chart.js" integrity="sha512-HJ+fjW1Hyzl79N1FHXTVgXGost+3N5d1i3rr6URACJItm5CjhEVy2UWlNNmFPHgX94k1RMrGACdmGgVi0vptrw==" crossorigin="anonymous"></script>
</body>

Related

Save graph in a project folder from program in python and pyplot graph in Javascript

I'm writing in python a program to recognize emotions from voice (it's a web interface and I'm using flask). I passed the variables in JavaScript I created a graph using Plotly. Only now I want to save the graph in a project specific folder called "graphs". How can I do?
I don't want to have to pass the graph from javascript to python and save it. if so how can I do it?
Here's how to build the graph in JavaScript
const x1 = JSON.parse('{{data.audio_len}}');
const y1 = JSON.parse('{{data.val_outputs}}');
console.log(x1);
console.log(y1);
var data = [];
const trace1Values = [];
for (let i = 0; i < x1.length; i++) {
trace1Values.push(y1[i][0]);
}
var Disgusto = {
x: x1,
y: trace1Values,
mode: 'lines+markers',
line: {
shape: 'spline'
},
name: "Disgusto",
};
data.push(Disgusto);
const trace2Values = [];
for (let i = 0; i < x1.length; i++) {
trace2Values.push(y1[i][1]);
}
var Gioia = {
x: x1,
y: trace2Values,
mode: 'lines+markers',
line: {
shape: 'spline'
},
name: "Gioia",
};
data.push(Gioia);
const trace3Values = [];
for (let i = 0; i < x1.length; i++) {
trace3Values.push(y1[i][2]);
}
var Paura = {
x: x1,
y: trace3Values,
mode: 'lines+markers',
line: {
shape: 'spline'
},
name: "Paura",
};
data.push(Paura);
const trace4Values = [];
for (let i = 0; i < x1.length; i++) {
trace4Values.push(y1[i][3]);
}
var Rabbia = {
x: x1,
y: trace4Values,
mode: 'lines+markers',
line: {
shape: 'spline'
},
name: "Rabbia",
};
data.push(Rabbia);
const trace5Values = [];
for (let i = 0; i < x1.length; i++) {
trace5Values.push(y1[i][4]);
}
var Sorpresa = {
x: x1,
y: trace5Values,
mode: 'lines+markers',
line: {
shape: 'spline'
},
name: "Sorpresa",
};
data.push(Sorpresa);
const trace6Values = [];
for (let i = 0; i < x1.length; i++) {
trace6Values.push(y1[i][5]);
}
var Tristezza = {
x: x1,
y: trace6Values,
mode: 'lines+markers',
line: {
shape: 'spline'
},
name: "Tristezza",
};
data.push(Tristezza);
const trace7Values = [];
for (let i = 0; i < x1.length; i++) {
trace7Values.push(y1[i][6]);
}
var Neutrale = {
x: x1,
y: trace7Values,
mode: 'lines+markers',
line: {
shape: 'spline'
},
name: "Neutrale",
};
data.push(Neutrale);
var layout = {
title: '{{data.name_audio}}',
xaxis: {
title: 'Tempo audio in sec'
},
yaxis: {
title: 'Emozioni',
range: [0, 1]
}
};
Plotly.newPlot('myDiv', data, layout);
<div class="grafico" id="myDiv" src='https://cdn.plot.ly/plotly-2.18.0.min.js'></div>
I tried to use this code to save the graph in a folder of my project but when I run the code and show the graph it doesn't save me
Plotly.newPlot('myDiv', data, layout).then(function () {
Plotly.writeImage('myDiv',
{ format: 'png', width: 300, height: 300 },
{ folder: 'grafico/grafico.png' });
});

Are you able to offset a secondary y-axis in ChartJS, by a decimal value, whilst keeping the same scale for both y-axes?

I am currently working with two datasets, both in meters, but the left hand axis displays a dataset with an offset of 11.74m along the y-axis. The right hand axis ignores this offset, hence y1 == y2 when y1 = 11.74 and y2 = 0.
This being the case, is there a way to keep integer tick values on both axes despite the decimal offset between the two? Not sure if I've got the Y2 offset correct in the graph below, but I think this is roughly what I'm trying to achieve - basically fixed gridline/tick intervals of Y1 for both axes, except for Y2:
The live code I'm working on is a bit too unwieldly for Stack Overflow, but the code below roughly achieves what I'm after - would be nice if there was a way to cleanly declare an offset of -0.26 without then also having to explicitly declare the rest of the ticks:
var ticks = [5, 4, 3, 2, 1, -0.26];
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
datasets: [{
data: [0, 0.1, 0.5, 5, 3.5, 3, 3.25, 2, 1.5, 1]
}]
},
options: {
scales: {
yAxes: [{
ticks: {
autoSkip: false,
min: ticks[ticks.length - 1],
max: ticks[0]
},
afterBuildTicks: function(scale) {
scale.ticks = ticks;
return;
},
beforeUpdate: function(oScale) {
return;
}
}]
}
}
});
https://jsfiddle.net/wxp1fLk0/5/
Solution below after much fiddling. offset in the getTickArray() function specifies the left-hand axis value that coincides with 0 on the right hand axis. I think the afterBuildTicks and beforeUpdate keys then allow you to position ticks with more precision (I think).
https://jsfiddle.net/zjxukf57/47/
function getRandomDataset(lowerBound, upperBound, count) {
let output = [];
for (let index = 0; index < count; index++) {
let newPoint = Math.floor((Math.random() * upperBound) + lowerBound);
output.push(newPoint);
}
return output;
}
function arrayMin(arr) {
var len = arr.length, min = Infinity;
while (len--) {
if (arr[len] < min) {
min = arr[len];
}
}
return min;
}
function arrayMax(arr) {
var len = arr.length, max = -Infinity;
while (len--) {
if (arr[len] > max) {
max = arr[len];
}
}
return max;
}
function getTickArray(offset, increment, leftData, rightData) {
let ticksLeft = [];
let ticksRight = [];
let leftMin = arrayMin(leftData);
let leftMax = arrayMax(leftData);
let rightMin = arrayMin(rightData);
let rightMax = arrayMax(rightData);
let tick = leftMin;
let tickRight = tick - offset;
let wholeTick = Math.ceil(tick); // ? Gets first left-hand integer above minimum tick value
let wholeTickRight = Math.ceil(tickRight); // ? Gets first right-hand integer above minimum tick value
let maxValue = leftMax > rightMax + offset ? leftMax : rightMax + offset;
// ? Push minimum decimal ticks
ticksLeft.push(tick);
ticksRight.push(tickRight);
while (wholeTick < maxValue) {
ticksLeft.push(wholeTick);
ticksRight.push(wholeTickRight);
wholeTick = wholeTick + 1*increment;
wholeTickRight = wholeTickRight + 1*increment;
}
// ? Push minimum decimal ticks
ticksLeft.push(maxValue);
ticksRight.push(maxValue - offset);
return [ ticksLeft, ticksRight ];
}
let datasetOne = getRandomDataset(8, 15, 10); // ? Ten random numbers between 8 and 15
let datasetTwo = getRandomDataset(0, 7, 10); // ? Ten random numbers between 0 and 7
var ticks = getTickArray(11.76, 2, datasetOne, datasetTwo);
console.log(ticks)
var ticks1 = ticks[0];
var ticks2 = ticks[1];
console.log(datasetOne);
console.log(datasetTwo);
// ? Chart Config
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
datasets: [{
data: datasetOne,
yAxisID: 'A',
label: "left",
borderColor: "#FF0000",
backgroundColor: 'rgba(0, 0, 0, 0)'
},
{
data: datasetTwo,
yAxisID: 'B',
label: "right",
borderColor: "#348632",
backgroundColor: 'rgba(0, 0, 0, 0)'
}]
},
options: {
scales: {
yAxes: [{
id: 'A',
ticks: {
autoSkip: false,
min: ticks1[ticks1.length - 1],
max: ticks1[0]
},
afterBuildTicks: function(scale) {
scale.ticks = ticks1;
return;
},
beforeUpdate: function(oScale) {
return;
},
gridLines: {
color: "#FF0000"
}
},
{
id: 'B',
ticks: {
autoSkip: false,
min: ticks2[ticks2.length - 1],
max: ticks2[0],
callback: function(value, index, values) {
return value;
}
},
afterBuildTicks: function(scale) {
scale.ticks = ticks2;
return;
},
beforeUpdate: function(oScale) {
return;
},
position: "right",
gridLines: {
color: "#348632"
}
}]
}
}
});

graph of an equation animated javascript (crash game)

i don't know how to get out of this problem
I have the animation of the graph of the equation y = x ^ 2
this:
const labels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
const totalDuration = 2000;
const delayBetweenPoints = totalDuration / labels.length;
const previousY = (ctx) => ctx.index === 0 ? ctx.chart.scales.y.getPixelForValue(100) : ctx.chart.getDatasetMeta(ctx.datasetIndex).data[ctx.index - 1].getProps(['y'], true).y;
var options = {
type: 'line',
data: {
labels,
datasets: [{
label: '# of Votes',
data: [],
borderWidth: 1,
function: function(x) {
return x * x
},
borderColor: "rgba(153, 102, 255, 1)",
fill: true
}]
},
options: {
scales: {
y: {
max: 200
},
x: {
suggestedMax: 210
}
},
animation: {
x: {
type: 'number',
easing: 'linear',
duration: delayBetweenPoints,
from: NaN, // the point is initially skipped
delay(ctx) {
if (ctx.type !== 'data' || ctx.xStarted) {
return 0;
}
ctx.xStarted = true;
return ctx.index * delayBetweenPoints;
}
},
y: {
type: 'number',
easing: 'linear',
duration: delayBetweenPoints,
from: previousY,
delay(ctx) {
if (ctx.type !== 'data' || ctx.yStarted) {
return 0;
}
ctx.yStarted = true;
return ctx.index * delayBetweenPoints;
}
}
}
},
plugins: [{
id: 'data',
beforeInit: function(chart) {
var data = chart.config.data;
for (var i = 0; i < data.datasets.length; i++) {
for (var j = 0; j < data.labels.length; j++) {
var fct = data.datasets[i].function,
x = data.labels[j],
y = fct(x);
data.datasets[i].data.push(y);
}
}
}
}]
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
var chart = new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.0.1/chart.js" integrity="sha512-HJ+fjW1Hyzl79N1FHXTVgXGost+3N5d1i3rr6URACJItm5CjhEVy2UWlNNmFPHgX94k1RMrGACdmGgVi0vptrw==" crossorigin="anonymous"></script>
</body>
I have to add 3 things and I don't know how to get out of it
how can I define a Y value for which the line stops going up?
if this Y is bigger than the axis data, how can they adapt?
how can I create a button which when clicked tells me the exact Y value at that moment during the animation?
I wish something like this graph would come out:
https://www.youtube.com/watch?v=w48ahDZQPnQ
You can try setting the Y max value like this in your code to auto adjust Y axis scale.
beforeInit: function(chart) {
var data = chart.config.data;
let maxValue = 0;
for (var i = 0; i < data.datasets.length; i++) {
for (var j = 0; j < data.labels.length; j++) {
var fct = data.datasets[i].function,
x = data.labels[j],
y = fct(x);
if (maxValue < y) {
maxValue = y;
}
data.datasets[i].data.push(y);
}
}
chart.options.scales.y.max = maxValue;
}

Display only certain labels with chart.js

The X axis of this graph represents time in milliseconds.
I basically need to display only one 5 labels, one each second (1,2,3,4 and 5), however the graph contains too many elements and not every label is shown.
I tried looking on the Chart.js documentation but haven't found anything useful to my case.
Do you guys have any ideas on how can I do it?
Im gonna post my code below:
<head>
<script>
$(document).ready(function () {
function generateLabels() {
var chartLabels = [];
for (x = 0; x < 5000; x++) {
if(x%1000 == 0)
chartLabels.push(x/1000);
else
chartLabels.push('');
}
return chartLabels;
}
function generateData() {
var chartData = [];
for (x = 0; x < 5000; x++) {
chartData.push(Math.floor((Math.random() * 100) + 1));
}
return chartData;
}
function addData(numData, chart) {
for (var i = 0; i < numData; i++) {
chart.data.datasets[0].data.push(Math.random() * 100);
chart.data.labels.push("Label" + i);
var newwidth = $('.chartAreaWrapper2').width(); // + 60
$('.chartAreaWrapper2').width(newwidth);
}
}
var chartData = {
labels: generateLabels(),
datasets: [{
label: "Test Data Set",
lineTension: 0,
fill:false,
pointBackgroundColor: "green", //Point Color
pointBorderColor: "green",
borderColor: "green", //Line Color
pointStyle: "point",
data: generateData()
}]
};
$(function () {
var rectangleSet = false;
var canvasTest = $('#chart-Test');
var chartTest = new Chart(canvasTest, {
type: 'line',
data: chartData,
maintainAspectRatio: false,
responsive: true,
options: {
elements:{
point:{
radius:1
}
},
tooltips: {
titleFontSize: 0,
titleMarginBottom: 0,
bodyFontSize: 12
},
legend: {
display: false
},
scales: {
xAxes: [{
ticks: {
fontSize: 12,
display: true
}
}],
yAxes: [{
ticks: {
fontSize: 12,
beginAtZero: true
}
}]
}
}
});
addData(5, chartTest);
});
});
</script>
</head>
<body>
<div class="chartWrapper">
<div class="chartAreaWrapper">
<canvas id="chart-Test" height="300" width="5000"></canvas>
</div>
<canvas id="axis-Test" height="300" width="0"></canvas>
</div>
Thanks in advance, have a nice day!
If i understand correct, you want to show only 5 labels in your x-axis (1, 2, 3 ,4, second). Try this one:
var options = {
scales: {
xAxes: [{
afterTickToLabelConversion: function(data){
var xLabels = data.ticks;
xLabels.forEach(function (labels, i) {
if (i % 1000 != 0){
xLabels[i] = '';
}
});
}
}]
}
}

Chart js legend are being cut off if the bar height is equal to port height - chart js

I am using chart js to display barchart as :
$(function(){
let aid;
let $radio_input;
let none_obs;
let display = true;
let $js_dom_array = ["76.44", "120.00"];
let $js_am_label_arr = ["None $0", "Terrace - Large $2000"];
if($js_am_label_arr.length > 20){
display = false;
}
let $js_backgroundColor = ["rgba(26,179,148,0.5)", "rgba(26,179,148,0.5)"];
// let $div = document.getElementById("barChart");
// $div.height="140";
let ctx2 = document.getElementById("barChart").getContext("2d");
let chart = new Chart(ctx2, {
type: 'bar',
data: {
labels: $js_am_label_arr,
datasets: [{
label: 'DOM',
data: $js_dom_array,
backgroundColor: $js_backgroundColor,
barPercentage: 0.4,
maxBarThickness: 50,
// maxBarLength: 5,
}]
},
options: {
legend: {
display: false
},
responsive: true,
maintainAspectRatio: false,
legendCallback: function(chart) {
var text = [];
for (var i=0; i<chart.data.datasets.length; i++) {
text.push(chart.data.labels[i]);
}
return text.join("");
},
tooltips: {
mode: 'index',
callbacks: {
// Use the footer callback to display the sum of the items showing in the tooltip
title: function(tooltipItem, data) {
let title_str = data['labels'][tooltipItem[0]['index']];
// let lastIndex = title_str.lastIndexOf(" ");
// return title_str.substring(0, lastIndex);
return title_str;
},
label: function(tooltipItem, data) {
return 'Avg. DOM: '+data['datasets'][0]['data'][tooltipItem['index']];
},
},
},
scales: {
xAxes: [{
stacked: false,
beginAtZero: true,
// scaleLabel: {
// labelString: 'Month'
// },
ticks: {
display: display,
min: 0,
autoSkip: false,
maxRotation: 60,
callback: function(label, index, labels) {
// let lastIndex = label.lastIndexOf(" ");
// let avg_amount = label.split(" ").pop();
// let am_name = label.substring(0, lastIndex);
// let truncated_am_name = am_name.length > 30 ? (am_name.substring(0, 30)+'...') : am_name;
// return truncated_am_name+' '+avg_amount;
return label;
}
}
}]
},
layout: {
margin: {
top: 5
}
},
},
plugins:[{
afterDatasetsDraw: function(chart,options) {
// var chartInstance = chart,
let ctx = chart.ctx;
ctx.font = Chart.defaults.global.defaultFontStyle;
ctx.fillStyle = Chart.defaults.global.textColor;
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
chart.data.datasets.forEach(function (dataset, i) {
var meta = chart.controller.getDatasetMeta(i);
meta.data.forEach(function (bar, index) {
ctx.fillText(Math.round(dataset.data[index]), bar._model.x, bar._model.y); //bar._model.y - 5
});
})
}
}]
});
document.getElementById('barChart').innerHTML = chart.generateLegend();
})
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.3"></script>
<div style="height:400px;">
<canvas id="barChart" xheight="140px"></canvas>
</div>
If you need jsfiddle
Here, the value of second barchart is 120 and it is being cut off. I could pull text little down as: ctx.fillText(Math.round(dataset.data[index]), bar._model.x, bar._model.y + 5); But I don't wat the value to be overlapped with the bar. I have also tried with following options
layout: {
margin: {
top: 5
}
},
and
axisY:{
viewportMaximum: 130
},
But, none of these seems to work. Is there any way to increase the height or viewport of the chart js? It would be helpful if you could provide the js fiddle as well.
Instead of layout.margin.top, you need to define layout.padding.top as follows:
layout: {
padding: {
top: 20
}
},

Categories

Resources