From e0c37920bb2cc46ee559e3992470572d4b4d27e6 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 28 Jul 2009 20:20:51 -0700 Subject: [PATCH] output: Make chart geometry the responsibility of the output driver. Currently, with libplot, all charts have the same geometry, because libplot allows us to reasonably set the dimensions of the drawing area to the same 1000x1000 size. But cairo will produce strangely scaled results if we attempt to do the same thing there (distorted font sizes, etc.). So make the output drivers responsible for setting up the chart geometry, so that the output drivers can tell the chart drawing routines the size of the drawing area. --- src/output/ascii.c | 5 +++- src/output/chart-provider.h | 39 ++++++++++++++++-------------- src/output/chart.c | 28 ++++++++++++---------- src/output/chart.h | 1 - src/output/charts/box-whisker.c | 17 ++++++------- src/output/charts/np-plot.c | 42 ++++++++++++++------------------- src/output/charts/piechart.c | 22 +++++++---------- src/output/charts/plot-hist.c | 36 +++++++++++++--------------- src/output/html.c | 5 +++- src/output/postscript.c | 5 +++- 10 files changed, 98 insertions(+), 102 deletions(-) diff --git a/src/output/ascii.c b/src/output/ascii.c index c01e36cc..15af515f 100644 --- a/src/output/ascii.c +++ b/src/output/ascii.c @@ -867,6 +867,7 @@ static void ascii_output_chart (struct outp_driver *this, const struct chart *chart) { struct ascii_driver_ext *x = this->ext; + struct chart_geometry geom; struct outp_text t; char *file_name; plPlotter *lp; @@ -880,7 +881,9 @@ ascii_output_chart (struct outp_driver *this, const struct chart *chart) NULL, &file_name, &lp)) return; x->chart_cnt++; - chart_draw (chart, lp); + chart_geometry_init (lp, &geom, 1000.0, 1000.0); + chart_draw (chart, lp, &geom); + chart_geometry_free (lp); pl_deletepl_r (lp); /* Mention chart in output. diff --git a/src/output/chart-provider.h b/src/output/chart-provider.h index 2ff4aafa..fbec5d25 100644 --- a/src/output/chart-provider.h +++ b/src/output/chart-provider.h @@ -28,23 +28,6 @@ struct chart_colour uint8_t blue; }; -struct chart_class - { - void (*draw) (const struct chart *, plPlotter *); - void (*destroy) (struct chart *); - }; - -struct chart - { - const struct chart_class *class; - int ref_cnt; - }; - -void chart_init (struct chart *, const struct chart_class *); -bool chart_create_file (const char *type, const char *file_name_tmpl, - int number, plPlotterParams *, - char **file_namep, plPlotter **lpp); - /* The geometry of a chart. */ struct chart_geometry { @@ -76,7 +59,27 @@ struct chart_geometry double y_max; }; -void chart_geometry_init (plPlotter *, struct chart_geometry *); +struct chart_class + { + void (*draw) (const struct chart *, plPlotter *, struct chart_geometry *); + void (*destroy) (struct chart *); + }; + +struct chart + { + const struct chart_class *class; + int ref_cnt; + }; + +void chart_init (struct chart *, const struct chart_class *); +bool chart_create_file (const char *type, const char *file_name_tmpl, + int number, plPlotterParams *, + char **file_namep, plPlotter **lpp); + +void chart_geometry_init (plPlotter *, struct chart_geometry *, + double width, double length); void chart_geometry_free (plPlotter *); +void chart_draw (const struct chart *, plPlotter *, struct chart_geometry *); + #endif /* output/chart-provider.h */ diff --git a/src/output/chart.c b/src/output/chart.c index 8d99f41f..fb561a26 100644 --- a/src/output/chart.c +++ b/src/output/chart.c @@ -48,13 +48,14 @@ chart_init (struct chart *chart, const struct chart_class *class) } void -chart_geometry_init (plPlotter *lp, struct chart_geometry *geom) +chart_geometry_init (plPlotter *lp, struct chart_geometry *geom, + double width, double length) { /* Start output page. */ pl_openpl_r (lp); /* Set coordinate system. */ - pl_fspace_r (lp, 0.0, 0.0, 1000.0, 1000.0); + pl_fspace_r (lp, 0.0, 0.0, width, length); /* Set line thickness. */ pl_flinewidth_r (lp, 0.25); @@ -67,15 +68,15 @@ chart_geometry_init (plPlotter *lp, struct chart_geometry *geom) pl_savestate_r(lp); /* Set default chartetry. */ - geom->data_top = 900; - geom->data_right = 800; - geom->data_bottom = 120; - geom->data_left = 150; - geom->abscissa_top = 70; - geom->ordinate_right = 120; - geom->title_bottom = 920; - geom->legend_left = 810; - geom->legend_right = 1000; + geom->data_top = 0.900 * length; + geom->data_right = 0.800 * width; + geom->data_bottom = 0.120 * length; + geom->data_left = 0.150 * width; + geom->abscissa_top = 0.070 * length; + geom->ordinate_right = 0.120 * width; + geom->title_bottom = 0.920 * length; + geom->legend_left = 0.810 * width; + geom->legend_right = width; geom->font_size = 0; geom->fill_colour.red = 255; @@ -100,9 +101,10 @@ chart_geometry_free (plPlotter *lp) } void -chart_draw (const struct chart *chart, plPlotter *lp) +chart_draw (const struct chart *chart, plPlotter *lp, + struct chart_geometry *geom) { - chart->class->draw (chart, lp); + chart->class->draw (chart, lp, geom); } struct chart * diff --git a/src/output/chart.h b/src/output/chart.h index 598c91eb..b05b5ba4 100644 --- a/src/output/chart.h +++ b/src/output/chart.h @@ -28,7 +28,6 @@ struct chart; -void chart_draw (const struct chart *, plPlotter *); struct chart *chart_ref (const struct chart *); void chart_unref (struct chart *); diff --git a/src/output/charts/box-whisker.c b/src/output/charts/box-whisker.c index 24b29145..d799d743 100644 --- a/src/output/charts/box-whisker.c +++ b/src/output/charts/box-whisker.c @@ -233,26 +233,23 @@ boxplot_draw_yscale (plPlotter *lp, struct chart_geometry *geom, } static void -boxplot_chart_draw (const struct chart *chart, plPlotter *lp) +boxplot_chart_draw (const struct chart *chart, plPlotter *lp, + struct chart_geometry *geom) { const struct boxplot *boxplot = (struct boxplot *) chart; - struct chart_geometry geom; double box_width; size_t i; - chart_geometry_init (lp, &geom); - boxplot_draw_yscale (lp, &geom, boxplot->y_max, boxplot->y_min); - chart_write_title (lp, &geom, "%s", boxplot->title); + boxplot_draw_yscale (lp, geom, boxplot->y_max, boxplot->y_min); + chart_write_title (lp, geom, "%s", boxplot->title); - box_width = (geom.data_right - geom.data_left) / boxplot->n_boxes / 2.0; + box_width = (geom->data_right - geom->data_left) / boxplot->n_boxes / 2.0; for (i = 0; i < boxplot->n_boxes; i++) { const struct box *box = &boxplot->boxes[i]; - const double box_centre = (i * 2 + 1) * box_width + geom.data_left; - boxplot_draw_box (lp, &geom, box_centre, box_width, box->bw, box->label); + const double box_centre = (i * 2 + 1) * box_width + geom->data_left; + boxplot_draw_box (lp, geom, box_centre, box_width, box->bw, box->label); } - - chart_geometry_free (lp); } static void diff --git a/src/output/charts/np-plot.c b/src/output/charts/np-plot.c index df91add5..dba20bac 100644 --- a/src/output/charts/np-plot.c +++ b/src/output/charts/np-plot.c @@ -121,60 +121,54 @@ dnp_plot_create (const struct np *np, const struct casereader *reader, } static void -np_plot_chart_draw (const struct chart *chart, plPlotter *lp) +np_plot_chart_draw (const struct chart *chart, plPlotter *lp, + struct chart_geometry *geom) { const struct np_plot_chart *npp = (struct np_plot_chart *) chart; - struct chart_geometry geom; struct casereader *data; struct ccase *c; - chart_geometry_init (lp, &geom); - chart_write_title (lp, &geom, _("Normal Q-Q Plot of %s"), npp->label); - chart_write_xlabel (lp, &geom, _("Observed Value")); - chart_write_ylabel (lp, &geom, _("Expected Normal")); - chart_write_xscale (lp, &geom, + chart_write_title (lp, geom, _("Normal Q-Q Plot of %s"), npp->label); + chart_write_xlabel (lp, geom, _("Observed Value")); + chart_write_ylabel (lp, geom, _("Expected Normal")); + chart_write_xscale (lp, geom, npp->x_lower - npp->slack, npp->x_upper + npp->slack, 5); - chart_write_yscale (lp, &geom, npp->y_first, npp->y_last, 5); + chart_write_yscale (lp, geom, npp->y_first, npp->y_last, 5); data = casereader_clone (npp->data); for (; (c = casereader_read (data)) != NULL; case_unref (c)) - chart_datum (lp, &geom, 0, + chart_datum (lp, geom, 0, case_data_idx (c, NP_IDX_Y)->f, case_data_idx (c, NP_IDX_NS)->f); casereader_destroy (data); - chart_line (lp, &geom, npp->slope, npp->intercept, + chart_line (lp, geom, npp->slope, npp->intercept, npp->y_first, npp->y_last, CHART_DIM_Y); - - chart_geometry_free (lp); } static void -dnp_plot_chart_draw (const struct chart *chart, plPlotter *lp) +dnp_plot_chart_draw (const struct chart *chart, plPlotter *lp, + struct chart_geometry *geom) { const struct np_plot_chart *dnpp = (struct np_plot_chart *) chart; - struct chart_geometry geom; struct casereader *data; struct ccase *c; - chart_geometry_init (lp, &geom); - chart_write_title (lp, &geom, _("Detrended Normal Q-Q Plot of %s"), + chart_write_title (lp, geom, _("Detrended Normal Q-Q Plot of %s"), dnpp->label); - chart_write_xlabel (lp, &geom, _("Observed Value")); - chart_write_ylabel (lp, &geom, _("Dev from Normal")); - chart_write_xscale (lp, &geom, dnpp->y_min, dnpp->y_max, 5); - chart_write_yscale (lp, &geom, dnpp->dns_min, dnpp->dns_max, 5); + chart_write_xlabel (lp, geom, _("Observed Value")); + chart_write_ylabel (lp, geom, _("Dev from Normal")); + chart_write_xscale (lp, geom, dnpp->y_min, dnpp->y_max, 5); + chart_write_yscale (lp, geom, dnpp->dns_min, dnpp->dns_max, 5); data = casereader_clone (dnpp->data); for (; (c = casereader_read (data)) != NULL; case_unref (c)) - chart_datum (lp, &geom, 0, case_data_idx (c, NP_IDX_Y)->f, + chart_datum (lp, geom, 0, case_data_idx (c, NP_IDX_Y)->f, case_data_idx (c, NP_IDX_DNS)->f); casereader_destroy (data); - chart_line (lp, &geom, 0, 0, dnpp->y_min, dnpp->y_max, CHART_DIM_X); - - chart_geometry_free (lp); + chart_line (lp, geom, 0, 0, dnpp->y_min, dnpp->y_max, CHART_DIM_X); } static void diff --git a/src/output/charts/piechart.c b/src/output/charts/piechart.c index 94881b41..e33fd086 100644 --- a/src/output/charts/piechart.c +++ b/src/output/charts/piechart.c @@ -77,10 +77,10 @@ piechart_create (const char *title, const struct slice *slices, int n_slices) } static void -piechart_draw (const struct chart *chart, plPlotter *lp) +piechart_draw (const struct chart *chart, plPlotter *lp, + struct chart_geometry *geom) { struct piechart *pie = (struct piechart *) chart; - struct chart_geometry geom; double total_magnitude; double left_label, right_label; double centre_x, centre_y; @@ -88,18 +88,16 @@ piechart_draw (const struct chart *chart, plPlotter *lp) double angle; int i; - chart_geometry_init (lp, &geom); + left_label = geom->data_left + (geom->data_right - geom->data_left)/10.0; + right_label = geom->data_right - (geom->data_right - geom->data_left)/10.0; - left_label = geom.data_left + (geom.data_right - geom.data_left)/10.0; - right_label = geom.data_right - (geom.data_right - geom.data_left)/10.0; + centre_x = (geom->data_right + geom->data_left) / 2.0 ; + centre_y = (geom->data_top + geom->data_bottom) / 2.0 ; - centre_x = (geom.data_right + geom.data_left) / 2.0 ; - centre_y = (geom.data_top + geom.data_bottom) / 2.0 ; + radius = MIN (5.0 / 12.0 * (geom->data_top - geom->data_bottom), + 1.0 / 4.0 * (geom->data_right - geom->data_left)); - radius = MIN (5.0 / 12.0 * (geom.data_top - geom.data_bottom), - 1.0 / 4.0 * (geom.data_right - geom.data_left)); - - chart_write_title (lp, &geom, "%s", pie->title); + chart_write_title (lp, geom, "%s", pie->title); total_magnitude = 0.0; for (i = 0; i < pie->n_slices; i++) @@ -143,8 +141,6 @@ piechart_draw (const struct chart *chart, plPlotter *lp) /* Draw an outline to the pie */ pl_filltype_r (lp,0); pl_fcircle_r (lp, centre_x, centre_y, radius); - - chart_geometry_free (lp); } /* Fill a segment with the current fill colour */ diff --git a/src/output/charts/plot-hist.c b/src/output/charts/plot-hist.c index 0e52889f..97656751 100644 --- a/src/output/charts/plot-hist.c +++ b/src/output/charts/plot-hist.c @@ -147,19 +147,17 @@ histogram_chart_create (const struct histogram *hist, const char *label, } static void -histogram_chart_draw (const struct chart *chart, plPlotter *lp) +histogram_chart_draw (const struct chart *chart, plPlotter *lp, + struct chart_geometry *geom) { struct histogram_chart *h = (struct histogram_chart *) chart; - struct chart_geometry geom; int i; int bins; - chart_geometry_init (lp, &geom); + chart_write_title (lp, geom, _("HISTOGRAM")); - chart_write_title (lp, &geom, _("HISTOGRAM")); - - chart_write_ylabel (lp, &geom, _("Frequency")); - chart_write_xlabel (lp, &geom, h->label); + chart_write_ylabel (lp, geom, _("Frequency")); + chart_write_xlabel (lp, geom, h->label); if (h->gsl_hist == NULL) { @@ -169,12 +167,12 @@ histogram_chart_draw (const struct chart *chart, plPlotter *lp) bins = gsl_histogram_bins (h->gsl_hist); - chart_write_yscale (lp, &geom, 0, gsl_histogram_max_val (h->gsl_hist), 5); + chart_write_yscale (lp, geom, 0, gsl_histogram_max_val (h->gsl_hist), 5); for (i = 0; i < bins; i++) - hist_draw_bar (lp, &geom, h->gsl_hist, i); + hist_draw_bar (lp, geom, h->gsl_hist, i); - histogram_write_legend (lp, &geom, h->n, h->mean, h->stddev); + histogram_write_legend (lp, geom, h->n, h->mean, h->stddev); if (h->show_normal && h->n != SYSMIS && h->mean != SYSMIS && h->stddev != SYSMIS) @@ -190,26 +188,24 @@ histogram_chart_draw (const struct chart *chart, plPlotter *lp) range = not_used - x_min; gsl_histogram_get_range (h->gsl_hist, bins - 1, ¬_used, &x_max); - abscissa_scale = (geom.data_right - geom.data_left) / (x_max - x_min); - ordinate_scale = (geom.data_top - geom.data_bottom) / + abscissa_scale = (geom->data_right - geom->data_left) / (x_max - x_min); + ordinate_scale = (geom->data_top - geom->data_bottom) / gsl_histogram_max_val (h->gsl_hist); - pl_move_r (lp, geom.data_left, geom.data_bottom); - for (d = geom.data_left; - d <= geom.data_right; - d += (geom.data_right - geom.data_left) / 100.0) + pl_move_r (lp, geom->data_left, geom->data_bottom); + for (d = geom->data_left; + d <= geom->data_right; + d += (geom->data_right - geom->data_left) / 100.0) { - const double x = (d - geom.data_left) / abscissa_scale + x_min; + const double x = (d - geom->data_left) / abscissa_scale + x_min; const double y = h->n * range * gsl_ran_gaussian_pdf (x - h->mean, h->stddev); - pl_fcont_r (lp, d, geom.data_bottom + y * ordinate_scale); + pl_fcont_r (lp, d, geom->data_bottom + y * ordinate_scale); } pl_endpath_r (lp); } - - chart_geometry_free (lp); } diff --git a/src/output/html.c b/src/output/html.c index 8c1a6530..d943f192 100644 --- a/src/output/html.c +++ b/src/output/html.c @@ -208,6 +208,7 @@ static void html_output_chart (struct outp_driver *this, const struct chart *chart) { struct html_driver_ext *x = this->ext; + struct chart_geometry geom; char *file_name; plPlotter *lp; @@ -216,7 +217,9 @@ html_output_chart (struct outp_driver *this, const struct chart *chart) NULL, &file_name, &lp)) return; x->chart_cnt++; - chart_draw (chart, lp); + chart_geometry_init (lp, &geom, 1000.0, 1000.0); + chart_draw (chart, lp, &geom); + chart_geometry_free (lp); pl_deletepl_r (lp); link_image (x->file, file_name); diff --git a/src/output/postscript.c b/src/output/postscript.c index bec23de6..743aea4e 100644 --- a/src/output/postscript.c +++ b/src/output/postscript.c @@ -607,6 +607,7 @@ static void ps_output_chart (struct outp_driver *this, const struct chart *chart) { struct ps_driver_ext *x = this->ext; + struct chart_geometry geom; plPlotterParams *params; int x_origin, y_origin; char buf[BUFSIZ]; @@ -644,7 +645,9 @@ ps_output_chart (struct outp_driver *this, const struct chart *chart) } /* Draw chart and free plotter. */ - chart_draw (chart, lp); + chart_geometry_init (lp, &geom, 1000.0, 1000.0); + chart_draw (chart, lp, &geom); + chart_geometry_free (lp); pl_deletepl_r (lp); /* Write prologue for chart. */ -- 2.30.2