Show analytics of registered users for last 12 months using chart - javascript

I'm trying to get all users for the last 12 months from database and show some statistics using chart.For that purpose I'm using chartJS.
$registeredUsersData = $connection->fetchAll(
'SELECT
COUNT(id) AS registered_users,
CONCAT(MONTHNAME(created_on), " ", YEAR(created_on)) AS created_on
FROM users
WHERE created_on
BETWEEN CURDATE() - INTERVAL 12 MONTH AND CURDATE()
GROUP BY YEAR(created_on), MONTH(created_on)
ORDER BY YEAR(created_on) DESC, MONTH(created_on) DESC;
');
We pass it by symfony controller and render html template.
$registeredUsersCount = array_column($registeredUsersData, 'registered_users');
$registeredUserMonths = array_column($registeredUsersData, 'created_on');
return $this->render('dashboard/admin/index.html.twig', [
'registered_users_count' => $registeredUsersCount,
'registered_users_months' => $registeredUserMonths
]);
In the template I'm trying to display using a bar diagram that data where year and month should be combined and display on the abscissa(X-axis) and the count respectively on the ordinate(Y-axis).
<div class="chart-container">
<canvas id="canvas"></canvas>
</div>
let months = {{ registered_users_months|json_encode|raw }};
let users = {{ registered_users_count|json_encode|raw }};
const ctx = document.getElementById('canvas').getContext('2d');
const myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: months,
datasets: [{
label: 'Registered Users Monthly',
data: users,
backgroundColor: 'rgba(90, 80, 191, 0.2)',
borderColor: 'rgba(90, 80, 191, 1)',
borderWidth: 1
}]
},
options: {
maintainAspectRatio: false,
responsive: true,
scales: {
yAxes: [{
ticks: {
beginAtZero: true
},
}]
}
}
});
Data is properly displayed but not all "previous" 12 months are displayed.If a month does not have registered users it must be displayed as well but with count of zero. Unfortunately, the given query does not support that function currently, how could I modify it?

You need to make changes in your query like below:
$start = new DateTime(date('Y-m-d'));
$end = new DateTime(date('Y-m-d'));
$end->modify('+12 month');
$interval = DateInterval::createFromDateString('1 month');
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $dt) {
$registeredUsersData[$dt->format('Y-m')] = 0;
}
$registeredUsersData = $connection->fetchAll(
'SELECT
COUNT(id) AS registered_users,
DATE_FORMAT(created_on,'%Y-%m') AS created_on
FROM users
WHERE created_on BETWEEN CURDATE() - INTERVAL 12 MONTH AND CURDATE()
GROUP BY DATE_FORMAT(created_on,'%Y-%m')
ORDER BY DATE_FORMAT(created_on,'%Y-%m') DESC;
');
foreach($registeredUsersData as $registeredUser) {
$registeredUsersData[$registeredUser['created_on']] = $registeredUser['registered_users'];
}
return $this->render('dashboard/admin/index.html.twig', [
'registered_users_count' => array_values($registeredUsersData),
'registered_users_months' => array_keys($registeredUsersData)
]);
I also updated your PHP have all dates for 12 months

I am more of a caveman coder than eloquent, but I believe this gets the result set you are looking for without changing your query... add this after your query to send the new data set to your controller.
for ($i = 1; $i < 12; $i++) {
$monthToCheck[$i]['registered_users'] = 0;
$monthToCheck[$i]['month_of_creation'] = date("F", strtotime( date( 'Y-m-01' )." -$i months"));
$monthToCheck[$i]['year_of_creation'] = date("Y", strtotime( date( 'Y-m-01' )." -$i months"));
}
return (array_merge($registeredUsersData,$monthToCheck));

Related

Filling ApexCharts in Vue3 from an array

I'm not able to fill a Chart with my Array.
This is the Json: https://pastebin.com/KLUWqDFS
I'm trying to create a "Area" chart and fill it. Each element in the Json is half an hour.
let series = []
for(let i = 0; i < props.rrd.length; i++) {
series.push({
data: [
{
x: props.rrd[i].cpu * 100,
y: moment(props.rrd[i].time).format('hh:mm')
}
]
})
}
const chartOptions = {
yaxis: {
show: true
},
xaxis: {
show: true
}
}
This is what I'm using. Somehow all I get is this:
My Result
Eventhough it should show me the last 24 hours in the chart.

Using Numeral.js to round JSON numbers in %

I am fetching json data from a API and I have to display some of the numbers as %. The json data displays them as 0.00. I tried this method, but it didn't work. I want to use a url to fetch my data, and then use Numeral.js to make the filtered data I got in %. What am I doing wrong? I create a template for my graph. I then make a fetch request to get my data and filter it, so I get the values I need. Then I take that value and try to format it. The new value I want to put on the graph.
const data = {
labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
datasets: [
{
label: "ADOPTION",
data: [18, 12, 6, 9, 12, 3, 9],
backgroundColor: "rgba(73, 117, 197, 1)",
borderColor: "rgba(73, 117, 197, 1)"
},
{
label: "Target",
data: [0.654, 0.654, 0.751],
backgroundColor: "rgba(236, 123, 46, 1)",
borderColor: "rgba(236, 123, 46, 1)"
}
]
};
// config for graph
const config = {
type: "line",
data: data,
options: {
plugins: {
title: {
display: true,
text: 'data'
},
},
scales: {
y: {
beginAtZero: true
}
}
}
};
// render init block
const myChart = new Chart(
document.getElementById("data"),
config
);
// Fethc block for the graph
async function fetchJSON() {
const url="link";
const response = await fetch(url);
//* loads waiting to complete the request
const datapoints = await response.json();
return datapoints;
}
fetchJSON().then((datapoints) => {
const month = datapoints.map(function (index) {
return index.PERIOD_NAME; //*reffers to jSon word from file
});
console.log(month);
myChart.config.data.labels = month;
myChart.update();
});
fetchJSON().then((datapoints) => {
const total = datapoints.map(function (index) {
return index.ADOPTION //*reffers to jSon word from file
});
var string = numeral(datapoints).format('0.000%');
console.log(string);
myChart.config.data.datasets[0].data = total;
myChart.update();
});
<div class="col-sm-12 col-md-4 col-lg-4">
<canvas id="data"></canvas>
</div>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/chart.js"></script>
I'm guessing datapoints is an array. Numeral takes numbers or strings that it trys to convert into a number. You can use datapoints.map(val => numeral(val).format('0.00%')) to format the datapoints elements.

ChartJS x-axis show only months of year

So I'm making this mobile app using Cordova, which allows me to use HTML, CSS and JavaScript. I'm currently using SQLite as a database (works almost same as mySQL) but that isn't that important. All I do is get my data from that database. I get both the date (of when the data was added to the Database) and the weight of a person.
I'm using a linegraph which show the weight on the Y-axis and the data on the X-axis.
What I want to do is only show the months as labels on the x-axis but still make it so that it show data for each day seperate. So for example if I add data on the 1st of January, the 2nd of January and the 3rd of January. I want to be able to see all 3 days as dots on my graph but on the X-axis it should only say 'January'.
I've been looking into the 'time' option of Chart.JS but can't really make any sense of how I'm supposed to do it.
HTML:
<canvas id="myChart" style="margin-top: 20px;"></canvas>
JavaScript:
//these are the arrays that I will fill dynamically. Labels will be my months and data will be the weight
var labels = [];
var data = [];
var ctx = document.getElementById('myChart').getContext('2d');
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'line',
// The data for our dataset
data: {
labels: labels,
datasets: [{
backgroundColor: 'rgba(255, 119, 0, 0.5)',
borderColor: 'rgba(255, 119, 0, 1)',
data: data
}]
},
// Configuration options go here
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
Use the time-type in your x-axis. With time: { unit: 'month' } (always months) or minUnit (months and years if necessary) you can get the month labels.
As label for your data you need to pass a Date or moment
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'month'
}
}],
}
Here is a complete example.
Check the moment docs for dates, especially the creation and parsing of dates. Chart.js works with moment dates so it's quite important (and quite easy btw).

JSON api timestamp + data parsing

I'm making a chart using Highcharts.js
The API I'm using has a different output than what Highchart uses.
Highchart reads JSON data as [timestamp, data]
which looks something like this: [1512000000000,171.85],
furthermore, the rest of the data is parsed within the same call.
Now MY Api outputs data by a single call for each timestamp (via url &ts=1511929853 for example
outputs {"ENJ":{"USD":0.02154}} (the price for that point in time)
Now here's where things get complicated. I would need to parse the price from a certain date, till now.
I've already made a ++ variable for the timestamp, but how would I include the timestamp and the price for that timestamp within the array for the data output.
It's a bit confusing, as the calls would have to be repeated so many times to draw a historical graph of the price. Some help would be appreciated. If you need more clarification, I'm right here.
Data is parsed via data function
full code here
var startDate = 1511929853;
var endDate = Math.floor((new Date).getTime()/1000);
function count() {
if (startDate != endDate) {
startDate++
}
else {
return false;
}
};
count();
$.getJSON('https://min-api.cryptocompare.com/data/pricehistorical?fsym=ENJ&tsyms=USD&ts=' + startDate, function (data) {
// Create the chart
var enjPrice = `${data.ENJ.USD}`;
console.log(enjPrice);
Highcharts.stockChart('container', {
xAxis: {
gapGridLineWidth: 0
},
rangeSelector: {
buttons: [{
type: 'hour',
count: 1,
text: '1h'
}, {
type: 'day',
count: 1,
text: '1D'
}, {
type: 'all',
count: 1,
text: 'All'
}],
selected: 1,
inputEnabled: false
},
series: [{
name: 'AAPL',
type: 'area',
data: JSON.parse("[" + enjPrice + "]"),
gapSize: 5,
tooltip: {
valueDecimals: 2
}
}]
});
});
You can use spread operator, like this,
let var = [new Date().getTime(), { ...data }.ENJ.USD]
This will result [1512000000000, 171.85] as you expected.
You need to make different functions for getting the data and generating the chart. Below is an example of how would you do it.
var startDate = 1511929853;
var endDate = Math.floor((new Date).getTime() / 1000);
var data = [];
function count() {
if (startDate != endDate) {
data.push(getPrice(startDate));
startDate++;
} else {
generateChart();
}
};
count();
function getPrice(timestamp) {
$.getJSON('https://min-api.cryptocompare.com/data/pricehistorical?fsym=ENJ&tsyms=USD&ts=' + startDate, function(data) {
return [timestamp, data.ENJ.USD];
});
}
function generateChart() {
Highcharts.stockChart('container', {
xAxis: {
gapGridLineWidth: 0
},
rangeSelector: {
buttons: [{
type: 'hour',
count: 1,
text: '1h'
}, {
type: 'day',
count: 1,
text: '1D'
}, {
type: 'all',
count: 1,
text: 'All'
}],
selected: 1,
inputEnabled: false
},
series: [{
name: 'AAPL',
type: 'area',
data,
gapSize: 5,
tooltip: {
valueDecimals: 2
}
}]
});
}
Though this is not the best way how you would do it but you get an idea.
I managed to solve the problem, by using a different API, which indexes data for past 30 days. I iterated into each index, 31, of them and grabbed the time and high(price) values and parsed them into a number since I was getting a "string" and then looped them into an array and put them into the final data [array]. just what I needed for the chart to work. If anyone needs any help just ask away. :) PS: Excuse the console.logs as I was using them to debug and test which helped me tremendously, you can remove them, as shall I
$.getJSON('https://min-api.cryptocompare.com/data/histoday?fsym=ENJ&tsym=USD', function(data) {
var x = `${data.Data[0].time}`;
var y = `${data.Data[0].high}`;
console.log(x);
console.log(y);
var tempData = [];
console.log(tempData);
for (var i = 0; i < 31; i++ ) {
var a = `${data.Data[i].time}`;
var b = `${data.Data[i].high}`;
function numberfy(val){
parseFloat(val);
}
a = parseFloat(a);
a = a * 1000;
b = parseFloat(b);
x = [a , b];
tempData.push(x);
};
data = tempData;
console.log(data.length);
Highcharts.stockChart('container', {

PHP MySQL: count views per month for jQuery charts

i work with jQuery chart.js for show view counter by month using PHP and MySql. I insert/Put each views page to MySql like this :
| id | ip | page | date(timestamp) |
| 1 | 138.86.20.20 | test.php | 1375710823 |
| 2 | 100.86.123.10 | test.php | 1380206563 |
for chart.js :
var data = {
labels: ["january","February", "March", "April", "May", "June", "July"],
datasets: [{
fillColor: "rgba(220,220,220,0.5)",
strokeColor: "rgba(220,220,220,1)",
data: [150,59, 90, 81, 56, 55, 40]
}, {
fillColor: "rgba(151,187,205,0.5)",
strokeColor: "rgba(151,187,205,1)",
data: [20,48, 40, 59, 500, 127, 100]
}]
}
var options = {animation :true};
//Get the context of the canvas element we want to select
var c = $('#daily-chart');
var ct = c.get(0).getContext('2d');
var ctx = document.getElementById("daily-chart").getContext("2d");
//Run function when window resizes
$(window).resize(respondCanvas);
function respondCanvas() {
c.attr('width', jQuery("#daily").width());
c.attr('height', jQuery("#daily").height());
//Call a function to redraw other content (texts, images etc)
myNewChart = new Chart(ct).Bar(data, options);
}
//Initial call
respondCanvas();
Now, I need to count views by/per month for chart.js data ouput using json format.
[150,59, 90, 81, 56, 55, 40,12,54,65,365,2] for 12 month strat #january.
How to crate this?!
NOTE: charts datasets have two color : 1- unique user 2- all user
You could use a query to group the visits by month:
SELECT COUNT(*), MONTH(date(timestamp)), YEAR(date(timestamp))
FROM table
GROUP BY MONTH(FROM_UNIXTIME(date(timestamp)), YEAR(FROM_UNIXTIME(date(timestamp))
Which will return the number of visits, with the year and month they correspond to.
\EDIT\
To loop through and print each month's value, use a mysqli_query and WHILE in PHP:
$query = mysqli_query($con, "THE QUERY ABOVE ^^");
while($row = mysqli_fetch_array($query {
echo $row['date(timestamp)'].",";
}

Categories

Resources