Initial commit, console stuff works
This commit is contained in:
commit
8b62721068
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/composer.lock
|
||||||
|
/vendor
|
||||||
|
/.*
|
17
composer.json
Normal file
17
composer.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "noccylabs/histogram",
|
||||||
|
"description": "Useful histograms everywhere",
|
||||||
|
"type": "library",
|
||||||
|
"license": "GPL-3.0-OR-LATER",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Christopher Vagnetoft",
|
||||||
|
"email": "cvagnetoft@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"NoccyLabs\\Histogram\\": "src/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
examples/basic.php
Normal file
25
examples/basic.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__."/../vendor/autoload.php";
|
||||||
|
|
||||||
|
$histogram = new NoccyLabs\Histogram\Output\TerminalHistogram(40);
|
||||||
|
$buffer = $histogram->getBuffer();
|
||||||
|
|
||||||
|
for ($n = 0; $n<40; $n++) {
|
||||||
|
$s = sin($n/5) + 1;
|
||||||
|
$buffer->pushSamples($s);
|
||||||
|
}
|
||||||
|
|
||||||
|
//$buffer->pushSamples(0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.5, 0.7, 0.9, 1.0, 1.1, 1.5, 1.0, 0.9, 0.7, null, 0.4, null, 0.3);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
echo $histogram . "\n\n";
|
||||||
|
|
||||||
|
echo join("\n", $histogram->getMultiHistogram(3)) . "\n\n";
|
||||||
|
|
||||||
|
$histogram->setMax(2.0);
|
||||||
|
echo join("\n", $histogram->getMultiHistogram(3)) . "\n\n";
|
||||||
|
|
||||||
|
$histogram->setMax(5.0);
|
||||||
|
echo join("\n", $histogram->getMultiHistogram(3)) . "\n\n";
|
22
phpunit.xml
Normal file
22
phpunit.xml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/8.5/phpunit.xsd"
|
||||||
|
bootstrap="vendor/autoload.php"
|
||||||
|
executionOrder="depends,defects"
|
||||||
|
forceCoversAnnotation="true"
|
||||||
|
beStrictAboutCoversAnnotation="true"
|
||||||
|
beStrictAboutOutputDuringTests="true"
|
||||||
|
beStrictAboutTodoAnnotatedTests="true"
|
||||||
|
verbose="true">
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="default">
|
||||||
|
<directory suffix="Test.php">tests</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||||
|
<directory suffix=".php">src</directory>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
</phpunit>
|
71
src/Buffer.php
Normal file
71
src/Buffer.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Histogram;
|
||||||
|
|
||||||
|
use Countable;
|
||||||
|
|
||||||
|
class Buffer implements Countable
|
||||||
|
{
|
||||||
|
|
||||||
|
private $samples = [];
|
||||||
|
|
||||||
|
private $maxSamples = 50;
|
||||||
|
|
||||||
|
public function __construct(int $maxSamples=50)
|
||||||
|
{
|
||||||
|
$this->maxSamples = max(1, $maxSamples);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count(): int
|
||||||
|
{
|
||||||
|
return count($this->samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pushSamples(...$samples)
|
||||||
|
{
|
||||||
|
array_push($this->samples, ...$samples);
|
||||||
|
$this->trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSampleMax(): float
|
||||||
|
{
|
||||||
|
return (float)max($this->samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSampleMin(): float
|
||||||
|
{
|
||||||
|
return (float)min($this->samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSampleAverage(): ?float
|
||||||
|
{
|
||||||
|
$clean = array_filter($this->samples, function ($s) { return $s !== null; });
|
||||||
|
if (count($clean) === 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
$total = array_sum($clean);
|
||||||
|
$average = $total / count($clean);
|
||||||
|
return (float)$average;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMappedSamples(float $inMin, float $inMax, float $outMin=0.0, float $outMax=1.0, ?int $numSamples=null)
|
||||||
|
{
|
||||||
|
$map = function ($v) use ($inMin, $inMax, $outMin, $outMax) {
|
||||||
|
if ($v === null) return null;
|
||||||
|
$v = max($inMin, min($inMax, $v));
|
||||||
|
return (($v - $inMin) / ($inMax - $inMin)) * ($outMax - $outMin) + $outMin;
|
||||||
|
};
|
||||||
|
return array_map($map, $numSamples?array_slice($this->samples,-$numSamples,$numSamples):$this->samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSamples(?int $numSamples=null)
|
||||||
|
{
|
||||||
|
return $numSamples?array_slice($this->samples,-$numSamples,$numSamples):$this->samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function trim()
|
||||||
|
{
|
||||||
|
while (count($this->samples) > $this->maxSamples)
|
||||||
|
array_shift($this->samples);
|
||||||
|
}
|
||||||
|
}
|
100
src/Output/TerminalHistogram.php
Normal file
100
src/Output/TerminalHistogram.php
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Histogram\Output;
|
||||||
|
|
||||||
|
use NoccyLabs\Histogram\Buffer;
|
||||||
|
|
||||||
|
class TerminalHistogram
|
||||||
|
{
|
||||||
|
|
||||||
|
public static $MaxWidth = 50;
|
||||||
|
|
||||||
|
private $width;
|
||||||
|
|
||||||
|
private $max = null;
|
||||||
|
|
||||||
|
/** @var Buffer */
|
||||||
|
private $buffer;
|
||||||
|
|
||||||
|
private $bars = [
|
||||||
|
" ",
|
||||||
|
"\u{2581}",
|
||||||
|
"\u{2582}",
|
||||||
|
"\u{2583}",
|
||||||
|
"\u{2584}",
|
||||||
|
"\u{2585}",
|
||||||
|
"\u{2586}",
|
||||||
|
"\u{2587}",
|
||||||
|
"\u{2588}",
|
||||||
|
];
|
||||||
|
|
||||||
|
public function __construct(int $width, Buffer $buffer=null)
|
||||||
|
{
|
||||||
|
$this->width = max(1, min($width, self::$MaxWidth));
|
||||||
|
$this->buffer = $buffer ?? new Buffer(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBuffer(): Buffer
|
||||||
|
{
|
||||||
|
return $this->buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMax(?float $max)
|
||||||
|
{
|
||||||
|
$this->max = $max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHistogram()
|
||||||
|
{
|
||||||
|
$max = ($this->max === null)?1.0:$this->max;
|
||||||
|
$samples = $this->buffer->getMappedSamples(0.0, $max, 0, 8, $this->width);
|
||||||
|
$output = null;
|
||||||
|
if (count($samples) < $this->width) {
|
||||||
|
$output .= str_repeat(" ", $this->width - count($samples));
|
||||||
|
}
|
||||||
|
foreach ($samples as $sample) {
|
||||||
|
if ($sample === null) {
|
||||||
|
$output .= "\u{2a09}";
|
||||||
|
} else {
|
||||||
|
$output .= $this->bars[floor($sample)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMultiHistogram(int $lines): array
|
||||||
|
{
|
||||||
|
$max = ($this->max === null)?1.0:$this->max;
|
||||||
|
$samples = $this->buffer->getMappedSamples(0.0, $max, 0, 8*$lines, $this->width);
|
||||||
|
$result = [];
|
||||||
|
$topmin = 8*($lines-1);
|
||||||
|
for ($line = 0; $line < $lines; $line++) {
|
||||||
|
$rowmin = $topmin - ($line * 8);
|
||||||
|
$output = null;
|
||||||
|
if (count($samples) < $this->width) {
|
||||||
|
$output .= str_repeat(" ", $this->width - count($samples));
|
||||||
|
}
|
||||||
|
foreach ($samples as $sample) {
|
||||||
|
if ($sample === null) {
|
||||||
|
$output .= "\u{2a09}";
|
||||||
|
} else {
|
||||||
|
$remain = $sample - $rowmin;
|
||||||
|
if ($remain <= 0) {
|
||||||
|
$output.= " ";
|
||||||
|
} else {
|
||||||
|
$sample = min(8, $remain);
|
||||||
|
$output .= $this->bars[floor($sample)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$result[] = $output;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return $this->getHistogram();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
42
tests/BufferTest.php
Normal file
42
tests/BufferTest.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Histogram;
|
||||||
|
|
||||||
|
|
||||||
|
class BufferTest extends \PhpUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function testThatCreatingBufferSetsSize()
|
||||||
|
{
|
||||||
|
$buffer = new Buffer(2);
|
||||||
|
$buffer->pushSamples(1, 2, 3);
|
||||||
|
|
||||||
|
$this->assertEquals(2, count($buffer));
|
||||||
|
$this->assertEquals([2, 3], $buffer->getSamples());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGettingSampleMaxMinValues()
|
||||||
|
{
|
||||||
|
$buffer = new Buffer(5);
|
||||||
|
$buffer->pushSamples(10, 20, 30, 40, 50);
|
||||||
|
|
||||||
|
$this->assertEquals(10, $buffer->getSampleMin());
|
||||||
|
$this->assertEquals(30, $buffer->getSampleAverage());
|
||||||
|
$this->assertEquals(50, $buffer->getSampleMax());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMappingTheBuffer()
|
||||||
|
{
|
||||||
|
$buffer = new Buffer(5);
|
||||||
|
$buffer->pushSamples(10, 20, 30, 40, 50);
|
||||||
|
|
||||||
|
$mapped = $buffer->getMappedSamples(0, 1000, 0, 100);
|
||||||
|
$this->assertEquals([1, 2, 3, 4, 5], $mapped);
|
||||||
|
|
||||||
|
$mapped = $buffer->getMappedSamples(0, 100, 500, 600);
|
||||||
|
$this->assertEquals([510, 520, 530, 540, 550], $mapped);
|
||||||
|
|
||||||
|
$mapped = $buffer->getMappedSamples(0, 100);
|
||||||
|
$this->assertEquals([0.1, 0.2, 0.3, 0.4, 0.5], $mapped);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user