1 /*
2  * gog-histogram.c
3  *
4  * Copyright (C) 2005-2010 Jean Brefort (jean.brefort@normalesup.org)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) version 3.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
19  * USA
20  */
21 
22 #include <goffice/goffice-config.h>
23 #include "gog-histogram.h"
24 #include <goffice/data/go-data.h>
25 #include <goffice/graph/gog-axis.h>
26 #include <goffice/graph/gog-chart.h>
27 #include <goffice/graph/gog-chart-map.h>
28 #include <goffice/graph/gog-renderer.h>
29 #include <goffice/graph/gog-series-lines.h>
30 #include <goffice/math/go-math.h>
31 #include <goffice/utils/go-format.h>
32 #include <goffice/utils/go-path.h>
33 #include <goffice/utils/go-persist.h>
34 #include <goffice/utils/go-styled-object.h>
35 #include <glib/gi18n-lib.h>
36 #include <gsf/gsf-impl-utils.h>
37 
38 #define GOG_TYPE_HISTOGRAM_PLOT_SERIES	(gog_histogram_plot_series_get_type ())
39 #define GOG_HISTOGRAM_PLOT_SERIES(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_TYPE_HISTOGRAM_PLOT_SERIES, GogHistogramPlotSeries))
40 #define GOG_IS_HISTOGRAM_PLOT_SERIES(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_TYPE_HISTOGRAM_PLOT_SERIES))
41 
42 typedef struct {
43 	GogSeries base;
44 	GogObject *droplines;
45 	double *x, *y, *y_; /* y_ is the second data for double histograms. */
46 	double *real_x, *real_y, *real_y_;
47 } GogHistogramPlotSeries;
48 typedef GogSeriesClass GogHistogramPlotSeriesClass;
49 
50 GType gog_histogram_plot_series_get_type (void);
51 GType gog_histogram_plot_view_get_type (void);
52 
53 static GogObjectClass *histogram_plot_parent_klass;
54 
55 /* Tests if product is strictly positive without causing overflow.  */
56 static gboolean
pos_product(double x1,double x2)57 pos_product (double x1, double x2)
58 {
59 	return ((x1 > 0 && x2 > 0) ||
60 		(x1 < 0 && x2 < 0));
61 }
62 
63 
64 static void
gog_histogram_plot_clear_formats(GogHistogramPlot * model)65 gog_histogram_plot_clear_formats (GogHistogramPlot *model)
66 {
67 	go_format_unref (model->x.fmt);
68 	model->x.fmt = NULL;
69 
70 	go_format_unref (model->y.fmt);
71 	model->y.fmt = NULL;
72 }
73 
74 static char const *
gog_histogram_plot_type_name(G_GNUC_UNUSED GogObject const * item)75 gog_histogram_plot_type_name (G_GNUC_UNUSED GogObject const *item)
76 {
77 	/* xgettext : the base for how to name histogram-plot objects
78 	 * eg The 2nd histogram-plot in a chart will be called
79 	 * 	Histogram2 */
80 	return N_("Histogram");
81 }
82 
83 static void
gog_histogram_plot_update(GogObject * obj)84 gog_histogram_plot_update (GogObject *obj)
85 {
86 	GogHistogramPlot *model = GOG_HISTOGRAM_PLOT (obj);
87 	GogHistogramPlotSeries *series = GOG_HISTOGRAM_PLOT_SERIES (
88 		model->base.series->data);
89 	double x_min, x_max, y_min = DBL_MAX, y_max = -DBL_MAX, *x_vals = NULL, *y_vals = NULL, val;
90 	unsigned i, y_len = 0;
91 
92 	if (!gog_series_is_valid (GOG_SERIES (series)) || series->base.num_elements == 0)
93 			return;
94 
95 	g_free (series->x);
96 	series->x = g_new (double, series->base.num_elements);
97 	if (series->real_x != NULL)
98 		x_vals = series->real_x;
99 	else if (series->base.values[0].data != NULL)
100 		x_vals = go_data_get_values (series->base.values[0].data);
101 	if (x_vals != NULL) {
102 		x_min = x_vals[0];
103 		x_max = x_vals[series->base.num_elements];
104 		if (series->base.values[0].data) {
105 			if (model->x.fmt == NULL)
106 				model->x.fmt = go_data_preferred_fmt (series->base.values[0].data);
107 			model->x.date_conv = go_data_date_conv (series->base.values[0].data);
108 		}
109 		for (i = 0; i < series->base.num_elements; i++)
110 			series->x[i] = (x_vals[i] + x_vals[i+1]) / 2;
111 	} else {
112 		x_vals = NULL;
113 		x_min = 0;
114 		x_max = series->base.num_elements;
115 		for (i = 0; i < series->base.num_elements; i++)
116 			series->x[i] = (double) i + 0.5;
117 	}
118 	if (model->x.minima != x_min || model->x.maxima != x_max) {
119 		model->x.minima = x_min;
120 		model->x.maxima = x_max;
121 		gog_axis_bound_changed (model->base.axis[model->vertical? 0: 1], GOG_OBJECT (model));
122 	}
123 	g_free (series->y);
124 	series->y = NULL;
125 	if (series->real_y != NULL) {
126 		y_vals = series->real_y;
127 		y_len = series->base.num_elements;
128 	} else if (series->base.values[1].data != NULL) {
129 		y_vals = go_data_get_values (series->base.values[1].data);
130 		y_len = go_data_get_vector_size (series->base.values[1].data);
131 		if (y_len > series->base.num_elements)
132 			y_len = series->base.num_elements;
133 	}
134 	if (y_vals != NULL) {
135 		double sum = 0.;
136 		series->y = g_new0 (double, series->base.num_elements);
137 		for (i = 0; i < y_len; i++)
138 			if (go_finite (y_vals[i])) {
139 				if (model->cumulative)
140 					sum += y_vals[i];
141 				else
142 					sum = y_vals[i];
143 				series->y[i] = val = sum / (x_vals[i+1] - x_vals[i]);
144 				if (val < y_min)
145 					y_min = val;
146 				if (val > y_max)
147 					y_max = val;
148 			} else
149 				series->y[i] = model->cumulative ? sum : 0.;
150 		if (model->y.fmt == NULL)
151 			model->y.fmt = go_data_preferred_fmt (series->base.values[1].data);
152 		model->y.date_conv = go_data_date_conv (series->base.values[1].data);
153 	}
154 	if (GOG_IS_DOUBLE_HISTOGRAM_PLOT (model) && series->base.values[2].data != NULL) {
155 		double max = 0.;
156 		g_free (series->y_);
157 		series->y_ = NULL;
158 		if (series->real_y_ != NULL) {
159 			y_vals = series->real_y_;
160 			y_len = series->base.num_elements;
161 		} else if (series->base.values[1].data != NULL) {
162 			y_vals = go_data_get_values (series->base.values[1].data);
163 			y_len = go_data_get_vector_size (series->base.values[1].data);
164 			if (y_len > series->base.num_elements)
165 				y_len = series->base.num_elements;
166 		} else
167 			y_vals = NULL;
168 		if (y_vals != NULL) {
169 			double sum = 0.;
170 			y_min = 0.;
171 			series->y_ = g_new0 (double, series->base.num_elements);
172 			for (i = 0; i < y_len; i++)
173 				if (go_finite (y_vals[i])) {
174 					if (model->cumulative)
175 						sum += y_vals[i];
176 					else
177 						sum = y_vals[i];
178 					series->y_[i] = val = -sum / (x_vals[i+1] - x_vals[i]);
179 					if (val < y_min)
180 						y_min = val;
181 					if (val > max)
182 						max = val;
183 				} else
184 					series->y_[i] = model->cumulative ? sum : 0.;
185 		}
186 		if (y_max < 0)
187 			y_max = max;
188 	}
189 	if (y_min > y_max)
190 		y_min = y_max = go_nan;
191 	if (model->y.minima != y_min || model->y.maxima != y_max) {
192 		model->y.minima = y_min;
193 		model->y.maxima = y_max;
194 		gog_axis_bound_changed (model->base.axis[model->vertical? 1: 0], GOG_OBJECT (model));
195 	}
196 	gog_object_emit_changed (GOG_OBJECT (obj), FALSE);
197 }
198 
199 static GOData *
gog_histogram_plot_axis_get_bounds(GogPlot * plot,GogAxisType axis,GogPlotBoundInfo * bounds)200 gog_histogram_plot_axis_get_bounds (GogPlot *plot, GogAxisType axis,
201 			      GogPlotBoundInfo *bounds)
202 {
203 	GogHistogramPlot *model = GOG_HISTOGRAM_PLOT (plot);
204 
205 
206 	if ((axis == GOG_AXIS_X && model->vertical) || (axis == GOG_AXIS_Y && !model->vertical)) {
207 		bounds->val.minima = model->x.minima;
208 		bounds->val.maxima = model->x.maxima;
209 		if (bounds->fmt == NULL && model->x.fmt != NULL)
210 			bounds->fmt = go_format_ref (model->x.fmt);
211 		if (model->x.date_conv)
212 			bounds->date_conv = model->x.date_conv;
213 	} else {
214 		bounds->val.minima = model->y.minima;
215 		bounds->val.maxima = model->y.maxima;
216 		if (bounds->fmt == NULL && model->y.fmt != NULL)
217 			bounds->fmt = go_format_ref (model->y.fmt);
218 		if (model->y.date_conv)
219 			bounds->date_conv = model->y.date_conv;
220 	}
221 	bounds->is_discrete = FALSE;
222 	return NULL;
223 }
224 
225 enum {
226 	HISTOGRAM_PROP_0,
227 	HISTOGRAM_PROP_VERTICAL,
228 	HISTOGRAM_PROP_CUMULATIVE,
229 	HISTOGRAM_PROP_BEFORE_GRID
230 };
231 
232 static void
gog_histogram_plot_get_property(GObject * obj,guint param_id,GValue * value,GParamSpec * pspec)233 gog_histogram_plot_get_property (GObject *obj, guint param_id,
234 		       GValue *value, GParamSpec *pspec)
235 {
236 	GogHistogramPlot *model = GOG_HISTOGRAM_PLOT (obj);
237 	switch (param_id) {
238 	case HISTOGRAM_PROP_VERTICAL:
239 		g_value_set_boolean (value, model->vertical);
240 		break;
241 	case HISTOGRAM_PROP_CUMULATIVE:
242 		g_value_set_boolean (value, model->cumulative);
243 		break;
244 	case HISTOGRAM_PROP_BEFORE_GRID:
245 		g_value_set_boolean (value, GOG_PLOT (obj)->rendering_order == GOG_PLOT_RENDERING_BEFORE_GRID);
246 		break;
247 
248 	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
249 		 break;
250 	}
251 }
252 
253 static void
gog_histogram_plot_set_property(GObject * obj,guint param_id,GValue const * value,GParamSpec * pspec)254 gog_histogram_plot_set_property (GObject *obj, guint param_id,
255 		       GValue const *value, GParamSpec *pspec)
256 {
257 	GogHistogramPlot *model = GOG_HISTOGRAM_PLOT (obj);
258 	switch (param_id) {
259 	case HISTOGRAM_PROP_VERTICAL:
260 		if (g_value_get_boolean (value) != model->vertical) {
261 			model->vertical = !model->vertical;
262 			/* force axis bounds reevaluation */
263 			model->x.minima = model->y.minima = G_MAXDOUBLE;
264 			gog_object_request_update (GOG_OBJECT (model));
265 		}
266 		break;
267 	case HISTOGRAM_PROP_CUMULATIVE:
268 		if (g_value_get_boolean (value) != model->cumulative) {
269 			model->cumulative = !model->cumulative;
270 			gog_object_request_update (GOG_OBJECT (model));
271 		}
272 		break;
273 	case HISTOGRAM_PROP_BEFORE_GRID:
274 		GOG_PLOT (obj)->rendering_order =
275 			(g_value_get_boolean (value)
276 			 ? GOG_PLOT_RENDERING_BEFORE_GRID
277 			 : GOG_PLOT_RENDERING_LAST);
278 		gog_object_emit_changed (GOG_OBJECT (obj), FALSE);
279 		break;
280 
281 	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
282 		 return; /* NOTE : RETURN */
283 	}
284 }
285 
286 #ifdef GOFFICE_WITH_GTK
287 #include <goffice/gtk/goffice-gtk.h>
288 
289 static void
vertical_changed_cb(GtkToggleButton * btn,GogHistogramPlot * model)290 vertical_changed_cb (GtkToggleButton *btn, GogHistogramPlot *model)
291 {
292 	if (gtk_toggle_button_get_active (btn) != model->vertical) {
293 		model->vertical = !model->vertical;
294 		gog_object_request_update (GOG_OBJECT (model));
295 		/* force axis bounds reevaluation */
296 		model->x.minima = model->y.minima = G_MAXDOUBLE;
297 	}
298 }
299 
300 static void
cumulative_changed_cb(GtkToggleButton * btn,GogHistogramPlot * model)301 cumulative_changed_cb (GtkToggleButton *btn, GogHistogramPlot *model)
302 {
303 	if (gtk_toggle_button_get_active (btn) != model->cumulative) {
304 		model->cumulative = !model->cumulative;
305 		gog_object_request_update (GOG_OBJECT (model));
306 	}
307 }
308 
309 static void
display_before_grid_cb(GtkToggleButton * btn,GObject * obj)310 display_before_grid_cb (GtkToggleButton *btn, GObject *obj)
311 {
312 	g_object_set (obj, "before-grid", gtk_toggle_button_get_active (btn), NULL);
313 }
314 
315 static void
gog_histogram_plot_populate_editor(GogObject * item,GOEditor * editor,G_GNUC_UNUSED GogDataAllocator * dalloc,GOCmdContext * cc)316 gog_histogram_plot_populate_editor (GogObject *item,
317 			      GOEditor *editor,
318 			      G_GNUC_UNUSED GogDataAllocator *dalloc,
319 			      GOCmdContext *cc)
320 {
321 	GtkWidget  *w;
322 	GogHistogramPlot *hist = GOG_HISTOGRAM_PLOT (item);
323 	GtkBuilder *gui =
324 		go_gtk_builder_load ("res:go:plot_distrib/gog-histogram-prefs.ui",
325 				    GETTEXT_PACKAGE, cc);
326         if (gui != NULL) {
327 		w = go_gtk_builder_get_widget (gui, "vertical");
328 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), hist->vertical);
329 		g_signal_connect (w, "toggled", G_CALLBACK (vertical_changed_cb), hist);
330 
331 		w = go_gtk_builder_get_widget (gui, "cumulative");
332 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), hist->cumulative);
333 		g_signal_connect (w, "toggled", G_CALLBACK (cumulative_changed_cb), hist);
334 
335 		w = go_gtk_builder_get_widget (gui, "before-grid");
336 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w),
337 				(GOG_PLOT (item))->rendering_order == GOG_PLOT_RENDERING_BEFORE_GRID);
338 		g_signal_connect (G_OBJECT (w),
339 			"toggled",
340 			G_CALLBACK (display_before_grid_cb), item);
341 
342 		w = go_gtk_builder_get_widget (gui, "histogram-prefs");
343 		go_editor_add_page (editor, w , _("Properties"));
344 		g_object_unref (gui);
345 	}
346 
347 	(GOG_OBJECT_CLASS(histogram_plot_parent_klass)->populate_editor) (item, editor, dalloc, cc);
348 }
349 #endif
350 
351 static void
gog_histogram_plot_finalize(GObject * obj)352 gog_histogram_plot_finalize (GObject *obj)
353 {
354 	gog_histogram_plot_clear_formats (GOG_HISTOGRAM_PLOT (obj));
355 	G_OBJECT_CLASS (histogram_plot_parent_klass)->finalize (obj);
356 }
357 
358 static void
gog_histogram_plot_class_init(GogPlotClass * gog_plot_klass)359 gog_histogram_plot_class_init (GogPlotClass *gog_plot_klass)
360 {
361 	GObjectClass *gobject_klass = (GObjectClass *) gog_plot_klass;
362 	GogObjectClass *gog_object_klass = (GogObjectClass *) gog_plot_klass;
363 
364 	histogram_plot_parent_klass = g_type_class_peek_parent (gog_plot_klass);
365 
366 	gobject_klass->finalize = gog_histogram_plot_finalize;
367 	gobject_klass->get_property = gog_histogram_plot_get_property;
368 	gobject_klass->set_property = gog_histogram_plot_set_property;
369 
370 	g_object_class_install_property (gobject_klass, HISTOGRAM_PROP_VERTICAL,
371 		g_param_spec_boolean ("vertical",
372 			_("Vertical"),
373 			_("Draw the histogram vertically or horizontally"),
374 			TRUE,
375 			GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
376 	g_object_class_install_property (gobject_klass, HISTOGRAM_PROP_CUMULATIVE,
377 		g_param_spec_boolean ("cumulative",
378 			_("Cumulative"),
379 			_("Use cumulated data"),
380 			FALSE,
381 			GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
382 	g_object_class_install_property (gobject_klass, HISTOGRAM_PROP_BEFORE_GRID,
383 		g_param_spec_boolean ("before-grid",
384 			_("Displayed under the grids"),
385 			_("Should the plot be displayed before the grids"),
386 			FALSE,
387 			GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
388 
389 	gog_object_klass->type_name	= gog_histogram_plot_type_name;
390 	gog_object_klass->view_type	= gog_histogram_plot_view_get_type ();
391 	gog_object_klass->update	= gog_histogram_plot_update;
392 #ifdef GOFFICE_WITH_GTK
393 	gog_object_klass->populate_editor = gog_histogram_plot_populate_editor;
394 #endif
395 
396 	{
397 		static GogSeriesDimDesc dimensions[] = {
398 			{ N_("Limits"), GOG_SERIES_SUGGESTED, FALSE,
399 			  GOG_DIM_INDEX, GOG_MS_DIM_CATEGORIES },
400 			{ N_("Values"), GOG_SERIES_REQUIRED, FALSE,
401 			  GOG_DIM_VALUE, GOG_MS_DIM_VALUES },
402 		};
403 		gog_plot_klass->desc.series.dim = dimensions;
404 		gog_plot_klass->desc.series.num_dim = G_N_ELEMENTS (dimensions);
405 	}
406 	gog_plot_klass->desc.num_series_max = 1;
407 	gog_plot_klass->series_type = gog_histogram_plot_series_get_type ();
408 	gog_plot_klass->axis_set = GOG_AXIS_SET_XY;
409 	gog_plot_klass->desc.series.style_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL;
410 	gog_plot_klass->axis_get_bounds   	 = gog_histogram_plot_axis_get_bounds;
411 }
412 
413 static void
gog_histogram_plot_init(GogHistogramPlot * hist)414 gog_histogram_plot_init (GogHistogramPlot *hist)
415 {
416 	GogPlot *plot = GOG_PLOT (hist);
417 
418 	plot->rendering_order = GOG_PLOT_RENDERING_BEFORE_AXIS;
419 	hist->vertical = TRUE;
420 }
421 
GSF_DYNAMIC_CLASS(GogHistogramPlot,gog_histogram_plot,gog_histogram_plot_class_init,gog_histogram_plot_init,GOG_TYPE_PLOT)422 GSF_DYNAMIC_CLASS (GogHistogramPlot, gog_histogram_plot,
423 	gog_histogram_plot_class_init, gog_histogram_plot_init,
424 	GOG_TYPE_PLOT)
425 
426 /*****************************************************************************/
427 /*   Double histograms                                                       */
428 
429 static GObjectClass *double_histogram_plot_parent_klass;
430 
431 #ifdef GOFFICE_WITH_GTK
432 static void
433 gog_double_histogram_plot_populate_editor (GogObject	*gobj,
434 			       GOEditor	*editor,
435 			       GogDataAllocator	*dalloc,
436 			       GOCmdContext	*cc)
437 {
438 	GtkGrid *grid;
439 	GtkWidget *w;
440 	GogDataset *set = GOG_DATASET (gobj);
441 	GtkBuilder *gui =
442 		go_gtk_builder_load ("res:go:plot_distrib/gog-double-histogram-prefs.ui",
443 				    GETTEXT_PACKAGE, cc);
444 	if (gui != NULL) {
445 		grid = GTK_GRID (gtk_builder_get_object (gui, "double-histogram-prefs"));
446 		w = GTK_WIDGET (gog_data_allocator_editor (dalloc, set, 0, GOG_DATA_SCALAR));
447 		gtk_widget_set_tooltip_text (w, _("Label for the first Y category. If not set or empty, \"First values\" will be used."));
448 		gtk_widget_show (w);
449 		gtk_widget_set_hexpand (w, TRUE);
450 		gtk_grid_attach (grid, w, 1, 0, 1, 1);
451 		w = GTK_WIDGET (gog_data_allocator_editor (dalloc, set, 1, GOG_DATA_SCALAR));
452 		gtk_widget_set_tooltip_text (w, _("Label for the second Y category. If not set or empty, \"Second values\" will be used."));
453 		gtk_widget_show (w);
454 		gtk_widget_set_hexpand (w, TRUE);
455 		gtk_grid_attach (grid, w, 1, 1, 1, 1);
456 		go_editor_add_page (editor,
457 				     go_gtk_builder_get_widget (gui, "double-histogram-prefs"),
458 				     _("Categories labels"));
459 	}
460 	(GOG_OBJECT_CLASS (double_histogram_plot_parent_klass)->populate_editor) (gobj, editor, dalloc, cc);
461 }
462 #endif
463 
464 static void
gog_double_histogram_plot_finalize(GObject * obj)465 gog_double_histogram_plot_finalize (GObject *obj)
466 {
467 	GogDoubleHistogramPlot *plot = GOG_DOUBLE_HISTOGRAM_PLOT (obj);
468 	if (plot->labels != NULL) {
469 		gog_dataset_finalize (GOG_DATASET (obj));
470 		g_free (plot->labels);
471 		plot->labels = NULL;
472 	}
473 	(*double_histogram_plot_parent_klass->finalize) (obj);
474 }
475 
476 static void
gog_double_histogram_plot_class_init(GogPlotClass * gog_plot_klass)477 gog_double_histogram_plot_class_init (GogPlotClass *gog_plot_klass)
478 {
479 	GObjectClass *gobject_klass = (GObjectClass *) gog_plot_klass;
480 	GogObjectClass *gog_klass = (GogObjectClass *) gog_plot_klass;
481 	double_histogram_plot_parent_klass = g_type_class_peek_parent (gog_klass);
482 	gobject_klass->finalize	    = gog_double_histogram_plot_finalize;
483 #ifdef GOFFICE_WITH_GTK
484 	gog_klass->populate_editor  = gog_double_histogram_plot_populate_editor;
485 #endif
486 	{
487 		static GogSeriesDimDesc dimensions[] = {
488 			{ N_("Limits"), GOG_SERIES_REQUIRED, FALSE,
489 			  GOG_DIM_INDEX, GOG_MS_DIM_CATEGORIES },
490 			{ N_("First values"), GOG_SERIES_REQUIRED, FALSE,
491 			  GOG_DIM_VALUE, GOG_MS_DIM_VALUES },
492 			{ N_("Second values"), GOG_SERIES_REQUIRED, FALSE,
493 			  GOG_DIM_VALUE, GOG_MS_DIM_EXTRA1 },
494 		};
495 		gog_plot_klass->desc.series.dim = dimensions;
496 		gog_plot_klass->desc.series.num_dim = G_N_ELEMENTS (dimensions);
497 		gog_plot_klass->desc.series.style_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL | GO_STYLE_FONT;
498 	}
499 }
500 
501 static void
gog_double_histogram_plot_init(GogDoubleHistogramPlot * plot)502 gog_double_histogram_plot_init (GogDoubleHistogramPlot *plot)
503 {
504 	plot->labels = g_new0 (GogDatasetElement, 2);
505 }
506 
507 static void
gog_double_histogram_plot_dataset_dims(GogDataset const * set,int * first,int * last)508 gog_double_histogram_plot_dataset_dims (GogDataset const *set, int *first, int *last)
509 {
510 	*first = 0;
511 	*last = 1;
512 }
513 
514 static GogDatasetElement *
gog_double_histogram_plot_dataset_get_elem(GogDataset const * set,int dim_i)515 gog_double_histogram_plot_dataset_get_elem (GogDataset const *set, int dim_i)
516 {
517 	GogDoubleHistogramPlot const *plot = GOG_DOUBLE_HISTOGRAM_PLOT (set);
518 	g_return_val_if_fail (2 > dim_i, NULL);
519 	g_return_val_if_fail (dim_i >= 0, NULL);
520 	return plot->labels + dim_i;
521 }
522 
523 static void
gog_double_histogram_plot_dataset_dim_changed(GogDataset * set,int dim_i)524 gog_double_histogram_plot_dataset_dim_changed (GogDataset *set, int dim_i)
525 {
526 	gog_object_request_update (GOG_OBJECT (set));
527 }
528 
529 static void
gog_double_histogram_plot_dataset_init(GogDatasetClass * iface)530 gog_double_histogram_plot_dataset_init (GogDatasetClass *iface)
531 {
532 	iface->get_elem	   = gog_double_histogram_plot_dataset_get_elem;
533 	iface->dims	   = gog_double_histogram_plot_dataset_dims;
534 	iface->dim_changed = gog_double_histogram_plot_dataset_dim_changed;
535 }
536 
537 GSF_DYNAMIC_CLASS_FULL (GogDoubleHistogramPlot, gog_double_histogram_plot,
538 	NULL, NULL, gog_double_histogram_plot_class_init, NULL,
539         gog_double_histogram_plot_init, GOG_TYPE_HISTOGRAM_PLOT, 0,
540         GSF_INTERFACE (gog_double_histogram_plot_dataset_init, GOG_TYPE_DATASET))
541 
542 /*****************************************************************************/
543 typedef GogPlotView		GogHistogramPlotView;
544 typedef GogPlotViewClass	GogHistogramPlotViewClass;
545 
546 static void
gog_histogram_plot_view_render(GogView * view,GogViewAllocation const * bbox)547 gog_histogram_plot_view_render (GogView *view, GogViewAllocation const *bbox)
548 {
549 	GogHistogramPlot const *model = GOG_HISTOGRAM_PLOT (view->model);
550 	GogChart *chart = GOG_CHART (view->model->parent);
551 	GogChartMap *chart_map;
552 	GogAxisMap *x_map, *y_map;
553 	GogViewAllocation const *area;
554 	GogHistogramPlotSeries const *series;
555 	double *x_vals = NULL, *y_vals, y0;
556 	unsigned i;
557 	GOPath *path ;
558 	GSList *ptr;
559 	GOStyle *style;
560 
561 	if (model->base.series == NULL)
562 		return;
563 	series = GOG_HISTOGRAM_PLOT_SERIES (model->base.series->data);
564 	style = GOG_STYLED_OBJECT (series)->style;
565 	if (series->base.num_elements < 1)
566 		return;
567 	area = gog_chart_view_get_plot_area (view->parent);
568 	chart_map = gog_chart_map_new (chart, area,
569 				       GOG_PLOT (model)->axis[GOG_AXIS_X],
570 				       GOG_PLOT (model)->axis[GOG_AXIS_Y],
571 				       NULL, FALSE);
572 	if (!gog_chart_map_is_valid (chart_map)) {
573 		gog_chart_map_free (chart_map);
574 		return;
575 	}
576 
577 	/* clip the plot to it's allocated rectangle, see #684195 */
578 	gog_renderer_push_clip_rectangle (view->renderer, area->x, area->y, area->w, area->h);
579 
580 	x_map = gog_chart_map_get_axis_map (chart_map, 0);
581 	y_map = gog_chart_map_get_axis_map (chart_map, 1);
582 
583 	if (series->real_x)
584 		x_vals = series->real_x;
585 	else if (series->base.values[0].data)
586 		x_vals = go_data_get_values (series->base.values[0].data);
587 	y_vals = series->y ? series->y : go_data_get_values (series->base.values[1].data);
588 
589 	path = go_path_new ();
590 	go_path_set_options (path, GO_PATH_OPTIONS_SHARP);
591 	if (model->vertical) {
592 		double curx = gog_axis_map_to_view (x_map, x_vals ? x_vals[0] : 0);
593 		go_path_move_to (path, curx, y0 = gog_axis_map_get_baseline (y_map));
594 		for (i = 0; i < series->base.num_elements; i++) {
595 			double cury = gog_axis_map_to_view (y_map, y_vals[i]);
596 			go_path_line_to (path, curx, cury);
597 			curx = gog_axis_map_to_view (x_map, x_vals ? x_vals[i+1] : 0);
598 			go_path_line_to (path, curx, cury);
599 		}
600 		go_path_line_to (path, curx, y0);
601 	} else {
602 		double curx = gog_axis_map_to_view (y_map, x_vals ? x_vals[0] : 0);
603 		go_path_move_to (path, y0 = gog_axis_map_get_baseline (x_map), curx);
604 		for (i = 0; i < series->base.num_elements; i++) {
605 			double cury = gog_axis_map_to_view (x_map, y_vals[i]);
606 			go_path_line_to (path, cury, curx);
607 			curx = gog_axis_map_to_view (y_map, x_vals ? x_vals[i+1] : 0);
608 			go_path_line_to (path, cury, curx);
609 		}
610 		go_path_line_to (path, y0, curx);
611 	}
612 	go_path_close (path);
613 	gog_renderer_push_style (view->renderer, style);
614 	gog_renderer_fill_shape (view->renderer, path);
615 
616 	if (series->droplines) {
617 		GOPath *drop_path = go_path_new ();
618 		double cury = y0;
619 		go_path_set_options (drop_path, GO_PATH_OPTIONS_SHARP);
620 		gog_renderer_push_style (view->renderer,
621 			go_styled_object_get_style (GO_STYLED_OBJECT (series->droplines)));
622 		if (model->vertical) {
623 			for (i = 1; i < series->base.num_elements; i++) {
624 				double x = x_vals ? x_vals[i] : 0;
625 				double y = y_vals[i];
626 				double y_prev = y_vals[i - 1];
627 				double curx = gog_axis_map_to_view (x_map, x);
628 
629 				if (pos_product (y, y_prev)) {
630 					go_path_move_to (drop_path, curx, y0);
631 					cury = gog_axis_map_to_view
632 						(y_map,
633 						 y > 0 ? MIN (y_prev, y) : MAX (y_prev, y));
634 				} else {
635 					go_path_move_to (drop_path, curx, cury);
636 					cury = gog_axis_map_to_view (y_map, y);
637 				}
638 				go_path_line_to (drop_path, curx, cury);
639 			}
640 		} else {
641 			for (i = 1; i < series->base.num_elements; i++) {
642 				double x = x_vals ? x_vals[i] : 0;
643 				double y = y_vals[i];
644 				double y_prev = y_vals[i - 1];
645 				double curx = gog_axis_map_to_view (y_map, x);
646 
647 				if (pos_product (y, y_prev)) {
648 					go_path_move_to (drop_path, y0, curx);
649 					cury = gog_axis_map_to_view
650 						(x_map,
651 						 y > 0 ? MIN (y_prev, y) : MAX (y_prev, y));
652 				} else {
653 					go_path_move_to (drop_path, cury, curx);
654 					cury = gog_axis_map_to_view (x_map, y);
655 				}
656 				go_path_line_to (drop_path, cury, curx);
657 			}
658 		}
659 		gog_renderer_stroke_serie (view->renderer, drop_path);
660 		go_path_free (drop_path);
661 		gog_renderer_pop_style (view->renderer);
662 	}
663 	gog_renderer_stroke_shape (view->renderer, path);
664 	gog_renderer_pop_style (view->renderer);
665 	go_path_free (path);
666 	/* Redo the same for the other side of a double histogram. */
667 	if (GOG_IS_DOUBLE_HISTOGRAM_PLOT (model) && series->base.values[2].data != NULL) {
668 		y_vals = series->y_ ? series->y_ : go_data_get_values (series->base.values[2].data);
669 		path = go_path_new ();
670 		go_path_set_options (path, GO_PATH_OPTIONS_SHARP);
671 		if (model->vertical) {
672 			double curx = gog_axis_map_to_view (x_map, x_vals ? x_vals[0]: 0);
673 			go_path_move_to (path, curx, y0);
674 			for (i = 0; i < series->base.num_elements; i++) {
675 				double cury = gog_axis_map_to_view (y_map, y_vals[i]);
676 				go_path_line_to (path, curx, cury);
677 				curx = gog_axis_map_to_view (x_map, (x_vals ? x_vals[i+1]: 0.));
678 				go_path_line_to (path, curx, cury);
679 			}
680 			go_path_line_to (path, curx, y0);
681 		} else {
682 			double curx = gog_axis_map_to_view (y_map, x_vals ? x_vals[0]: 0);
683 			go_path_move_to (path, y0, curx);
684 			for (i = 0; i < series->base.num_elements; i++) {
685 				double cury = gog_axis_map_to_view (x_map, y_vals[i]);
686 				go_path_line_to (path, cury, curx);
687 				curx = gog_axis_map_to_view (y_map, (x_vals ? x_vals[i+1]: 0.));
688 				go_path_line_to (path, cury, curx);
689 			}
690 			go_path_line_to (path, y0, curx);
691 		}
692 		go_path_close (path);
693 		gog_renderer_push_style (view->renderer, style);
694 		gog_renderer_fill_shape (view->renderer, path);
695 
696 		if (series->droplines) {
697 			GOPath *drop_path = go_path_new ();
698 			double cury = y0;
699 			go_path_set_options (drop_path, GO_PATH_OPTIONS_SHARP);
700 			gog_renderer_push_style (view->renderer,
701 				go_styled_object_get_style (GO_STYLED_OBJECT (series->droplines)));
702 			if (model->vertical) {
703 				for (i = 1; i < series->base.num_elements; i++) {
704 					double x = x_vals ? x_vals[i] : 0;
705 					double y = y_vals[i];
706 					double y_prev = y_vals[i - 1];
707 					double curx = gog_axis_map_to_view (x_map, x);
708 
709 					if (pos_product (y_prev, y)) {
710 						go_path_move_to (drop_path, curx, y0);
711 						cury = gog_axis_map_to_view
712 							(y_map,
713 							 y > 0 ? MIN (y_prev, y) : MAX (y_prev, y));
714 					} else {
715 						go_path_move_to (drop_path, curx, cury);
716 						cury = gog_axis_map_to_view (y_map, y);
717 					}
718 					go_path_line_to (drop_path, curx, cury);
719 				}
720 			} else {
721 				for (i = 1; i < series->base.num_elements; i++) {
722 					double x = x_vals ? x_vals[i] : 0;
723 					double y = y_vals[i];
724 					double y_prev = y_vals[i - 1];
725 					double curx = gog_axis_map_to_view (y_map, x);
726 
727 					if (pos_product (y_prev, y)) {
728 						go_path_move_to (drop_path, y0, curx);
729 						cury = gog_axis_map_to_view
730 							(x_map,
731 							 y > 0 ? MIN (y_prev, y) : MAX (y_prev, y));
732 					} else {
733 						go_path_move_to (drop_path, cury, curx);
734 						cury = gog_axis_map_to_view (x_map, y);
735 					}
736 					go_path_line_to (drop_path, cury, curx);
737 				}
738 			}
739 			gog_renderer_stroke_serie (view->renderer, drop_path);
740 			go_path_free (drop_path);
741 			gog_renderer_pop_style (view->renderer);
742 		}
743 		gog_renderer_stroke_shape (view->renderer, path);
744 		go_path_free (path);
745 
746 		/* Now display labels FIXME: might be optional */
747 		{
748 			char *text1 = NULL, *text2 = NULL;
749 			char const *text;
750 			GogViewAllocation alloc;
751 			GogDoubleHistogramPlot *dbl = GOG_DOUBLE_HISTOGRAM_PLOT (model);
752 			if (dbl->labels[0].data) {
753 				text1 = go_data_get_scalar_string (dbl->labels[0].data);
754 				if (text1 && !*text1) {
755 					g_free (text1);
756 					text1 = NULL;
757 				}
758 			}
759 			if (dbl->labels[1].data) {
760 				text2 = go_data_get_scalar_string (dbl->labels[1].data);
761 				if (text2 && !*text2) {
762 					g_free (text2);
763 					text2 = NULL;
764 				}
765 			}
766 			text = text1 ? text1 : _("First values");
767 			if (model->cumulative) {
768 				if (model->vertical) {
769 					alloc.x = area->x + 2; /* FIXME: replace 2 by something configurable */
770 					alloc.y = area->y + 2;
771 					gog_renderer_draw_text (view->renderer, text, &alloc,
772 							        GO_ANCHOR_NORTH_WEST, FALSE,
773 					                        GO_JUSTIFY_LEFT, -1.);
774 					text =  text2 ? text2 : _("Second values");
775 					alloc.y = area->y + area->h - 2;
776 					gog_renderer_draw_text (view->renderer, text, &alloc,
777 							        GO_ANCHOR_SOUTH_WEST, FALSE,
778 					                        GO_JUSTIFY_LEFT, -1.);
779 				} else {
780 					alloc.x = area->x + area->w - 2; /* FIXME: replace 2 by something configurable */
781 					alloc.y = area->y + area->h - 2;
782 					gog_renderer_draw_text (view->renderer, text, &alloc,
783 							        GO_ANCHOR_SOUTH_EAST, FALSE,
784 					                        GO_JUSTIFY_LEFT, -1.);
785 					text = text2 ? text2 : _("Second values");
786 					alloc.x = area->x + 2;
787 					gog_renderer_draw_text (view->renderer, text, &alloc,
788 							        GO_ANCHOR_SOUTH_WEST, FALSE,
789 					                        GO_JUSTIFY_LEFT, -1.);
790 				}
791 			} else {
792 				alloc.x = area->x + area->w - 2; /* FIXME: replace 2 by something configurable */
793 				alloc.y = area->y + 2;
794 				gog_renderer_draw_text (view->renderer, text, &alloc,
795 					                GO_ANCHOR_NORTH_EAST, FALSE,
796 				                        GO_JUSTIFY_LEFT, -1.);
797 				text = text2 ? text2 : _("Second values");
798 				if (model->vertical) {
799 					alloc.y = area->y + area->h - 2;
800 					gog_renderer_draw_text (view->renderer, text, &alloc,
801 							        GO_ANCHOR_SOUTH_EAST, FALSE,
802 					                        GO_JUSTIFY_LEFT, -1.);
803 				} else {
804 					alloc.x = area->x + 2;
805 					gog_renderer_draw_text (view->renderer, text, &alloc,
806 							        GO_ANCHOR_NORTH_WEST, FALSE,
807 					                        GO_JUSTIFY_LEFT, -1.);
808 				}
809 			}
810 			g_free (text1);
811 			g_free (text2);
812 		}
813 		gog_renderer_pop_style (view->renderer);
814 	}
815 	gog_renderer_pop_clip (view->renderer);
816 
817 	/* Now render children */
818 	for (ptr = view->children ; ptr != NULL ; ptr = ptr->next)
819 		gog_view_render	(ptr->data, bbox);
820 
821 	gog_chart_map_free (chart_map);
822 }
823 
824 static GogViewClass *histogram_plot_view_parent_klass;
825 
826 static void
gog_histogram_plot_view_size_allocate(GogView * view,GogViewAllocation const * allocation)827 gog_histogram_plot_view_size_allocate (GogView *view, GogViewAllocation const *allocation)
828 {
829 	GSList *ptr;
830 	for (ptr = view->children; ptr != NULL; ptr = ptr->next)
831 		gog_view_size_allocate (GOG_VIEW (ptr->data), allocation);
832 	(histogram_plot_view_parent_klass->size_allocate) (view, allocation);
833 }
834 
835 static void
gog_histogram_plot_view_class_init(GogViewClass * view_klass)836 gog_histogram_plot_view_class_init (GogViewClass *view_klass)
837 {
838 	histogram_plot_view_parent_klass = (GogViewClass*) g_type_class_peek_parent (view_klass);
839 	view_klass->render	  = gog_histogram_plot_view_render;
840 	view_klass->size_allocate = gog_histogram_plot_view_size_allocate;
841 	view_klass->clip	  = FALSE;
842 }
843 
844 GSF_DYNAMIC_CLASS (GogHistogramPlotView, gog_histogram_plot_view,
845 	gog_histogram_plot_view_class_init, NULL,
846 	GOG_TYPE_PLOT_VIEW)
847 
848 /*****************************************************************************/
849 
850 typedef GogView		GogHistogramSeriesView;
851 typedef GogViewClass	GogHistogramSeriesViewClass;
852 
853 #define GOG_TYPE_HISTOGRAM_SERIES_VIEW	(gog_histogram_series_view_get_type ())
854 #define GOG_HISTOGRAM_SERIES_VIEW(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_TYPE_HISTOGRAM_SERIES_VIEW, GogHistogramSeriesView))
855 #define GOG_IS_HISTOGRAM_SERIES_VIEW(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_TYPE_HISTOGRAM_SERIES_VIEW))
856 
857 static void
gog_histogram_series_view_render(GogView * view,GogViewAllocation const * bbox)858 gog_histogram_series_view_render (GogView *view, GogViewAllocation const *bbox)
859 {
860 	GSList *ptr;
861 	for (ptr = view->children ; ptr != NULL ; ptr = ptr->next)
862 		gog_view_render	(ptr->data, bbox);
863 }
864 
865 static void
gog_histogram_series_view_size_allocate(GogView * view,GogViewAllocation const * allocation)866 gog_histogram_series_view_size_allocate (GogView *view, GogViewAllocation const *allocation)
867 {
868 	GSList *ptr;
869 
870 	for (ptr = view->children; ptr != NULL; ptr = ptr->next)
871 		gog_view_size_allocate (GOG_VIEW (ptr->data), allocation);
872 }
873 
874 static void
gog_histogram_series_view_class_init(GogHistogramSeriesViewClass * gview_klass)875 gog_histogram_series_view_class_init (GogHistogramSeriesViewClass *gview_klass)
876 {
877 	GogViewClass *view_klass = GOG_VIEW_CLASS (gview_klass);
878 	view_klass->render = gog_histogram_series_view_render;
879 	view_klass->size_allocate = gog_histogram_series_view_size_allocate;
880 	view_klass->build_toolkit = NULL;
881 }
882 
GSF_DYNAMIC_CLASS(GogHistogramSeriesView,gog_histogram_series_view,gog_histogram_series_view_class_init,NULL,GOG_TYPE_VIEW)883 GSF_DYNAMIC_CLASS (GogHistogramSeriesView, gog_histogram_series_view,
884 	gog_histogram_series_view_class_init, NULL,
885 	GOG_TYPE_VIEW)
886 
887 /*****************************************************************************/
888 
889 static gboolean
890 drop_lines_can_add (GogObject const *parent)
891 {
892 	GogHistogramPlotSeries *series = GOG_HISTOGRAM_PLOT_SERIES (parent);
893 	return (series->droplines == NULL);
894 }
895 
896 static void
drop_lines_post_add(GogObject * parent,GogObject * child)897 drop_lines_post_add (GogObject *parent, GogObject *child)
898 {
899 	GogHistogramPlotSeries *series = GOG_HISTOGRAM_PLOT_SERIES (parent);
900 	series->droplines = child;
901 	gog_object_request_update (child);
902 }
903 
904 static void
drop_lines_pre_remove(GogObject * parent,GogObject * child)905 drop_lines_pre_remove (GogObject *parent, GogObject *child)
906 {
907 	GogHistogramPlotSeries *series = GOG_HISTOGRAM_PLOT_SERIES (parent);
908 	series->droplines = NULL;
909 }
910 
911 /****************************************************************************/
912 
913 static GogObjectClass *gog_histogram_plot_series_parent_klass;
914 
915 static GObjectClass *series_parent_klass;
916 
917 static void
gog_histogram_plot_series_update(GogObject * obj)918 gog_histogram_plot_series_update (GogObject *obj)
919 {
920 	double *x_vals = NULL, *y_vals = NULL, *y__vals = NULL, cur;
921 	int x_len = 1, y_len = 0, y__len = 0, max, nb = 0, i, y_0 = 0, y__0 = 0;
922 	GogHistogramPlotSeries *series = GOG_HISTOGRAM_PLOT_SERIES (obj);
923 	unsigned old_num = series->base.num_elements;
924 	GSList *ptr;
925 	gboolean y_as_raw = FALSE;
926 	double width = -1., origin = 0.;
927 
928 	g_free (series->real_x);
929 	series->real_x = NULL;
930 	g_free (series->real_y);
931 	series->real_y = NULL;
932 	g_free (series->real_y_);
933 	series->real_y_ = NULL;
934 	if (series->base.values[1].data != NULL) {
935 		y_vals = go_data_get_values (series->base.values[1].data);
936 		nb = y_len = go_data_get_vector_size (series->base.values[1].data);
937 	}
938 	if (GOG_IS_DOUBLE_HISTOGRAM_PLOT (series->base.plot) && series->base.values[2].data != NULL) {
939 		y__vals = go_data_get_values (series->base.values[2].data);
940 		y__len = go_data_get_vector_size (series->base.values[2].data);
941 		if (y__len > y_len)
942 			nb = y__len;
943 	}
944 	if (series->base.values[0].data != NULL) {
945 		x_vals = go_data_get_values (series->base.values[0].data);
946 		max = go_data_get_vector_size (series->base.values[0].data);
947 		if (max == 2) {
948 			origin = x_vals[1];
949 			max = 1;
950 		}
951 		if (max == 1) {
952 			/* use the value as bin width */
953 			width = x_vals[0];
954 			if (!go_finite (width))
955 				width = -1.;
956 			y_as_raw = TRUE;
957 		} else if (max > nb) {
958 			if (max > 0 && go_finite (x_vals[0])) {
959 				cur = x_vals[0];
960 				for (i = 1; i < max; i++) {
961 					if (go_finite (x_vals[i]) && x_vals[i] > cur) {
962 						cur = x_vals[i];
963 						x_len++;
964 					} else
965 						break;
966 				}
967 			}
968 		} else {
969 			x_len = max;
970 			y_as_raw = TRUE;
971 		}
972 	} else
973 		y_as_raw = TRUE;
974 	if (y_as_raw) {
975 		double *y = NULL, *y_ = NULL;
976 		if (y_vals) {
977 			y = go_range_sort (y_vals, y_len);
978 			while (y_0 < y_len && !go_finite (y[y_0]))
979 				y_0++;
980 			while (y_len > y_0 && !go_finite (y[y_len-1]))
981 				y_len--;
982 		}
983 		if (y__vals) {
984 			y_ = go_range_sort (y__vals, y__len);
985 			while (y__0 < y__len && !go_finite (y[y__0]))
986 				y__0++;
987 			while (y__len > y__0 && !go_finite (y_[y__len-1]))
988 				y__len--;
989 		}
990 		if (!x_vals || x_len <= 1) {
991 			/* guess reasonable values */
992 			if (width <= 0) {
993 				max = go_fake_round (sqrt (MAX (y_len, y__len)));
994 				if (y && y_len - y_0 > 2)
995 					width = (y[y_len-1] - y[y_0]) / max;
996 				if (y_ && y__len - y__0 > 2) {
997 					double w_ = (y_[y__len-1] - y_[y__0]) / max;
998 					width = MAX (width, w_);
999 				}
1000 				if (width > 0.) {
1001 					width = log10 (width);
1002 					max = floor (width);
1003 					width -= max;
1004 					if (width < 0.15)
1005 						width = pow (10, max);
1006 					else if (width < 0.45)
1007 						width = 2 * pow (10, max);
1008 					else if (width < 0.85)
1009 						width = 2 * pow (10, max);
1010 					else
1011 						width = pow (10, max + 1);
1012 				}
1013 			}
1014 			if (width > 0. && (y || y_)) {
1015 				double m, M, nm;
1016 				/* ignore nans */
1017 				if (y) {
1018 					m = y_ ? (MIN (y[y_0], y_[y__0])) : y[y_0];
1019 					M = y_ ? MAX (y[y_len-1], y_[y__len-1]) : y[y_len-1];
1020 				} else {
1021 					m = y_[y__0];
1022 					M = y_[y__len-1];
1023 				}
1024 				if (!go_finite (m) || !go_finite (M))
1025 					return;
1026 				/* round m */
1027 				nm = floor ((m - origin)/ width) * width + origin;
1028 				/* we need to include all data so we must ensure that the
1029 				 * first bin must be lower than the first value, see  #742996 */
1030 				m = (nm == m)? nm - width: nm;
1031 				x_len = ceil ((M - m) / width) + 1;
1032 				series->real_x = g_new (double, x_len);
1033 				for (max = 0; max < x_len; max++) {
1034 					series->real_x[max] = m;
1035 					m += width;
1036 				}
1037 			}
1038 		} else
1039 			series->real_x = go_range_sort (x_vals, x_len);
1040 		if (x_len > 1) {
1041 			series->real_y = g_new0 (double, x_len - 1);
1042 			for (i = 0; i < y_len && y[i] <= series->real_x[0]; i++);
1043 			for (max = 1; i < y_len; i++)
1044 				if (go_finite (y[i])) {
1045 					while (max < x_len - 1 && y[i] > series->real_x[max])
1046 						max++;
1047 					if (y[i] >  series->real_x[max])
1048 						break;
1049 					series->real_y[max-1]++;
1050 			}
1051 			if (y__len > 0) {
1052 				series->real_y_ = g_new0 (double, x_len - 1);
1053 				for (i = 0; i < y__len && y_[i] <= series->real_x[0]; i++);
1054 				for (max = 1;  i < y__len; i++)
1055 					if (go_finite (y_[i])) {
1056 						while (y_[i] > series->real_x[max]) {
1057 							max++;
1058 							if (max == x_len - 1)
1059 								break;
1060 						}
1061 						series->real_y_[max-1]++;
1062 			}
1063 			}
1064 		}
1065 	}
1066 	series->base.num_elements = (x_len > 0 ? MIN (x_len - 1, nb) : 0);
1067 
1068 	/* update children */
1069 	for (ptr = obj->children; ptr != NULL; ptr = ptr->next)
1070 		if (!GOG_IS_SERIES_LINES (ptr->data))
1071 			gog_object_request_update (GOG_OBJECT (ptr->data));
1072 
1073 	/* queue plot for redraw */
1074 	gog_object_request_update (GOG_OBJECT (series->base.plot));
1075 	if (old_num != series->base.num_elements)
1076 		gog_plot_request_cardinality_update (series->base.plot);
1077 
1078 	if (gog_histogram_plot_series_parent_klass->update)
1079 		gog_histogram_plot_series_parent_klass->update (obj);
1080 }
1081 
1082 static void
gog_histogram_plot_series_finalize(GObject * obj)1083 gog_histogram_plot_series_finalize (GObject *obj)
1084 {
1085 	GogHistogramPlotSeries *series = GOG_HISTOGRAM_PLOT_SERIES (obj);
1086 
1087 	g_free (series->y);
1088 	series->y = NULL;
1089 	g_free (series->y_);
1090 	series->y_ = NULL;
1091 	g_free (series->x);
1092 	series->x = NULL;
1093 	g_free (series->real_x);
1094 	series->real_x = NULL;
1095 	g_free (series->real_y);
1096 	series->real_y = NULL;
1097 	g_free (series->real_y_);
1098 	series->real_y_ = NULL;
1099 
1100 	G_OBJECT_CLASS (series_parent_klass)->finalize (obj);
1101 }
1102 
1103 static unsigned
gog_histogram_plot_series_get_xy_data(GogSeries const * series,double const ** x,double const ** y)1104 gog_histogram_plot_series_get_xy_data (GogSeries const *series,
1105 					double const **x, double const **y)
1106 {
1107 	GogHistogramPlotSeries *hist_ser = GOG_HISTOGRAM_PLOT_SERIES (series);
1108 
1109 	*x = hist_ser->x;
1110 	*y = hist_ser->y ? hist_ser->y : go_data_get_values (series->values[1].data);
1111 
1112 	return series->num_elements;
1113 }
1114 
1115 static void
gog_histogram_plot_series_class_init(GogObjectClass * obj_klass)1116 gog_histogram_plot_series_class_init (GogObjectClass *obj_klass)
1117 {
1118 	static GogObjectRole const roles[] = {
1119 		{ N_("Drop lines"), "GogSeriesLines", 0,
1120 			GOG_POSITION_SPECIAL, GOG_POSITION_SPECIAL, GOG_OBJECT_NAME_BY_ROLE,
1121 			drop_lines_can_add,
1122 			NULL,
1123 			NULL,
1124 			drop_lines_post_add,
1125 			drop_lines_pre_remove,
1126 			NULL },
1127 	};
1128 	GogSeriesClass *series_klass = (GogSeriesClass*) obj_klass;
1129 	GogObjectClass *gog_klass = (GogObjectClass *)obj_klass;
1130 	GObjectClass *gobject_klass = (GObjectClass *) obj_klass;
1131 
1132 	series_parent_klass = g_type_class_peek_parent (obj_klass);
1133 	gobject_klass->finalize		= gog_histogram_plot_series_finalize;
1134 
1135 	gog_histogram_plot_series_parent_klass = g_type_class_peek_parent (obj_klass);
1136 	obj_klass->update = gog_histogram_plot_series_update;
1137 	gog_klass->view_type	= gog_histogram_series_view_get_type ();
1138 
1139 	gog_object_register_roles (gog_klass, roles, G_N_ELEMENTS (roles));
1140 
1141 	series_klass->get_xy_data = gog_histogram_plot_series_get_xy_data;
1142 }
1143 
1144 static void
gog_histogram_plot_series_init(GObject * obj)1145 gog_histogram_plot_series_init (GObject *obj)
1146 {
1147 	GogSeries *series = GOG_SERIES (obj);
1148 
1149 	series->acceptable_children = GOG_SERIES_ACCEPT_TREND_LINE;
1150 }
1151 
1152 GSF_DYNAMIC_CLASS (GogHistogramPlotSeries, gog_histogram_plot_series,
1153 	gog_histogram_plot_series_class_init, gog_histogram_plot_series_init,
1154 	GOG_TYPE_SERIES)
1155