I am trying to extract data from one object, restructure and create a new one.
Simplified example for the source object
var res = [{
DateTime: '00:00',
Number: 1,
WeekDay: 1
},
{
DateTime: '00:00',
Number: 4,
WeekDay: 1
},
{
DateTime: '00:00',
Number: 1,
WeekDay: 2
},
{
DateTime: '00:30',
Number: 1,
WeekDay: 2
}]
From here I want to create a new object where "number" is summed by
1. WeekDay
2. Half hour interval
var intervals = ['00:00', '00:30']
var weekdays = [1, 2]
var target = []
var intervalObj = [];
for (i = 0; i < intervals.length; i++) {
intervalObj.push({
interval: intervals[i],
number: 0
})
}
for (i = 0; i < weekdays.length; i++) {
var day = i + 1;
target.push({
day: day,
data: intervalObj,
})
}
And then populate the new object like this:
for(var row in res) {
var dt = res[row].DateTime;
var wd = res[row].WeekDay;
var wdidx = weekdays.indexOf(wd)
var dtidx = intervals.indexOf(dt)
var num = res[row].Number;
target[wdidx].data[dtidx].number += num;
}
This does not work when creating the target object like above. The summed results gets repeated for the same interval over all week days.
However, when object is statically:
var target = [{
day: 1,
data: [{
interval: '00:00',
number: 0
},
{
interval: '00:30',
number: 0
}]
},
{
day: 2,
data: [{
interval: '00:00',
number: 0
},
{
interval: '00:30',
number: 0
}]
}]
It works as expected. I cannot figure out why.
Here is a fiddle example:
https://jsfiddle.net/oceansmoving/wkfL9e3o/
You are using the same array reference intervalObj for data in each instance of loop. Need to create new array for each instance
Change
var intervalObj = [];
for (i = 0; i < weekdays.length; i++) {
var day = i + 1;
target.push({
day: day,
data: intervalObj,
})
}
To
//var intervalObj = [];
for (i = 0; i < weekdays.length; i++) {
var day = i + 1;
target.push({
day: day,
data: [],
})
}
Related
I want to create an app on Vue where I update through a slider a value and the other value get's updated. Something like this:
Can someone give me a helping hand? I'm going insane. I've been trying to get the formula right for the past 3 days.
This is what I've written so far:
updateRarities(trait, raritySlider){
var property = this.currentCollection.properties.items.find(property => property.id === trait.propertyID);
var numOfTraits = property.traits.items.length;
let newRarityCurrentTrait = 1 / numOfTraits * Number(raritySlider);
for (let i = 0; i < property.traits.items.length; i++) {
if (property.traits.items[i].id !== trait.id) {
let updatedTrait = {
id: property.traits.items[i].id,
// calculate the rarity of the other traits
rarity: (1 - newRarityCurrentTrait) * property.traits.items[i].raritySlider,
updatedAt: new Date(),
}
API.graphql(graphqlOperation(mutations.updateTrait, { input: updatedTrait}));
}
else {
let updatedTrait = {
id: trait.id,
rarity: newRarityCurrentTrait,
raritySlider: raritySlider,
updatedAt: new Date(),
}
API.graphql(graphqlOperation(mutations.updateTrait, { input: updatedTrait}));
}
}
}
Ok I figured it out, after messing a bit with Excel:
updateRarities(trait, raritySlider){
var property = this.currentCollection.properties.items.find(property => property.id === trait.propertyID);
// sum of every raritySlider
let sumOfSliders = 0;
for (let i = 0; i < property.traits.items.length; i++) {
sumOfSliders = Number(sumOfSliders) + Number(property.traits.items[i].raritySlider);
}
for (let i = 0; i < property.traits.items.length; i++) {
if (property.traits.items[i].id !== trait.id) {
let updatedTrait = {
id: property.traits.items[i].id,
// calculate the rarity of the other traits
rarity: 1/sumOfSliders*property.traits.items[i].raritySlider,
updatedAt: new Date(),
}
API.graphql(graphqlOperation(mutations.updateTrait, { input: updatedTrait}));
}
else {
let updatedTrait = {
id: trait.id,
rarity: 1/sumOfSliders*raritySlider,
raritySlider: raritySlider,
updatedAt: new Date(),
}
API.graphql(graphqlOperation(mutations.updateTrait, { input: updatedTrait}));
}
}
}
I just needed to sum the value of the sliders.
Seen below is a time series bar graph with a range selector in plotly.js.
In it, I am trying to figure out how to group the values by week, but cannot seem to accomplish this. Is there a setting in plotly.js to group these by week when changing the time range selection? I cannot seem to figure out if it is possible.
Here are the main documentation pages they offer, of which I tried as many settings as I thought pertained to accomplishing this, but could not figure it out.
https://plot.ly/javascript/time-series/
https://plot.ly/javascript/bar-charts/
var days = (function(start,count){
var days = [];
var MSday = 1000 * 60 * 60 * 24;
for(var i = 0; i < count; i++){
days.push(new Date(+start + i*MSday));
}
return days;
})(new Date(2018,0,1),100);
function vals(){
var vals = [];
for(var i = 0; i < 100; i++){
vals.push((Math.random() * 2 * i) | 0);
}
return vals;
}
var selectorOptions = {
buttons: [{
step: 'month',
stepmode: 'backward',
count: 1,
label: '1m'
}, {
step: 'month',
stepmode: 'backward',
count: 6,
label: '6m'
}, {
step: 'year',
stepmode: 'todate',
count: 1,
label: 'YTD'
}, {
step: 'year',
stepmode: 'backward',
count: 1,
label: '1y'
}, {
step: 'all',
}],
};
var trace1 = {
x: days,
y: vals(),
type: 'bar',
name: 'Trace 1'
};
var trace2 = {
x: days,
y: vals(),
type: 'bar',
name: 'Trace 2'
};
var data = [trace1, trace2];
var layout = {
title: 'Bar Demo',
barmode: 'group',
xaxis: {
rangeselector: selectorOptions
}
};
Plotly.newPlot('myDiv', data, layout);
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id="myDiv"><!-- Plotly chart will be drawn inside this DIV --></div>
How can I make the 6 month selection group by week instead of by day on the graph?
Apparently this isn't built in. If it is, or becomes built in at some point, please indicate that here in a comment or another answer.
The only option I was able to determine as viable was to hook into the relayout event using .on('plotly_relayout', function () {, taking the arguments from the range selector buttons (which seem limited, only a from and to date, if there is a better way to determine the origination please also let me know and I will update here), and then roughly based on that to bin the dates by week and adjust the x and y values in the plot.
This is just a basic implementation as proof of concept. Using it in production would require refactoring this code to work with the existing data structures with regards to design and page implementation.
There is a lot going on here. Basically, it will iterate through the set of dates to create sunday bins which will hold the weekly data (note that it still lacks a display update to show it is a week from the start date). Once it has the bins it sums the dates in each bin range. Then it replaces the data set using restyle. If the range selected is not 6m then it will use the a slice of the backup data because plotly modifies arrays in place, and as a result it will overwrite the data if there is no backup copy in addition with a single copy every time the backup is used.
See below for a working demo.
function sum(array){
return array.reduce(function(sum,curr){
return sum + curr;
},0);
};
Date.MSday = 1000 * 60 * 60 * 24;
Date.prototype.floor = function(){
return new Date(this.getFullYear(),this.getMonth(),this.getDate());
}
Date.prototype.addDays = function(days){
var time = +this - +this.floor();
var addedDays = new Date(+this.floor() + Date.MSday*days);
return new Date(+addedDays + time);
}
function weeksFromDates(datesArray, valsArray){
var lastDay = datesArray[datesArray.length -1];
var firstDay = datesArray[0];
var dayOfWeek = firstDay.getDay();
var firstSunday = firstDay.addDays(-dayOfWeek);
var sundays = [];
var currentSunday = firstSunday;
while(currentSunday < lastDay){
sundays.push(currentSunday);
currentSunday = currentSunday.addDays(7);
}
currentSunday = currentSunday.addDays(7);
sundays.push(currentSunday);
var valSets = [];
var n = 0;
for(var i = 1; i < sundays.length; i++){
var last = sundays[i-1];
var next = sundays[i];
var theseVals = [];
for(; n < datesArray.length && last <= datesArray[n] && next > datesArray[n]; n++){
theseVals.push(valsArray[n]);
}
valSets.push(sum(theseVals));
}
sundays.pop();
return {x: sundays, y: valSets};
}
var MSday = 1000 * 60 * 60 * 24;
var days = (function(start,count){
var days = [];
for(var i = 0; i < count; i++){
days.push(new Date(+start + i*MSday));
}
return days;
})(new Date(2018,0,1),100);
function vals(){
var vals = [];
for(var i = 0; i < 100; i++){
vals.push((Math.random() * 2 * i) | 0);
}
return vals;
}
var selectorOptions = {
buttons: [{
step: 'month',
stepmode: 'backward',
count: 1,
label: '1m'
}, {
step: 'month',
stepmode: 'backward',
count: 6,
label: '6m'
}, {
step: 'year',
stepmode: 'todate',
count: 1,
label: 'YTD'
}, {
step: 'year',
stepmode: 'backward',
count: 1,
label: '1y'
}, {
step: 'all',
}],
};
var trace1 = {
x: days,
y: vals(),
type: 'bar',
name: 'Trace 1',
orientation: 'v'
};
var trace2 = {
x: days,
y: vals(),
type: 'bar',
name: 'Trace 2',
orientation: 'v'
};
var data = [trace1, trace2];
var dataBackup = $.extend(true,{},data);
var layout = {
title: 'Bar Demo',
barmode: 'group',
xaxis: {
rangeselector: selectorOptions
}
};
Plotly.newPlot('myDiv', data, layout);
$('#myDiv').on('plotly_relayout', function () {
var lower = new Date(arguments[1]['xaxis.range[0]']);
var upper = new Date(arguments[1]['xaxis.range[1]']);
var dayRange = (+upper - +lower) / MSday;
if( dayRange < 190 && dayRange > 170 ){
//6m
for(var n = 0; n < data.length; n++){
var weekly = weeksFromDates(dataBackup[n].x,dataBackup[n].y);
Plotly.restyle('myDiv',{x:[weekly.x],y: [weekly.y]},n);
}
}else{
for(var n = 0; n < data.length; n++){
Plotly.restyle('myDiv',{x:[dataBackup[n].x.slice()],y: [dataBackup[n].y.slice()]},n);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id="myDiv"><!-- Plotly chart will be drawn inside this DIV --></div>
Blimey! There is a much simpler option...
use 7 days:
step: 'day',
stepmode: 'backward',
count: 7,
label: '1w'
My custom X-axis values are not displayed in flot js.
Code for drawing the line chart as below :
var length = 0;
var length1 = 0;
var dataXY = [];
var data = [];
var dataX = [];
length = allVenues.length;
for (var i = 0; i < length; i++) {
length1 = allVenues[i].length;
for (var j = 0; j < length1; j++) {
dataX.push([j, returnDate(allVenues[i][j].date)]);
dataXY.push([returnTimestamp(allVenues[i][j].date), allVenues[i][j].price, "<b>X</b> : " + returnDate(allVenues[i][j].date) + " | " + " <b>Y</b>: " + allVenues[i][j].price]);
}
}
var result = {'label': 'Demo Graph', 'data': dataXY};
data = [result];
var options = {
lines: {
show: true
},
points: {
show: true
},
xaxis: {
ticks: dataX
},
grid: {
hoverable: true,
clickable: true
},
tooltip: {
show: true,
content: "%s | X: %x | Y: %y"
}
};
function returnTimestamp(val) {
var dateTime = new Date(val);
return moment(dateTime).unix();
}
function returnDate(val) {
var dateTime = new Date(val);
return moment(dateTime).format("YYYY-MM-DD hh:mm:ss A");
}
$.plot("#placeholder", data, options);
dataXY array values are:
{"label":"Demo Graph","data":[[1455776629,12],[1455801889,30],[1455962948,45]]}
dataX array values are:
[[0, "2016-02-18 11:53:49 AM"], [1, "2016-02-18 06:54:49 PM"], [2, "2016-02-20 03:39:08 PM"]]
Now i want to set this "dataX" array as X axis values (ticks) on the chart.
This values display below in each point of line graph with X-Axis.
Here dataX and dataXY from allVenues Json Array.
My graph is woking fine except the X-Axis data. You can see in the image below.
Your dataX array for the ticks must have the same x values (timestamps) as your real data array:
[[1455776629, "2016-02-18 11:53:49 AM"], [1455801889, "2016-02-18 06:54:49 PM"], [1455962948, "2016-02-20 03:39:08 PM"]]
PS: I would also suggest to put a linebreak (<br>) between date and time in the labels.
I am trying to push the objects to an array and the differences of the objects are just one property.
Code snippet:
var categoryList = ['product1', 'product2', 'product3'...more]
var productlist = [];
var date = new Date();
var year = date.getFullYear();
var nextYear = year++
for (var a = 0; a < categoryList.length; a++) {
productList.push({
date: year + '-' + categoryList[a],
'items': [{
'quatity': 0 'type': 'new'
}]
});
productList.push({
date: nextYear + '-' + categoryList[a],
'items': [{
'quantity': 0 'type': 'new',
}]
});
}
I need to add this year and next year to the object but I am not sure if there are any better ways to simplified the above codes. Thanks for the help!
With your current code you will (currently) end up with year == 2015 and nextYear == 2014. I think that you meant to do this:
var nextYear = year + 1;
You can refactor the code to use a function to add items to the product list. (I assume that the quatity property is just a typo, so that the only difference is the year.)
function addProduct(year, product) {
productList.push({
date: year + '-' + product,
items: [{
quantity: 0,
type: 'new'
}]
});
}
for (var a = 0; a < categoryList.length; a++) {
addProduct(year, categoryList[a]);
addProduct(nextYear, categoryList[a]);
}
You could do this;
function addProduct(prodDate) {
productList.push({
'date':prodDate,
'items' : [ {
'quatity' : 0,
'type' : 'new'
} ]
});
}
for (var a=0; a < categoryList.length; a++) {
addProduct(year + '-' + categoryList[a]);
addProduct(nextYear + '-' + categoryList[a]);
}
I have this json which i need to work with amCharts line chart,
var chartData = [{
date: "2009/10/2",
value: 5,
name: 5
}, {
date: "2009/10/3",
value: 15,
name: 5
}, {
date: "2009/10/4",
value: 13,
name: 10
}, {
date: "2009/10/5",
value: 17,
name: 30
}, {
date: "2009/10/6",
value: 15,
name: 5
}, {
date: "2009/10/7",
value: 19,
name: 5
}];
in order to be compatible with amCharts i need to assign date value as a Date object so i did through the following function,
function parseDate(){
for( var i = 0; i < chartData.length; ++i ) {
var dateArray = chartData[i]["date"].split("/");
chartData[i]["date"] = new Date(Number(dateArray[0]), Number(dateArray[1])-1, Number(dateArray[2]));
window.alert(chartData[i]["date"]);//for debugging purposes
}
return chartData;
}
But still i get an empty graph with no lines.. :( but if i hard code the json as follows,
var chartData = [{
date: new Date(2009, 10, 2),
value: 5,
name: 5
}, {
date: new Date(2009, 10, 3),
value: 15,
name: 5
}, {
date: new Date(2009, 10, 4),
value: 13,
name: 10
}, {
date: new Date(2009, 10, 5),
value: 17,
name: 30
}, {
date: new Date(2009, 10, 6),
value: 15,
name: 5
}, {
date: new Date(2009, 10, 7),
value: 19,
name: 5
}];
The chart is displayed ,Please help me on this one.
Thank you very much :)
EDIT: CODE TO GENERATE GRAPH (FYI)
AmCharts.ready(function () {
parseDate();
// SERIAL CHART
chart = new AmCharts.AmSerialChart();
chart.pathToImages = "../amcharts/images/";
chart.zoomOutButton = {
backgroundColor: '#000000',
backgroundAlpha: 0.15
};
chart.dataProvider = chartData;
chart.categoryField = "date";
// listen for "dataUpdated" event (fired when chart is inited) and call zoomChart method when it happens
chart.addListener("dataUpdated", zoomChart);
// AXES
// category
var categoryAxis = chart.categoryAxis;
categoryAxis.parseDates = true; // as our data is date-based, we set parseDates to true
categoryAxis.minPeriod = "DD"; // our data is daily, so we set minPeriod to DD
categoryAxis.dashLength = 2;
categoryAxis.gridAlpha = 0.15;
categoryAxis.axisColor = "#DADADA";
var i = 0;
for (var key in chartData[0]) {
if (key != 'date') {
var valueAxis = new AmCharts.ValueAxis();
valueAxis.offset = i * 40;
valueAxis.dashLength = 4;
valueAxis.axisColor = "#FF6600";
valueAxis.axisAlpha = 0;
chart.addValueAxis(valueAxis);
// GRAPH
var graph = new AmCharts.AmGraph();
graph.valueAxis = valueAxis; // we have to indicate which value axis should be used
graph.type = "line";
graph.title = "infection # " + i;
graph.valueField = key;
graph.customBullet = "images/star.gif"; // bullet for all data points
graph.bulletSize = 14; // bullet image should be a rectangle (width = height)
graph.customBulletField = "customBullet"; // this will make the graph to display custom bullet (red star)
chart.addGraph(graph);
}
i = i + 1;
}
// CURSOR
var chartCursor = new AmCharts.ChartCursor();
chartCursor.cursorPosition = "mouse";
chart.addChartCursor(chartCursor);
// SCROLLBAR
var chartScrollbar = new AmCharts.ChartScrollbar();
chart.addChartScrollbar(chartScrollbar);
// LEGEND
var legend = new AmCharts.AmLegend();
legend.marginLeft = 110;
chart.addLegend(legend);
// WRITE
chart.write("chartdiv");
});
Try this:
function parseDate() {
for( var i = 0; i < chartData.length; ++i )
chartData[i]["date"] = new Date(chartData[i]["date"]);
return chartData;
}