Skip to content
Snippets Groups Projects
Commit 3307ab89 authored by tag2y19's avatar tag2y19
Browse files

Add log scale options

--xlog, --ylog and --yrlog.  pretty() needed tweaking to handle it and
some of the position calculations have been moved around a bit to make
things neater.
parent 532286d2
Branches
No related tags found
No related merge requests found
...@@ -93,6 +93,10 @@ struct context { ...@@ -93,6 +93,10 @@ struct context {
} max, min; } max, min;
} yrange, yrrange; } yrange, yrrange;
bool xlog;
bool ylog;
bool yrlog;
PangoFontDescription* tick_font_description; PangoFontDescription* tick_font_description;
double margins[4]; double margins[4];
...@@ -167,7 +171,7 @@ static void parse_headers( struct context* context ); ...@@ -167,7 +171,7 @@ static void parse_headers( struct context* context );
static void parse_data( struct context* context ); static void parse_data( struct context* context );
static void plot_draw( GtkDrawingArea* plot, static void plot_draw( GtkDrawingArea* plot,
cairo_t* cr, int width, int height, void* data ); cairo_t* cr, int width, int height, void* data );
static int pretty( double* lo, double* up, int ndiv ); static int pretty( double* lo, double* up, int ndiv, bool log );
/* PUBLIC FUNK!!! */ /* PUBLIC FUNK!!! */
...@@ -236,6 +240,27 @@ int main( int argc, char** argv ) { ...@@ -236,6 +240,27 @@ int main( int argc, char** argv ) {
.arg_data = &( context->yrrange.arg ), .arg_data = &( context->yrrange.arg ),
.description = "Right y-axis range [min]:[max]", .description = "Right y-axis range [min]:[max]",
.arg_description = "range", .arg_description = "range",
}, {
.long_name = "xlog",
.short_name = '\0',
.flags = G_OPTION_FLAG_IN_MAIN,
.arg = G_OPTION_ARG_NONE,
.arg_data = &( context->xlog ),
.description = "Use log scale for the x axis",
}, {
.long_name = "ylog",
.short_name = '\0',
.flags = G_OPTION_FLAG_IN_MAIN,
.arg = G_OPTION_ARG_NONE,
.arg_data = &( context->ylog ),
.description = "Use log scale for the y axis",
}, {
.long_name = "yrlog",
.short_name = '\0',
.flags = G_OPTION_FLAG_IN_MAIN,
.arg = G_OPTION_ARG_NONE,
.arg_data = &( context->yrlog ),
.description = "Use log scale for the right y axis",
}, { }, {
.long_name = "font", .long_name = "font",
.short_name = 'f', .short_name = 'f',
...@@ -1645,11 +1670,14 @@ static void plot_draw( GtkDrawingArea* plot, ...@@ -1645,11 +1670,14 @@ static void plot_draw( GtkDrawingArea* plot,
yrrange[1] = context->yrrange.max.value; yrrange[1] = context->yrrange.max.value;
} }
int xdivs = pretty( &( xrange[0] ), &( xrange[1] ), 10 ); int xdivs = pretty(
&( xrange[0] ), &( xrange[1] ), 10, context->xlog );
int yldivs = lset ? int yldivs = lset ?
pretty( &( ylrange[0] ), &( ylrange[1] ), 10 ) : 0; pretty(
&( ylrange[0] ), &( ylrange[1] ), 10, context->ylog ) : 0;
int yrdivs = rset ? int yrdivs = rset ?
pretty( &( yrrange[0] ), &( yrrange[1] ), 10 ) : 0; pretty(
&( yrrange[0] ), &( yrrange[1] ), 10, context->yrlog ) : 0;
char tick_buffer[512]; char tick_buffer[512];
...@@ -1672,15 +1700,21 @@ static void plot_draw( GtkDrawingArea* plot, ...@@ -1672,15 +1700,21 @@ static void plot_draw( GtkDrawingArea* plot,
context->xtick_layouts.layouts[i], context->xtick_layouts.layouts[i],
context->tick_font_description ); context->tick_font_description );
} }
if ( context->time ) { double x;
time_t t = xrange[0] + ( (double) i ) / ( xdivs - 1 ) * if ( context->xlog ) {
x = pow( 10.0, log10( xrange[0] ) +
( (double) i ) / ( xdivs - 1 ) *
log10( xrange[1] / xrange[0] ) );
} else {
x = xrange[0] + ( (double) i ) / ( xdivs - 1 ) *
( xrange[1] - xrange[0] ); ( xrange[1] - xrange[0] );
}
if ( context->time ) {
time_t t = (time_t) x;
struct tm* tm = localtime( &t ); struct tm* tm = localtime( &t );
strftime( tick_buffer, 512, "%H:%M:%S", tm ); strftime( tick_buffer, 512, "%H:%M:%S", tm );
} else { } else {
sprintf( tick_buffer, "%.3g", sprintf( tick_buffer, "%.3g", x );
xrange[0] + ( (double) i ) / ( xdivs - 1 ) *
( xrange[1] - xrange[0] ) );
} }
pango_layout_set_text( pango_layout_set_text(
context->xtick_layouts.layouts[i], tick_buffer, -1 ); context->xtick_layouts.layouts[i], tick_buffer, -1 );
...@@ -1712,8 +1746,16 @@ static void plot_draw( GtkDrawingArea* plot, ...@@ -1712,8 +1746,16 @@ static void plot_draw( GtkDrawingArea* plot,
context->yltick_layouts.layouts[i], context->yltick_layouts.layouts[i],
context->tick_font_description ); context->tick_font_description );
} }
sprintf( tick_buffer, "%.3g", ylrange[0] + double y;
( (double) i ) / ( yldivs - 1 ) * ( ylrange[1] - ylrange[0] ) ); if ( context->ylog ) {
y = pow( 10.0, log10( ylrange[0] ) +
( (double) i ) / ( yldivs - 1 ) *
log10( ylrange[1] / ylrange[0] ) );
} else {
y = ylrange[0] + ( (double) i ) / ( yldivs - 1 ) *
( ylrange[1] - ylrange[0] );
}
sprintf( tick_buffer, "%.3g", y );
pango_layout_set_text( pango_layout_set_text(
context->yltick_layouts.layouts[i], tick_buffer, -1 ); context->yltick_layouts.layouts[i], tick_buffer, -1 );
int tick_size; int tick_size;
...@@ -1744,8 +1786,16 @@ static void plot_draw( GtkDrawingArea* plot, ...@@ -1744,8 +1786,16 @@ static void plot_draw( GtkDrawingArea* plot,
context->yrtick_layouts.layouts[i], context->yrtick_layouts.layouts[i],
context->tick_font_description ); context->tick_font_description );
} }
sprintf( tick_buffer, "%.3g", yrrange[0] + double y;
( (double) i ) / ( yrdivs - 1 ) * ( yrrange[1] - yrrange[0] ) ); if ( context->yrlog ) {
y = pow( 10.0, log10( yrrange[0] ) +
( (double) i ) / ( yrdivs - 1 ) *
log10( yrrange[1] / yrrange[0] ) );
} else {
y = yrrange[0] + ( (double) i ) / ( yrdivs - 1 ) *
( yrrange[1] - yrrange[0] );
}
sprintf( tick_buffer, "%.3g", y );
pango_layout_set_text( pango_layout_set_text(
context->yrtick_layouts.layouts[i], tick_buffer, -1 ); context->yrtick_layouts.layouts[i], tick_buffer, -1 );
int tick_size; int tick_size;
...@@ -1793,10 +1843,21 @@ static void plot_draw( GtkDrawingArea* plot, ...@@ -1793,10 +1843,21 @@ static void plot_draw( GtkDrawingArea* plot,
double* yrange = context->data->y[i].axis == LEFT ? double* yrange = context->data->y[i].axis == LEFT ?
ylrange : yrrange; ylrange : yrrange;
cairo_rectangle( cr, width / 2 - 1, double y;
height - 5 - ( height - 10 ) * if ( ( context->data->y[i].axis == LEFT &&
context->ylog ) ||
( context->data->y[i].axis == RIGHT &&
context->yrlog ) ) {
y = height - 5 - ( height - 10 ) *
log10( context->data->y[i].v / yrange[0] ) /
log10( yrange[1] / yrange[0] );
} else {
y = height - 5 - ( height - 10 ) *
( context->data->y[i].v - yrange[0] ) / ( context->data->y[i].v - yrange[0] ) /
( yrange[1] - yrange[0] ) - 1, 2, 2 ); ( yrange[1] - yrange[0] );
}
cairo_rectangle( cr, width / 2 - 1, y - 1, 2, 2 );
cairo_fill( cr ); cairo_fill( cr );
} }
...@@ -1832,16 +1893,39 @@ static void plot_draw( GtkDrawingArea* plot, ...@@ -1832,16 +1893,39 @@ static void plot_draw( GtkDrawingArea* plot,
double* yrange = context->data->y[i].axis == LEFT ? double* yrange = context->data->y[i].axis == LEFT ?
ylrange : yrrange; ylrange : yrrange;
bool log = ( context->data->y[i].axis == LEFT &&
context->ylog ) ||
( context->data->y[i].axis == RIGHT &&
context->yrlog );
double x;
double xnext;
double y;
double ynext;
if ( context->data->y[i].present ) { if ( context->data->y[i].present ) {
cairo_move_to( cr, if ( context->xlog ) {
m[1] + ( width - m[1] - m[3] ) * x = m[1] + ( width - m[1] - m[3] ) *
log10( context->data->x / xrange[0] ) /
log10( xrange[1] / xrange[0] );
} else {
x = m[1] + ( width - m[1] - m[3] ) *
( context->data->x - xrange[0] ) / ( context->data->x - xrange[0] ) /
( xrange[1] - xrange[0] ), ( xrange[1] - xrange[0] );
height - m[0] - ( height - m[0] - m[2] ) * }
if ( log ) {
y = height - m[0] - ( height - m[0] - m[2] ) *
log10( context->data->y[i].v / yrange[0] ) /
log10( yrange[1] / yrange[0] );
} else {
y = height - m[0] - ( height - m[0] - m[2] ) *
( context->data->y[i].v - yrange[0] ) / ( context->data->y[i].v - yrange[0] ) /
( yrange[1] - yrange[0] ) ); ( yrange[1] - yrange[0] );
}
cairo_move_to( cr, x, y );
} }
...@@ -1849,28 +1933,70 @@ static void plot_draw( GtkDrawingArea* plot, ...@@ -1849,28 +1933,70 @@ static void plot_draw( GtkDrawingArea* plot,
NULL != data; NULL != data;
data = data->next ) { data = data->next ) {
if ( context->xlog ) {
x = m[1] + ( width - m[1] - m[3] ) *
log10( data->x / xrange[0] ) /
log10( xrange[1] / xrange[0] );
} else {
x = m[1] + ( width - m[1] - m[3] ) *
( data->x - xrange[0] ) /
( xrange[1] - xrange[0] );
}
if ( data->y[i].present ) { if ( data->y[i].present ) {
if ( NULL != data->next && data->next->y[i].present ) { if ( log ) {
y = height - m[0] - ( height - m[0] - m[2] ) *
log10( data->y[i].v / yrange[0] ) /
log10( yrange[1] / yrange[0] );
} else {
y = height - m[0] - ( height - m[0] - m[2] ) *
( data->y[i].v - yrange[0] ) /
( yrange[1] - yrange[0] );
}
cairo_line_to( cr, }
m[1] + ( width - m[1] - m[3] ) *
if ( NULL != data->next ) {
if ( context->xlog ) {
xnext = m[1] + ( width - m[1] - m[3] ) *
log10( data->next->x / xrange[0] ) /
log10( xrange[1] / xrange[0] );
} else {
xnext = m[1] + ( width - m[1] - m[3] ) *
( data->next->x - xrange[0] ) / ( data->next->x - xrange[0] ) /
( xrange[1] - xrange[0] ), ( xrange[1] - xrange[0] );
height - m[0] - ( height - m[0] - m[2] ) * }
if ( data->next->y[i].present ) {
if ( log ) {
ynext = height - m[0] -
( height - m[0] - m[2] ) *
log10( data->next->y[i].v / yrange[0] ) /
log10( yrange[1] / yrange[0] );
} else {
ynext = height - m[0] -
( height - m[0] - m[2] ) *
( data->next->y[i].v - yrange[0] ) / ( data->next->y[i].v - yrange[0] ) /
( yrange[1] - yrange[0] ) ); ( yrange[1] - yrange[0] );
}
}
}
if ( data->y[i].present ) {
if ( NULL != data->next && data->next->y[i].present ) {
cairo_line_to( cr, xnext, ynext );
} else if ( NULL == data->prev || } else if ( NULL == data->prev ||
!data->prev->y[i].present ) { !data->prev->y[i].present ) {
cairo_rectangle( cr, cairo_rectangle( cr, x - 1, y - 1, 2, 2 );
m[1] + ( width - m[1] - m[3] ) *
( data->x - xrange[0] ) /
( xrange[1] - xrange[0] ),
height - m[0] - ( height - m[0] - m[2] ) *
( data->y[i].v - yrange[0] ) /
( yrange[1] - yrange[0] ) - 1, 2, 2 );
cairo_fill( cr ); cairo_fill( cr );
} else { } else {
...@@ -1883,13 +2009,7 @@ static void plot_draw( GtkDrawingArea* plot, ...@@ -1883,13 +2009,7 @@ static void plot_draw( GtkDrawingArea* plot,
if ( NULL != data->next && data->next->y[i].present ) { if ( NULL != data->next && data->next->y[i].present ) {
cairo_move_to( cr, cairo_move_to( cr, xnext, ynext );
m[1] + ( width - m[1] - m[3] ) *
( data->next->x - xrange[0] ) /
( xrange[1] - xrange[0] ),
height - m[0] - ( height - m[0] - m[2] ) *
( data->next->y[i].v - yrange[0] ) /
( yrange[1] - yrange[0] ) );
} }
...@@ -2134,10 +2254,10 @@ static void plot_draw( GtkDrawingArea* plot, ...@@ -2134,10 +2254,10 @@ static void plot_draw( GtkDrawingArea* plot,
} }
static int pretty( double* lo, double* up, int ndiv ) { static int pretty( double* lo, double* up, int ndiv, bool log ) {
/* Shamelessly filched from the R language's source code. /* Shamelessly filched from the R language's source code.
* (src/appl/pretty.c) */ * (src/appl/pretty.c), adapted for log scales */
#define rounding_eps 1E-10 #define rounding_eps 1E-10
#define h 1.5 #define h 1.5
...@@ -2148,6 +2268,10 @@ static int pretty( double* lo, double* up, int ndiv ) { ...@@ -2148,6 +2268,10 @@ static int pretty( double* lo, double* up, int ndiv ) {
double lo_ = *lo; double lo_ = *lo;
double up_ = *up; double up_ = *up;
if ( log ) {
lo_ = log10( lo_ );
up_ = log10( up_ );
}
double dx = up_ - lo_; double dx = up_ - lo_;
double cell = fabs( lo_ ) > fabs( up_ ) ? fabs( lo_ ) : fabs( up_ ); double cell = fabs( lo_ ) > fabs( up_ ) ? fabs( lo_ ) : fabs( up_ );
...@@ -2197,11 +2321,11 @@ static int pretty( double* lo, double* up, int ndiv ) { ...@@ -2197,11 +2321,11 @@ static int pretty( double* lo, double* up, int ndiv ) {
double ns = floor( lo_ / unit + rounding_eps ); double ns = floor( lo_ / unit + rounding_eps );
double nu = ceil( up_ / unit - rounding_eps ); double nu = ceil( up_ / unit - rounding_eps );
while ( ns * unit > *lo + rounding_eps * unit ) { while ( ns * unit > lo_ + rounding_eps * unit ) {
ns--; ns--;
} }
while ( nu * unit < *up - rounding_eps * unit ) { while ( nu * unit < up_ - rounding_eps * unit ) {
nu++; nu++;
} }
...@@ -2225,11 +2349,13 @@ static int pretty( double* lo, double* up, int ndiv ) { ...@@ -2225,11 +2349,13 @@ static int pretty( double* lo, double* up, int ndiv ) {
ndiv = k; ndiv = k;
} }
if ( ns * unit < *lo ) {
*lo = ns * unit; *lo = ns * unit;
if ( log ) {
*lo = pow( 10.0, *lo );
} }
if ( nu * unit > *up ) {
*up = nu * unit; *up = nu * unit;
if ( log ) {
*up = pow( 10.0, *up );
} }
return ndiv + 1; return ndiv + 1;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment