2

I'm plotting graphs with Perl using RRDs/RRDtool. I'm able to generate a graph with a legend, but I'm struggling to align the fields in the legend.

The code I'm using is:

"COMMENT:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\\n",
"COMMENT:\t\t\t\t\t\t\tMinimum\t\t\tMaximum\t\t\tAverage\t\t\t\tCurrent\\n",
"COMMENT:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\\n",

"LINE2:e2gran#DF01D7:\t2GRAN\t\t\t\t",
"GPRINT:e2gmin:\t%6.3lf %s\t\t",
"GPRINT:e2gmax:\t%6.3lf %s\t\t",
"GPRINT:e2gaver:\t%6.3lf %s\t\t",
"GPRINT:e2glast:\t%6.3lf %s\\n",

"LINE2:e3gran#0000FF:\t3GRAN\t\t\t\t",
"GPRINT:e3gmin:\t%6.3lf %s\t\t",
"GPRINT:e3gmax:\t%6.3lf %s\t\t",
"GPRINT:e3gaver:\t%6.3lf %s\t\t",
"GPRINT:e3glast:\t%6.3lf %s\\n",

"LINE2:e4gran#FF8000:\t4GRAN\t\t\t\t",
"GPRINT:e4gmin:\t%6.3lf %s\t\t",
"GPRINT:e4gmax:\t%6.3lf %s\t\t",
"GPRINT:e4gaver:\t%6.3lf %s\t\t",
"GPRINT:e4glast:\t%6.3lf %s\\n",

"LINE2:e2gtran#FFFF00:\t2GTRAN\t\t\t",
"GPRINT:e2gtmin:\t%6.3lf %s\t\t",
"GPRINT:e2gtmax:\t%6.3lf %s\t\t",
"GPRINT:e2gtaver:\t%6.3lf %s\t\t",
"GPRINT:e2gtlast:\t%6.3lf %s\\n",

"LINE2:allregmax#FF0000:\tALL_REGIONS\t\t",
"GPRINT:allmin:%6.3lf%s\t\t",
"GPRINT:allmax:%6.3lf%s\t\t",
"GPRINT:allaver:%6.3lf%s\t\t",
"GPRINT:alllast:%6.3lf%s\\n",

"LINE3:wrongdata#000000:\\tINCOMPLETE DATA\\n",

The font used for the legend is Arial. The output looks like this:

Legend with fields not aligned in columns

While I'm aiming for something like this:

Legend with fields nicely aligned in columns

I have tried TEXTALIGN, fiddling with spaces and tabs, and checked the RRDtool docs and different tutorials, but I just can't figure this out.

ThisSuitIsBlackNot
  • 23,492
  • 9
  • 63
  • 110
taiko
  • 438
  • 1
  • 8
  • 20

2 Answers2

4

You have two problems.

The font

The first problem is that the Arial font is proportional. Every glyph has a different width. That looks nice in a book, but doesn't work for reports.

You need to use a monospaced font (like Courier New) for this to work at all.

The tabs

Your second problem are the \ts.

If stuff is too wide, you might have one \t too much. That's why you are seeing things being one set of 8 spaces too far left. To fix this, don't use whitespace and tabs directly. The underlying sprintf has syntax to create columns.

You can do %-20s to make a right-aligned column of width 20 characters that will always be filled up with spaces. You can also do % 15s to make a 15 character column that is left-aligned.

If we put that into practice, we'll get:

my @cols = (
    sprintf( '%-20s',     '2GRAN' ),
    sprintf( '% 15.3lf', 10_754 ),
    sprintf( '% 15.3lf', 48_964 ),
    sprintf( '% 15.3lf', 12_812 ),
);

print join '', @cols;

This creates:

2GRAN                     10754.000      48964.000      12812.000

Now if we do multiple lines, it still looks nice.

foreach my $row (
    [qw/ 2GRAN  10754 48964 12812 /],
    [qw/ ASDFLONGERSTUFF  123 4444444 12312313 /],
)
{
    CORE::say join '',
        sprintf( '%-20s',    $row->[0] ),
        sprintf( '% 15.3lf', $row->[1] ),
        sprintf( '% 15.3lf', $row->[2] ),
        sprintf( '% 15.3lf', $row->[3] );
}

__END__
2GRAN                     10754.000      48964.000      12812.000
ASDFLONGERSTUFF             123.000    4444444.000   12312313.000

Remember that all this stuff that you showed in your question is also just Perl code. Part of this is from the question, and another part is from chat.

sub process_all_regions { 
my ($region, $start,$end,$description) = @_; 
RRDs::graph "$img/$region-$description-$start-days.png", 
"-s -$start d", 
"-e -$end d", 
#"-s -1$duration*86400", 
"--font","TITLE:18:Arial", 
"--font","AXIS:11:Arial", 
"--font","LEGEND:14:Courier New",
 "COMMENT:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\\n",
 "COMMENT:\t\t\t\t\t\t\tMinimum\t\t\tMaximum\t\t\tAverage\t\t\t\tCurrent\\n",
 "COMMENT:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\\n",
 "LINE2:e2gran#DF01D7:\t2GRAN\t\t\t\t",
 "GPRINT:e2gmin:\t%6.3lf %s\t\t",
 "GPRINT:e2gmax:\t%6.3lf %s\t\t",
 "GPRINT:e2gaver:\t%6.3lf %s\t\t",
 "GPRINT:e2glast:\t%6.3lf %s\\n",

All of those lines with the sprintf patterns are just arguments to graph(). You don't have to put the verbatim into your code. You can create them programmatically. So if you wanted to have the header the with the same column width as the data, you can just use sprintf yourself to construct that.

sprintf('COMMENT:%s\\n', '-' x 80),
sprintf('COMMENT:% 35s%15s%15s%15s\n', qw/Minimum Maximum Average Current/),
sprintf('COMMENT:%s\\n', '-' x 80),
Community
  • 1
  • 1
simbabque
  • 53,749
  • 8
  • 73
  • 136
  • 1
    hmm, I believe I can't use sprintf with RRDTOOL/RRDs, or at least don't now how I would do that. – taiko Feb 24 '17 at 11:56
  • @taiko it uses `sprintf` internally. Those patterns you pass in get fed into `sprintf`. You can see that from the `%6.3lf %s`. It creates a floating point number `%f` in `l` (interpret integer as C type "long") with six digits and three decimals `%6.3` and the `%s` is for the `k`. Just try. – simbabque Feb 24 '17 at 11:58
  • but I still have to change the font in the same time, to have everything properly aligned, or not ? – taiko Feb 24 '17 at 12:11
  • 1
    @taiko yes. Changing the font is the first thing you have to do. It might be enough but if you have a twelve combination of very small and very large numbers you might still end up with a mess. So I would not only change the font but change the patterns too. – simbabque Feb 24 '17 at 12:28
  • see it already. I'm almost there. The values in the legend are nice and tidy , but I'm still busy with header of the legend, which is plotted with COMMENT instruction, where I can't use sprintf I believe – taiko Feb 24 '17 at 12:32
  • @taiko now you know exactly how wide it is because you set it. So that's easy. Also the `x` operator is your friend. `q{-} x 20` – simbabque Feb 24 '17 at 12:34
  • Not really, for the first part (2GRAN) I couldn't use formatting and also I'm not sure, I can use any code inside COMMENT – taiko Feb 24 '17 at 12:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/136547/discussion-between-simbabque-and-taiko). – simbabque Feb 24 '17 at 12:43
2

Thanks to the great help and hints from simbabque, I managed to use this (in the RRD:graph declaration):

"--font","LEGEND:14:Courier New",
sprintf('COMMENT:%s\\n', '-' x 110),
sprintf('COMMENT:% 35s%18s%19s%19s\n', qw/Minimum Maximum Average Current/),
sprintf('COMMENT:%s\\n', '-' x 110),
sprintf('LINE2:e2gran#DF01D7:%-11s','2GRAN'),
"GPRINT:e2gmin:% 19.0lf",
"GPRINT:e2gmax:% 16.0lf",
"GPRINT:e2gaver:% 16.0lf",
"GPRINT:e2glast:% 16.0lf\\n",

to get this Well-aligned RRDtool graph legend which is much better than before.

Community
  • 1
  • 1
taiko
  • 438
  • 1
  • 8
  • 20