Disabling stacking candles on AmCharts v4 Candlestick chart - amcharts4

I am building a simple candlestick chart in a hourly timeframe. I figured out out to avoid candles to being grouped within the same day using both "dateFormat" and "inputDateFormat" parameters. For some reason, depending on the dataset, it doesn't always work.
Below two examples that differ only for the dataset (chart.data).
Any idea about what is wrong?
Thanks
<script src="https://cdn.amcharts.com/lib/4/core.js"></script>
<script src="https://cdn.amcharts.com/lib/4/charts.js"></script>
<script src="https://cdn.amcharts.com/lib/4/themes/animated.js"></script>
<!-- Chart code -->
<script>
am4core.ready(function() {
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
// Create chart
var chart = am4core.create("chartdiv_stock", am4charts.XYChart);
// Load data
chart.data=[{"Date":"2020-10-29 12:00:00","Open":"329.21","High":"329.87","Low":"327.82","Close":"328.43","Volume":"9903193"},{"Date":"2020-10-29 11:00:00","Open":"327.87","High":"329.82","Low":"327.11","Close":"329.22","Volume":"14505192"},{"Date":"2020-10-29 10:00:00","Open":"327.08","High":"329.485","Low":"325.09","Close":"327.83","Volume":"11636626"}];
chart.leftAxesContainer.layout = "vertical";
chart.dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss";
chart.dateFormatter.inputDateFormat = "yyyy-MM-dd HH:mm:ss";
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.renderer.grid.template.location = 0;
dateAxis.renderer.minGridDistance = 60;
dateAxis.skipEmptyPeriods=true;
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.tooltip.disabled = false;
valueAxis.renderer.grid.template.strokeOpacity = 0;
dateAxis.renderer.grid.template.strokeOpacity = 0;
var series = chart.series.push(new am4charts.CandlestickSeries());
series.dataFields.dateX = "Date";
series.dataFields.openValueY = "Open";
series.dataFields.valueY = "Close";
series.dataFields.lowValueY = "Low";
series.dataFields.highValueY = "High";
//series.tooltipText = "Open: [bold]${openValueY.value}[/]\nLow: [bold]${lowValueY.value}[/]\nHigh: [bold]${highValueY.value}[/]\nClose: [bold]${valueY.value}[/]";
series.connect = true;
series.dropFromOpenState.properties.fill = am4core.color("black");
series.dropFromOpenState.properties.stroke = am4core.color("black");
series.riseFromOpenState.properties.fill = am4core.color("white");
series.riseFromOpenState.properties.stroke = am4core.color("black");
series.riseFromPreviousState.properties.fillOpacity = 0;
series.dropFromPreviousState.properties.fillOpacity = 1;
chart.cursor = new am4charts.XYCursor();
chart.scrollbarX = new am4core.Scrollbar();
}); // end am4core.ready()
</script>
<div id="chartdiv_stock" style="width:100%;height:500px;float:left;" ></div>
<script src="https://cdn.amcharts.com/lib/4/core.js"></script>
<script src="https://cdn.amcharts.com/lib/4/charts.js"></script>
<script src="https://cdn.amcharts.com/lib/4/themes/animated.js"></script>
<!-- Chart code -->
<script>
am4core.ready(function() {
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
// Create chart
var chart = am4core.create("chartdiv_stock", am4charts.XYChart);
// Load data
chart.data=[{"Date":"2020-12-04 15:00:00","Open":"368.74","High":"369.28","Low":"368.55","Close":"369.2","Volume":"4558835"},{"Date":"2020-12-04 16:00:00","Open":"369.2","High":"369.85","Low":"368.67","Close":"369.83","Volume":"13766958"},{"Date":"2020-12-04 17:00:00","Open":"369.82","High":"369.94","Low":"368.94","Close":"369.01","Volume":"7618573"},{"Date":"2020-12-04 18:00:00","Open":"369","High":"369.85","Low":"369","Close":"369.15","Volume":"413998"},{"Date":"2020-12-04 19:00:00","Open":"369.15","High":"369.34","Low":"369.11","Close":"369.19","Volume":"38254"},{"Date":"2020-12-04 20:00:00","Open":"369.21","High":"369.25","Low":"369.14","Close":"369.22","Volume":"22622"}];
chart.leftAxesContainer.layout = "vertical";
chart.dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss";
chart.dateFormatter.inputDateFormat = "yyyy-MM-dd HH:mm:ss";
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.renderer.grid.template.location = 0;
dateAxis.renderer.minGridDistance = 60;
dateAxis.skipEmptyPeriods=true;
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.tooltip.disabled = false;
valueAxis.renderer.grid.template.strokeOpacity = 0;
dateAxis.renderer.grid.template.strokeOpacity = 0;
var series = chart.series.push(new am4charts.CandlestickSeries());
series.dataFields.dateX = "Date";
series.dataFields.openValueY = "Open";
series.dataFields.valueY = "Close";
series.dataFields.lowValueY = "Low";
series.dataFields.highValueY = "High";
//series.tooltipText = "Open: [bold]${openValueY.value}[/]\nLow: [bold]${lowValueY.value}[/]\nHigh: [bold]${highValueY.value}[/]\nClose: [bold]${valueY.value}[/]";
series.connect = true;
series.dropFromOpenState.properties.fill = am4core.color("black");
series.dropFromOpenState.properties.stroke = am4core.color("black");
series.riseFromOpenState.properties.fill = am4core.color("white");
series.riseFromOpenState.properties.stroke = am4core.color("black");
series.riseFromPreviousState.properties.fillOpacity = 0;
series.dropFromPreviousState.properties.fillOpacity = 1;
chart.cursor = new am4charts.XYCursor();
chart.scrollbarX = new am4core.Scrollbar();
}); // end am4core.ready()
</script>
<div id="chartdiv_stock" style="width:100%;height:500px;float:left;" ></div>

It's seems it was due to the ordering, the "not working" case had Data descending. Changing to ascending solved the issue.

Related

Array & slideshow

I'm using the below code in order to display a photo in slide show, i need to display: name,job and quote for each person, but actually only photos change on time interval specified ...can anyone help?
var img1 = document.getElementById("img1");
var testname = document.getElementById("testname");
var testjob = document.getElementById("testjob");
var testpa = document.getElementById("testpa");
var currentPos = 0;
var images = ["ch1.jpg", "ch2.jpg", "ch3.jpg"]
var testname = [“John Smith” ,”Jan Rosso”,”Raphael Matthew”]
var testjob = [“Manager” ,”Director”,”Supervisor”]
var testpa = [“I like this company”,”It’s amazing”,”Wondeful atmospher”]
function volgendefoto() {
if (++currentPos >= images.length)
currentPos = 0;
img1.src = images[currentPos];
testname.value = testname[currentPos];
testjob.value = testjob[currentPos];
testpa.value = testpa[currentPos];
}
setInterval(volgendefoto, 3000);
function test(){
document.getElementById('text').value=document.getElementById('testname').value
}
testName and the others may need to be updated via innerHTML
function volgendefoto() {
if (++currentPos >= images.length)
currentPos = 0;
img1.src = images[currentPos];
testname.innerHtml = testname[currentPos];
testjob.innerHtml = testjob[currentPos];
testpa.innerHtml = testpa[currentPos];
}

Problem with If/Then code with Google Sheet Script

Someone please help.
I am trying to create a simple script which records button presses in order.
I have:
function P1Buzzer() {
var sheet = SpreadsheetApp.getActiveSheet();
var row = 6;
var col = 1;
var Name = sheet.getRange(row, col).getValue();
var sheet = SpreadsheetApp.getActiveSheet();
var row = 192;
var col = 1;
var AnswerPosition = sheet.getRange(row, col).getValue();
if (AnswerPosition = 1) {
sheet.getRange(199, 1).setValue(Name);
var AnswerPosition = AnswerPosition + 1
sheet.getRange(192, 1).setValue(AnswerPosition);
}
if (AnswerPosition = 2) {
sheet.getRange(200, 1).setValue(Name);
var AnswerPosition = AnswerPosition + 1
sheet.getRange(192, 1).setValue(AnswerPosition);
}
}
The problem I have is that when I run the script it does both the commands, ignoring the if command.
Any ideas?
First, you are setting the value to 1 by using = instead of ==. Second, if it was 1, you add one to it and then check to see if it is 2. I'll bet it is!
if (AnswerPosition == 1) {
sheet.getRange(199, 1).setValue(Name);
var AnswerPosition = AnswerPosition + 1
sheet.getRange(192, 1).setValue(AnswerPosition);
} else if (AnswerPosition == 2) {
...

Google Apps Scripts If function not skipping rows with null value

I am writing a function that will search a spreadsheet for days an employee has worked hours, create an array with the values for job number, job name, employee name, hours, and date, and then put them onto another spreadsheet. It also only shows hours that were within the past 8 days so that time can be worked out for the week when we have to report hours (I'm scheduling it to run the day time is due). I also have been filtering out days with blank hours, which limits the amount of data that gets copied over.
I am encountering an issue where on one employee the function to skip the blank hours does not work. For other employees I have been able to use "" to indicate an empty cell. I have also tried to use (null) as a value, but that only ignores 6 of 7 days (It still logs days with no hours that are adjacent to cells that calculate hours in the week).
What I can't figure out is why this doesn't work on just one sheet out of the whole Google Sheets document. I have simplified my spreadsheet to reduce personal information, and to make it easier to parse the script, but in my original document I track 6 employees with similar code, and only one is showing this issue.
https://docs.google.com/spreadsheets/d/1ve0EPVQJ2vmWG1NYHMncw1ZljP3yXd28dMeNC38Jiy4/edit?usp=sharing
Is a link to the spreadsheet. Code is below.
function shoptime(){
var ss = SpreadsheetApp.getActive().getId();
var stephensheet = Sheets.Spreadsheets.Values.get(ss, 'Stephen!A2:G');
var tiffanysheet = Sheets.Spreadsheets.Values.get(ss, 'Tiffany!A2:G');
var scripts = SpreadsheetApp.getActive().getSheetByName("Scripts");
var currentDate = new Date();
var pastweek = new Date();
pastweek.setDate(currentDate.getDate() -8);
var array=[];
for (var a = 0; a < stephensheet.values.length; a++){
var jobdate = stephensheet.values[a][1];
var intime = stephensheet.values[a][2];
var outtime = stephensheet.values[a][3];
var dailyhours = stephensheet.values[a][4];
if (new Date(jobdate) > pastweek){
if (dailyhours != (null)){
array.push(["NA","Office","Stephen",dailyhours,jobdate]);
}
}
}
for (var a = 0; a < tiffanysheet.values.length; a++){
var jobdate = tiffanysheet.values[a][1];
var intime = tiffanysheet.values[a][2];
var outtime = tiffanysheet.values[a][3];
var dailyhours = tiffanysheet.values[a][4];
if (new Date(jobdate) > pastweek){
if (dailyhours != ("")){
array.push(["NA","Office","Tiffany",dailyhours,jobdate]);
}
}
}
if(array[0]){
scripts.getRange(scripts.getLastRow()+1,1,array.length,5).setValues(array);
}
SpreadsheetApp.flush();
}
I'm not sure of the exact issue but checking for cells that have a value rather than cells that are not null should work for you.
function shoptime(){
var ss = SpreadsheetApp.getActive().getId();
var stephensheet = Sheets.Spreadsheets.Values.get(ss, 'Stephen!A2:G');
var tiffanysheet = Sheets.Spreadsheets.Values.get(ss, 'Tiffany!A2:G');
var scripts = SpreadsheetApp.getActive().getSheetByName("Scripts");
var currentDate = new Date();
var pastweek = new Date();
pastweek.setDate(currentDate.getDate() -8);
var array=[];
for (var a = 0; a < stephensheet.values.length; a++){
var jobdate = stephensheet.values[a][1];
var intime = stephensheet.values[a][2];
var outtime = stephensheet.values[a][3];
var dailyhours = stephensheet.values[a][4];
if (new Date(jobdate) > pastweek){
if (dailyhours){
array.push(["NA","Office","Stephen",dailyhours,jobdate]);
}
}
}
for (var a = 0; a < tiffanysheet.values.length; a++){
var jobdate = tiffanysheet.values[a][1];
var intime = tiffanysheet.values[a][2];
var outtime = tiffanysheet.values[a][3];
var dailyhours = tiffanysheet.values[a][4];
if (new Date(jobdate) > pastweek){
if (dailyhours){
array.push(["NA","Office","Tiffany",dailyhours,jobdate]);
}
}
}
if(array[0]){
scripts.getRange(scripts.getLastRow()+1,1,array.length,5).setValues(array);
}
SpreadsheetApp.flush();
}
And to modify the code to use the built-in service with is much more straight forward in this case;
function shoptime(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var stephensheet = ss.getSheetByName('Stephen').getDataRange().getValues();
var tiffanysheet = ss.getSheetByName('Tiffany').getDataRange().getValues();
var scripts = ss.getSheetByName("Scripts");
var currentDate = new Date();
var pastweek = new Date();
pastweek.setDate(currentDate.getDate() -8);
var array=[];
for (var a = 0; a < stephensheet.length; a++){
var jobdate = stephensheet[a][1];
var intime = stephensheet[a][2];
var outtime = stephensheet[a][3];
var dailyhours = stephensheet[a][4];
if (new Date(jobdate) > pastweek){
if (dailyhours != ""){
array.push(["NA","Office","Stephen",dailyhours,jobdate]);
}
}
}
for (var a = 0; a < tiffanysheet.length; a++){
var jobdate = tiffanysheet[a][1];
var intime = tiffanysheet[a][2];
var outtime = tiffanysheet[a][3];
var dailyhours = tiffanysheet[a][4];
if (new Date(jobdate) > pastweek){
if (dailyhours != ""){
array.push(["NA","Office","Tiffany",dailyhours,jobdate]);
}
}
}
if(array[0]){
scripts.getRange(scripts.getLastRow()+1,1,array.length,5).setValues(array);
}
SpreadsheetApp.flush();
}
Finally, if you are scraping data from 6 sheets in the exact same format then a another loop and an array of the sheet names will save on repetition of code
function shoptime() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ['Stephen', 'Tiffany'] // add the aditional sheet names here
var scripts = SpreadsheetApp.getActive().getSheetByName("Scripts");
var currentDate = new Date();
var pastweek = new Date();
pastweek.setDate(currentDate.getDate() - 8);
var array = [];
for (var i = 0; i < sheets.length; i++) {
var sheet = ss.getSheetByName(sheets[i]);
var data = sheet.getDataRange().getValues();
for (var a = 0; a < data.length; a++) {
var jobdate = data[a][1];
var intime = data[a][2];
var outtime = data[a][3];
var dailyhours = data[a][4];
if (new Date(jobdate) > pastweek) {
if (dailyhours) {
array.push(["NA", "Office", sheets[i], dailyhours, jobdate]);
}
}
}
}
if (array[0]) {
scripts.getRange(scripts.getLastRow() + 1, 1, array.length, 5).setValues(array);
}
SpreadsheetApp.flush();
}

chartjs how to apply after animation

trying to extend a chart, so that i can draw lines up to the data point, but this is happening before the default animation. it would look smoother if it applied after.
i have got most of it to work.. but how do i get this to apply after chart animation.
var originalLineDraw = Chart.controllers.line.prototype.draw;
Chart.helpers.extend(Chart.controllers.line.prototype, {
draw: function () {
originalLineDraw.apply(this, arguments);
var chart = this.chart;
var ctx = chart.chart.ctx;
var index = chart.config.data.lineAtIndex;
if (index) {
var xaxis = chart.scales['x-axis-0'];
var yaxis = chart.scales['y-axis-1']
var points = this.chart.getDatasetMeta(this.index).data;
for (var i = 0; i < points.length; i++) {
// var point_x = points[i]._model.x;
var point_y = points[i]._model.y;
ctx.beginPath();
ctx.setLineDash([5, 5]);/*dashes are 5px and spaces are 3px*/
ctx.moveTo(xaxis.getPixelForValue(undefined, i), point_y);
ctx.strokeStyle = '#fff';
ctx.lineTo(xaxis.getPixelForValue(undefined, i), yaxis.bottom);
ctx.stroke();
}
}
}
});
Update...
altho the darw is incorrect it still is playing after animation
var verticalLinePlugin = {
renderVerticalLine: function (chartInstance) {
var chart = chartInstance;
var ctx = chart.chart.ctx;
var maxpoint = [];
//loop the datasets
for (var y = 0; y < chart.config.data.datasets.length; y++) {
var dataset = chart.config.data.datasets[y];
if (dataset.hidden)
continue;
var points = chart.getDatasetMeta(y).data;
for (var i = 0; i < points.length; i++) {
var point_y = points[i]._model.y;
if (point_y < 0)
continue;
var point = maxpoint[i];
if (point == undefined) {
maxpoint.push({ id: i, y: point_y });
} else {
if (point.y > point_y) {
point.y = point_y;
}
}
}
}
var xaxis = chart.scales['x-axis-0'];
var yaxis = chart.scales['y-axis-1']
chart.data.datasets.forEach(function (dataset, i) {
var ds = dataset;
var meta = chart.getDatasetMeta(i);
meta.data.forEach(function (element, index) {
var value = maxpoint[i];
ctx.beginPath();
ctx.setLineDash([5, 5]);
ctx.moveTo(xaxis.getPixelForValue(undefined, i), value.y);
ctx.strokeStyle = '#fff';
ctx.lineTo(xaxis.getPixelForValue(undefined, i), yaxis.bottom);
ctx.stroke();
});
});
},
afterRender: function (chart) {
this.renderVerticalLine(chart);
}
};
Chart.plugins.register(verticalLinePlugin);
I made some small changes (non-intuitive!), and the vertical lines now appear after the animation.
Get the x values from the metadata instead of the data.
Either:
var x_point = element._model.x;
or:
var position = element.tooltipPosition();
var x_point = position.x;
Wrap the drawing in if(!hidden){}, then the vertical lines will disapear and reappear with the data. (The ternary assignment fixes a clash if the data starts hidden)
Do you need the value=max[i]? If just drawing the line up to the points, can get the y_point the same as for x.
var xaxis = chart.scales['x-axis-0'];
var yaxis = chart.scales['y-axis-1'];
chart.data.datasets.forEach(function (dataset, i) {
var meta = chart.getDatasetMeta(i);
var hidden = (meta.hidden != undefined) ? meta.hidden : dataset.hidden
if(!hidden){
meta.data.forEach(function (element, index) {
//var value = maxpoint[i];
var x_point = element._model.x;
var y_point = element._model.y;
ctx.beginPath();
ctx.save();
ctx.setLineDash([5, 5])
ctx.strokeStyle = '#fff';
ctx.moveTo(x_point, y_point); // or value.y
ctx.lineTo(x_point, yaxis.bottom)
ctx.stroke();
ctx.restore();
});
}
});

How to display data value on selected graph only, in a mixed chart? (ChartJS)

I have a mixed chart of bar and line graphs. Both are showing their data labels but I only want the bar graph to show its own data labels and not the line graph.
I've got this code from How to show data values or index labels in ChartJs (Latest Version)
How should I tweak it?
animation: {
onComplete: function() {
var ctx = this.chart.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
ctx.fillStyle = "white";
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
this.data.datasets.forEach(function (dataset)
{
for( var i = 0; i < dataset.data.length; i++ )
{
for(var key in dataset._meta)
{
var model = dataset._meta[key].data[i]._model;
ctx.fillText(dataset.data[i], model.x, model.y+15);
}
}
});
}
}