1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2004, 2008, 2009 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include <output/charts/np-plot.h>
21 #include <gsl/gsl_cdf.h>
23 #include <data/casereader.h>
24 #include <data/casewriter.h>
25 #include <libpspp/cast.h>
26 #include <libpspp/message.h>
28 #include <output/chart-provider.h>
29 #include <output/charts/cartesian.h>
30 #include <output/charts/plot-chart.h>
32 #include "gl/minmax.h"
35 #define _(msgid) gettext (msgid)
37 /* An NP or DNP plot. */
42 struct casereader *data;
44 /* Copied directly from struct np. */
46 double dns_min, dns_max;
49 double slope, intercept;
50 double y_first, y_last;
51 double x_lower, x_upper;
55 static const struct chart_class np_plot_chart_class;
56 static const struct chart_class dnp_plot_chart_class;
59 make_np_plot (const struct chart_class *class,
60 const struct np *np, const struct casereader *reader,
63 struct np_plot_chart *npp;
68 npp = xmalloc (sizeof *npp);
69 chart_init (&npp->chart, class);
70 npp->label = xstrdup (label);
71 npp->data = casereader_clone (reader);
72 npp->y_min = np->y_min;
73 npp->y_max = np->y_max;
74 npp->dns_min = np->dns_min;
75 npp->dns_max = np->dns_max;
77 /* Slope and intercept of the ideal normal probability line. */
78 npp->slope = 1.0 / np->stddev;
79 npp->intercept = -np->mean / np->stddev;
81 npp->y_first = gsl_cdf_ugaussian_Pinv (1 / (np->n + 1));
82 npp->y_last = gsl_cdf_ugaussian_Pinv (np->n / (np->n + 1));
84 /* Need to make sure that both the scatter plot and the ideal fit into the
86 npp->x_lower = MIN (np->y_min, (npp->y_first - npp->intercept) / npp->slope);
87 npp->x_upper = MAX (np->y_max, (npp->y_last - npp->intercept) / npp->slope);
88 npp->slack = (npp->x_upper - npp->x_lower) * 0.05;
93 /* Creates and returns a normal probability plot corresponding to
94 the calculations in NP and the data in READER, and label the
95 plot with LABEL. The data in READER must have Y-values in
96 value index NP_IDX_Y and NS-values in value index NP_IDX_NS.
98 Returns a null pointer if the data set is empty.
100 The caller retains ownership of NP and READER. */
102 np_plot_create (const struct np *np, const struct casereader *reader,
105 return make_np_plot (&np_plot_chart_class, np, reader, label);
108 /* Creates and returns a detrended normal probability plot
109 corresponding to the calculations in NP and the data in
110 READER, and label the plot with LABEL. The data in READER
111 must have Y-values in value index NP_IDX_Y and DNS-values in
112 value index NP_IDX_DNS.
114 Returns a null pointer if the data set is empty.
116 The caller retains ownership of NP and READER. */
118 dnp_plot_create (const struct np *np, const struct casereader *reader,
121 return make_np_plot (&dnp_plot_chart_class, np, reader, label);
125 np_plot_chart_draw (const struct chart *chart, cairo_t *cr,
126 struct chart_geometry *geom)
128 const struct np_plot_chart *npp = UP_CAST (chart, struct np_plot_chart,
130 struct casereader *data;
133 chart_write_title (cr, geom, _("Normal Q-Q Plot of %s"), npp->label);
134 chart_write_xlabel (cr, geom, _("Observed Value"));
135 chart_write_ylabel (cr, geom, _("Expected Normal"));
136 chart_write_xscale (cr, geom,
137 npp->x_lower - npp->slack,
138 npp->x_upper + npp->slack, 5);
139 chart_write_yscale (cr, geom, npp->y_first, npp->y_last, 5);
141 data = casereader_clone (npp->data);
142 for (; (c = casereader_read (data)) != NULL; case_unref (c))
143 chart_datum (cr, geom, 0,
144 case_data_idx (c, NP_IDX_Y)->f,
145 case_data_idx (c, NP_IDX_NS)->f);
146 casereader_destroy (data);
148 chart_line (cr, geom, npp->slope, npp->intercept,
149 npp->y_first, npp->y_last, CHART_DIM_Y);
153 dnp_plot_chart_draw (const struct chart *chart, cairo_t *cr,
154 struct chart_geometry *geom)
156 const struct np_plot_chart *dnpp = UP_CAST (chart, struct np_plot_chart,
158 struct casereader *data;
161 chart_write_title (cr, geom, _("Detrended Normal Q-Q Plot of %s"),
163 chart_write_xlabel (cr, geom, _("Observed Value"));
164 chart_write_ylabel (cr, geom, _("Dev from Normal"));
165 chart_write_xscale (cr, geom, dnpp->y_min, dnpp->y_max, 5);
166 chart_write_yscale (cr, geom, dnpp->dns_min, dnpp->dns_max, 5);
168 data = casereader_clone (dnpp->data);
169 for (; (c = casereader_read (data)) != NULL; case_unref (c))
170 chart_datum (cr, geom, 0, case_data_idx (c, NP_IDX_Y)->f,
171 case_data_idx (c, NP_IDX_DNS)->f);
172 casereader_destroy (data);
174 chart_line (cr, geom, 0, 0, dnpp->y_min, dnpp->y_max, CHART_DIM_X);
178 np_plot_chart_destroy (struct chart *chart)
180 struct np_plot_chart *npp = UP_CAST (chart, struct np_plot_chart, chart);
181 casereader_destroy (npp->data);
186 static const struct chart_class np_plot_chart_class =
189 np_plot_chart_destroy
192 static const struct chart_class dnp_plot_chart_class =
195 np_plot_chart_destroy