diff --git a/src/main.c b/src/main.c
index 2a5b73cca71055d4a41654d1e54995e1f5273082..4aa256e94ce539922f21b9dc793ee46e91535c6d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2,6 +2,7 @@
 #include <ctype.h>
 #include <fcntl.h>
 #include <gtk/gtk.h>
+#include <pango/pangocairo.h>
 
 /* TYPES!!! */
 
@@ -45,6 +46,17 @@ struct context {
 	struct timespec start_time;
 
 	GtkWidget* plot;
+	PangoFontDescription* font_description;
+	char* title;
+	PangoLayout* title_layout;
+	char* xlab;
+	PangoLayout* xlab_layout;
+	char* yllab;
+	PangoLayout* yllab_layout;
+	char* yrlab;
+	PangoLayout* yrlab_layout;
+
+	double margins[4];
 
 	char* xaxis;
 	size_t xaxis_n;
@@ -63,6 +75,11 @@ struct context {
 	double yrdist; /* 0 for fit all */
 	double yrpos;
 
+	struct {
+		PangoLayout** layouts;
+		int n;
+	} xtick_layouts, yltick_layouts, yrtick_layouts;
+
 };
 
 struct fd_source {
@@ -102,6 +119,8 @@ int main( int argc, char** argv ) {
 	context->read_buffer_len = 512;
 	context->xfit = true;
 	context->xfollow = true;
+	context->font_description =
+		pango_font_description_from_string( "Sans 12px" );
 
 	static const char* colours[] = {
 		"#005C84", "#FCBC00", "#0C838C", "#E63037",
@@ -135,7 +154,8 @@ int main( int argc, char** argv ) {
 			.flags = G_OPTION_FLAG_IN_MAIN,
 			.arg = G_OPTION_ARG_CALLBACK,
 			.arg_data = &add_to_column_list,
-			.description = "Use right axis for column",
+			.description = "Use right axis for column "
+				"(can be given multiple times)",
 			.arg_description = "column"
 		}, {
 			.long_name = "ignore",
@@ -143,8 +163,41 @@ int main( int argc, char** argv ) {
 			.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",
+			.description = "Do not plot the data in column "
+				"(can be given multiple times)",
 			.arg_description = "column"
+		}, {
+			.long_name = "title",
+			.short_name = 't',
+			.flags = G_OPTION_FLAG_IN_MAIN,
+			.arg = G_OPTION_ARG_STRING,
+			.arg_data = &( context->title ),
+			.description = "Main graph title",
+			.arg_description = "title",
+		}, {
+			.long_name = "xlab",
+			.short_name = '\0',
+			.flags = G_OPTION_FLAG_IN_MAIN,
+			.arg = G_OPTION_ARG_STRING,
+			.arg_data = &( context->xlab ),
+			.description = "X-Axis label",
+			.arg_description = "label",
+		}, {
+			.long_name = "ylab",
+			.short_name = '\0',
+			.flags = G_OPTION_FLAG_IN_MAIN,
+			.arg = G_OPTION_ARG_STRING,
+			.arg_data = &( context->yllab ),
+			.description = "Left y-axis label",
+			.arg_description = "label",
+		}, {
+			.long_name = "yrlab",
+			.short_name = '\0',
+			.flags = G_OPTION_FLAG_IN_MAIN,
+			.arg = G_OPTION_ARG_STRING,
+			.arg_data = &( context->yrlab ),
+			.description = "Right y-axis label",
+			.arg_description = "label",
 		}, {
 			NULL,
 		},
@@ -786,6 +839,66 @@ static void plot_draw( GtkDrawingArea* plot,
 	struct context* context = (struct context*) data;
 	(void) plot;
 
+	/* Texts */
+
+	double margin_reqs[4] = { 5., 5., 5., 5. };
+
+	if ( NULL == context->title_layout && NULL != context->title ) {
+		context->title_layout = pango_cairo_create_layout( cr );
+		pango_layout_set_font_description( context->title_layout,
+			context->font_description );
+		pango_layout_set_text(
+			context->title_layout, context->title, -1 );
+	}
+	if ( NULL != context->title_layout ) {
+		int height;
+		pango_layout_get_pixel_size(
+			context->title_layout, NULL, &height );
+		margin_reqs[2] += height + 3;
+	}
+
+	if ( NULL == context->xlab_layout && NULL != context->xlab ) {
+		context->xlab_layout = pango_cairo_create_layout( cr );
+		pango_layout_set_font_description( context->xlab_layout,
+			context->font_description );
+		pango_layout_set_text(
+			context->xlab_layout, context->xlab, -1 );
+	}
+	if ( NULL != context->xlab_layout ) {
+		int height;
+		pango_layout_get_pixel_size(
+			context->xlab_layout, NULL, &height );
+		margin_reqs[0] += height + 3;
+	}
+
+	if ( NULL == context->yllab_layout && NULL != context->yllab ) {
+		context->yllab_layout = pango_cairo_create_layout( cr );
+		pango_layout_set_font_description( context->yllab_layout,
+			context->font_description );
+		pango_layout_set_text(
+			context->yllab_layout, context->yllab, -1 );
+	}
+	if ( NULL != context->yllab_layout ) {
+		int height;
+		pango_layout_get_pixel_size(
+			context->yllab_layout, NULL, &height );
+		margin_reqs[1] += height + 3;
+	}
+
+	if ( NULL == context->yrlab_layout && NULL != context->yrlab ) {
+		context->yrlab_layout = pango_cairo_create_layout( cr );
+		pango_layout_set_font_description( context->yrlab_layout,
+			context->font_description );
+		pango_layout_set_text(
+			context->yrlab_layout, context->yrlab, -1 );
+	}
+	if ( NULL != context->yrlab_layout ) {
+		int height;
+		pango_layout_get_pixel_size(
+			context->yrlab_layout, NULL, &height );
+		margin_reqs[3] += height + 3;
+	}
+
 	/* Clear */
 
 	cairo_save( cr );
@@ -793,19 +906,6 @@ static void plot_draw( GtkDrawingArea* plot,
 	cairo_paint( cr );
 	cairo_restore( cr );
 
-	/* Axes */
-
-	cairo_save( cr );
-	cairo_set_source_rgb( cr, 0, 0, 0 );
-	cairo_set_line_width( cr, 1 );
-	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 );
-
 	if ( NULL == context->data ) {
 		return;
 	}
@@ -919,8 +1019,128 @@ static void plot_draw( GtkDrawingArea* plot,
 	}
 
 	int xdivs = pretty( &( xrange[0] ), &( xrange[1] ), 10 );
-	int yldivs = pretty( &( ylrange[0] ), &( ylrange[1] ), 10 );
-	int yrdivs = pretty( &( yrrange[0] ), &( yrrange[1] ), 10 );
+	int yldivs = lset ?
+		pretty( &( ylrange[0] ), &( ylrange[1] ), 10 ) : 0;
+	int yrdivs = rset ?
+		pretty( &( yrrange[0] ), &( yrrange[1] ), 10 ) : 0;
+
+	char tick_buffer[512];
+
+	if ( xdivs > context->xtick_layouts.n ) {
+		context->xtick_layouts.layouts = realloc(
+			context->xtick_layouts.layouts,
+			xdivs * sizeof *( context->xtick_layouts.layouts ) );
+		for ( int i = context->xtick_layouts.n; i < xdivs; i++ ) {
+			context->xtick_layouts.layouts[i] = NULL;
+		}
+		context->xtick_layouts.n = xdivs;
+	}
+
+	int max_tick_size = 0;
+	for ( int i = 0; i < xdivs; i++ ) {
+		if ( NULL == context->xtick_layouts.layouts[i] ) {
+			context->xtick_layouts.layouts[i] =
+				pango_cairo_create_layout( cr );
+			pango_layout_set_font_description(
+				context->xtick_layouts.layouts[i],
+				context->font_description );
+		}
+		sprintf( tick_buffer, "%.3g",
+			xrange[0] + ( (double) i ) / ( xdivs - 1 ) * ( xrange[1] - xrange[0] ) );
+		pango_layout_set_text(
+			context->xtick_layouts.layouts[i], tick_buffer, -1 );
+		int tick_size;
+		pango_layout_get_pixel_size( context->xtick_layouts.layouts[i],
+			NULL, &tick_size );
+		if ( tick_size > max_tick_size ) {
+			max_tick_size = tick_size;
+		}
+	}
+	margin_reqs[0] += max_tick_size + 3;
+
+	if ( yldivs > context->yltick_layouts.n ) {
+		context->yltick_layouts.layouts = realloc(
+			context->yltick_layouts.layouts,
+			yldivs * sizeof *( context->yltick_layouts.layouts ) );
+		for ( int i = context->yltick_layouts.n; i < yldivs; i++ ) {
+			context->yltick_layouts.layouts[i] = NULL;
+		}
+		context->yltick_layouts.n = yldivs;
+	}
+
+	max_tick_size = 0;
+	for ( int i = 0; i < yldivs; i++ ) {
+		if ( NULL == context->yltick_layouts.layouts[i] ) {
+			context->yltick_layouts.layouts[i] =
+				pango_cairo_create_layout( cr );
+			pango_layout_set_font_description(
+				context->yltick_layouts.layouts[i],
+				context->font_description );
+		}
+		sprintf( tick_buffer, "%.3g", ylrange[0] +
+			( (double) i ) / ( yldivs - 1 ) * ( ylrange[1] - ylrange[0] ) );
+		pango_layout_set_text(
+			context->yltick_layouts.layouts[i], tick_buffer, -1 );
+		int tick_size;
+		pango_layout_get_pixel_size( context->yltick_layouts.layouts[i],
+			&tick_size, NULL );
+		if ( tick_size > max_tick_size ) {
+			max_tick_size = tick_size;
+		}
+	}
+	margin_reqs[1] += max_tick_size + 3;
+
+	if ( yrdivs > context->yrtick_layouts.n ) {
+		context->yrtick_layouts.layouts = realloc(
+			context->yrtick_layouts.layouts,
+			yrdivs * sizeof *( context->yrtick_layouts.layouts ) );
+		for ( int i = context->yrtick_layouts.n; i < yrdivs; i++ ) {
+			context->yrtick_layouts.layouts[i] = NULL;
+		}
+		context->yrtick_layouts.n = yrdivs;
+	}
+
+	max_tick_size = 0;
+	for ( int i = 0; i < yrdivs; i++ ) {
+		if ( NULL == context->yrtick_layouts.layouts[i] ) {
+			context->yrtick_layouts.layouts[i] =
+				pango_cairo_create_layout( cr );
+			pango_layout_set_font_description(
+				context->yrtick_layouts.layouts[i],
+				context->font_description );
+		}
+		sprintf( tick_buffer, "%.3g", yrrange[0] +
+			( (double) i ) / ( yrdivs - 1 ) * ( yrrange[1] - yrrange[0] ) );
+		pango_layout_set_text(
+			context->yrtick_layouts.layouts[i], tick_buffer, -1 );
+		int tick_size;
+		pango_layout_get_pixel_size( context->yrtick_layouts.layouts[i],
+			&tick_size, NULL );
+		if ( tick_size > max_tick_size ) {
+			max_tick_size = tick_size;
+		}
+	}
+	margin_reqs[3] += max_tick_size + 3;
+
+	for ( int i = 0; i < 4; i++ ) {
+		if ( margin_reqs[i] > context->margins[i] ) {
+			context->margins[i] = 1.25 * margin_reqs[i];
+		}
+	}
+	double* m = context->margins;
+
+	/* Axes */
+
+	cairo_save( cr );
+	cairo_set_source_rgb( cr, 0, 0, 0 );
+	cairo_set_line_width( cr, 1 );
+	cairo_move_to( cr, width - m[3], height - m[0] );
+	cairo_line_to( cr, m[1], height - m[0] );
+	cairo_line_to( cr, m[1], m[2] );
+	cairo_line_to( cr, width - m[3], m[2] );
+	cairo_line_to( cr, width - m[3], height - m[0] );
+	cairo_stroke( cr );
+	cairo_restore( cr );
 
 	/* Data */
 
@@ -959,11 +1179,11 @@ static void plot_draw( GtkDrawingArea* plot,
 	}
 
 	cairo_save( cr );
-	cairo_move_to( cr, 4, 4 );
-	cairo_line_to( cr, width - 4, 4 );
-	cairo_line_to( cr, width - 4, height - 4 );
-	cairo_line_to( cr, 4, height - 4 );
-	cairo_line_to( cr, 4, 4 );
+	cairo_move_to( cr, m[1] - 1, m[2] - 1 );
+	cairo_line_to( cr, width - m[3] + 1, m[2] - 1 );
+	cairo_line_to( cr, width - m[3] + 1, height - m[0] + 1);
+	cairo_line_to( cr, m[1] - 1, height - m[0] + 1 );
+	cairo_line_to( cr, m[1] - 1, m[2] - 1 );
 	cairo_clip( cr );
 	cairo_set_line_width( cr, 1 );
 
@@ -986,17 +1206,17 @@ static void plot_draw( GtkDrawingArea* plot,
 				if ( data->next->y[i].present ) {
 
 					cairo_move_to( cr,
-						5 + ( width - 10 ) *
+						m[1] + ( width - m[1] - m[3] ) *
 							( data->x - xrange[0] ) /
 							( xrange[1] - xrange[0] ),
-						height - 5 - ( height - 10 ) *
+						height - m[0] - ( height - m[0] - m[2] ) *
 							( data->y[i].v - yrange[0] ) /
 							( yrange[1] - yrange[0] ) );
 					cairo_line_to( cr,
-						5 + ( width - 10 ) *
+						m[1] + ( width - m[1] - m[3] ) *
 							( data->next->x - xrange[0] ) /
 							( xrange[1] - xrange[0] ),
-						height - 5 - ( height - 10 ) *
+						height - m[0] - ( height - m[0] - m[2] ) *
 							( data->next->y[i].v - yrange[0] ) /
 							( yrange[1] - yrange[0] ) );
 					cairo_stroke( cr );
@@ -1005,10 +1225,10 @@ static void plot_draw( GtkDrawingArea* plot,
 						!data->prev->y[i].present ) {
 
 					cairo_rectangle( cr,
-						5 + ( width - 10 ) *
+						m[1] + ( width - m[1] - m[3] ) *
 							( data->x - xrange[0] ) /
 							( xrange[1] - xrange[0] ),
-						height - 5 - ( height - 10 ) *
+						height - m[0] - ( height - m[0] - m[2] ) *
 							( data->y[i].v - yrange[0] ) /
 							( yrange[1] - yrange[0] ) - 1, 2, 2 );
 					cairo_fill( cr );
@@ -1027,34 +1247,123 @@ static void plot_draw( GtkDrawingArea* plot,
 
 	for ( int i = 0; i < xdivs; i++ ) {
 		cairo_move_to( cr,
-			5 + i * ( width - 10 ) / ( xdivs - 1 ),
-			height - 5 );
+			m[1] + i * ( width - m[1] - m[3] ) / ( xdivs - 1 ),
+			height - m[0] );
 		cairo_line_to( cr,
-			5 + i * ( width - 10 ) / ( xdivs - 1 ),
-			height - 2 );
+			m[1] + i * ( width - m[1] - m[3] ) / ( xdivs - 1 ),
+			height - m[0] + 3 );
 		cairo_stroke( cr );
+		int text_w;
+		pango_layout_get_pixel_size( context->xtick_layouts.layouts[i],
+			&text_w, NULL );
+		cairo_move_to( cr,
+			m[1] + i * ( width - m[1] - m[3] ) / ( xdivs - 1 ) -
+				text_w / 2,
+			height - m[0] + 5 );
+		pango_cairo_show_layout( cr,
+			context->xtick_layouts.layouts[i] );
 	}
 
 	for ( int i = 0; i < yldivs && lset; i++ ) {
 		cairo_move_to( cr,
-			2,
-			5 + i * ( height - 10 ) / ( yldivs - 1 ) );
+			m[1] - 3,
+			m[2] + i * ( height - m[2] - m[0] ) / ( yldivs - 1 ) );
 		cairo_line_to( cr,
-			5,
-			5 + i * ( height - 10 ) / ( yldivs - 1 ) );
+			m[1],
+			m[2] + i * ( height - m[2] - m[0] ) / ( yldivs - 1 ) );
 		cairo_stroke( cr );
+		int text_w;
+		int text_h;
+		pango_layout_get_pixel_size(
+			context->yltick_layouts.layouts[yldivs - i - 1],
+			&text_w, &text_h );
+		cairo_move_to( cr,
+			m[1] - 5 - text_w,
+			m[2] + i * ( height - m[2] - m[0] ) / ( yldivs - 1 ) -
+				text_h / 2 );
+		pango_cairo_show_layout( cr,
+			context->yltick_layouts.layouts[yldivs - i - 1] );
 	}
 
 	for ( int i = 0; i < yrdivs && rset; i++ ) {
 		cairo_move_to( cr,
-			width - 5,
-			5 + i * ( height - 10 ) / ( yrdivs - 1 ) );
+			width - m[3],
+			m[2] + i * ( height - m[2] - m[0] ) / ( yrdivs - 1 ) );
 		cairo_line_to( cr,
-			width - 2,
-			5 + i * ( height - 10 ) / ( yrdivs - 1 ) );
+			width - m[3] + 3,
+			m[2] + i * ( height - m[2] - m[0] ) / ( yrdivs - 1 ) );
 		cairo_stroke( cr );
+		int text_h;
+		pango_layout_get_pixel_size(
+			context->yrtick_layouts.layouts[yrdivs - i -1],
+			NULL, &text_h );
+		cairo_move_to( cr,
+			width - m[3] + 5,
+			m[2] + i * ( height - m[2] - m[0] ) / ( yrdivs - 1 ) -
+				text_h / 2 );
+		pango_cairo_show_layout( cr,
+			context->yrtick_layouts.layouts[yrdivs - i - 1] );
+	}
+
+	cairo_restore( cr );
+
+	/* Titles */
+
+	cairo_save( cr );
+
+	if ( NULL != context->title_layout ) {
+		int title_w;
+		pango_layout_get_pixel_size( context->title_layout,
+			&title_w, NULL );
+		cairo_move_to( cr,
+			m[1] + ( width - m[1] - m[3] ) / 2 - title_w / 2, 3 );
+		pango_cairo_show_layout( cr, context->title_layout );
+	}
+
+	cairo_restore( cr );
+	cairo_save( cr );
+
+	if ( NULL != context->xlab_layout ) {
+		int xlab_w;
+		int xlab_h;
+		pango_layout_get_pixel_size( context->xlab_layout,
+			&xlab_w, &xlab_h );
+		cairo_move_to( cr,
+			m[1] + ( width - m[1] - m[3] ) / 2 - xlab_w / 2,
+			height - xlab_h - 3 );
+		pango_cairo_show_layout( cr, context->xlab_layout );
+	}
+
+	cairo_restore( cr );
+	cairo_save( cr );
+
+	if ( NULL != context->yllab_layout ) {
+		int yllab_w;
+		pango_layout_get_pixel_size( context->yllab_layout,
+			&yllab_w, NULL );
+		cairo_move_to( cr,
+			3,
+			m[2] + ( height - m[2] - m[0] ) / 2 + yllab_w / 2 );
+		cairo_rotate( cr, - M_PI / 2 );
+		pango_cairo_show_layout( cr, context->yllab_layout );
+	}
+
+	cairo_restore( cr );
+	cairo_save( cr );
+
+	if ( NULL != context->yrlab_layout ) {
+		int yrlab_w;
+		pango_layout_get_pixel_size( context->yrlab_layout,
+			&yrlab_w, NULL );
+		cairo_move_to( cr,
+			width - 3,
+			m[2] + ( height - m[2] - m[0] ) / 2 - yrlab_w / 2 );
+		cairo_rotate( cr, M_PI / 2 );
+		pango_cairo_show_layout( cr, context->yrlab_layout );
 	}
 
+	cairo_restore( cr );
+
 }
 
 static int pretty( double* lo, double* up, int ndiv ) {
@@ -1155,6 +1464,6 @@ static int pretty( double* lo, double* up, int ndiv ) {
 		*up = nu * unit;
 	}
 
-	return ndiv;
+	return ndiv + 1;
 
 }