From 7cf4046da1b88ea12d5934c625c28fade7d5e924 Mon Sep 17 00:00:00 2001 From: John Darrington Date: Fri, 21 May 2010 09:59:30 +0200 Subject: [PATCH] Implemented a rotations subdialog for the FACTOR command --- src/ui/gui/factor-dialog.c | 181 +++++++++++++++++++++++++++++--- src/ui/gui/factor.ui | 205 +++++++++++++++++++++++++++++++++++-- 2 files changed, 364 insertions(+), 22 deletions(-) diff --git a/src/ui/gui/factor-dialog.c b/src/ui/gui/factor-dialog.c index 1480e067..61427cc2 100644 --- a/src/ui/gui/factor-dialog.c +++ b/src/ui/gui/factor-dialog.c @@ -45,7 +45,7 @@ struct extraction_parameters { gdouble mineigen; gint n_factors; - gint iterations; + gint n_iterations; gboolean explicit_nfactors; gboolean covariance; @@ -56,9 +56,35 @@ struct extraction_parameters gboolean paf; }; +enum rotation_type { + ROT_NONE, + ROT_VARIMAX, + ROT_QUARTIMAX, + ROT_EQUIMAX +}; + +static const char *rot_method_syntax[] = + { + "NOROTATE", + "VARIMAX", + "QUARTIMAX", + "EQUAMAX" + }; + +struct rotation_parameters +{ + gboolean rotated_solution; + gint iterations; + + enum rotation_type method; +}; + + static const struct extraction_parameters default_extraction_parameters = {1.0, 0, 25, FALSE, TRUE, FALSE, TRUE, FALSE}; +static const struct rotation_parameters default_rotation_parameters = {TRUE, 25, ROT_VARIMAX}; + struct factor { GtkBuilder *xml; @@ -69,10 +95,11 @@ struct factor /* The Extraction subdialog */ GtkWidget *extraction_dialog; + GtkWidget *rotation_dialog; GtkWidget *n_factors; GtkWidget *mineigen; - GtkWidget *iterations; + GtkWidget *extract_iterations; GtkWidget *nfactors_toggle; GtkWidget *mineigen_toggle; @@ -85,15 +112,57 @@ struct factor GtkWidget *extraction_combo; + + /* Rotation Widgets */ + GtkWidget *rotate_iterations; + GtkWidget *display_rotated_solution; + GtkWidget *rotation_none; + GtkWidget *rotation_varimax; + GtkWidget *rotation_quartimax; + GtkWidget *rotation_equimax; + + struct extraction_parameters extraction; + struct rotation_parameters rotation; }; +static void +load_rotation_parameters (struct factor *fd, const struct rotation_parameters *p) +{ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->display_rotated_solution), + p->rotated_solution); + + gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->rotate_iterations), + p->iterations); + + switch (p->method) + { + case ROT_NONE: + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->rotation_none), TRUE); + break; + case ROT_VARIMAX: + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->rotation_varimax), TRUE); + break; + case ROT_QUARTIMAX: + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->rotation_quartimax), TRUE); + break; + case ROT_EQUIMAX: + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->rotation_equimax), TRUE); + break; + default: + g_assert_not_reached (); + break; + } +} + static void load_extraction_parameters (struct factor *fd, const struct extraction_parameters *p) { gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->mineigen), p->mineigen); gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->n_factors), p->n_factors); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->iterations), p->iterations); + + gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->extract_iterations), p->n_iterations); + if (p->explicit_nfactors) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->nfactors_toggle), TRUE); @@ -117,11 +186,31 @@ load_extraction_parameters (struct factor *fd, const struct extraction_parameter } static void -set_extraction_parameters (struct extraction_parameters *p, const struct factor *fd) +set_rotation_parameters (const struct factor *fd, struct rotation_parameters *p) +{ + p->iterations = gtk_spin_button_get_value (GTK_SPIN_BUTTON (fd->rotate_iterations)); + p->rotated_solution = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->display_rotated_solution)); + + + if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->rotation_none))) + p->method = ROT_NONE; + + if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->rotation_varimax))) + p->method = ROT_VARIMAX; + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->rotation_quartimax))) + p->method = ROT_QUARTIMAX; + + if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->rotation_equimax))) + p->method = ROT_EQUIMAX; +} + +static void +set_extraction_parameters (const struct factor *fd, struct extraction_parameters *p) { p->mineigen = gtk_spin_button_get_value (GTK_SPIN_BUTTON (fd->mineigen)); p->n_factors = gtk_spin_button_get_value (GTK_SPIN_BUTTON (fd->n_factors)); - p->iterations = gtk_spin_button_get_value (GTK_SPIN_BUTTON (fd->iterations)); + p->n_iterations = gtk_spin_button_get_value (GTK_SPIN_BUTTON (fd->extract_iterations)); p->explicit_nfactors = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->nfactors_toggle)); p->covariance = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->covariance_toggle)); @@ -132,7 +221,8 @@ set_extraction_parameters (struct extraction_parameters *p, const struct factor p->paf = (gtk_combo_box_get_active (GTK_COMBO_BOX (fd->extraction_combo)) == 1); } -static void run_extractions_subdialog (struct factor *fd) +static void +run_extractions_subdialog (struct factor *fd) { struct extraction_parameters *ex = &fd->extraction; @@ -141,7 +231,7 @@ static void run_extractions_subdialog (struct factor *fd) if ( response == PSPPIRE_RESPONSE_CONTINUE ) { /* Set the parameters from their respective widgets */ - set_extraction_parameters (ex, fd); + set_extraction_parameters (fd, ex); } else { @@ -150,6 +240,25 @@ static void run_extractions_subdialog (struct factor *fd) } } +static void +run_rotations_subdialog (struct factor *fd) +{ + struct rotation_parameters *rot = &fd->rotation; + + gint response = psppire_dialog_run (PSPPIRE_DIALOG (fd->rotation_dialog)); + + if ( response == PSPPIRE_RESPONSE_CONTINUE ) + { + /* Set the parameters from their respective widgets */ + set_rotation_parameters (fd, rot); + } + else + { + /* Cancelled. Reset the widgets to their old state */ + load_rotation_parameters (fd, rot); + } +} + static char * generate_syntax (const struct factor *rd); @@ -162,6 +271,7 @@ refresh (struct factor *fd) gtk_list_store_clear (GTK_LIST_STORE (liststore)); load_extraction_parameters (fd, &default_extraction_parameters); + load_rotation_parameters (fd, &default_rotation_parameters); } @@ -210,16 +320,20 @@ factor_dialog (PsppireDataWindow *dw) GtkWidget *dialog ; GtkWidget *source ; GtkWidget *extraction_button ; + GtkWidget *rotation_button ; fd.xml = builder_new ("factor.ui"); fd.extraction = default_extraction_parameters; + fd.rotation = default_rotation_parameters; dialog = get_widget_assert (fd.xml, "factor-dialog"); source = get_widget_assert (fd.xml, "dict-view"); - extraction_button = get_widget_assert (fd.xml, "button-extraction"); + extraction_button = get_widget_assert (fd.xml, "button-extractions"); + rotation_button = get_widget_assert (fd.xml, "button-rotations"); fd.extraction_dialog = get_widget_assert (fd.xml, "extractions-dialog"); + fd.rotation_dialog = get_widget_assert (fd.xml, "rotations-dialog"); fd.de = dw; @@ -232,7 +346,7 @@ factor_dialog (PsppireDataWindow *dw) fd.nfactors_toggle = get_widget_assert (fd.xml, "nfactors-radiobutton"); fd.mineigen_toggle = get_widget_assert (fd.xml, "mineigen-radiobutton"); fd.n_factors = get_widget_assert (fd.xml, "spinbutton-nfactors"); - fd.iterations = get_widget_assert (fd.xml, "spinbutton-iterations"); + fd.extract_iterations = get_widget_assert (fd.xml, "spinbutton-extract-iterations"); fd.covariance_toggle = get_widget_assert (fd.xml, "covariance-radiobutton"); fd.correlation_toggle = get_widget_assert (fd.xml, "correlations-radiobutton"); @@ -247,7 +361,19 @@ factor_dialog (PsppireDataWindow *dw) gtk_widget_show_all (eigenvalue_extraction); } + { + fd.rotate_iterations = get_widget_assert (fd.xml, "spinbutton-rot-iterations"); + + fd.display_rotated_solution = get_widget_assert (fd.xml, "checkbutton-rotated-solution"); + + fd.rotation_none = get_widget_assert (fd.xml, "radiobutton-none"); + fd.rotation_varimax = get_widget_assert (fd.xml, "radiobutton-varimax"); + fd.rotation_quartimax = get_widget_assert (fd.xml, "radiobutton-quartimax"); + fd.rotation_equimax = get_widget_assert (fd.xml, "radiobutton-equimax"); + } + g_signal_connect_swapped (extraction_button, "clicked", G_CALLBACK (run_extractions_subdialog), &fd); + g_signal_connect_swapped (rotation_button, "clicked", G_CALLBACK (run_rotations_subdialog), &fd); g_signal_connect_swapped (fd.extraction_dialog, "show", G_CALLBACK (on_show), &fd); @@ -257,6 +383,7 @@ factor_dialog (PsppireDataWindow *dw) gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (fd.de)); gtk_window_set_transient_for (GTK_WINDOW (fd.extraction_dialog), GTK_WINDOW (fd.de)); + gtk_window_set_transient_for (GTK_WINDOW (fd.rotation_dialog), GTK_WINDOW (fd.de)); g_object_get (vs, "dictionary", &fd.dict, NULL); g_object_set (source, "model", fd.dict, NULL); @@ -311,6 +438,20 @@ generate_syntax (const struct factor *rd) psppire_var_view_append_names (PSPPIRE_VAR_VIEW (rd->variables), 0, string); + + g_string_append (string, "\n\t/CRITERIA = "); + if ( rd->extraction.explicit_nfactors ) + g_string_append_printf (string, "FACTORS (%d)", rd->extraction.n_factors); + else + g_string_append_printf (string, "MINEIGEN (%g)", rd->extraction.mineigen); + + /* + The CRITERIA = ITERATE subcommand is overloaded. + It applies to the next /ROTATION and/or EXTRACTION command whatever comes first. + */ + g_string_append_printf (string, " ITERATE (%d)", rd->extraction.n_iterations); + + g_string_append (string, "\n\t/EXTRACTION ="); if ( rd->extraction.paf) g_string_append (string, "PAF"); @@ -318,6 +459,8 @@ generate_syntax (const struct factor *rd) g_string_append (string, "PC"); + + g_string_append (string, "\n\t/METHOD = "); if ( rd->extraction.covariance ) g_string_append (string, "COVARIANCE"); @@ -325,12 +468,6 @@ generate_syntax (const struct factor *rd) g_string_append (string, "CORRELATION"); - g_string_append (string, "\n\t/CRITERIA = "); - if ( rd->extraction.explicit_nfactors ) - g_string_append_printf (string, "FACTORS (%d)", rd->extraction.n_factors); - else - g_string_append_printf (string, "MINEIGEN (%g)", rd->extraction.mineigen); - if ( rd->extraction.scree ) { @@ -340,9 +477,21 @@ generate_syntax (const struct factor *rd) g_string_append (string, "\n\t/PRINT = "); g_string_append (string, "INITIAL "); + if ( rd->extraction.unrotated ) g_string_append (string, "EXTRACTION "); - g_string_append (string, "ROTATION"); + + if ( rd->rotation.rotated_solution ) + g_string_append (string, "ROTATION"); + + + /* The CRITERIA = ITERATE subcommand is overloaded. + It applies to the next /ROTATION and/or EXTRACTION command whatever comes first. + */ + g_string_append_printf (string, "\n\t/CRITERIA = ITERATE (%d)", rd->rotation.iterations ); + + g_string_append (string, "\n\t/ROTATION = "); + g_string_append (string, rot_method_syntax[rd->rotation.method]); g_string_append (string, ".\n"); diff --git a/src/ui/gui/factor.ui b/src/ui/gui/factor.ui index 2bf61b2b..4d2c612d 100644 --- a/src/ui/gui/factor.ui +++ b/src/ui/gui/factor.ui @@ -44,10 +44,10 @@ spread - Descriptives... - False + _Descriptives... True True + True False @@ -56,11 +56,12 @@ - - Extraction... + + _Extraction... True True True + True False @@ -69,7 +70,18 @@ - + + _Rotations... + True + True + True + True + + + False + False + 2 + @@ -467,7 +479,7 @@ - + True True @@ -517,4 +529,185 @@ 1 10 + + 100 + 1 + 10 + + + Factor Analysis: Rotation + True + + + True + 2 + + + True + 5 + 5 + 5 + 5 + + + True + vertical + 5 + + + True + 0 + + + True + 12 + + + True + 2 + 2 + + + _None + True + True + False + True + True + True + + + + + _Varimax + True + True + False + True + True + True + radiobutton-none + + + 1 + 2 + + + + + _Quartimax + True + True + False + True + True + True + radiobutton-none + + + 1 + 2 + + + + + _Equimax + True + True + False + True + True + True + radiobutton-none + + + 1 + 2 + 1 + 2 + + + + + + + + + True + Method + True + + + + + 0 + + + + + _Display rotated solution + True + True + False + True + True + + + 1 + + + + + True + + + True + Maximum iterations for convergence: + + + 0 + + + + + True + True + + adjustment3 + + + 1 + + + + + False + 2 + + + + + + + 0 + + + + + True + 5 + vertical + 5 + PSPPIRE_BUTTON_CONTINUE_MASK | PSPPIRE_BUTTON_CANCEL_MASK | PSPPIRE_BUTTON_HELP_MASK + + + False + False + end + 1 + + + + + -- 2.30.2