Represent Stripe Charge Amount and Date with Chart.js - ruby-on-rails

My code comes from this and Im displaying the data with chart.js inside of a React component. Im using Rails 4. In the controller, the charge props comes out as: #charges = charges_by_date = {}.as_json
jsx:
var ctx = document.getElementById("moneyHistory");
var hash = this.props.charges;
var amount = [];
var d = [];
var chargeDate = Object.keys(hash).forEach(function(k) {
var cost = hash[k];
var date = moment(k).format("Do MMM");
amount.push(cost);
d.push(date);
});
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: d.sort(),
datasets: [{
label: 'Amount',
data: amount.sort(),
backgroundColor: 'rgba(0, 126, 255, 0.72)',
borderColor: '#1b6ac9',
width: 100
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
},
render: function() {
return(
<div>
<canvas id="moneyHistory" width="400" height="150"></canvas>
</div>
)
}
Chart displays great but I want to have 7 days on the graph (today + 6 days ago). I want to replace the hash dates with:
var staticDates = [
moment().subtract(6, 'days').format("Do MMM"),
moment().subtract(5, 'days').format("Do MMM"),
moment().subtract(4, 'days').format("Do MMM"),
moment().subtract(3, 'days').format("Do MMM"),
moment().subtract(2, 'days').format("Do MMM"),
moment().subtract(1, 'days').format("Do MMM"),
moment().subtract(0, 'days').format("Do MMM")
];
...
data: {
labels: staticDates,
...
Now, I need to associate those charge with those date. How to achieve this?
Edit:
I'd like this dates on the graph to be like this where today's date (30th Apr) always be on the right:

I don't think you want to do all this date processing in Javascript. Let Ruby/Rails do the heavy lifting for you.
Suppose you have a method that maps charges to a date, where each key in the hash is a day and the value is a count:
def each_stripe_charge_for_customer(customer_id, created)
starting_after = nil
loop do
customer_charges = Stripe::Charge.all customer: customer_id,
created: created,
limit: 100,
starting_after: starting_after
break if customer_charges.none?
customer_charges.each do |charge|
yield charge
end
starting_after = customer_charges.data.last.id
end
end
def daily_charges_for_customer(customer_id, created=nil)
charges_by_date = Hash.new(0)
# For each Stripe charge, store the date and amount into a hash.
each_stripe_charge_for_customer(customer_id, created) do |stripe_charge|
# Parses Stripe's timestamp to a Ruby date object. `to_date` converts a DateTime object to a date (daily resolution).
charge_date = Time.at(stripe_charge.created).to_date
charge_amount = stripe_charge.amount
charges_by_date[charge_date] += charge_amount
end
charges_by_date
end
So now, daily_charges_for_customer(customer_id, 1.week.ago.to_i) returns something like:
{
'19 Jan' => 10,
'20 Jan' => 20
}
You should cache this result whenever possible so you're not constantly hitting the Stripe API
Now, you can pass this as a data-attribute within the DOM:
In your view:
<%= content_tag :canvas, "", id: "myChart", width: "400", height: "200", data: { charges: daily_charges_for_customer(customer_id, 1.week.ago.to_i) } %>
This will simplify your javascript considerably:
In your JS code:
var ctx = $("#moneyHistory");
var cumulative_daily_charges = ctx.data("charges");
var date_labels = Object.keys(cumulative_daily_charges);
var daily_charges = date_labels.map(function(v) { return cumulative_daily_charges[v]; });
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: date_labels,
datasets: [{
label: 'Date',
data: daily_charges
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
I'm writing this sort of "off the cuff" so you may need to fix some typos/syntax errors, but the logic and major nuts-and-bolts should work. Let me know if you run into any issues.
EDIT
Also, I don't think amount.sort() and d.sort() will act as you expect them to. If they're separate arrays, they'll be sorted independently.

Related

How to display grouped bar chart using chart.js?

I am currently building a grouped bar chart, with two different datasets using chart.js. The code in the component.js file is as follows:
createChart(){
var lbls = ['Selling', 'Cost', 'Gross'];
var curYearData = [2345, 1234, 1111];
var preYearData = [3456, 2345, 1111];
var ctx = document.getElementById(‘barChart') as HTMLCanvasElement;
var barChart = new Chart(ctx, {
type: 'bar',
data: {
labels: lbls,
datasets: [
{
label: ‘2020',
data: curYearData,
backgroundColor: 'blue',
},
{
label: ‘2019',
data: preYearData,
backgroundColor: 'red',
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
However, I see no data displayed and instead I get an empty screen. How to create a grouped bar chart in chart.js?
There are two problems in your code.
First you don't correctly retrieve the 2D-Context.
var ctx = document.getElementById('barChart').getContext('2d');
Further you have some strange apostrophes that need to be changed.
Please have a look at your amended code below.
var lbls = ['Selling', 'Cost', 'Gross'];
var curYearData = [2345, 1234, 1111];
var preYearData = [3456, 2345, 1111];
var ctx = document.getElementById('barChart').getContext('2d');
var barChart = new Chart(ctx, {
type: 'bar',
data: {
labels: lbls,
datasets: [{
label: '2020',
data: curYearData,
backgroundColor: 'blue',
},
{
label: '2019',
data: preYearData,
backgroundColor: 'red',
}
]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="barChart"></canvas>

How to create a chart in MVC Having three values to show

I am new in MVC 5, not having much idea about creating chart.
i need to create a chart which will show the Four values from a table as such below FormatName,Month,SuccessCount, FailCount .
I want to show success and Failcount on the basis of Month for each Format.
Formats are client names.
I tried with several sites , but no idea how to show the three values.
Month FormatName SuccessCount FailedCount
Jan HPCL 20 32
Feb FG 23 0
Mar abcd 13 34
Apr Test 12 23
Above is the table which i want to show on chart.Unfortunately i cannot add image as it is not permitted yet on stackoverflow.
I have used below method to show the data in chart.
`public List BindFormatByMonth(string status)
{
DataTable dt1 = new DataTable();
DataTable dt2 = new DataTable();
dt1 = PBMSCommon.Database.ExecuteDataSet("usp_sel_DedupeDetails", status).Tables[0]; // success records
List ochartmodel = new List();
foreach (DataRow row in dt1.Rows)
{
FormatStatus omodel = new FormatStatus();
omodel.FormatName = Convert.ToString(row["NVFormatCode"]);
omodel.month = Convert.ToString(row["Month"]);
omodel.successCount = Convert.ToInt32(row["Status"]);
ochartmodel.Add(omodel);
}`
any help will be appreciated.
Pooja
You can use vertical bar chart for your requirement. I will suggest you to use chart.js. It responsive and user friendly.
So I have added a fiddler here! It would be use full to you!
Fiddle
Html:
<canvas id="myChart" width="400" height="400"></canvas>
Javascript:
var ctx = document.getElementById("myChart").getContext("2d");
var data = {
labels: ["Jan", "Feb", "Mar"],
datasets: [{
label: "HPCL",
backgroundColor: "skyblue",
data: [20, 32, 12]
}, {
label: "FG ",
backgroundColor: "maroon",
data: [23, 10, 15]
}, {
label: "abcd",
backgroundColor: "green",
data: [13, 34, 16]
}, {
label: "test",
backgroundColor: "violet",
data: [12, 23, 16]
}]
};
var myBarChart = new Chart(ctx, {
type: 'bar',
data: data,
options: {
barValueSpacing: 20,
scales: {
yAxes: [{
ticks: {
min: 0,
}
}]
}
}
});
Fiddle

Export data from jqxgrid

I want to export all data in my jqxgrid into json and send it to another page via AJAX.
My problem is when I click export button, the data in the grid and data before export was not the same. It change float number to Interger. Here is my code:
Javascript:
$('#export_bt').on('click', function(){
var row = $("#jqxgrid").jqxGrid('exportdata', 'json');
$('#debug').html(row);
console.log(row);
});
var tableDatas = [
{"timestamp":"06:00:00","A":99.49,"B":337.77,"C":155.98},
{"timestamp":"07:00:00","A":455.67,"B":474.1,"C":751.68},
{"timestamp":"08:00:00","A":1071.02,"B":598.14,"C":890.47}
];
var tableDatafields = [
{"name":"timestamp","type":"string"},
{"name":"A","type":"number"},
{"name":"B","type":"number"},
{"name":"C","type":"number"}
];
var tableColumns = [
{"text":"Times","datafield":"timestamp","editable":"false","align":"center","cellsalign":"center","width":150},
{"text":"A","datafield":"A","editable":"false","align":"center"},
{"text":"B","datafield":"B","editable":"false","align":"center"},
{"text":"C","datafield":"C","editable":"false","align":"center"}
];
function setTableData(table_data,table_column,table_datafields)
{
sourceTable.localdata = table_data;
sourceTable.datafields = table_datafields;
dataAdapterTable = new $.jqx.dataAdapter(sourceTable);
$("#jqxgrid").jqxGrid({columns:table_column});
$("#jqxgrid").jqxGrid('updatebounddata');
$('#jqxgrid').jqxGrid('sortby', 'timestamp', 'asc');
$("#jqxgrid").jqxGrid('autoresizecolumns');
for(var i=0;i<table_column.length;i++){
$('#jqxgrid').jqxGrid('setcolumnproperty',table_column[i].datafield,'cellsrenderer',cellsrenderer);
}
}
var cellsrenderer = function (row, columnfield, value, defaulthtml, columnproperties) {
if (value||value===0) {
return value;
}
else {
return '-';
}
};
var sourceTable ={ localdata: '', datatype: 'array'};
var dataAdapterTable = new $.jqx.dataAdapter(sourceTable);
dataAdapterTable.dataBind();
$("#jqxgrid").jqxGrid({
width: '500',
autoheight:true,
source: dataAdapterTable,
sortable: true,
columnsresize: false,
selectionmode: 'none',
columns: [{ text: '', datafield: 'timestamp', width:'100%' , editable: false, align:'center'}]
});
setTableData(tableDatas,tableColumns,tableDatafields);
Html:
<div id="jqxgrid"></div>
<button id="export_bt">Export</button>
<div id="debug"></div>
http://jsfiddle.net/jedipalm/jHE7k/1/
You can add the data type in your source object as below.
datafields: [{ "name": "timestamp", "type": "number" }]
And also I suggest you to apply cellsformat in your column definition.
{ text: 'timestamp', datafield: 'timestamp', cellsalign: 'right', cellsformat: 'd' }
The possible formats can be seen here.
Hope that helps
You can export data in very fast way just like it is id jqxGrid with
var rows = $("#jqxGrid").jqxGrid("getrows");
It will be json array.

Custom YTD Option in HighStock Range Selector

Using the Highstock charting library, Is there any way using the Highstock Range selector to display a custom YTD option?
Current when you use a type of 'ytd' in the range selector, it defaults to using the calendar year. For my use case (and i would have thought for financial institutions as well) i need to display data running from 1st April - 31st March as a 'ytd' option
It's probably not possible without hacking sources, find in Highstock:
else if (type === 'ytd') {
now = new Date(dataMax);
year = now.getFullYear();
newMin = rangeMin = mathMax(dataMin || 0, Date.UTC(year, 0, 1));
now = now.getTime();
newMax = mathMin(dataMax || now, now);
}
So as you can see, dates are hardcoded. You can change them to needed.
Here's how i've done it. Doesn't cope with looking at a previous Financial YTD (Which is a common use case for what i need it for), but i'm sure i could hack something up to do it.
JSFiddle here
$(function() {
var startDate = new Date("April 01, 2012 00:00:00");
var today = new Date();
var count = parseInt((today.getTime() - startDate)/(24*3600*1000)) -1;
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=aapl-c.json&callback=?', function(data) {
// Create the chart
window.chart = new Highcharts.StockChart({
chart : {
renderTo : 'container'
},
rangeSelector : {
selected: 1,
buttonTheme: {
width:100
},
buttons: [{
type: 'ytd',
count: 1,
text: 'Calendar YTD'
},
{
type: 'day',
count: count,
text: 'Financial YTD'
}]
},
title : {
text : 'AAPL Stock Price'
},
series : [{
name : 'AAPL',
data : data,
tooltip: {
valueDecimals: 2
}
}]
} );
});
});

Flot won't Plot (Ruby)

I'm playing around with FLOT with Ruby and I'm having a hard time passing the code to javascript; I know my javascript isn't reading the data correctly from Ruby. I need some syntax help.
o={};
o= {'label' => "A", 'data' => #example.collect{|x| [Time.utc(x.date).to_i, x.num]}}
render :text => o.to_json
I have successfully rendered the output as such:
{"label":"A","data":[[1281225600,1.31],[1281225600,1.31],[1281225600,1.25]]}
The HTML outputs this data only.
My javascript is as follows:
var obj = jQuery.parseJSON(text);
var options = {
lines: { show: true },
points: { show: true },
xaxis: { mode: "time", timeformat: "%m/%d/%y", minTickSize: [1, "day"]}
};
var data = obj;
$.plot(placeholder,[data],options);
}
What you are missing is that Ruby puts out timestamps in the Unix format (i.e. seconds since the epoch 1281225600). Flot requires javascript timestamps, which count the milliseconds since the epoch, i.e. 1281225600*1000.
So in your Ruby code, your best bet is to do something like this:
o={};
o= {'label' => "A", 'data' => #example.collect{|x| [Time.utc(x.date).to_i*1000, x.num]}}
render :text => o.to_json
Or if you prefer, you could loop over the obj.data and do the multiplication on the Javascript side:
for (i=0;i<obj.data.length;i++){
obj.data[i] = obj.data[i]*1000;
}
Ok I got it....
Ruby code:
#o={};
#o= {'label' => "A", 'data' => #example.collect{|x| [Time.utc(x.date).to_i, x.num]}}
Java code:
$(function () {
var obj = <%= #o.to_json %>;
var options = {
lines: { show: true },
points: { show: true },
xaxis: { mode: "time", timeformat: "%m/%d/%y", minTickSize: [1, "day"]}
};
var data = obj;
$.plot(placeholder,[data],options);
});

Resources