[goffice] Make histogram able to use raw data.



commit ec4e808cb0466d797e1e80d86f86fad5076dd4e4
Author: Jean Brefort <jean brefort normalesup org>
Date:   Thu Jun 24 14:56:17 2010 +0200

    Make histogram able to use raw data.

 ChangeLog                              |   27 ++
 pixmaps/Makefile.am                    |    3 +-
 plugins/plot_distrib/Makefile.am       |    5 +-
 plugins/plot_distrib/gog-boxplot.c     |    2 +-
 plugins/plot_distrib/gog-histogram.c   |  726 ++++++++++++++++++++++++++++---
 plugins/plot_distrib/gog-histogram.h   |   16 +-
 plugins/plot_distrib/plot-types.xml.in |   21 +-
 plugins/plot_distrib/plugin.c          |    2 +
 plugins/plot_distrib/plugin.xml.in     |    7 +-
 9 files changed, 732 insertions(+), 77 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index f5be74c..652d4b3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2010-06-24  Jean Brefort  <jean brefort normalesup org>
+
+	* pixmaps/Makefile.am: add new icons.
+	* plugins/plot_distrib/Makefile.am: enhance histograms.
+	* plugins/plot_distrib/gog-boxplot.c (gog_box_plot_pref):
+	* plugins/plot_distrib/gog-histogram.c (gog_histogram_plot_update),
+	(gog_histogram_plot_axis_get_bounds),
+	(gog_histogram_plot_get_property),
+	(gog_histogram_plot_set_property), (vertical_changed_cb),
+	(cumulative_changed_cb), (gog_histogram_plot_populate_editor),
+	(gog_histogram_plot_class_init), (gog_histogram_plot_init),
+	(gog_double_histogram_plot_populate_editor),
+	(gog_double_histogram_plot_finalize),
+	(gog_double_histogram_plot_class_init),
+	(gog_double_histogram_plot_init),
+	(gog_double_histogram_plot_dataset_dims),
+	(gog_double_histogram_plot_dataset_get_elem),
+	(gog_double_histogram_plot_dataset_dim_changed),
+	(gog_double_histogram_plot_dataset_init),
+	(gog_histogram_plot_view_render),
+	(gog_histogram_plot_series_update),
+	(gog_histogram_plot_series_finalize): ditto.
+	* plugins/plot_distrib/gog-histogram.h: ditto.
+	* plugins/plot_distrib/plot-types.xml.in: ditto.
+	* plugins/plot_distrib/plugin.c (go_plugin_init): ditto.
+	* plugins/plot_distrib/plugin.xml.in: ditto.
+
 2010-06-16  Morten Welinder <terra gnome org>
 
 	* configure.in: Post-release bump.
diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am
index a8c919d..821c728 100644
--- a/pixmaps/Makefile.am
+++ b/pixmaps/Makefile.am
@@ -40,7 +40,8 @@ dist_icon_DATA = \
 	chart_dropbar_1_1.png	chart_dropbar_1_2.png \
 	chart_minmax_1_1.png	chart_minmax_1_2.png \
 	chart_minmax_2_1.png	chart_minmax_2_2.png \
-	chart_histogram_1_1.png \
+	chart_histogram_1_1.png chart_histogram_2_1.png \
+	chart_histogram_1_3.png chart_histogram_1_4.png \
 	chart_surface_2_1.png	chart_surface_2_2.png \
 	chart_prob_1_1.png \
 	\
diff --git a/plugins/plot_distrib/Makefile.am b/plugins/plot_distrib/Makefile.am
index d64808b..7ef3df6 100644
--- a/plugins/plot_distrib/Makefile.am
+++ b/plugins/plot_distrib/Makefile.am
@@ -22,7 +22,10 @@ if WITH_GTK
 	go-distribution-prefs.c	\
 	go-distribution-prefs.h
 endif
-ui_DATA = gog-boxplot-prefs.ui
+ui_DATA = \
+	gog-boxplot-prefs.ui \
+	gog-histogram-prefs.ui \
+	gog-double-histogram-prefs.ui
 
 @INTLTOOL_XML_RULE@
 
diff --git a/plugins/plot_distrib/gog-boxplot.c b/plugins/plot_distrib/gog-boxplot.c
index d7e5ab4..8ef44b4 100644
--- a/plugins/plot_distrib/gog-boxplot.c
+++ b/plugins/plot_distrib/gog-boxplot.c
@@ -108,7 +108,7 @@ gog_box_plot_pref (GogObject *obj,
 	GtkWidget  *w;
 	GogBoxPlot *boxplot = GOG_BOX_PLOT (obj);
 	char const *dir = go_plugin_get_dir_name (
-		go_plugins_get_plugin_by_id ("GOffice_plot_boxes"));
+		go_plugins_get_plugin_by_id ("GOffice_plot_distrib"));
 	char	 *path = g_build_filename (dir, "gog-boxplot-prefs.ui", NULL);
 	GtkBuilder *gui = go_gtk_builder_new (path, GETTEXT_PACKAGE, cc);
 
diff --git a/plugins/plot_distrib/gog-histogram.c b/plugins/plot_distrib/gog-histogram.c
index 1ab1c5f..3ea7378 100644
--- a/plugins/plot_distrib/gog-histogram.c
+++ b/plugins/plot_distrib/gog-histogram.c
@@ -2,7 +2,7 @@
 /*
  * gog-histogram.c
  *
- * Copyright (C) 2005 Jean Brefort (jean brefort normalesup org)
+ * Copyright (C) 2005-2010 Jean Brefort (jean brefort normalesup org)
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
@@ -30,6 +30,7 @@
 #include <goffice/math/go-math.h>
 #include <goffice/utils/go-format.h>
 #include <goffice/utils/go-path.h>
+#include <goffice/utils/go-persist.h>
 #include <goffice/utils/go-styled-object.h>
 #include <glib/gi18n-lib.h>
 #include <gsf/gsf-impl-utils.h>
@@ -41,7 +42,8 @@
 typedef struct {
 	GogSeries base;
 	GogObject *droplines;
-	double *x, *y;
+	double *x, *y, *y_; /* y_ is the second data for double histograms. */
+	double *real_x, *real_y, *real_y_;
 } GogHistogramPlotSeries;
 typedef GogSeriesClass GogHistogramPlotSeriesClass;
 
@@ -75,21 +77,26 @@ gog_histogram_plot_update (GogObject *obj)
 	GogHistogramPlot *model = GOG_HISTOGRAM_PLOT (obj);
 	GogHistogramPlotSeries *series = GOG_HISTOGRAM_PLOT_SERIES (
 		model->base.series->data);
-	double x_min, x_max, y_min = DBL_MAX, y_max = -DBL_MAX, *x_vals, *y_vals, val;
-	unsigned i;
+	double x_min, x_max, y_min = DBL_MAX, y_max = -DBL_MAX, *x_vals = NULL, *y_vals = NULL, val;
+	unsigned i, y_len = 0;
 
 	if (!gog_series_is_valid (GOG_SERIES (series)) || series->base.num_elements == 0)
 			return;
 
 	g_free (series->x);
 	series->x = g_new (double, series->base.num_elements);
-	if (series->base.values[0].data != NULL) {
+	if (series->real_x != NULL)
+		x_vals = series->real_x;
+	else if (series->base.values[0].data != NULL)
 		x_vals = go_data_get_values (series->base.values[0].data);
+	if (x_vals != NULL) {
 		x_min = x_vals[0];
 		x_max = x_vals[series->base.num_elements];
-		if (model->x.fmt == NULL)
-			model->x.fmt = go_data_preferred_fmt (series->base.values[0].data);
-		model->x.date_conv = go_data_date_conv (series->base.values[0].data);
+		if (series->base.values[0].data) {
+			if (model->x.fmt == NULL)
+				model->x.fmt = go_data_preferred_fmt (series->base.values[0].data);
+			model->x.date_conv = go_data_date_conv (series->base.values[0].data);
+		}
 		for (i = 0; i < series->base.num_elements; i++)
 			series->x[i] = (x_vals[i] + x_vals[i+1]) / 2;
 	} else {
@@ -102,35 +109,80 @@ gog_histogram_plot_update (GogObject *obj)
 	if (model->x.minima != x_min || model->x.maxima != x_max) {
 		model->x.minima = x_min;
 		model->x.maxima = x_max;
-		gog_axis_bound_changed (model->base.axis[0], GOG_OBJECT (model));
+		gog_axis_bound_changed (model->base.axis[model->vertical? 0: 1], GOG_OBJECT (model));
 	}
 	g_free (series->y);
 	series->y = NULL;
-	if (series->base.values[1].data != NULL) {
-		if (x_vals) {
-			series->y = g_new (double, series->base.num_elements);
+	if (series->real_y != NULL) {
+		y_vals = series->real_y;
+		y_len = series->base.num_elements;
+	} else if (series->base.values[1].data != NULL) {
+		y_vals = go_data_get_values (series->base.values[1].data);
+		y_len = go_data_get_vector_size (series->base.values[1].data);
+		if (y_len > series->base.num_elements)
+			y_len = series->base.num_elements;
+	}
+	if (y_vals != NULL) {
+		double sum = 0.;
+		series->y = g_new0 (double, series->base.num_elements);
+		for (i = 0; i < y_len; i++)
+			if (go_finite (y_vals[i])) {
+				if (model->cumulative)
+					sum += y_vals[i];
+				else
+					sum = y_vals[i];
+				series->y[i] = val = sum / (x_vals[i+1] - x_vals[i]);
+				if (val < y_min)
+					y_min = val;
+				if (val > y_max)
+					y_max = val;
+			} else
+				series->y[i] = (model->cumulative)? sum: 0.;
+		if (model->y.fmt == NULL)
+			model->y.fmt = go_data_preferred_fmt (series->base.values[1].data);
+		model->y.date_conv = go_data_date_conv (series->base.values[1].data);
+	}
+	if (GOG_IS_DOUBLE_HISTOGRAM_PLOT (model) && series->base.values[2].data != NULL) {
+		double max = 0.;
+		g_free (series->y_);
+		series->y_ = NULL;
+		if (series->real_y_ != NULL) {
+			y_vals = series->real_y_;
+			y_len = series->base.num_elements;
+		} else if (series->base.values[1].data != NULL) {
 			y_vals = go_data_get_values (series->base.values[1].data);
-			for (i = 0; i < series->base.num_elements; i++)
+			y_len = go_data_get_vector_size (series->base.values[1].data);
+			if (y_len > series->base.num_elements)
+				y_len = series->base.num_elements;
+		} else
+			y_vals = NULL;
+		if (y_vals != NULL) {
+			double sum = 0.;
+			y_min = 0.;
+			series->y_ = g_new0 (double, series->base.num_elements);
+			for (i = 0; i < y_len; i++)
 				if (go_finite (y_vals[i])) {
-					series->y[i] = val = y_vals[i] / (x_vals[i+1] - x_vals[i]);
+					if (model->cumulative)
+						sum += y_vals[i];
+					else
+						sum = y_vals[i];
+					series->y_[i] = val = -sum / (x_vals[i+1] - x_vals[i]);
 					if (val < y_min)
 						y_min = val;
-					if (val > y_max)
-						y_max = val;
+					if (val > max)
+						max = val;
 				} else
-					series->y[i] = 0.;
-		} else
-			go_data_get_bounds (series->base.values[1].data, &y_min, &y_max);
-		if (model->y.fmt == NULL)
-			model->y.fmt = go_data_preferred_fmt (series->base.values[1].data);
-		model->y.date_conv = go_data_date_conv (series->base.values[1].data);
+					series->y_[i] = (model->cumulative)? sum: 0.;
+		}
+		if (y_max < 0)
+			y_max = max;
 	}
 	if (y_min > y_max)
 		y_min = y_max = go_nan;
 	if (model->y.minima != y_min || model->y.maxima != y_max) {
 		model->y.minima = y_min;
 		model->y.maxima = y_max;
-		gog_axis_bound_changed (model->base.axis[1], GOG_OBJECT (model));
+		gog_axis_bound_changed (model->base.axis[model->vertical? 1: 0], GOG_OBJECT (model));
 	}
 	gog_object_emit_changed (GOG_OBJECT (obj), FALSE);
 }
@@ -142,7 +194,7 @@ gog_histogram_plot_axis_get_bounds (GogPlot *plot, GogAxisType axis,
 	GogHistogramPlot *model = GOG_HISTOGRAM_PLOT (plot);
 
 
-	if (axis == GOG_AXIS_X) {
+	if ((axis == GOG_AXIS_X && model->vertical) || (axis == GOG_AXIS_Y && !model->vertical)) {
 		bounds->val.minima = model->x.minima;
 		bounds->val.maxima = model->x.maxima;
 		if (bounds->fmt == NULL && model->x.fmt != NULL)
@@ -161,6 +213,111 @@ gog_histogram_plot_axis_get_bounds (GogPlot *plot, GogAxisType axis,
 	return NULL;
 }
 
+enum {
+	HISTOGRAM_PROP_0,
+	HISTOGRAM_PROP_VERTICAL,
+	HISTOGRAM_PROP_CUMULATIVE
+};
+
+static void
+gog_histogram_plot_get_property (GObject *obj, guint param_id,
+		       GValue *value, GParamSpec *pspec)
+{
+	GogHistogramPlot *model = GOG_HISTOGRAM_PLOT (obj);
+	switch (param_id) {
+	case HISTOGRAM_PROP_VERTICAL:
+		g_value_set_boolean (value, model->vertical);
+		break;
+	case HISTOGRAM_PROP_CUMULATIVE:
+		g_value_set_boolean (value, model->cumulative);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+		 break;
+	}
+}
+
+static void
+gog_histogram_plot_set_property (GObject *obj, guint param_id,
+		       GValue const *value, GParamSpec *pspec)
+{
+	GogHistogramPlot *model = GOG_HISTOGRAM_PLOT (obj);
+	switch (param_id) {
+	case HISTOGRAM_PROP_VERTICAL:
+		if (g_value_get_boolean (value) != model->vertical) {
+			model->vertical = !model->vertical;
+			/* force axis bounds reevaluation */
+			model->x.minima = model->y.minima = G_MAXDOUBLE;
+			gog_object_request_update (GOG_OBJECT (model));
+		}	
+		break;
+	case HISTOGRAM_PROP_CUMULATIVE:
+		if (g_value_get_boolean (value) != model->cumulative) {
+			model->cumulative = !model->cumulative;
+			gog_object_request_update (GOG_OBJECT (model));
+		}	
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+		 return; /* NOTE : RETURN */
+	}
+}
+
+#ifdef GOFFICE_WITH_GTK
+#include <goffice/gtk/goffice-gtk.h>
+
+static void
+vertical_changed_cb (GtkToggleButton *btn, GogHistogramPlot *model)
+{
+	if (gtk_toggle_button_get_active (btn) != model->vertical) {
+		model->vertical = !model->vertical;
+		gog_object_request_update (GOG_OBJECT (model));
+		/* force axis bounds reevaluation */
+		model->x.minima = model->y.minima = G_MAXDOUBLE;
+	}	
+}
+
+static void
+cumulative_changed_cb (GtkToggleButton *btn, GogHistogramPlot *model)
+{
+	if (gtk_toggle_button_get_active (btn) != model->cumulative) {
+		model->cumulative = !model->cumulative;
+		gog_object_request_update (GOG_OBJECT (model));
+	}	
+}
+
+static void
+gog_histogram_plot_populate_editor (GogObject *item,
+			      GOEditor *editor,
+			      G_GNUC_UNUSED GogDataAllocator *dalloc,
+			      GOCmdContext *cc)
+{
+	GtkWidget  *w;
+	GogHistogramPlot *hist = GOG_HISTOGRAM_PLOT (item);
+	char const *dir = go_plugin_get_dir_name (
+		go_plugins_get_plugin_by_id ("GOffice_plot_distrib"));
+	char	 *path = g_build_filename (dir, "gog-histogram-prefs.ui", NULL);
+	GtkBuilder *gui = go_gtk_builder_new (path, GETTEXT_PACKAGE, cc);
+
+	g_free (path);
+        if (gui != NULL) {
+		w = go_gtk_builder_get_widget (gui, "vertical");
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), hist->vertical);
+		g_signal_connect (w, "toggled", G_CALLBACK (vertical_changed_cb), hist);
+
+		w = go_gtk_builder_get_widget (gui, "cumulative");
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), hist->cumulative);
+		g_signal_connect (w, "toggled", G_CALLBACK (cumulative_changed_cb), hist);
+
+		w = go_gtk_builder_get_widget (gui, "histogram-prefs");
+		go_editor_add_page (editor, w , _("Properties"));
+		g_object_unref (gui);
+	}
+
+	(GOG_OBJECT_CLASS(histogram_plot_parent_klass)->populate_editor) (item, editor, dalloc, cc);
+}
+#endif
+
 static void
 gog_histogram_plot_finalize (GObject *obj)
 {
@@ -173,31 +330,48 @@ gog_histogram_plot_class_init (GogPlotClass *gog_plot_klass)
 {
 	GObjectClass *gobject_klass = (GObjectClass *) gog_plot_klass;
 	GogObjectClass *gog_object_klass = (GogObjectClass *) gog_plot_klass;
-	GogPlotClass   *plot_klass = (GogPlotClass *) gog_plot_klass;
 
 	histogram_plot_parent_klass = g_type_class_peek_parent (gog_plot_klass);
 
 	gobject_klass->finalize = gog_histogram_plot_finalize;
+	gobject_klass->get_property = gog_histogram_plot_get_property;
+	gobject_klass->set_property = gog_histogram_plot_set_property;
+
+	g_object_class_install_property (gobject_klass, HISTOGRAM_PROP_VERTICAL,
+		g_param_spec_boolean ("vertical", 
+			_("Vertical"),
+			_("Draw the histogram vertically or horizontally"), 
+			TRUE,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+	g_object_class_install_property (gobject_klass, HISTOGRAM_PROP_CUMULATIVE,
+		g_param_spec_boolean ("cumulative", 
+			_("Cumulative"),
+			_("Use cumulated data"), 
+			FALSE,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
 
 	gog_object_klass->type_name	= gog_histogram_plot_type_name;
 	gog_object_klass->view_type	= gog_histogram_plot_view_get_type ();
 	gog_object_klass->update	= gog_histogram_plot_update;
+#ifdef GOFFICE_WITH_GTK
+	gog_object_klass->populate_editor = gog_histogram_plot_populate_editor;
+#endif
 
 	{
 		static GogSeriesDimDesc dimensions[] = {
-			{ N_("Limits"), GOG_SERIES_REQUIRED, FALSE,
+			{ N_("Limits"), GOG_SERIES_SUGGESTED, FALSE,
 			  GOG_DIM_INDEX, GOG_MS_DIM_CATEGORIES },
 			{ N_("Values"), GOG_SERIES_REQUIRED, FALSE,
 			  GOG_DIM_VALUE, GOG_MS_DIM_VALUES },
 		};
-		plot_klass->desc.series.dim = dimensions;
-		plot_klass->desc.series.num_dim = G_N_ELEMENTS (dimensions);
+		gog_plot_klass->desc.series.dim = dimensions;
+		gog_plot_klass->desc.series.num_dim = G_N_ELEMENTS (dimensions);
 	}
-	plot_klass->desc.num_series_max = 1;
-	plot_klass->series_type = gog_histogram_plot_series_get_type ();
-	plot_klass->axis_set = GOG_AXIS_SET_XY;
-	plot_klass->desc.series.style_fields	= GO_STYLE_OUTLINE | GO_STYLE_FILL;
-	plot_klass->axis_get_bounds   		= gog_histogram_plot_axis_get_bounds;
+	gog_plot_klass->desc.num_series_max = 1;
+	gog_plot_klass->series_type = gog_histogram_plot_series_get_type ();
+	gog_plot_klass->axis_set = GOG_AXIS_SET_XY;
+	gog_plot_klass->desc.series.style_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL;
+	gog_plot_klass->axis_get_bounds   	 = gog_histogram_plot_axis_get_bounds;
 }
 
 static void
@@ -206,6 +380,7 @@ gog_histogram_plot_init (GogHistogramPlot *hist)
 	GogPlot *plot = GOG_PLOT (hist);
 
 	plot->render_before_axes = TRUE;
+	hist->vertical = TRUE;
 }
 
 GSF_DYNAMIC_CLASS (GogHistogramPlot, gog_histogram_plot,
@@ -213,6 +388,124 @@ GSF_DYNAMIC_CLASS (GogHistogramPlot, gog_histogram_plot,
 	GOG_TYPE_PLOT)
 
 /*****************************************************************************/
+/*   Double histograms                                                       */
+
+static GObjectClass *double_histogram_plot_parent_klass;
+
+#ifdef GOFFICE_WITH_GTK
+static void
+gog_double_histogram_plot_populate_editor (GogObject	*gobj,
+			       GOEditor	*editor,
+			       GogDataAllocator	*dalloc,
+			       GOCmdContext	*cc)
+{
+	GtkTable *table;
+	GtkWidget *w;
+	GogDataset *set = GOG_DATASET (gobj);
+	char const *dir = go_plugin_get_dir_name (
+		go_plugins_get_plugin_by_id ("GOffice_plot_distrib"));
+	char	 *path = g_build_filename (dir, "gog-double-histogram-prefs.ui", NULL);
+	GtkBuilder *gui = go_gtk_builder_new (path, GETTEXT_PACKAGE, cc);
+
+	g_free (path);
+
+	if (gui != NULL) {
+		table = GTK_TABLE (gtk_builder_get_object (gui, "double-histogram-prefs"));
+		w = GTK_WIDGET (gog_data_allocator_editor (dalloc, set, 0, GOG_DATA_SCALAR));
+		gtk_widget_set_tooltip_text (w, _("Label for the first Y category. If not set or empty, \"First values\" will be used."));
+		gtk_widget_show (w);
+		gtk_table_attach (table, w, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+		w = GTK_WIDGET (gog_data_allocator_editor (dalloc, set, 1, GOG_DATA_SCALAR));
+		gtk_widget_set_tooltip_text (w, _("Label for the second Y category. If not set or empty, \"Second values\" will be used."));
+		gtk_widget_show (w);
+		gtk_table_attach (table, w, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+		go_editor_add_page (editor,
+				     go_gtk_builder_get_widget (gui, "double-histogram-prefs"),
+				     _("Categories labels"));
+	}
+	(GOG_OBJECT_CLASS (double_histogram_plot_parent_klass)->populate_editor) (gobj, editor, dalloc, cc);
+}
+#endif
+
+static void
+gog_double_histogram_plot_finalize (GObject *obj)
+{
+	GogDoubleHistogramPlot *plot = GOG_DOUBLE_HISTOGRAM_PLOT (obj);
+	if (plot->labels != NULL) {
+		gog_dataset_finalize (GOG_DATASET (obj));
+		g_free (plot->labels);
+		plot->labels = NULL;
+	}
+	(*double_histogram_plot_parent_klass->finalize) (obj);
+}
+
+static void
+gog_double_histogram_plot_class_init (GogPlotClass *gog_plot_klass)
+{
+	GObjectClass *gobject_klass = (GObjectClass *) gog_plot_klass;
+	GogObjectClass *gog_klass = (GogObjectClass *) gog_plot_klass;
+	double_histogram_plot_parent_klass = g_type_class_peek_parent (gog_klass);
+	gobject_klass->finalize	    = gog_double_histogram_plot_finalize;
+#ifdef GOFFICE_WITH_GTK
+	gog_klass->populate_editor  = gog_double_histogram_plot_populate_editor;
+#endif
+	{
+		static GogSeriesDimDesc dimensions[] = {
+			{ N_("Limits"), GOG_SERIES_REQUIRED, FALSE,
+			  GOG_DIM_INDEX, GOG_MS_DIM_CATEGORIES },
+			{ N_("First values"), GOG_SERIES_REQUIRED, FALSE,
+			  GOG_DIM_VALUE, GOG_MS_DIM_VALUES },
+			{ N_("Second values"), GOG_SERIES_REQUIRED, FALSE,
+			  GOG_DIM_VALUE, GOG_MS_DIM_EXTRA1 },
+		};
+		gog_plot_klass->desc.series.dim = dimensions;
+		gog_plot_klass->desc.series.num_dim = G_N_ELEMENTS (dimensions);
+		gog_plot_klass->desc.series.style_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL | GO_STYLE_FONT;
+	}
+}
+
+static void
+gog_double_histogram_plot_init (GogDoubleHistogramPlot *plot)
+{
+	plot->labels = g_new0 (GogDatasetElement, 2);
+}
+
+static void
+gog_double_histogram_plot_dataset_dims (GogDataset const *set, int *first, int *last)
+{
+	*first = 0;
+	*last = 1;
+}
+
+static GogDatasetElement *
+gog_double_histogram_plot_dataset_get_elem (GogDataset const *set, int dim_i)
+{
+	GogDoubleHistogramPlot const *plot = GOG_DOUBLE_HISTOGRAM_PLOT (set);
+	g_return_val_if_fail (2 > dim_i, NULL);
+	g_return_val_if_fail (dim_i >= 0, NULL);
+	return plot->labels + dim_i;
+}
+
+static void
+gog_double_histogram_plot_dataset_dim_changed (GogDataset *set, int dim_i)
+{
+	gog_object_request_update (GOG_OBJECT (set));
+}
+
+static void
+gog_double_histogram_plot_dataset_init (GogDatasetClass *iface)
+{
+	iface->get_elem	   = gog_double_histogram_plot_dataset_get_elem;
+	iface->dims	   = gog_double_histogram_plot_dataset_dims;
+	iface->dim_changed = gog_double_histogram_plot_dataset_dim_changed;
+}
+
+GSF_DYNAMIC_CLASS_FULL (GogDoubleHistogramPlot, gog_double_histogram_plot,
+	NULL, NULL, gog_double_histogram_plot_class_init, NULL,
+        gog_double_histogram_plot_init, GOG_TYPE_HISTOGRAM_PLOT, 0,
+        GSF_INTERFACE (gog_double_histogram_plot_dataset_init, GOG_TYPE_DATASET))
+
+/*****************************************************************************/
 typedef GogPlotView		GogHistogramPlotView;
 typedef GogPlotViewClass	GogHistogramPlotViewClass;
 
@@ -251,21 +544,36 @@ gog_histogram_plot_view_render (GogView *view, GogViewAllocation const *bbox)
 	x_map = gog_chart_map_get_axis_map (chart_map, 0);
 	y_map = gog_chart_map_get_axis_map (chart_map, 1);
 
-	if (series->base.values[0].data)
+	if (series->real_x)
+		x_vals = series->real_x;
+	else if (series->base.values[0].data)
 		x_vals = go_data_get_values (series->base.values[0].data);
-	y_vals = (x_vals)? series->y: go_data_get_values (series->base.values[1].data);
+	y_vals = (series->y)? series->y: go_data_get_values (series->base.values[1].data);
 
 	path = go_path_new ();
 	go_path_set_options (path, GO_PATH_OPTIONS_SHARP);
-	curx = gog_axis_map_to_view (x_map, ((x_vals)? x_vals[0]: 0.));
-	go_path_move_to (path, curx, y0 = gog_axis_map_get_baseline (y_map));
-	for (i = 0, j = 1; i < series->base.num_elements; i++) {
-		cury = gog_axis_map_to_view (y_map, y_vals[i]);
-		go_path_line_to (path, curx, cury);
-		curx = gog_axis_map_to_view (x_map, ((x_vals)? x_vals[i+1]: 0.));
-		go_path_line_to (path, curx, cury);
+	if (model->vertical) {
+		curx = gog_axis_map_to_view (x_map, ((x_vals)? x_vals[0]: 0.));
+		go_path_move_to (path, curx, y0 = gog_axis_map_get_baseline (y_map));
+		for (i = 0, j = 1; i < series->base.num_elements; i++) {
+			cury = gog_axis_map_to_view (y_map, y_vals[i]);
+			go_path_line_to (path, curx, cury);
+			curx = gog_axis_map_to_view (x_map, ((x_vals)? x_vals[i+1]: 0.));
+			go_path_line_to (path, curx, cury);
+		}
+		go_path_line_to (path, curx, y0);
+	} else {
+		curx = gog_axis_map_to_view (y_map, ((x_vals)? x_vals[0]: 0.));
+		go_path_move_to (path, y0 = gog_axis_map_get_baseline (x_map), curx);
+		for (i = 0, j = 1; i < series->base.num_elements; i++) {
+			cury = gog_axis_map_to_view (x_map, y_vals[i]);
+			go_path_line_to (path, cury, curx);
+			curx = gog_axis_map_to_view (y_map, ((x_vals)? x_vals[i+1]: 0.));
+			go_path_line_to (path, cury, curx);
+		}
+		go_path_line_to (path, y0, curx);
 	}
-	go_path_line_to (path, curx, y0);
+	go_path_close (path);
 	gog_renderer_push_style (view->renderer, style);
 	gog_renderer_fill_shape (view->renderer, path);
 
@@ -275,23 +583,42 @@ gog_histogram_plot_view_render (GogView *view, GogViewAllocation const *bbox)
 		gog_renderer_push_style (view->renderer,
 			go_styled_object_get_style (GO_STYLED_OBJECT (series->droplines)));
 		cury = y0;
-		for (i = 1; i < series->base.num_elements; i++) {
-			curx = gog_axis_map_to_view (x_map, ((x_vals)? x_vals[i]: 0.));
-			if (y_vals[i-1] * y_vals[i] > 0.) {
-				go_path_move_to (drop_path, curx, y0);
-				if (y_vals[i] > 0.)
-					cury = gog_axis_map_to_view (y_map,
-						MIN (y_vals[i-1], y_vals[i]));
-				else
-					cury = gog_axis_map_to_view (y_map,
-						MAX (y_vals[i-1], y_vals[i]));
-
-			} else {
-				go_path_move_to (drop_path, curx, cury);
-				cury = gog_axis_map_to_view (y_map, y_vals[i]);
+		if (model->vertical)
+			for (i = 1; i < series->base.num_elements; i++) {
+				curx = gog_axis_map_to_view (x_map, ((x_vals)? x_vals[i]: 0.));
+				if (y_vals[i-1] * y_vals[i] > 0.) {
+					go_path_move_to (drop_path, curx, y0);
+					if (y_vals[i] > 0.)
+						cury = gog_axis_map_to_view (y_map,
+							MIN (y_vals[i-1], y_vals[i]));
+					else
+						cury = gog_axis_map_to_view (y_map,
+							MAX (y_vals[i-1], y_vals[i]));
+
+				} else {
+					go_path_move_to (drop_path, curx, cury);
+					cury = gog_axis_map_to_view (y_map, y_vals[i]);
+				}
+				go_path_line_to (drop_path, curx, cury);
+			}
+		else
+			for (i = 1; i < series->base.num_elements; i++) {
+				curx = gog_axis_map_to_view (y_map, ((x_vals)? x_vals[i]: 0.));
+				if (y_vals[i-1] * y_vals[i] > 0.) {
+					go_path_move_to (drop_path, y0, curx);
+					if (y_vals[i] > 0.)
+						cury = gog_axis_map_to_view (x_map,
+							MIN (y_vals[i-1], y_vals[i]));
+					else
+						cury = gog_axis_map_to_view (x_map,
+							MAX (y_vals[i-1], y_vals[i]));
+
+				} else {
+					go_path_move_to (drop_path, cury, curx);
+					cury = gog_axis_map_to_view (x_map, y_vals[i]);
+				}
+				go_path_line_to (drop_path, cury, curx);
 			}
-			go_path_line_to (drop_path, curx, cury);
-		}
 		gog_renderer_stroke_serie (view->renderer, drop_path);
 		go_path_free (drop_path);
 		gog_renderer_pop_style (view->renderer);
@@ -299,6 +626,147 @@ gog_histogram_plot_view_render (GogView *view, GogViewAllocation const *bbox)
 	gog_renderer_stroke_shape (view->renderer, path);
 	gog_renderer_pop_style (view->renderer);
 	go_path_free (path);
+	/* Redo the same for the other side of a double histogram. */
+	if (GOG_IS_DOUBLE_HISTOGRAM_PLOT (model) && series->base.values[2].data != NULL) {
+		y_vals = (series->y_)? series->y_: go_data_get_values (series->base.values[2].data);
+		path = go_path_new ();
+		go_path_set_options (path, GO_PATH_OPTIONS_SHARP);
+		if (model->vertical) {
+			curx = gog_axis_map_to_view (x_map, ((x_vals)? x_vals[0]: 0.));
+			go_path_move_to (path, curx, y0);
+			for (i = 0, j = 1; i < series->base.num_elements; i++) {
+				cury = gog_axis_map_to_view (y_map, y_vals[i]);
+				go_path_line_to (path, curx, cury);
+				curx = gog_axis_map_to_view (x_map, ((x_vals)? x_vals[i+1]: 0.));
+				go_path_line_to (path, curx, cury);
+			}
+			go_path_line_to (path, curx, y0);
+		} else {
+			curx = gog_axis_map_to_view (y_map, ((x_vals)? x_vals[0]: 0.));
+			go_path_move_to (path, y0, curx);
+			for (i = 0, j = 1; i < series->base.num_elements; i++) {
+				cury = gog_axis_map_to_view (x_map, y_vals[i]);
+				go_path_line_to (path, cury, curx);
+				curx = gog_axis_map_to_view (y_map, ((x_vals)? x_vals[i+1]: 0.));
+				go_path_line_to (path, cury, curx);
+			}
+			go_path_line_to (path, y0, curx);
+		}
+		go_path_close (path);
+		gog_renderer_push_style (view->renderer, style);
+		gog_renderer_fill_shape (view->renderer, path);
+
+		if (series->droplines) {
+			GOPath *drop_path = go_path_new ();
+			go_path_set_options (drop_path, GO_PATH_OPTIONS_SHARP);
+			gog_renderer_push_style (view->renderer,
+				go_styled_object_get_style (GO_STYLED_OBJECT (series->droplines)));
+			cury = y0;
+			if (model->vertical)
+				for (i = 1; i < series->base.num_elements; i++) {
+					curx = gog_axis_map_to_view (x_map, ((x_vals)? x_vals[i]: 0.));
+					if (y_vals[i-1] * y_vals[i] > 0.) {
+						go_path_move_to (drop_path, curx, y0);
+						if (y_vals[i] > 0.)
+							cury = gog_axis_map_to_view (y_map,
+								MIN (y_vals[i-1], y_vals[i]));
+						else
+							cury = gog_axis_map_to_view (y_map,
+								MAX (y_vals[i-1], y_vals[i]));
+
+					} else {
+						go_path_move_to (drop_path, curx, cury);
+						cury = gog_axis_map_to_view (y_map, y_vals[i]);
+					}
+					go_path_line_to (drop_path, curx, cury);
+				}
+			else
+				for (i = 1; i < series->base.num_elements; i++) {
+					curx = gog_axis_map_to_view (y_map, ((x_vals)? x_vals[i]: 0.));
+					if (y_vals[i-1] * y_vals[i] > 0.) {
+						go_path_move_to (drop_path, y0, curx);
+						if (y_vals[i] > 0.)
+							cury = gog_axis_map_to_view (x_map,
+								MIN (y_vals[i-1], y_vals[i]));
+						else
+							cury = gog_axis_map_to_view (x_map,
+								MAX (y_vals[i-1], y_vals[i]));
+
+					} else {
+						go_path_move_to (drop_path, cury, curx);
+						cury = gog_axis_map_to_view (x_map, y_vals[i]);
+					}
+					go_path_line_to (drop_path, cury, curx);
+				}
+			gog_renderer_stroke_serie (view->renderer, drop_path);
+			go_path_free (drop_path);
+			gog_renderer_pop_style (view->renderer);
+		}
+		gog_renderer_stroke_shape (view->renderer, path);
+		go_path_free (path);
+
+		/* Now display labels FIXME: might be optional */
+		{
+			char *text1 = NULL, *text2 = NULL;
+			char const *text;
+			GogViewAllocation alloc;
+			GogDoubleHistogramPlot *dbl = GOG_DOUBLE_HISTOGRAM_PLOT (model);
+			if (dbl->labels[0].data) {
+				text1 = go_data_get_scalar_string (dbl->labels[0].data);
+				if (text1 && !*text1) {
+					g_free (text1);
+					text1 = NULL;
+				}
+			}
+			if (dbl->labels[1].data) {
+				text2 = go_data_get_scalar_string (dbl->labels[1].data);
+				if (text2 && !*text2) {
+					g_free (text2);
+					text2 = NULL;
+				}
+			}
+			text = (text1)? text1: _("First values");
+			if (model->cumulative) {
+				if (model->vertical) {
+					alloc.x = area->x + 2; /* FIXME: replace 2 by something configurable */
+					alloc.y = area->y + 2;
+					gog_renderer_draw_text (view->renderer, text, &alloc,
+							        GTK_ANCHOR_NORTH_WEST, FALSE);
+					text = (text2)? text2: _("Second values");
+					alloc.y = area->y + area->h - 2;
+					gog_renderer_draw_text (view->renderer, text, &alloc,
+							        GTK_ANCHOR_SOUTH_WEST, FALSE);
+				} else {
+					alloc.x = area->x + area->w - 2; /* FIXME: replace 2 by something configurable */
+					alloc.y = area->y + area->h - 2;
+					gog_renderer_draw_text (view->renderer, text, &alloc,
+							        GTK_ANCHOR_SOUTH_EAST, FALSE);
+					text = (text2)? text2: _("Second values");
+					alloc.x = area->x + 2;
+					gog_renderer_draw_text (view->renderer, text, &alloc,
+							        GTK_ANCHOR_SOUTH_WEST, FALSE);
+				}
+			} else {
+				alloc.x = area->x + area->w - 2; /* FIXME: replace 2 by something configurable */
+				alloc.y = area->y + 2;
+				gog_renderer_draw_text (view->renderer, text, &alloc,
+					                GTK_ANCHOR_NORTH_EAST, FALSE);
+				text = (text2)? text2: _("Second values");
+				if (model->vertical) {
+					alloc.y = area->y + area->h - 2;
+					gog_renderer_draw_text (view->renderer, text, &alloc,
+							        GTK_ANCHOR_SOUTH_EAST, FALSE);
+				} else {
+					alloc.x = area->x + 2;
+					gog_renderer_draw_text (view->renderer, text, &alloc,
+							        GTK_ANCHOR_NORTH_WEST, FALSE);
+				}
+			}
+			g_free (text1);
+			g_free (text2);
+		}
+		gog_renderer_pop_style (view->renderer);
+	}
 	/* Now render children */
 	for (ptr = view->children ; ptr != NULL ; ptr = ptr->next)
 		gog_view_render	(ptr->data, bbox);
@@ -402,32 +870,140 @@ static GObjectClass *series_parent_klass;
 static void
 gog_histogram_plot_series_update (GogObject *obj)
 {
-	double *x_vals = NULL, *y_vals = NULL, cur;
-	int x_len = 1, y_len = 0, i, max;
+	double *x_vals = NULL, *y_vals = NULL, *y__vals = NULL, cur;
+	int x_len = 1, y_len = 0, y__len = 0, max, nb = 0, i;
 	GogHistogramPlotSeries *series = GOG_HISTOGRAM_PLOT_SERIES (obj);
 	unsigned old_num = series->base.num_elements;
 	GSList *ptr;
-
+	gboolean y_as_raw = FALSE;
+	double width = -1., origin = 0.;
+
+	g_free (series->real_x);
+	series->real_x = NULL;
+	g_free (series->real_y);
+	series->real_y = NULL;
+	g_free (series->real_y_);
+	series->real_y_ = NULL;
 	if (series->base.values[1].data != NULL) {
 		y_vals = go_data_get_values (series->base.values[1].data);
-		y_len = go_data_get_vector_size (series->base.values[1].data);
+		nb = y_len = go_data_get_vector_size (series->base.values[1].data);
+	}
+	if (GOG_IS_DOUBLE_HISTOGRAM_PLOT (series->base.plot) && series->base.values[2].data != NULL) {
+		y__vals = go_data_get_values (series->base.values[2].data);
+		y__len = go_data_get_vector_size (series->base.values[2].data);
+		if (y__len > y_len)
+			nb = y__len;
 	}
 	if (series->base.values[0].data != NULL) {
 		x_vals = go_data_get_values (series->base.values[0].data);
 		max = go_data_get_vector_size (series->base.values[0].data);
-		if (max > 0 && go_finite (x_vals[0])) {
-			cur = x_vals[0];
-			for (i = 1; i< max; i++) {
-				if (go_finite (x_vals[i]) && x_vals[i] > cur) {
-					cur = x_vals[i];
-					x_len++;
-				} else
-					break;
+		if (max == 2) {
+			origin = x_vals[1];
+			max = 1;
+		}
+		if (max == 1) {
+			/* use the value as bin width */
+			width = x_vals[0];
+			if (!go_finite (width))
+				width = -1.;
+			y_as_raw = TRUE;
+		} else if (max > nb) {
+			if (max > 0 && go_finite (x_vals[0])) {
+				cur = x_vals[0];
+				for (i = 1; i < max; i++) {
+					if (go_finite (x_vals[i]) && x_vals[i] > cur) {
+						cur = x_vals[i];
+						x_len++;
+					} else
+						break;
+				}
 			}
+		} else {
+			x_len = max;
+			y_as_raw = TRUE;
 		}
 	} else
-		x_len = y_len + 1;
-	series->base.num_elements = MIN (x_len - 1, y_len);
+		y_as_raw = TRUE;
+	if (y_as_raw) {
+		double *y = NULL, *y_ = NULL;
+		if (y_vals) {
+			y = go_range_sort (y_vals, y_len);
+		}
+		if (y__vals) {
+			y_ = go_range_sort (y__vals, y__len);
+		}
+		if (!x_vals || x_len <= 1) {
+			/* guess reasonable values */
+			if (width <= 0) {
+				max = go_fake_round (sqrt (MAX (y_len, y__len)));
+				if (y && y_len > 2)
+					width = (y[y_len-1] - y[0]) / max;
+				if (y_ && y__len > 2) {
+					double w_ = (y_[y__len-1] - y_[0]) / max;
+					width = MAX (width, w_);
+				}
+				if (width > 0.) {
+					width = log10 (width);
+					max = floor (width);
+					width -= max;
+					if (width < 0.15)
+						width = pow (10, max);
+					else if (width < 0.45)
+						width = 2 * pow (10, max);
+					else if (width < 0.85)
+						width = 2 * pow (10, max);
+					else
+						width = pow (10, max + 1);
+				}
+			}
+			if (width > 0. && (y || y_)) {
+				double m, M;
+				if (y) {
+					m = (y_)? (MIN (y[0], y_[0])): y[0];
+					M = (y_)? (MAX (y[y_len-1], y_[y__len-1])): y[y_len-1];
+				} else {
+					m = y_[0];
+					M = y_[y__len-1];
+				}
+				/* round m */
+				m = floor ((m - origin)/ width) * width + origin;
+				x_len = ceil ((M - m) / width) + 1;
+				series->real_x = g_new (double, x_len);
+				for (max = 0; max < x_len; max++) {
+					series->real_x[max] = m;
+					m += width;
+				}
+			}
+		} else
+			series->real_x = go_range_sort (x_vals, x_len);
+		if (x_len > 1) {
+			series->real_y = g_new0 (double, x_len - 1);
+			for (i = 0; i < y_len && y[i] <= series->real_x[0]; i++);
+			for (max = 1;  i < y_len; i++)
+				if (go_finite (y[i])) {
+					while (y[i] > series->real_x[max]) {
+						max++;
+						if (max == x_len - 1)
+							break;
+					}
+					series->real_y[max-1]++;
+			}
+			if (y__len > 0) {
+				series->real_y_ = g_new0 (double, x_len - 1);
+				for (i = 0; i < y__len && y_[i] <= series->real_x[0]; i++);
+				for (max = 1;  i < y__len; i++)
+					if (go_finite (y_[i])) {
+						while (y_[i] > series->real_x[max]) {
+							max++;
+							if (max == x_len - 1)
+								break;
+						}
+						series->real_y_[max-1]++;
+			}
+			}
+		}
+	}
+	series->base.num_elements = (x_len > 0)? MIN (x_len - 1, nb): 0;
 
 	/* update children */
 	for (ptr = obj->children; ptr != NULL; ptr = ptr->next)
@@ -450,8 +1026,16 @@ gog_histogram_plot_series_finalize (GObject *obj)
 
 	g_free (series->y);
 	series->y = NULL;
+	g_free (series->y_);
+	series->y_ = NULL;
 	g_free (series->x);
 	series->x = NULL;
+	g_free (series->real_x);
+	series->real_x = NULL;
+	g_free (series->real_y);
+	series->real_y = NULL;
+	g_free (series->real_y_);
+	series->real_y_ = NULL;
 
 	G_OBJECT_CLASS (series_parent_klass)->finalize (obj);
 }
diff --git a/plugins/plot_distrib/gog-histogram.h b/plugins/plot_distrib/gog-histogram.h
index 43a7a38..a4f0f8f 100644
--- a/plugins/plot_distrib/gog-histogram.h
+++ b/plugins/plot_distrib/gog-histogram.h
@@ -2,7 +2,7 @@
 /*
  * gog-histogram.h
  *
- * Copyright (C) 2005 Jean Brefort (jean brefort normalesup org)
+ * Copyright (C) 2005-2010 Jean Brefort (jean brefort normalesup org)
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
@@ -34,6 +34,8 @@ typedef struct {
 		GOFormat *fmt;
 		GODateConventions const *date_conv;
 	} x, y;
+	gboolean vertical;
+	gboolean cumulative;
 } GogHistogramPlot;
 typedef GogPlotClass GogHistogramPlotClass;
 
@@ -43,6 +45,18 @@ typedef GogPlotClass GogHistogramPlotClass;
 
 GType gog_histogram_plot_get_type (void);
 
+typedef struct {
+	GogHistogramPlot base;
+	GogDatasetElement *labels; /* labels for the two y categories */
+} GogDoubleHistogramPlot;
+typedef GogHistogramPlotClass GogDoubleHistogramPlotClass;
+
+#define GOG_DOUBLE_HISTOGRAM_PLOT_TYPE	(gog_double_histogram_plot_get_type ())
+#define GOG_DOUBLE_HISTOGRAM_PLOT(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_DOUBLE_HISTOGRAM_PLOT_TYPE, GogDoubleHistogramPlot))
+#define GOG_IS_DOUBLE_HISTOGRAM_PLOT(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_DOUBLE_HISTOGRAM_PLOT_TYPE))
+
+GType gog_double_histogram_plot_get_type (void);
+
 G_END_DECLS
 
 #endif /* GOG_HISTOGRAM_H */
diff --git a/plugins/plot_distrib/plot-types.xml.in b/plugins/plot_distrib/plot-types.xml.in
index 008e8c4..cd6af3c 100644
--- a/plugins/plot_distrib/plot-types.xml.in
+++ b/plugins/plot_distrib/plot-types.xml.in
@@ -30,13 +30,32 @@
 		<property name="vertical">true</property>
 		<property name="guru-hints">backplane</property>
 	</Type>
-	<Family _name="Histogram"	sample_image_file="hist.xpm" axis_set="xy"/>
 	<Type _name="Histogram" row="3" col="1"
 		engine="GogHistogramPlot" family="Statistics"
 		_description="Histogram."
 		sample_image_file="chart_histogram_1_1.png">
 		<property name="guru-hints">backplane</property>
 	</Type>
+	<Type _name="CumulativeHistogram" row="3" col="2"
+		engine="GogHistogramPlot" family="Statistics"
+		_description="Cumulative histogram."
+		sample_image_file="chart_histogram_2_1.png">
+		<property name="guru-hints">backplane</property>
+		<property name="cumulative">true</property>
+	</Type>
+<!--	<Type _name="DoubleHistogram" row="3" col="3"
+		engine="GogDoubleHistogramPlot" family="Statistics"
+		_description="Double histogram."
+		sample_image_file="chart_histogram_1_3.png">
+		<property name="guru-hints">backplane</property>
+	</Type>
+	<Type _name="PopulationPyramid" row="3" col="4"
+		engine="GogDoubleHistogramPlot" family="Statistics"
+		_description="Population pyramid."
+		sample_image_file="chart_histogram_1_4.png">
+		<property name="guru-hints">backplane</property>
+		<property name="vertical">false</property>
+	</Type> -->
 	<Type _name="ProbabilityPlot" row="4" col="1"
 		engine="GogProbabilityPlot" family="Statistics"
 		_description="Probability plot."
diff --git a/plugins/plot_distrib/plugin.c b/plugins/plot_distrib/plugin.c
index edf3332..c062bba 100644
--- a/plugins/plot_distrib/plugin.c
+++ b/plugins/plot_distrib/plugin.c
@@ -28,6 +28,7 @@ GOFFICE_PLUGIN_MODULE_HEADER;
 void gog_box_plot_register_type (GTypeModule *module);
 void gog_box_plot_view_register_type (GTypeModule *module);
 void gog_box_plot_series_register_type (GTypeModule *module);
+void gog_double_histogram_plot_register_type (GTypeModule *module);
 void gog_histogram_plot_register_type (GTypeModule *module);
 void gog_histogram_plot_series_register_type (GTypeModule *module);
 void gog_histogram_plot_view_register_type (GTypeModule *module);
@@ -48,6 +49,7 @@ go_plugin_init (GOPlugin *plugin, GOCmdContext *cc)
 	gog_histogram_plot_view_register_type (module);
 	gog_histogram_plot_series_register_type (module);
 	gog_histogram_series_view_register_type (module);
+	gog_double_histogram_plot_register_type (module);
 	gog_probability_plot_register_type (module);
 	gog_probability_plot_view_register_type (module);
 	gog_probability_plot_series_register_type (module);
diff --git a/plugins/plot_distrib/plugin.xml.in b/plugins/plot_distrib/plugin.xml.in
index 38a3e2f..f1fb53f 100644
--- a/plugins/plot_distrib/plugin.xml.in
+++ b/plugins/plot_distrib/plugin.xml.in
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<plugin id="GOffice_plot_boxes">
+<plugin id="GOffice_plot_distrib">
 	<information>
 		<_name>Charting : distribution related plots</_name>
 		<_description>box-plots, histograms, and other distribution related plots</_description>
@@ -21,6 +21,11 @@
 				<_description>Histograms plotting engine</_description>
 			</information>
 		</service>
+<!--		<service type="plot_engine" id="GogDoubleHistogramPlot">
+			<information>
+				<_description>Double histograms plotting engine</_description>
+			</information>
+		</service> -->
 		<service type="plot_engine" id="GogProbabilityPlot">
 			<information>
 				<_description>Probability plots engine</_description>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]