Initial commit, console stuff works

This commit is contained in:
Chris 2020-05-15 22:46:19 +02:00
commit 8b62721068
7 changed files with 280 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/composer.lock
/vendor
/.*

17
composer.json Normal file
View 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
View 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
View 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
View 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);
}
}

View 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
View 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);
}
}