Skip to content
Snippets Groups Projects
Commit 6e3d26b8 authored by tag2y19's avatar tag2y19 Committed by Tom Greig
Browse files

Add options to put columns on right axis or ignore

Involved restructuring the way the column settings are stored and the
way data is parsed a bit... for the better :)
parent 5e01dbe7
No related branches found
No related tags found
No related merge requests found
......@@ -5,6 +5,11 @@
/* TYPES!!! */
struct column_list {
struct column_list* next;
char* header;
};
struct data {
struct data* next;
......@@ -14,6 +19,7 @@ struct data {
struct {
double v;
bool present;
enum { LEFT, RIGHT, } axis;
} y[];
};
......@@ -26,8 +32,15 @@ struct context {
struct data* data;
struct data* data_end;
char** headers;
size_t n_headers;
struct column_list* left_columns;
struct column_list* ignore_columns;
struct {
char* header;
enum { XAXIS, LEFT_AXIS, RIGHT_AXIS, IGNORE, } type;
} * columns;
size_t n_columns;
size_t n_data_columns;
struct timespec start_time;
......@@ -44,8 +57,11 @@ struct context {
double xpos;
bool xfollow;
double ydist; /* 0 for fit all */
double ypos;
double yldist; /* 0 for fit all */
double ylpos;
double yrdist; /* 0 for fit all */
double yrpos;
};
......@@ -58,6 +74,8 @@ struct fd_source {
/* PROTOTYPES!!! */
static bool add_to_column_list( const char* option_name,
const char* value, void* data, GError** error );
static int parse_hex( float res[3], const char* hex );
static void app_activate( GtkApplication* app, void* data );
static int listener_prepare( GSource* source, int* timeout );
......@@ -105,20 +123,39 @@ int main( int argc, char** argv ) {
{
.long_name = "x-axis",
.short_name = 'x',
.flags = G_OPTION_FLAG_NONE,
.flags = G_OPTION_FLAG_IN_MAIN,
.arg = G_OPTION_ARG_STRING,
.arg_data = &( context->xaxis ),
.description = "Column to use as the x-axis",
.arg_description = "column",
}, {
.long_name = "right",
.short_name = 'r',
.flags = G_OPTION_FLAG_IN_MAIN,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = &add_to_column_list,
.description = "Use right axis for column",
.arg_description = "column"
}, {
.long_name = "ignore",
.short_name = 'i',
.flags = G_OPTION_FLAG_IN_MAIN,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = &add_to_column_list,
.description = "Do not plot the data in column",
.arg_description = "column"
}, {
NULL,
},
};
GOptionGroup* option_group = g_option_group_new( "", "", "",
context, NULL );
g_option_group_add_entries( option_group, options );
GtkApplication* app = gtk_application_new(
"uk.ac.soton.ecs.e-plot", G_APPLICATION_DEFAULT_FLAGS );
g_application_add_main_option_entries(
G_APPLICATION( app ), options );
g_application_add_option_group(
G_APPLICATION( app ), option_group );
g_signal_connect(
app, "activate", G_CALLBACK( app_activate ), context );
......@@ -132,6 +169,31 @@ int main( int argc, char** argv ) {
/* PRIVATE FUNK!!! */
static bool add_to_column_list( const char* option_name,
const char* value, void* data, GError** error ) {
struct context* context = (struct context*) data;
(void) error;
struct column_list* item = calloc( 1, sizeof *item );
item->header = strdup( value );
if ( 0 == strcmp( option_name, "-r" ) ||
0 == strcmp( option_name, "--right" ) ) {
item->next = context->left_columns;
context->left_columns = item;
} else if ( 0 == strcmp( option_name, "-i" ) ||
0 == strcmp( option_name, "--ignore" ) ) {
item->next = context->ignore_columns;
context->ignore_columns = item;
} else {
assert( false );
}
return true;
}
static int parse_hex( float res[3], const char* hex ) {
while ( ' ' == *hex || '\t' == *hex || '#' == *hex ) {
......@@ -375,7 +437,7 @@ static int data_callback( void* data ) {
*nl = '\0';
if ( NULL == context->headers ) {
if ( NULL == context->columns ) {
parse_headers( context );
......@@ -397,7 +459,7 @@ static int data_callback( void* data ) {
static void parse_headers( struct context* context ) {
assert( NULL == context->headers );
assert( NULL == context->columns );
const char* c = context->read_buffer;
char quote = '\0';
......@@ -409,7 +471,7 @@ static void parse_headers( struct context* context ) {
if ( '\0' == *c ) {
return;
}
context->n_headers = 1;
context->n_columns = 1;
while ( '\0' != *c ) {
......@@ -419,7 +481,7 @@ static void parse_headers( struct context* context ) {
c++;
}
if ( '\0' != *c ) {
context->n_headers++;
context->n_columns++;
}
} else if ( '"' == *c && '\0' == quote ) {
quote = '"';
......@@ -439,15 +501,16 @@ static void parse_headers( struct context* context ) {
}
context->headers = calloc(
context->n_headers, sizeof *( context->headers ) );
context->columns = calloc(
context->n_columns, sizeof *( context->columns ) );
context->n_data_columns = 0;
size_t n = 0;
char header[strlen( context->read_buffer )];
c = context->read_buffer;
quote = '\0';
bool found = false;
bool xfound = false;
while ( '\0' != *c ) {
......@@ -516,18 +579,43 @@ static void parse_headers( struct context* context ) {
if ( NULL != context->xaxis &&
0 == strcmp( stripped_header, context->xaxis ) ) {
found = true;
xfound = true;
context->columns[n].type = XAXIS;
} else {
context->headers[n] = strdup( stripped_header );
n++;
context->columns[n].type = LEFT_AXIS;
for ( struct column_list* item = context->left_columns;
NULL != item;
item = item->next ) {
if ( 0 == strcmp( stripped_header, item->header ) ) {
context->columns[n].type = RIGHT_AXIS;
break;
}
}
for ( struct column_list* item = context->ignore_columns;
NULL != item;
item = item->next ) {
if ( 0 == strcmp( stripped_header, item->header ) ) {
context->columns[n].type = IGNORE;
break;
}
}
if ( IGNORE != context->columns[n].type ) {
context->n_data_columns++;
}
}
context->columns[n].header = strdup( stripped_header );
n++;
}
if ( !found ) {
if ( !xfound ) {
free( context->xaxis );
context->xaxis = NULL;
context->xaxis_n = -1;
......@@ -537,7 +625,7 @@ static void parse_headers( struct context* context ) {
static void parse_data( struct context* context ) {
assert( 0 != context->n_headers );
assert( 0 != context->n_columns );
const char* c = context->read_buffer;
while ( ' ' == *c || '\t' == *c ) {
......@@ -549,7 +637,7 @@ static void parse_data( struct context* context ) {
}
struct data* data = calloc( 1, sizeof (struct data) +
context->n_headers * sizeof *( data->y ) );
context->n_data_columns * sizeof *( data->y ) );
struct timespec now;
clock_gettime( CLOCK_MONOTONIC, &now );
......@@ -558,11 +646,11 @@ static void parse_data( struct context* context ) {
data->x += ( now.tv_nsec - context->start_time.tv_nsec ) / 1E9;
size_t n = 0;
size_t data_n = 0;
char value[strlen( context->read_buffer )];
char quote = '\0';
bool timed = false;
while ( '\0' != *c && n < context->n_headers ) {
while ( '\0' != *c && n < context->n_columns ) {
value[0] = '\0';
......@@ -628,9 +716,8 @@ static void parse_data( struct context* context ) {
char* end_ptr = NULL;
double value = strtod( stripped_value, &end_ptr );
if ( n == context->xaxis_n && !timed ) {
if ( XAXIS == context->columns[n].type ) {
timed = true;
if ( '\0' == *end_ptr ) {
data->x = value;
} else {
......@@ -639,19 +726,23 @@ static void parse_data( struct context* context ) {
}
} else {
} else if ( IGNORE != context->columns[n].type ) {
if ( '\0' == *end_ptr ) {
data->y[n].v = value;
data->y[n].present = true;
data->y[data_n].v = value;
data->y[data_n].present = true;
data->y[data_n].axis =
LEFT_AXIS == context->columns[n].type ?
LEFT : RIGHT;
} else {
data->y[n].present = false;
data->y[data_n].present = false;
}
n++;
data_n++;
}
n++;
}
if ( NULL == context->data ) {
......@@ -709,6 +800,8 @@ static void plot_draw( GtkDrawingArea* plot,
cairo_move_to( cr, width - 5, height - 5 );
cairo_line_to( cr, 5, height - 5 );
cairo_line_to( cr, 5, 5 );
cairo_line_to( cr, width - 5, 5 );
cairo_line_to( cr, width - 5, height - 5 );
cairo_stroke( cr );
cairo_restore( cr );
......@@ -719,8 +812,10 @@ static void plot_draw( GtkDrawingArea* plot,
/* Ranges */
double xrange[2] = { context->data->x, };
double yrange[2];
bool set = false;
double yrrange[2];
double ylrange[2];
bool lset = false;
bool rset = false;
for ( struct data* data = context->data;
NULL != data;
......@@ -728,27 +823,43 @@ static void plot_draw( GtkDrawingArea* plot,
xrange[1] = data->x;
for ( size_t i = 0; i < context->n_headers; i++ ) {
for ( size_t i = 0; i < context->n_data_columns; i++ ) {
if ( !data->y[i].present ) {
continue;
}
if ( !set || data->y[i].v < yrange[0] ) {
yrange[0] = data->y[i].v;
if ( data->y[i].axis == LEFT ) {
if ( !lset || data->y[i].v < ylrange[0] ) {
ylrange[0] = data->y[i].v;
}
if ( !lset || data->y[i].v > ylrange[1] ) {
ylrange[1] = data->y[i].v;
}
lset = true;
} else {
if ( !rset || data->y[i].v < yrrange[0] ) {
yrrange[0] = data->y[i].v;
}
if ( !set || data->y[i].v > yrange[1] ) {
yrange[1] = data->y[i].v;
if ( !lset || data->y[i].v > yrrange[1] ) {
yrrange[1] = data->y[i].v;
}
set = true;
rset = true;
}
}
if ( !set ) {
}
if ( !lset && !rset ) {
return;
}
......@@ -792,9 +903,14 @@ static void plot_draw( GtkDrawingArea* plot,
xrange[1] += 0.5;
}
if ( yrange[0] == yrange[1] ) {
yrange[0] -= 0.5;
yrange[1] += 0.5;
if ( ylrange[0] == ylrange[1] ) {
ylrange[0] -= 0.5;
ylrange[1] += 0.5;
}
if ( yrrange[0] == yrrange[1] ) {
yrrange[0] -= 0.5;
yrrange[1] += 0.5;
}
if ( context->xfit ) {
......@@ -814,12 +930,15 @@ static void plot_draw( GtkDrawingArea* plot,
cairo_save( cr );
cairo_set_source_rgb( cr, 0, 0, 0 );
for ( size_t i = 0; i < context->n_headers; i++ ) {
for ( size_t i = 0; i < context->n_data_columns; i++ ) {
if ( !context->data->y[i].present ) {
return;
}
double* yrange = context->data->y[i].axis == LEFT ?
ylrange : yrrange;
cairo_rectangle( cr, width / 2 - 1,
height - 5 - ( height - 10 ) *
( context->data->y[i].v - yrange[0] ) /
......@@ -847,13 +966,16 @@ static void plot_draw( GtkDrawingArea* plot,
NULL != data->next;
data = data->next ) {
for ( size_t i = 0; i < context->n_headers; i++ ) {
for ( size_t i = 0; i < context->n_data_columns; i++ ) {
size_t c = i % context->n_colours;
cairo_set_source_rgb( cr, context->colours[c][0],
context->colours[c][1], context->colours[c][2] );
double* yrange = context->data->y[i].axis == LEFT ?
ylrange : yrrange;
if ( data->y[i].present ) {
if ( data->next->y[i].present ) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment