시계열에 대한 줄기와 잎 그림과 같은 것이 있습니까?

시계열에 대한 줄기와 잎 그림과 같은 것이 있습니까?

일련의 값의 분포를 빠르게 살펴보고 싶을 때 줄기-잎 도표는 믿을 수 없을 정도로 간단하면서도 강력한 도구입니다. 컴퓨터가 그림을 그리도록 가르치는 데 몇 분이 걸리거나 손으로 간단하게 그릴 수도 있습니다.

유일한 문제는 때때로 유용한 정보가 포함되어 있는 값의 순서를 유지하지 않는다는 것입니다. 나는 순서를 유지하면서 시계열을 그리는 똑같이 간단한 방법을 생각해 보았지만 뭔가를 생각해 내지 못했습니다.

X축에 시간을, Y축에 값을 지정하여 정규 시계열 차트를 작성하는 명백한 솔루션은 실제 렌더링에 들어가기 전에 상당한 준비 작업이 필요하다는 문제가 있습니다. 줄기와 잎 그림만큼 개념적으로 단순하지는 않습니다.

그런 게 있나요? 아니면 내가 요구하는 것이 불가능합니까?

아, 그리고 제가 잊어버릴 뻔한 중요한 요구 사항이 있습니다. 라인 버퍼 터미널에서 쉽게 인쇄할 수 있기를 바랍니다...


제가 여기서 묻는 이유는 이에 대한 주요 사용 사례가 상태 지표 및 서버의 기타 샘플이기 때문입니다. 시스템 오작동의 원인을 배제할 때 일부 하위 시스템이 시간이 지남에 따라 어떻게 작동하는지 빠르게 직관하는 것이 좋습니다.

답변1

이것이 조금 복잡하기 때문에 내가 찾고 있는 것이 전부인지는 확실하지 않지만 지금까지는 내 요구 사항을 충족했습니다.

저는 모두 편리하게 25~60°C 범위에 있는 온도로 작업을 시작했습니다. 따라서 간단히 문자열을 복제하여 *일종의 막대 그래프를 만들 수 있었습니다.

$ cat temps2.txt | perl -pe 'print "*" x $_ . " ";'
******************************************** 44.0
*************************************************** 51.0
******************************************* 43.0
********************************************* 45.0
************************************** 38.0
**************************************** 40.0
*********************************** 35.0
************************************ 36.0
******************************** 32.0
******************************** 32.0
******************************* 31.0
******************************* 31.0
******************************** 32.0
******************************** 32.0
******************************* 31.0
************************************ 36.0
******************************** 32.0
************************************ 36.0
******************************* 31.0
*********************************** 35.0
************************************ 36.0
************************************ 36.0
********************************* 33.0
******************************* 31.0
******************************** 32.0
******************************* 31.0
********************************* 33.0
******************************** 32.0
******************************** 32.0
************************************ 36.0

물론 이것은 편리한 범위에 있는 값에만 작동하지만, 그럴 때는 어리석게도 효과적입니다. 그렇지 않은 경우에는 $_반복 횟수를 나타내는 변수에 산술 조작을 추가하기만 하면 됩니다.

예를 들어, 초당 평균 프로세서 실행 대기열 길이(나의 경우 0~8 범위에 있음)에 10을 곱하여 출력에 교대 근무를 표시할 수 있습니다.

$ cat runq.txt | perl -pe 'print "*" x ($_ * 10) . " ";'
 0
 0
 0
 0
******************** 2
********** 1
******************** 2
**************************************** 4
****************************** 3
**************************************** 4
****************************** 3
****************************** 3
******************** 2
******************** 2
********** 1
********** 1
********** 1
************************************************************ 6
********** 1
********** 1
********** 1
 0
 0

이것은 내 요구를 절대적으로 만족시켰을 것입니다.


물론, 나는 이런 식으로 좌표 변환의 자동 계산 및 업데이트와 시스템 평균 및 자연 프로세스 한계의 스트리밍 계산을 포함하는 큰 스크립트를 만들었습니다.

$ cat temps2.txt | ./limits.pl
----------------------------------------------------------------
X:    51.0           [            | *         ]
X:    43.0         [           * |            ]
X:    45.0            [         |          ]
X:    38.0          [      *   |          ]
X:    40.0           [      *  |        ]
X:    35.0           [   *    |        ]
X:    36.0           [    *  |        ]
X:    32.0           [ *     |       ]
X:    32.0           [ *    |      ]
X:    31.0           [*     |     ]
X:    31.0           [*    |     ]
X:    32.0           [ *   |     ]
X:    32.0           [ *   |    ]
X:    31.0           [*   |    ]
X:    36.0           [    *     ]
X:    32.0           [ *  |     ]
X:    36.0          [     |     ]
X:    31.0          [ *   |     ]
X:    35.0          [    *|     ]
X:    36.0          [     |    ]
X:    36.0          [     *    ]
X:    33.0          [   * |    ]
X:    31.0          [ *   |    ]
X:    32.0          [  * |     ]
X:    31.0          [ *  |    ]
X:    33.0          [   *|    ]
X:    32.0          [  * |    ]
X:    32.0          [  * |    ]
X:    36.0          [    |*   ]
UPL=42.1
Xbar=35.2
LPL=28.2

이 스크립트에는 깨끗하지 않은 소스 코드도 첨부되어 있습니다. 이것은 첫 번째 초안이므로 잘못된 코드를 양해해 주시기 바랍니다.

#!/usr/bin/env perl

use v5.26;
use strict;
use warnings;
use List::Util qw( min max );

my $max_width = 52;

my $n = 0;
my $xbar = 0;
my $mrbar = 0;
my $lpl;
my $upl;

sub print_values {
    print "\n";
    printf "UPL=%.1f\n", $upl;
    printf "Xbar=%.1f\n", $xbar;
    printf "LPL=%.1f\n", $lpl;
}

$SIG{INT} = \&print_values;

my $min_y;
my $max_y;

my $xprev;
while (my $x = <>) {
    $n++;
    $xbar *= $n - 1;
    $xbar += $x;
    $xbar /= $n;

    if (defined($xprev)) {
        my $mr = abs ($x - $xprev);
        $mrbar *= $n - 2;
        $mrbar += $mr;
        $mrbar /= $n - 1;

        $lpl = $xbar - $mrbar * 2.66;
        $upl = $xbar + $mrbar * 2.66;

        my $space_changed;

        # If any point is about to be drawn outside of the screen space, expand
        # the space to include the currently drawn points and then some.
        if (min($lpl, $x) < $min_y or max($upl, $x) > $max_y) {
            my $min_diff = abs($min_y - min($lpl, $x));
            my $max_diff = abs($max_y - max($upl, $x));
            # Change min and max values in slightly larger steps to avoid
            # changing the space too often with a drifting process.
            $min_y -= $min_diff * 2;
            $max_y += $max_diff * 2;
            $space_changed = 1;
        }
        if ($min_y == $max_y) {
            $max_y = $min_y + 1;
        }

        my %screen_coords;
        $screen_coords{lpl} = $lpl;
        $screen_coords{upl} = $upl;
        $screen_coords{xbar} = $xbar;
        $screen_coords{x} = $x;

        # Transform the recorded values to the screen space.
        for my $coord (keys %screen_coords) {
            # Set offset to 0.
            $screen_coords{$coord} -= $min_y;
            # Divide by range to scale down to 0–1.
            $screen_coords{$coord} /= ($max_y - $min_y);
            # Scale up again to proper width.
            $screen_coords{$coord} *= ($max_width - 1);
        }

        # Render the recorded values into an array of characters.
        my @characters = split('', ' ' x $max_width);
        $characters[$screen_coords{xbar}] = '|';
        $characters[$screen_coords{lpl}] = '[';
        $characters[$screen_coords{upl}] = ']';
        $characters[$screen_coords{x}] = '*';

        # Print a separator whenever the space needs to be expanded.
        if ($space_changed) {
            printf ('-' x ($max_width + 12) . "\n");
        }

        printf "X: %7.1f %s\n", $x, join('', @characters);
    } else {
        $min_y = $x;
        $max_y = $x;
    }

    $xprev = $x;
}

print_values;

관련 정보