{
gdouble mineigen;
gint n_factors;
- gint iterations;
+ gint n_iterations;
gboolean explicit_nfactors;
gboolean covariance;
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;
/* 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;
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);
}
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));
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;
if ( response == PSPPIRE_RESPONSE_CONTINUE )
{
/* Set the parameters from their respective widgets */
- set_extraction_parameters (ex, fd);
+ set_extraction_parameters (fd, ex);
}
else
{
}
}
+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);
gtk_list_store_clear (GTK_LIST_STORE (liststore));
load_extraction_parameters (fd, &default_extraction_parameters);
+ load_rotation_parameters (fd, &default_rotation_parameters);
}
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;
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");
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);
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);
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");
g_string_append (string, "PC");
+
+
g_string_append (string, "\n\t/METHOD = ");
if ( rd->extraction.covariance )
g_string_append (string, "COVARIANCE");
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 )
{
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");
<property name="layout_style">spread</property>
<child>
<object class="GtkButton" id="button-descriptives">
- <property name="label" translatable="yes">Descriptives...</property>
- <property name="visible">False</property>
+ <property name="label" translatable="yes">_Descriptives...</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
+ <property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
</packing>
</child>
<child>
- <object class="GtkButton" id="button-extraction">
- <property name="label" translatable="yes">Extraction...</property>
+ <object class="GtkButton" id="button-extractions">
+ <property name="label" translatable="yes">_Extraction...</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
+ <property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
</packing>
</child>
<child>
- <placeholder/>
+ <object class="GtkButton" id="button-rotations">
+ <property name="label" translatable="yes">_Rotations...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
</child>
</object>
<packing>
</packing>
</child>
<child>
- <object class="GtkSpinButton" id="spinbutton-iterations">
+ <object class="GtkSpinButton" id="spinbutton-extract-iterations">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="PsppireDialog" id="rotations-dialog">
+ <property name="title" translatable="yes">Factor Analysis: Rotation</property>
+ <property name="modal">True</property>
+ <child internal-child="hbox">
+ <object class="GtkHBox" id="dialog-hbox8">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkAlignment" id="alignment7">
+ <property name="visible">True</property>
+ <property name="top_padding">5</property>
+ <property name="bottom_padding">5</property>
+ <property name="left_padding">5</property>
+ <property name="right_padding">5</property>
+ <child>
+ <object class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">5</property>
+ <child>
+ <object class="GtkFrame" id="frame5">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <child>
+ <object class="GtkAlignment" id="alignment8">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <child>
+ <object class="GtkRadioButton" id="radiobutton-none">
+ <property name="label" translatable="yes">_None</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="radiobutton-varimax">
+ <property name="label" translatable="yes">_Varimax</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">radiobutton-none</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="radiobutton-quartimax">
+ <property name="label" translatable="yes">_Quartimax</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">radiobutton-none</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="radiobutton-equimax">
+ <property name="label" translatable="yes">_Equimax</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">radiobutton-none</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Method</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="checkbutton-rotated-solution">
+ <property name="label" translatable="yes">_Display rotated solution</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox11">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Maximum iterations for convergence:</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spinbutton-rot-iterations">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="adjustment">adjustment3</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="PsppireVButtonBox" id="psppire-vbuttonbox3">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">5</property>
+ <property name="buttons">PSPPIRE_BUTTON_CONTINUE_MASK | PSPPIRE_BUTTON_CANCEL_MASK | PSPPIRE_BUTTON_HELP_MASK</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
</interface>