ctmf:
I might have done what you’re trying to do in regards to graphing some statistics over time, and maybe you’d have fun replicating some of it.
I pull the API down into InfluxDB, then I have a little PHP + Chart.js front-end I use to look at it. Here’s all the code
PHP Script - WaniKani API to InfluxDB
This file is on a cron-job every 6 hours and pulls down my statistics and pops them into a local instance of InfluxDB. You’ll need to set the WANIKANI_API_KEY environment variable.
<?php
/**
* Pulls down Wanikani API data and installs it into the local InfluxDB instance
*/
function pullWaniKaniData() {
$apiKey = getenv('WANIKANI_API_KEY');
try {
$wanikaniCurl = curl_init();
} catch (Exception $e) {
echo "Curl Initialization failed! Ensure php-curl is installed.\n";
exit;
}
curl_setopt($wanikaniCurl, CURLOPT_URL, "https://www.wanikani.com/api/user/$apiKey/srs-distribution");
curl_setopt($wanikaniCurl, CURLOPT_RETURNTRANSFER, 1);
try {
$output = curl_exec($wanikaniCurl);
$jsonData = json_decode($output, true)['requested_information'];
} catch (Exception $e) {
echo "Exception!" . $e->getMessage();
}
curl_close($wanikaniCurl);
return $jsonData;
}
/**
* Adds skill-levels and item count to the wanikani InfluxDB Database
* @param $wkSrsDistribution The key-value set of skill->counts data from WaniKani API v1.4
* This is the data encoded in the requested_information object.
* @return $dataString string The String used as a POST request to the InfluxDB Backend
*/
function buildInfluxPostString($wkSrsDistribution) {
$dataPoints = array();
foreach ($wkSrsDistribution as $skillLevel=>$counts) {
if (isset($counts['total'])) {
array_push($dataPoints, "$skillLevel=" . $counts['total']);
}
}
$dataString = 'progress ' . implode(',', $dataPoints);
return $dataString;
}
/**
* Creates a new entry in the influxDB Database for Wanikani statistics.
*
* @param $influxPostString string The formatted POST data to create a new entry
* This should be formatedw ith the buildInfluxPostString function
*/
function insertInfluxEntry($influxPostString) {
try {
$influxCurl = curl_init();
} catch (Exception $e) {
echo "Curl Initialization failed! Ensure php-curl is installed.\n";
exit;
}
print_r($influxPostString);
curl_setopt_array($influxCurl, array(
CURLOPT_URL => "http://localhost:8086/write?db=wanikani",
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $influxPostString,
CURLOPT_HEADER => 1,
CURLOPT_HTTPHEADER => array(
"Content-Type: text/plain",
"cache-control: no-cache"
),
));
try {
$output = curl_exec($influxCurl);
print_r($influxCurl);
} catch (Exception $e) {
echo "Exception!" . $e->getMessage();
}
curl_close($influxCurl);
}
/*****************************************************************************
* MAIN
****************************************************************************/
$jsonData = pullWaniKaniData();
$influxPostString = buildInfluxPostString($jsonData);
echo insertInfluxEntry($influxPostString);
PHP Backend for API Endpoint
This file sits on my webserver and is requested by the javascript front-end via GET request. I’m sure someone will cry at that sort function but hey, I was lazy…
<?php
/**
* Queries the influxDB and loads the JSON into a chartsJS compatible format
*/
function queryInfluxDb() {
try {
$influxCurl = curl_init();
} catch (Exception $e) {
echo "Curl Initialization failed! Ensure php-curl is installed.\n";
exit;
}
$query = urlencode("SELECT * FROM progress");
curl_setopt_array($influxCurl, array(
CURLOPT_URL => "http://localhost:8086/query?pretty=true&db=wanikani&q=" . $query,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_HTTPHEADER => array(
"cache-control: no-cache"
),
));
try {
$output = json_decode(curl_exec($influxCurl), True);
} catch (Exception $e) {
echo "Exception!" . $e->getMessage();
}
curl_close($influxCurl);
return $output['results'][0]['series'][0];
}
function generateChartData($influxQueryResult) {
$labels = array();
$datasets = array();
$labelMap = $influxQueryResult['columns'];
$colorMap = array('', '#dd0093', '#e49900', '#0093dd', '#882d9e', '#294ddb');
// Initialize Datasets - Skip Column 0
for( $i = 1; $i < sizeOf($influxQueryResult['columns']); $i++) {
$datasets[$i] = array(
"label" => $labelMap[$i],
"data" => array(),
"backgroundColor" => $colorMap[$i],
"borderColor" => $colorMap[$i],
);
}
// Build Time Labels and dataset values
foreach($influxQueryResult['values'] as $row) {
for ($i = 0; $i < sizeOf($row); $i++) {
// Time Labels are always first
if (0 == $i) {
array_push($labels, $row[0]);
} else {
array_push($datasets[$i]['data'], $row[$i]);
}
}
}
// Re-order Datasets
$orderedData[0] = $datasets[1];
$orderedData[1] = $datasets[4];
$orderedData[2] = $datasets[5];
$orderedData[3] = $datasets[3];
$orderedData[4] = $datasets[2];
// Fix Names
$orderedData[0]['label'] = "Apprentice";
$orderedData[1]['label'] = "Guru";
$orderedData[2]['label'] = "Master";
$orderedData[3]['label'] = "Enlightened";
$orderedData[4]['label'] = "Burned";
return array(
"labels" => $labels,
"datasets" => $orderedData,
);
}
$data = queryInfluxDb();
header('Content-type:application/json;charset=utf-8');
echo json_encode(generateChartData($data));
And the Javascript function to pull it to the web UI. I’ve scrubbed the URL I use below.
var loadWaniKani = (function loadWaniKaniChart() {
fetch('https://www.example.com/api/wanikani/progress')
.then((resp) => resp.json())
.then(function (data) {
var wkContext = document.getElementById("wkChart").getContext('2d');
var wkChart = new Chart(wkContext, {
type: 'line',
data: {
labels: data.labels,
datasets: Object.values(data.datasets),
},
options: {
elements: {
point: {
radius: 0
}
},
animation: false,
tooltips: {
mode: 'index',
},
hover: {
mode: 'index'
},
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'day',
unitStepSize: 1,
displayFormats: {
day: 'MMM D'
}
},
distribution: 'linear'
}],
yAxes: [{
stacked: true,
ticks: {
beginAtZero: true
}
}]
}
}
});
})
.catch(function (error) {
console.log(error);
});
})();
And then I wind up with this in the end!
I hope this helps!