[genius] Tue Feb 02 13:30:44 2010 Jiri (George) Lebl <jirka 5z com>



commit eea7eba557c226ff953b321229d55b89cd846b4f
Author: Jiri (George) Lebl <jirka 5z com>
Date:   Tue Feb 2 13:30:48 2010 -0600

    Tue Feb 02 13:30:44 2010  Jiri (George) Lebl <jirka 5z com>
    
    	* src/graphing.c: Allow changing variable names.  Either in the GUI
    	  or using the new parameter LinePlotVariableNames.
    
    	* help/C/gel-function-list.xml: document the new parameter

 ChangeLog                    |    7 +
 NEWS                         |    3 +-
 help/C/gel-function-list.xml |   27 +-
 src/graphing.c               |  963 +++++++++++++++++++++++++++++++++++-------
 4 files changed, 831 insertions(+), 169 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 6b232ea..7f62397 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Tue Feb 02 13:30:44 2010  Jiri (George) Lebl <jirka 5z com>
+
+	* src/graphing.c: Allow changing variable names.  Either in the GUI
+	  or using the new parameter LinePlotVariableNames.
+
+	* help/C/gel-function-list.xml: document the new parameter
+
 Tue Feb 02 10:32:53 2010  Jiri (George) Lebl <jirka 5z com>
 
 	* src/graphing.c, help/C/gel-function-list.xml: Add SlopefieldTicks
diff --git a/NEWS b/NEWS
index e3e4bf8..2577b57 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
 Changes to 1.0.10
 
-* Add SlopefieldTicks and VectorfieldTicks parameters
+* Allow changing variable names for all 2D plotting functions
+* Add SlopefieldTicks, VectorfieldTicks, and LinePlotVariableNames parameters
 * Add AskButtons interactive function
 * Allow comparisons (== and !=) with null, treating it as an empty matrix
 
diff --git a/help/C/gel-function-list.xml b/help/C/gel-function-list.xml
index a8d1b56..c0c59cd 100644
--- a/help/C/gel-function-list.xml
+++ b/help/C/gel-function-list.xml
@@ -572,26 +572,37 @@ except possibly user interface events are processed.</para>
          </listitem>
         </varlistentry>
 
-        <varlistentry id="gel-function-LinePlotWindow">
-         <term>LinePlotWindow</term>
+        <varlistentry id="gel-function-LinePlotDrawLegends">
+         <term>LinePlotDrawLegends</term>
          <listitem>
-          <synopsis>LinePlotWindow = [x1,x2,y1,y2]</synopsis>
-          <para>Sets the limits for <link linkend="genius-gel-function-list-plotting">line plotting
+          <synopsis>LinePlotDrawLegends = true</synopsis>
+          <para>Tells genius to draw the legends for <link linkend="genius-gel-function-list-plotting">line plotting
 	  functions</link> such as <link linkend="gel-function-LinePlot"><function>LinePlot</function></link>.
           </para>
          </listitem>
         </varlistentry>
 
-        <varlistentry id="gel-function-LinePlotDrawLegends">
-         <term>LinePlotDrawLegends</term>
+        <varlistentry id="gel-function-LinePlotVariableNames">
+         <term>LinePlotVariableNames</term>
          <listitem>
-          <synopsis>LinePlotDrawLegends = true</synopsis>
-          <para>Tells genius to draw the legends for <link linkend="genius-gel-function-list-plotting">line plotting
+          <synopsis>LinePlotVariableNames = ["x","y","z","t"]</synopsis>
+          <para>Tells genius which variable names are used as default names  for <link linkend="genius-gel-function-list-plotting">line plotting
+	  functions</link> such as <link linkend="gel-function-LinePlot"><function>LinePlot</function></link> and friends.
+          </para>
+         </listitem>
+        </varlistentry>
+
+        <varlistentry id="gel-function-LinePlotWindow">
+         <term>LinePlotWindow</term>
+         <listitem>
+          <synopsis>LinePlotWindow = [x1,x2,y1,y2]</synopsis>
+          <para>Sets the limits for <link linkend="genius-gel-function-list-plotting">line plotting
 	  functions</link> such as <link linkend="gel-function-LinePlot"><function>LinePlot</function></link>.
           </para>
          </listitem>
         </varlistentry>
 
+
         <varlistentry id="gel-function-MaxDigits">
          <term>MaxDigits</term>
          <listitem>
diff --git a/src/graphing.c b/src/graphing.c
index 74ce7ed..46784ce 100644
--- a/src/graphing.c
+++ b/src/graphing.c
@@ -95,8 +95,11 @@ static GtkPlotData *slopefield_data = NULL;
 static GtkPlotData *vectorfield_data = NULL;
 
 static GtkWidget *plot_entries[MAXFUNC] = { NULL };
+static GtkWidget *plot_y_labels[MAXFUNC] = { NULL };
 static GtkWidget *plot_entries_status[MAXFUNC] = { NULL };
 
+static GtkWidget *lineplot_info_label = NULL;
+
 static GtkWidget *parametric_entry_x = NULL;
 static GtkWidget *parametric_entry_y = NULL;
 static GtkWidget *parametric_entry_z = NULL;
@@ -104,17 +107,43 @@ static GtkWidget *parametric_status_x = NULL;
 static GtkWidget *parametric_status_y = NULL;
 static GtkWidget *parametric_status_z = NULL;
 
+static GtkWidget *parametric_info_label = NULL;
+static GtkWidget *parametric_x_label = NULL;
+static GtkWidget *parametric_y_label = NULL;
+static GtkWidget *parametric_z_label = NULL;
+static GtkWidget *parametric_trange_label = NULL;
+
 static GtkWidget *slopefield_entry = NULL;
 static GtkWidget *slopefield_status = NULL;
+static GtkWidget *slopefield_info_label = NULL;
+static GtkWidget *slopefield_der_label = NULL;
 
 static GtkWidget *solver_x_sb = NULL;
 static GtkWidget *solver_y_sb = NULL;
 
+static GtkWidget *solver_xinc_label = NULL;
+static GtkWidget *solver_tinc_label = NULL;
+static GtkWidget *solver_tlen_label = NULL;
+static GtkWidget *solver_x_pt_label = NULL;
+static GtkWidget *solver_y_pt_label = NULL;
+
 static GtkWidget *vectorfield_entry_x = NULL;
 static GtkWidget *vectorfield_status_x = NULL;
 static GtkWidget *vectorfield_entry_y = NULL;
 static GtkWidget *vectorfield_status_y = NULL;
 
+static GtkWidget *vectorfield_info_label = NULL;
+static GtkWidget *vectorfield_xder_label = NULL;
+static GtkWidget *vectorfield_yder_label = NULL;
+
+static GtkWidget *lineplot_x_range_label = NULL;
+static GtkWidget *lineplot_y_range_label = NULL;
+
+static char *lp_x_name = NULL;
+static char *lp_y_name = NULL;
+static char *lp_z_name = NULL;
+static char *lp_t_name = NULL;
+
 static GSList *solutions_list = NULL;
 
 static double spinx1 = -10;
@@ -253,7 +282,8 @@ static gboolean whack_window_after_plot = FALSE;
 static void plot_axis (void);
 
 /* lineplots */
-static void plot_functions (gboolean do_window_present);
+static void plot_functions (gboolean do_window_present,
+			    gboolean from_gui);
 
 /* surfaces */
 static void plot_surface_functions (gboolean do_window_present);
@@ -265,14 +295,18 @@ static void slopefield_draw_solution (double x, double y, double dx);
 static void vectorfield_draw_solution (double x, double y, double dt, double tlen);
 
 static GtkWidget *
-create_range_spinboxes (const char *title, double *val1, GtkWidget **w1,
+create_range_spinboxes (const char *title, GtkWidget **titlew,
+			double *val1, GtkWidget **w1,
 			double min1, double max1, double step1,
-			const char *totitle, double *val2, GtkWidget **w2,
+			const char *totitle, GtkWidget **totitlew,
+			double *val2, GtkWidget **w2,
 			double min2, double max2, double step2,
 			const char *bytitle, double *by, GtkWidget **wb,
 			double minby, double maxby, double stepby,
 			GCallback activate_callback);
 
+static void set_lineplot_labels (void);
+
 #define WIDTH 640
 #define HEIGHT 480
 #define ASPECT ((double)HEIGHT/(double)WIDTH)
@@ -290,6 +324,56 @@ enum {
 	RESPONSE_CLEAR
 };
 
+static gboolean
+is_letter_or_underscore (char l)
+{
+	if ((l >= 'a' && l <= 'z') ||
+	    (l >= 'A' && l <= 'Z') ||
+	    l == '_')
+		return TRUE;
+	else
+		return FALSE;
+}
+
+static gboolean
+is_letter_underscore_or_number (char l)
+{
+	if ((l >= 'a' && l <= 'z') ||
+	    (l >= 'A' && l <= 'Z') ||
+	    (l >= '0' && l <= '9') ||
+	    l == '_')
+		return TRUE;
+	else
+		return FALSE;
+}
+
+static gboolean
+is_identifier (const char *e)
+{
+	int i;
+	if ( ! is_letter_or_underscore (e[0]))
+		return FALSE;
+	for (i = 1; e[i] != '\0'; i++) {
+		if ( ! is_letter_underscore_or_number (e[i]))
+			return FALSE;
+	}
+	return TRUE;
+}
+
+
+static void
+init_var_names (void)
+{
+	/* this means we have already initialized */
+	if (lp_x_name != NULL)
+		return;
+
+	lp_x_name = g_strdup ("x");
+	lp_y_name = g_strdup ("y");
+	lp_z_name = g_strdup ("z");
+	lp_t_name = g_strdup ("t");
+}
+
 static void
 color_alloc (GdkColor *color)
 {
@@ -630,7 +714,7 @@ graph_window_response (GtkWidget *w, int response, gpointer data)
 }
 
 static void
-print_entry_activate (GtkWidget *entry, gpointer data)
+ok_dialog_entry_activate (GtkWidget *entry, gpointer data)
 {
 	gtk_dialog_response (GTK_DIALOG (data), GTK_RESPONSE_OK);
 }
@@ -672,7 +756,7 @@ plot_print_cb (void)
 
 	cmd = gtk_entry_new ();
 	g_signal_connect (G_OBJECT (cmd), "activate",
-			  G_CALLBACK (print_entry_activate), req);
+			  G_CALLBACK (ok_dialog_entry_activate), req);
 	gtk_box_pack_start (GTK_BOX (hbox), cmd, TRUE, TRUE, 0);
 
 	gtk_entry_set_text (GTK_ENTRY (cmd), last_cmd);
@@ -1612,9 +1696,11 @@ solver_cb (GtkWidget *item, gpointer data)
 		else
 			inc = 1;
 
-		w = create_range_spinboxes (_("X increment:"), &solver_xinc, NULL,
+		w = create_range_spinboxes (_("X increment:"),
+					    &solver_xinc_label,
+					    &solver_xinc, NULL,
 					    0, G_MAXDOUBLE, inc,
-					    NULL, NULL, NULL, 0, 0, 0,
+					    NULL, NULL, NULL, NULL, 0, 0, 0,
 					    NULL, NULL, NULL, 0, 0, 0,
 					    solver_entry_activate);
 		gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0);
@@ -1632,9 +1718,13 @@ solver_cb (GtkWidget *item, gpointer data)
 		else
 			inc = 1;
 
-		w = create_range_spinboxes (_("T increment:"), &solver_tinc, NULL,
+		w = create_range_spinboxes (_("T increment:"), 
+					    &solver_tinc_label,
+					    &solver_tinc, NULL,
 					    0, G_MAXDOUBLE, inc,
-					    _("T interval length:"), &solver_tlen, NULL,
+					    _("T interval length:"),
+					    &solver_tlen_label,
+					    &solver_tlen, NULL,
 					    0, G_MAXDOUBLE, 1,
 					    NULL, NULL, NULL, 0, 0, 0,
 					    solver_entry_activate);
@@ -1646,16 +1736,22 @@ solver_cb (GtkWidget *item, gpointer data)
 	if (solver_y < ploty1 || solver_y > ploty2)
 		solver_y = ploty1 + (ploty2-ploty1)/2;
 
-	w = create_range_spinboxes (_("Point x:"), &solver_x,
+	w = create_range_spinboxes (_("Point x:"),
+				    &solver_x_pt_label,
+				    &solver_x,
 				    &solver_x_sb,
 				    -G_MAXDOUBLE, G_MAXDOUBLE, 1,
-				    _("y:"), &solver_y,
+				    _("y:"),
+				    &solver_y_pt_label,
+				    &solver_y,
 				    &solver_y_sb,
 				    -G_MAXDOUBLE, G_MAXDOUBLE, 1,
 				    NULL, NULL, NULL, 0, 0, 0,
 				    solver_entry_activate);
 	gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0);
 
+	set_lineplot_labels ();
+
 	gtk_widget_show_all (solver_dialog);
 }
 
@@ -2872,6 +2968,26 @@ make_matrix_from_limits (void)
 	return n;
 }
 
+static GelETree *
+make_matrix_from_lp_varnames (void)
+{
+	GelETree *n;
+	GelMatrixW *m;
+	/*make us a new empty node*/
+	GEL_GET_NEW_NODE (n);
+	n->type = GEL_MATRIX_NODE;
+	m = n->mat.matrix = gel_matrixw_new ();
+	n->mat.quoted = FALSE;
+	gel_matrixw_set_size (m, 4, 1);
+
+	gel_matrixw_set_index (m, 0, 0) = gel_makenum_string (lp_x_name);
+	gel_matrixw_set_index (m, 1, 0) = gel_makenum_string (lp_y_name);
+	gel_matrixw_set_index (m, 2, 0) = gel_makenum_string (lp_z_name);
+	gel_matrixw_set_index (m, 3, 0) = gel_makenum_string (lp_t_name);
+
+	return n;
+}
+
 static gboolean
 get_limits_from_matrix_surf (GelETree *m, double *x1, double *x2, double *y1, double *y2, double *z1, double *z2)
 {
@@ -3427,6 +3543,8 @@ vectorfield_draw_solution (double x, double y, double dt, double tlen)
 static void
 replot_fields (void)
 {
+	init_var_names ();
+
 	if (slopefield_func != NULL) {
 		get_slopefield_points ();
 		if (plot_points_num > 0) {
@@ -3462,10 +3580,19 @@ replot_fields (void)
 
 				gtk_plot_flux_show_scale (GTK_PLOT_FLUX (slopefield_data), FALSE);
 
-				label = label_func (-1, slopefield_func, "x,y", slopefield_name);
+				tmp = g_strdup_printf ("%s,%s",
+						       lp_x_name,
+						       lp_y_name);
+				label = label_func (-1, slopefield_func, tmp, slopefield_name);
+				g_free (tmp);
 				/* FIXME: gtkextra is broken (adding the "  ")
 				 * and I don't feel like fixing it */
-				tmp = g_strconcat ("dy/dx = ", label, "  ", NULL);
+				/* add dy/dx = */
+				tmp = g_strconcat ("d",
+						   lp_y_name,
+						   "/d",
+						   lp_x_name,
+						   " = ", label, "  ", NULL);
 				g_free (label);
 				gtk_plot_data_set_legend (slopefield_data, tmp);
 				g_free (tmp);
@@ -3519,11 +3646,25 @@ replot_fields (void)
 
 				gtk_plot_flux_show_scale (GTK_PLOT_FLUX (vectorfield_data), FALSE);
 
-				l1 = label_func (-1, vectorfield_func_x, "x,y", vectorfield_name_x);
-				l2 = label_func (-1, vectorfield_func_y, "x,y", vectorfield_name_y);
+				tmp = g_strdup_printf ("%s,%s",
+						       lp_x_name,
+						       lp_y_name);
+				l1 = label_func (-1, vectorfield_func_x, tmp, vectorfield_name_x);
+				l2 = label_func (-1, vectorfield_func_y, tmp, vectorfield_name_y);
+				g_free (tmp);
 				/* FIXME: gtkextra is broken (adding the "  ")
 				 * and I don't feel like fixing it */
-				tmp = g_strconcat ("dx/dt = ", l1, ",  dy/dt = ", l2, "  ", NULL);
+				/*tmp = g_strconcat ("dx/dt = ", l1, ",  dy/dt = ", l2, "  ", NULL);*/
+				tmp = g_strconcat ("d",
+						   lp_x_name,
+						   "/d",
+						   lp_t_name,
+						   " = ", l1, ",  d",
+						   lp_y_name,
+						   "/d",
+						   lp_t_name,
+						   " = ", l2,
+						   "  ", NULL);
 				g_free (l1);
 				g_free (l2);
 				gtk_plot_data_set_legend (vectorfield_data, tmp);
@@ -3562,7 +3703,8 @@ init_plot_ctx (void)
 }
 
 static void
-plot_functions (gboolean do_window_present)
+plot_functions (gboolean do_window_present,
+		gboolean from_gui)
 {
 	char *colors[] = {
 		"darkblue",
@@ -3581,6 +3723,8 @@ plot_functions (gboolean do_window_present)
 	int i;
 	int color_i;
 
+	init_var_names ();
+
 	ensure_window (do_window_present);
 
 	if (plot_canvas != NULL /* sanity */)
@@ -3646,7 +3790,9 @@ plot_functions (gboolean do_window_present)
 						   GDK_JOIN_ROUND,
 						   2, &color);
 
-		label = label_func (i, plot_func[i], "x", plot_func_name[i]);
+		label = label_func (i, plot_func[i],
+				    lp_x_name,
+				    plot_func_name[i]);
 		gtk_plot_data_set_legend (line_data[i], label);
 		g_free (label);
 	}
@@ -3842,9 +3988,11 @@ entry_activate (void)
 }
 
 static GtkWidget *
-create_range_spinboxes (const char *title, double *val1, GtkWidget **w1,
+create_range_spinboxes (const char *title, GtkWidget **titlew,
+			double *val1, GtkWidget **w1,
 			double min1, double max1, double step1,
-			const char *totitle, double *val2, GtkWidget **w2,
+			const char *totitle, GtkWidget **totitlew,
+			double *val2, GtkWidget **w2,
 			double min2, double max2, double step2,
 			const char *bytitle, double *by, GtkWidget **wb,
 			double minby, double maxby, double stepby,
@@ -3855,6 +4003,13 @@ create_range_spinboxes (const char *title, double *val1, GtkWidget **w1,
 
 	b = gtk_hbox_new (FALSE, GENIUS_PAD);
 	w = gtk_label_new(title);
+	if (titlew != NULL) {
+		*titlew = w;
+		g_signal_connect (G_OBJECT (w),
+				  "destroy",
+				  G_CALLBACK (gtk_widget_destroyed),
+				  titlew);
+	}
 	gtk_box_pack_start (GTK_BOX (b), w, FALSE, FALSE, 0);
 	adj = (GtkAdjustment *)gtk_adjustment_new (*val1,
 						   min1,
@@ -3881,6 +4036,13 @@ create_range_spinboxes (const char *title, double *val1, GtkWidget **w1,
 
 	if (val2 != NULL) {
 		w = gtk_label_new (totitle);
+		if (totitlew != NULL) {
+			*totitlew = w;
+			g_signal_connect (G_OBJECT (w),
+					  "destroy",
+					  G_CALLBACK (gtk_widget_destroyed),
+					  totitlew);
+		}
 		gtk_box_pack_start (GTK_BOX (b), w, FALSE, FALSE, 0);
 		adj = (GtkAdjustment *)gtk_adjustment_new (*val2,
 							   min2,
@@ -3968,15 +4130,25 @@ create_int_spinbox (const char *title, int *val, int min, int max)
 
 static GtkWidget *
 create_expression_box (const char *label,
+		       GtkWidget **labelw,
 		       GtkWidget **entry,
 		       GtkWidget **status)
 {
 	GtkWidget *b;
+	GtkWidget *l;
 
 	b = gtk_hbox_new (FALSE, GENIUS_PAD);
 
-	gtk_box_pack_start (GTK_BOX (b),
-			    gtk_label_new (label), FALSE, FALSE, 0);
+	l = gtk_label_new (label);
+	if (labelw != NULL) {
+		*labelw = l;
+		g_signal_connect (G_OBJECT (l),
+				  "destroy",
+				  G_CALLBACK (gtk_widget_destroyed),
+				  labelw);
+	}
+
+	gtk_box_pack_start (GTK_BOX (b), l, FALSE, FALSE, 0);
 
 	*entry = gtk_entry_new ();
 	g_signal_connect (G_OBJECT (*entry), "activate",
@@ -3988,6 +4160,28 @@ create_expression_box (const char *label,
 	return b;
 }
 
+static GtkWidget *
+create_simple_expression_box (const char *label,
+			      GtkWidget **labelw,
+			      GtkWidget **entry)
+{
+	GtkWidget *b;
+	GtkWidget *l;
+
+	b = gtk_hbox_new (FALSE, GENIUS_PAD);
+
+	l = gtk_label_new (label);
+	if (labelw != NULL)
+		*labelw = l;
+
+	gtk_box_pack_start (GTK_BOX (b), l, FALSE, FALSE, 0);
+
+	*entry = gtk_entry_new ();
+	gtk_box_pack_start (GTK_BOX (b), *entry, TRUE, TRUE, 0);
+
+	return b;
+}
+
 /*option callback*/
 static void
 optioncb (GtkWidget * widget, int *data)
@@ -3998,13 +4192,339 @@ optioncb (GtkWidget * widget, int *data)
 		*data = FALSE;
 }
 
+static void
+set_lineplot_labels (void)
+{
+	char *s;
+
+	if (slopefield_info_label != NULL) {
+		s = g_strdup_printf (_("Type in function name or expression involving "
+				       "the %s and %s variables (or the %s variable which will be %s=%s+i%s) "
+				       "that gives the slope "
+				       "at the point (%s,%s)."),
+				     lp_x_name,
+				     lp_y_name,
+				     lp_z_name,
+				     lp_z_name,
+				     lp_x_name,
+				     lp_y_name,
+				     lp_x_name,
+				     lp_y_name);
+		gtk_label_set_text (GTK_LABEL (slopefield_info_label), s);
+		g_free (s);
+	}
+
+	if (slopefield_der_label != NULL) {
+		s = g_strdup_printf ("d%s/d%s=",
+				     lp_y_name,
+				     lp_x_name);
+		gtk_label_set_text (GTK_LABEL (slopefield_der_label), s);
+		g_free (s);
+	}
+
+	if (lineplot_x_range_label != NULL) {
+		s = g_strdup_printf (_("%s from:"),
+				     lp_x_name);
+		gtk_label_set_text (GTK_LABEL (lineplot_x_range_label), s);
+		g_free (s);
+	}
+
+	if (lineplot_y_range_label != NULL) {
+		s = g_strdup_printf (_("%s from:"),
+				     lp_y_name);
+		gtk_label_set_text (GTK_LABEL (lineplot_y_range_label), s);
+		g_free (s);
+	}
+
+	if (solver_xinc_label != NULL) {
+		s = g_strdup_printf (_("%s increment:"),
+				     lp_x_name);
+		gtk_label_set_text (GTK_LABEL (solver_xinc_label), s);
+		g_free (s);
+	}
+
+	if (solver_tinc_label != NULL) {
+		s = g_strdup_printf (_("%s increment:"),
+				     lp_t_name);
+		gtk_label_set_text (GTK_LABEL (solver_tinc_label), s);
+		g_free (s);
+	}
+
+	if (solver_tlen_label != NULL) {
+		s = g_strdup_printf (_("%s interval length:"),
+				     lp_t_name);
+		gtk_label_set_text (GTK_LABEL (solver_tlen_label), s);
+		g_free (s);
+	}
+
+	if (solver_x_pt_label != NULL) {
+		s = g_strdup_printf (_("Point %s:"),
+				     lp_x_name);
+		gtk_label_set_text (GTK_LABEL (solver_x_pt_label), s);
+		g_free (s);
+	}
+
+	if (solver_y_pt_label != NULL) {
+		s = g_strdup_printf ("%s:",
+				     lp_y_name);
+		gtk_label_set_text (GTK_LABEL (solver_y_pt_label), s);
+		g_free (s);
+	}
+	if (vectorfield_info_label != NULL) {
+		s = g_strdup_printf (_("Type in function names or expressions involving "
+				       "the %s and %s variables (or the %s variable which will be %s=%s+i%s) "
+				       "that give the d%s/d%s and d%s/d%s of the autonomous system to be plotted "
+				       "at the point (%s,%s)."),
+				     lp_x_name,
+				     lp_y_name,
+				     lp_z_name,
+				     lp_z_name,
+				     lp_x_name,
+				     lp_y_name,
+				     lp_x_name,
+				     lp_t_name,
+				     lp_y_name,
+				     lp_t_name,
+				     lp_x_name,
+				     lp_y_name);
+		gtk_label_set_text (GTK_LABEL (vectorfield_info_label), s);
+		g_free (s);
+	}
+
+	if (vectorfield_xder_label != NULL) {
+		s = g_strdup_printf ("d%s/d%s=",
+				     lp_x_name,
+				     lp_t_name);
+		gtk_label_set_text (GTK_LABEL (vectorfield_xder_label), s);
+		g_free (s);
+	}
+	if (vectorfield_yder_label != NULL) {
+		s = g_strdup_printf ("d%s/d%s=",
+				     lp_y_name,
+				     lp_t_name);
+		gtk_label_set_text (GTK_LABEL (vectorfield_yder_label), s);
+		g_free (s);
+	}
+
+	if (lineplot_info_label != NULL) {
+		s = g_strdup_printf (_("Type in function names or expressions involving "
+				       "the %s variable in the boxes below to graph "
+				       "them"), lp_x_name);
+		gtk_label_set_text (GTK_LABEL (lineplot_info_label), s);
+		g_free (s);
+	}
+
+	if (plot_y_labels[0] != NULL) {
+		int i;
+		s = g_strdup_printf ("%s=", lp_y_name);
+		for (i = 0; i < MAXFUNC; i++) {
+			gtk_label_set_text (GTK_LABEL (plot_y_labels[i]), s);
+		}
+		g_free (s);
+	}
+
+	if (parametric_info_label != NULL) {
+		s = g_strdup_printf (_("Type in function names or expressions involving "
+				       "the %s variable in the boxes below to graph "
+				       "them.  Either fill in both boxes with %s= and %s= "
+				       "in front of them giving the %s and %s coordinates "
+				       "separately, or alternatively fill in the %s= box "
+				       "giving %s and %s as the real and imaginary part of "
+				       "a complex number."),
+				     lp_t_name,
+				     lp_x_name,
+				     lp_y_name,
+				     lp_x_name,
+				     lp_y_name,
+				     lp_z_name,
+				     lp_x_name,
+				     lp_y_name);
+		gtk_label_set_text (GTK_LABEL (parametric_info_label), s);
+		g_free (s);
+	}
+
+	if (parametric_x_label != NULL) {
+		s = g_strdup_printf ("%s=",
+				     lp_x_name);
+		gtk_label_set_text (GTK_LABEL (parametric_x_label), s);
+		g_free (s);
+	}
+
+	if (parametric_y_label != NULL) {
+		s = g_strdup_printf ("%s=",
+				     lp_y_name);
+		gtk_label_set_text (GTK_LABEL (parametric_y_label), s);
+		g_free (s);
+	}
+
+	if (parametric_z_label != NULL) {
+		s = g_strdup_printf ("%s=",
+				     lp_z_name);
+		gtk_label_set_text (GTK_LABEL (parametric_z_label), s);
+		g_free (s);
+	}
+
+	if (parametric_trange_label != NULL) {
+		s = g_strdup_printf (_("Parameter %s from:"),
+				     lp_t_name);
+		gtk_label_set_text (GTK_LABEL (parametric_trange_label), s);
+		g_free (s);
+	}
+}
+
+static char *
+get_varname_from_entry (GtkEntry *e, const char *def, gboolean *ex)
+{
+	char *str = g_strdup (gtk_entry_get_text (GTK_ENTRY (e)));
+	if (ve_string_empty (str)) {
+		g_free (str); 
+		*ex = TRUE;
+		return g_strdup (def);
+	}
+
+	if ( ! is_identifier (str))
+		*ex = TRUE;
+
+	str = g_strcanon (str,
+			  G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "_",
+			  '_');
+	if (str[0] >= '0' && str[0] <= '9') {
+		*ex = TRUE;
+		str[0] = '_';
+	}
+
+	return str;
+}
+
+static void
+change_lineplot_varnames (GtkWidget *button, gpointer data)
+{
+	GtkWidget *req = NULL;
+	GtkWidget *b, *l;
+	GtkWidget *xe;
+	GtkWidget *ye;
+	GtkWidget *ze;
+	GtkWidget *te;
+	GtkWidget *errlabel;
+        GtkSizeGroup *sg;
+
+	req = gtk_dialog_new_with_buttons
+		(_("Change variable names") /* title */,
+		 GTK_WINDOW (graph_window) /* parent */,
+		 GTK_DIALOG_MODAL /* flags */,
+		 GTK_STOCK_OK,
+		 GTK_RESPONSE_OK,
+		 GTK_STOCK_CANCEL,
+		 GTK_RESPONSE_CANCEL,
+		 NULL);
+
+	gtk_dialog_set_default_response (GTK_DIALOG (req),
+					 GTK_RESPONSE_OK);
+
+	gtk_dialog_set_has_separator (GTK_DIALOG (req), FALSE);
+
+	sg = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+	errlabel = gtk_label_new (_("Some values were illegal"));
+	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (req)->vbox),
+			    errlabel, FALSE, FALSE, 0);
+
+	b = create_simple_expression_box (_("independent variable (x):"),
+					  &l, &xe);
+	gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
+	gtk_size_group_add_widget (sg, l);
+	gtk_entry_set_text (GTK_ENTRY (xe), lp_x_name);
+	g_signal_connect (G_OBJECT (xe), "activate",
+			  G_CALLBACK (ok_dialog_entry_activate), req);
+	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (req)->vbox),
+			    b, FALSE, FALSE, 0);
+
+	b = create_simple_expression_box (_("dependent variable (y):"),
+					  &l, &ye);
+	gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
+	gtk_size_group_add_widget (sg, l);
+	gtk_entry_set_text (GTK_ENTRY (ye), lp_y_name);
+	g_signal_connect (G_OBJECT (ye), "activate",
+			  G_CALLBACK (ok_dialog_entry_activate), req);
+	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (req)->vbox),
+			    b, FALSE, FALSE, 0);
+
+	b = create_simple_expression_box (_("complex variable (z = x+iy):"),
+					  &l, &ze);
+	gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
+	gtk_size_group_add_widget (sg, l);
+	gtk_entry_set_text (GTK_ENTRY (ze), lp_z_name);
+	g_signal_connect (G_OBJECT (ze), "activate",
+			  G_CALLBACK (ok_dialog_entry_activate), req);
+	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (req)->vbox),
+			    b, FALSE, FALSE, 0);
+
+	b = create_simple_expression_box (_("parameter variable (t):"),
+					  &l, &te);
+	gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
+	gtk_size_group_add_widget (sg, l);
+	gtk_entry_set_text (GTK_ENTRY (te), lp_t_name);
+	g_signal_connect (G_OBJECT (te), "activate",
+			  G_CALLBACK (ok_dialog_entry_activate), req);
+	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (req)->vbox),
+			    b, FALSE, FALSE, 0);
+
+	gtk_widget_show_all (req);
+	gtk_widget_hide (errlabel);
+
+run_dialog_again:
+
+	if (gtk_dialog_run (GTK_DIALOG (req)) == GTK_RESPONSE_OK) {
+		gboolean ex = FALSE;
+		char *xn, *yn, *zn, *tn;
+
+		xn = get_varname_from_entry (GTK_ENTRY (xe), "x", &ex);
+		yn = get_varname_from_entry (GTK_ENTRY (ye), "y", &ex);
+		zn = get_varname_from_entry (GTK_ENTRY (ze), "z", &ex);
+		tn = get_varname_from_entry (GTK_ENTRY (te), "t", &ex);
+		if (strcmp (xn, yn) == 0 ||
+		    strcmp (xn, zn) == 0 ||
+		    strcmp (xn, tn) == 0 ||
+		    strcmp (yn, zn) == 0 ||
+		    strcmp (yn, tn) == 0 ||
+		    strcmp (zn, tn) == 0)
+			ex = TRUE;
+		if (ex) {
+			gtk_entry_set_text (GTK_ENTRY (xe), xn);
+			gtk_entry_set_text (GTK_ENTRY (ye), yn);
+			gtk_entry_set_text (GTK_ENTRY (ze), zn);
+			gtk_entry_set_text (GTK_ENTRY (te), tn);
+			g_free (xn);
+			g_free (yn);
+			g_free (zn);
+			g_free (tn);
+			gtk_widget_show (errlabel);
+			goto run_dialog_again;
+		}
+
+		g_free (lp_x_name);
+		g_free (lp_y_name);
+		g_free (lp_z_name);
+		g_free (lp_t_name);
+		lp_x_name = xn;
+		lp_y_name = yn;
+		lp_z_name = zn;
+		lp_t_name = tn;
+	}
+	gtk_widget_destroy (req);
+
+	set_lineplot_labels ();
+}
+
 static GtkWidget *
 create_lineplot_box (void)
 {
 	GtkWidget *mainbox, *frame;
-	GtkWidget *box, *b, *fb, *w;
+	GtkWidget *box, *hbox, *b, *fb, *w;
+	char *s;
 	int i;
 
+	init_var_names ();
 
 	mainbox = gtk_vbox_new (FALSE, GENIUS_PAD);
 	gtk_container_set_border_width (GTK_CONTAINER (mainbox), GENIUS_PAD);
@@ -4017,13 +4537,15 @@ create_lineplot_box (void)
 	 */
 	box = gtk_vbox_new (FALSE, GENIUS_PAD);
 	gtk_container_set_border_width (GTK_CONTAINER (box), GENIUS_PAD);
-	w = gtk_label_new (_("Type in function names or expressions involving "
-			     "the x variable in the boxes below to graph "
-			     "them"));
-	gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5);
-	gtk_label_set_line_wrap (GTK_LABEL (w), TRUE);
-	gtk_widget_set_size_request (w, 610, -1);
-	gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0);
+	lineplot_info_label = gtk_label_new ("");
+	gtk_misc_set_alignment (GTK_MISC (lineplot_info_label), 0.0, 0.5);
+	gtk_label_set_line_wrap (GTK_LABEL (lineplot_info_label), TRUE);
+	gtk_widget_set_size_request (lineplot_info_label, 610, -1);
+	gtk_box_pack_start (GTK_BOX (box), lineplot_info_label, FALSE, FALSE, 0);
+	g_signal_connect (G_OBJECT (lineplot_info_label),
+			  "destroy",
+			  G_CALLBACK (gtk_widget_destroyed),
+			  &lineplot_info_label);
 
 	fb = box;
 
@@ -4047,6 +4569,7 @@ create_lineplot_box (void)
 
 	for (i = 0; i < MAXFUNC; i++) {
 		b = create_expression_box ("y=",
+					   &(plot_y_labels[i]),
 					   &(plot_entries[i]),
 					   &(plot_entries_status[i]));
 		gtk_box_pack_start (GTK_BOX (fb), b, FALSE, FALSE, 0);
@@ -4062,26 +4585,26 @@ create_lineplot_box (void)
 
 	box = gtk_vbox_new (FALSE, GENIUS_PAD);
 	gtk_container_set_border_width (GTK_CONTAINER (box), GENIUS_PAD);
-	w = gtk_label_new (_("Type in function names or expressions involving "
-			     "the t variable in the boxes below to graph "
-			     "them.  Either fill in both boxes with x= and y= "
-			     "in front of them giving the x and y coordinates "
-			     "separately, or alternatively fill in the z= box "
-			     "giving x and y as the real and imaginary part of "
-			     "a complex number."));
-	gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5);
-	gtk_label_set_line_wrap (GTK_LABEL (w), TRUE);
-	gtk_widget_set_size_request (w, 610, -1);
-	gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0);
+	parametric_info_label = gtk_label_new ("");
+	gtk_misc_set_alignment (GTK_MISC (parametric_info_label), 0.0, 0.5);
+	gtk_label_set_line_wrap (GTK_LABEL (parametric_info_label), TRUE);
+	gtk_widget_set_size_request (parametric_info_label, 610, -1);
+	gtk_box_pack_start (GTK_BOX (box), parametric_info_label, FALSE, FALSE, 0);
+	g_signal_connect (G_OBJECT (parametric_info_label),
+			  "destroy",
+			  G_CALLBACK (gtk_widget_destroyed),
+			  &parametric_info_label);
 
 	/* x */
 	b = create_expression_box ("x=",
+				   &parametric_x_label,
 				   &parametric_entry_x,
 				   &parametric_status_x);
 	gtk_box_pack_start (GTK_BOX (box), b, FALSE, FALSE, 0);
 
 	/* y */
 	b = create_expression_box ("y=",
+				   &parametric_y_label,
 				   &parametric_entry_y,
 				   &parametric_status_y);
 	gtk_box_pack_start (GTK_BOX (box), b, FALSE, FALSE, 0);
@@ -4092,6 +4615,7 @@ create_lineplot_box (void)
 
 	/* z */
 	b = create_expression_box ("z=",
+				   &parametric_z_label,
 				   &parametric_entry_z,
 				   &parametric_status_z);
 	gtk_box_pack_start (GTK_BOX (box), b, FALSE, FALSE, 0);
@@ -4100,9 +4624,13 @@ create_lineplot_box (void)
 	gtk_box_pack_start (GTK_BOX (box), gtk_label_new (""), FALSE, FALSE, 0);
 
 	/* t range */
-	b = create_range_spinboxes (_("Parameter t from:"), &spint1, NULL,
+	b = create_range_spinboxes (_("Parameter t from:"), 
+				    &parametric_trange_label,
+				    &spint1, NULL,
 				    -G_MAXDOUBLE, G_MAXDOUBLE, 1,
-				    _("to:"), &spint2, NULL,
+				    _("to:"),
+				    NULL,
+				    &spint2, NULL,
 				    -G_MAXDOUBLE, G_MAXDOUBLE, 1,
 				    _("by:"), &spintinc, NULL,
 				    -G_MAXDOUBLE, G_MAXDOUBLE, 1,
@@ -4119,17 +4647,20 @@ create_lineplot_box (void)
 
 	box = gtk_vbox_new (FALSE, GENIUS_PAD);
 	gtk_container_set_border_width (GTK_CONTAINER (box), GENIUS_PAD);
-	w = gtk_label_new (_("Type in function name or expression involving "
-			     "the x and y variables (or the z variable which will be z=x+iy) "
-			     "that gives the slope "
-			     "at the point (x,y)."));
-	gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5);
-	gtk_label_set_line_wrap (GTK_LABEL (w), TRUE);
-	gtk_widget_set_size_request (w, 610, -1);
-	gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0);
+
+	slopefield_info_label = gtk_label_new ("");
+	gtk_misc_set_alignment (GTK_MISC (slopefield_info_label), 0.0, 0.5);
+	gtk_label_set_line_wrap (GTK_LABEL (slopefield_info_label), TRUE);
+	gtk_widget_set_size_request (slopefield_info_label, 610, -1);
+	gtk_box_pack_start (GTK_BOX (box), slopefield_info_label, FALSE, FALSE, 0);
+	g_signal_connect (G_OBJECT (slopefield_info_label),
+			  "destroy",
+			  G_CALLBACK (gtk_widget_destroyed),
+			  &slopefield_info_label);
 
 	/* dy/dx */
 	b = create_expression_box ("dy/dx=",
+				   &slopefield_der_label,
 				   &slopefield_entry,
 				   &slopefield_status);
 	gtk_box_pack_start (GTK_BOX (box), b, FALSE, FALSE, 0);
@@ -4152,23 +4683,27 @@ create_lineplot_box (void)
 
 	box = gtk_vbox_new (FALSE, GENIUS_PAD);
 	gtk_container_set_border_width (GTK_CONTAINER (box), GENIUS_PAD);
-	w = gtk_label_new (_("Type in function names or expressions involving "
-			     "the x and y variables (or the z variable which will be z=x+iy) "
-			     "that give the dx/dt and dy/dt of the autonomous system to be plotted "
-			     "at the point (x,y)."));
-	gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5);
-	gtk_label_set_line_wrap (GTK_LABEL (w), TRUE);
-	gtk_widget_set_size_request (w, 610, -1);
-	gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0);
+	vectorfield_info_label = gtk_label_new ("");
+
+	gtk_misc_set_alignment (GTK_MISC (vectorfield_info_label), 0.0, 0.5);
+	gtk_label_set_line_wrap (GTK_LABEL (vectorfield_info_label), TRUE);
+	gtk_widget_set_size_request (vectorfield_info_label, 610, -1);
+	gtk_box_pack_start (GTK_BOX (box), vectorfield_info_label, FALSE, FALSE, 0);
+	g_signal_connect (G_OBJECT (vectorfield_info_label),
+			  "destroy",
+			  G_CALLBACK (gtk_widget_destroyed),
+			  &vectorfield_info_label);
 
 	/* dx/dt */
 	b = create_expression_box ("dx/dt=",
+				   &vectorfield_xder_label,
 				   &vectorfield_entry_x,
 				   &vectorfield_status_x);
 	gtk_box_pack_start (GTK_BOX (box), b, FALSE, FALSE, 0);
 
 	/* dy/dt */
 	b = create_expression_box ("dy/dt=",
+				   &vectorfield_yder_label,
 				   &vectorfield_entry_y,
 				   &vectorfield_status_y);
 	gtk_box_pack_start (GTK_BOX (box), b, FALSE, FALSE, 0);
@@ -4198,15 +4733,27 @@ create_lineplot_box (void)
 	 * Below notebook
 	 */
 
+	hbox = gtk_hbox_new (FALSE, GENIUS_PAD);
+	gtk_box_pack_start (GTK_BOX (mainbox), hbox, FALSE, FALSE, 0);
+
+	/* draw legend? */
 	w = gtk_check_button_new_with_mnemonic (_("_Draw legend"));
-	gtk_box_pack_start (GTK_BOX (mainbox), w, FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), 
 				      lineplot_draw_legends_cb);
 	g_signal_connect (G_OBJECT (w), "toggled",
 			  G_CALLBACK (optioncb),
 			  (gpointer)&lineplot_draw_legends_cb);
 
+	/* change varnames */
+	b = gtk_button_new_with_label (_("Change variable names..."));
+	gtk_box_pack_end (GTK_BOX (hbox), b, FALSE, FALSE, 0);
+	g_signal_connect (G_OBJECT (b), "clicked",
+			  G_CALLBACK (change_lineplot_varnames), NULL);
 
+
+
+	/* plot window */
 	frame = gtk_frame_new (_("Plot Window"));
 	gtk_box_pack_start (GTK_BOX (mainbox), frame, FALSE, FALSE, 0);
 	box = gtk_vbox_new (FALSE, GENIUS_PAD);
@@ -4216,9 +4763,10 @@ create_lineplot_box (void)
 	/*
 	 * X range
 	 */
-	b = create_range_spinboxes (_("X from:"), &spinx1, NULL,
+	b = create_range_spinboxes (_("X from:"), &lineplot_x_range_label,
+				    &spinx1, NULL,
 				    -G_MAXDOUBLE, G_MAXDOUBLE, 1,
-				    _("to:"), &spinx2, NULL,
+				    _("to:"), NULL, &spinx2, NULL,
 				    -G_MAXDOUBLE, G_MAXDOUBLE, 1,
 				    NULL, NULL, NULL, 0, 0, 0,
 				    entry_activate);
@@ -4227,14 +4775,18 @@ create_lineplot_box (void)
 	/*
 	 * Y range
 	 */
-	b = create_range_spinboxes (_("Y from:"), &spiny1, NULL,
+	b = create_range_spinboxes (_("Y from:"), &lineplot_y_range_label,
+				    &spiny1, NULL,
 				    -G_MAXDOUBLE, G_MAXDOUBLE, 1,
-				    _("to:"), &spiny2, NULL,
+				    _("to:"), NULL, &spiny2, NULL,
 				    -G_MAXDOUBLE, G_MAXDOUBLE, 1,
 				    NULL, NULL, NULL, 0, 0, 0,
 				    entry_activate);
 	gtk_box_pack_start (GTK_BOX(box), b, FALSE, FALSE, 0);
 
+	/* set labels correclty */
+	set_lineplot_labels ();
+
 	return mainbox;
 }
 
@@ -4282,9 +4834,9 @@ create_surface_box (void)
 	/*
 	 * X range
 	 */
-	b = create_range_spinboxes (_("X from:"), &surf_spinx1, NULL,
+	b = create_range_spinboxes (_("X from:"), NULL, &surf_spinx1, NULL,
 				    -G_MAXDOUBLE, G_MAXDOUBLE, 1,
-				    _("to:"), &surf_spinx2, NULL,
+				    _("to:"), NULL, &surf_spinx2, NULL,
 				    -G_MAXDOUBLE, G_MAXDOUBLE, 1,
 				    NULL, NULL, NULL, 0, 0, 0,
 				    entry_activate);
@@ -4293,9 +4845,9 @@ create_surface_box (void)
 	/*
 	 * Y range
 	 */
-	b = create_range_spinboxes (_("Y from:"), &surf_spiny1, NULL,
+	b = create_range_spinboxes (_("Y from:"), NULL, &surf_spiny1, NULL,
 				    -G_MAXDOUBLE, G_MAXDOUBLE, 1,
-				    _("to:"), &surf_spiny2, NULL,
+				    _("to:"), NULL, &surf_spiny2, NULL,
 				    -G_MAXDOUBLE, G_MAXDOUBLE, 1,
 				    NULL, NULL, NULL, 0, 0, 0,
 				    entry_activate);
@@ -4304,9 +4856,9 @@ create_surface_box (void)
 	/*
 	 * Z range
 	 */
-	b = create_range_spinboxes (_("Z from:"), &surf_spinz1, NULL,
+	b = create_range_spinboxes (_("Z from:"), NULL, &surf_spinz1, NULL,
 				    -G_MAXDOUBLE, G_MAXDOUBLE, 1,
-				    _("to:"), &surf_spinz2, NULL,
+				    _("to:"), NULL, &surf_spinz2, NULL,
 				    -G_MAXDOUBLE, G_MAXDOUBLE, 1,
 				    NULL, NULL, NULL, 0, 0, 0,
 				    entry_activate);
@@ -4331,42 +4883,6 @@ create_plot_dialog (void)
 	return plot_notebook;
 }
 
-static gboolean
-is_letter_or_underscore (char l)
-{
-	if ((l >= 'a' && l <= 'z') ||
-	    (l >= 'A' && l <= 'Z') ||
-	    l == '_')
-		return TRUE;
-	else
-		return FALSE;
-}
-
-static gboolean
-is_letter_underscore_or_number (char l)
-{
-	if ((l >= 'a' && l <= 'z') ||
-	    (l >= 'A' && l <= 'Z') ||
-	    (l >= '0' && l <= '9') ||
-	    l == '_')
-		return TRUE;
-	else
-		return FALSE;
-}
-
-static gboolean
-is_identifier (const char *e)
-{
-	int i;
-	if ( ! is_letter_or_underscore (e[0]))
-		return FALSE;
-	for (i = 1; e[i] != '\0'; i++) {
-		if ( ! is_letter_underscore_or_number (e[i]))
-			return FALSE;
-	}
-	return TRUE;
-}
-
 static GelEFunc *
 function_from_expression (const char *e, const char *var, gboolean *ex)
 {
@@ -4419,7 +4935,11 @@ function_from_expression (const char *e, const char *var, gboolean *ex)
 }
 
 static GelEFunc *
-function_from_expression2 (const char *e, gboolean *ex)
+function_from_expression2 (const char *e,
+			   const char *xname,
+			   const char *yname,
+			   const char *zname,
+			   gboolean *ex)
 {
 	GelEFunc *f = NULL;
 	GelETree *value;
@@ -4431,9 +4951,9 @@ function_from_expression2 (const char *e, gboolean *ex)
 
 	ce = g_strstrip (g_strdup (e));
 	if (is_identifier (ce) &&
-	    strcmp (ce, "x") != 0 &&
-	    strcmp (ce, "y") != 0 &&
-	    strcmp (ce, "z") != 0) {
+	    strcmp (ce, xname) != 0 &&
+	    strcmp (ce, yname) != 0 &&
+	    strcmp (ce, zname) != 0) {
 		f = d_lookup_global (d_intern (ce));
 		g_free (ce);
 		if (f != NULL) {
@@ -4458,30 +4978,30 @@ function_from_expression2 (const char *e, gboolean *ex)
 	gel_got_eof = FALSE;
 
 	/* FIXME: funcbody?  I think it must be done. */
-	got_x = gel_eval_find_identifier (value, d_intern ("x"), TRUE /*funcbody*/);
-	got_y = gel_eval_find_identifier (value, d_intern ("y"), TRUE /*funcbody*/);
-	got_z = gel_eval_find_identifier (value, d_intern ("z"), TRUE /*funcbody*/);
+	got_x = gel_eval_find_identifier (value, d_intern (xname), TRUE /*funcbody*/);
+	got_y = gel_eval_find_identifier (value, d_intern (yname), TRUE /*funcbody*/);
+	got_z = gel_eval_find_identifier (value, d_intern (zname), TRUE /*funcbody*/);
 
 	/* FIXME: if "x" or "y" or "z" not used try to evaluate and if it returns a function use that */
 	if (value != NULL) {
 		if ( ! got_x && ! got_y && got_z) {
 			f = d_makeufunc (NULL /* id */,
 					 value,
-					 g_slist_append (NULL, d_intern ("z")),
+					 g_slist_append (NULL, d_intern (zname)),
 					 1,
 					 NULL /* extra_dict */);
 		} else if ( ! got_z) {
-			GSList *l = g_slist_append (NULL, d_intern ("x"));
-			l = g_slist_append (l, d_intern ("y"));
+			GSList *l = g_slist_append (NULL, d_intern (xname));
+			l = g_slist_append (l, d_intern (yname));
 			f = d_makeufunc (NULL /* id */,
 					 value,
 					 l,
 					 2,
 					 NULL /* extra_dict */);
 		} else {
-			GSList *l = g_slist_append (NULL, d_intern ("x"));
-			l = g_slist_append (l, d_intern ("y"));
-			l = g_slist_append (l, d_intern ("z"));
+			GSList *l = g_slist_append (NULL, d_intern (xname));
+			l = g_slist_append (l, d_intern (yname));
+			l = g_slist_append (l, d_intern (zname));
 			f = d_makeufunc (NULL /* id */,
 					 value,
 					 l,
@@ -4526,11 +5046,14 @@ get_func_from_entry (GtkWidget *entry, GtkWidget *status,
 
 static GelEFunc *
 get_func_from_entry2 (GtkWidget *entry, GtkWidget *status,
+		      const char *xname,
+		      const char *yname,
+		      const char *zname,
 		      gboolean *ex)
 {
 	GelEFunc *f;
 	const char *str = gtk_entry_get_text (GTK_ENTRY (entry));
-	f = function_from_expression2 (str, ex);
+	f = function_from_expression2 (str, xname, yname, zname, ex);
 	if (f != NULL) {
 		gtk_image_set_from_stock
 			(GTK_IMAGE (status),
@@ -4569,7 +5092,8 @@ surface_from_dialog (void)
 	genius_setup.error_box = TRUE;
 
 	ex = FALSE;
-	func = get_func_from_entry2 (surface_entry, surface_entry_status, &ex);
+	func = get_func_from_entry2 (surface_entry, surface_entry_status, 
+				     "x", "y", "z", &ex);
 
 	if (func == NULL) {
 		error_to_print = _("No functions to plot or no functions "
@@ -4723,7 +5247,7 @@ plot_from_dialog_lineplot (void)
 		gboolean ex = FALSE;
 		f = get_func_from_entry (plot_entries[i],
 					 plot_entries_status[i],
-					 "x",
+					 lp_x_name,
 					 &ex);
 		if (f != NULL) {
 			func[i] = f;
@@ -4783,7 +5307,8 @@ plot_from_dialog_lineplot (void)
 		}
 	}
 
-	plot_functions (TRUE /* do_window_present */);
+	plot_functions (TRUE /* do_window_present */,
+			TRUE /* from_gui */);
 
 	if (gel_interrupted)
 		gel_interrupted = FALSE;
@@ -4817,7 +5342,7 @@ plot_from_dialog_parametric (void)
 	double x1, x2, y1, y2;
 	gboolean last_info;
 	gboolean last_error;
-	const char *error_to_print = NULL;
+	char *error_to_print = NULL;
 	gboolean exx = FALSE;
 	gboolean exy = FALSE;
 	gboolean exz = FALSE;
@@ -4831,31 +5356,32 @@ plot_from_dialog_parametric (void)
 
 	funcpx = get_func_from_entry (parametric_entry_x,
 				      parametric_status_x,
-				      "t",
+				      lp_t_name,
 				      &exx);
 	funcpy = get_func_from_entry (parametric_entry_y,
 				      parametric_status_y,
-				      "t",
+				      lp_t_name,
 				      &exy);
 	funcpz = get_func_from_entry (parametric_entry_z,
 				      parametric_status_z,
-				      "t",
+				      lp_t_name,
 				      &exz);
 	if (((funcpx || exx) || (funcpy || exy)) && (funcpz || exz)) {
-		error_to_print = _("Only specify x and y, or z, not all at once.");
+		error_to_print = g_strdup_printf (_("Only specify %s and %s, or %s, not all at once."), lp_x_name, lp_y_name, lp_z_name);
 		goto whack_copied_funcs;
 	}
 
 	if ( ! ( (funcpz == NULL && funcpx != NULL && funcpy != NULL) ||
 		 (funcpz != NULL && funcpx == NULL && funcpy == NULL))) {
-		error_to_print = _("No functions to plot or no functions "
-				   "could be parsed");
+		error_to_print = g_strdup (_("No functions to plot or no functions "
+					     "could be parsed"));
 		goto whack_copied_funcs;
 	}
 
 	if (spint1 >= spint2 ||
 	    spintinc <= 0.0) {
-		error_to_print = _("Invalid t range");
+		error_to_print = g_strdup_printf (_("Invalid %s range"),
+						  lp_t_name);
 		goto whack_copied_funcs;
 	}
 
@@ -4877,12 +5403,14 @@ plot_from_dialog_parametric (void)
 	}
 
 	if (x1 == x2) {
-		error_to_print = _("Invalid X range");
+		error_to_print = g_strdup_printf (_("Invalid %s range"),
+						  lp_x_name);
 		goto whack_copied_funcs;
 	}
 
 	if (y1 == y2) {
-		error_to_print = _("Invalid Y range");
+		error_to_print = g_strdup_printf (_("Invalid %s range"),
+						  lp_y_name);
 		goto whack_copied_funcs;
 	}
 
@@ -4909,7 +5437,8 @@ plot_from_dialog_parametric (void)
 					       NULL);
 	}
 
-	plot_functions (TRUE /* do_window_present */);
+	plot_functions (TRUE /* do_window_present */,
+			TRUE /* from_gui */);
 
 	if (gel_interrupted)
 		gel_interrupted = FALSE;
@@ -4932,8 +5461,10 @@ whack_copied_funcs:
 	genius_setup.info_box = last_info;
 	genius_setup.error_box = last_error;
 
-	if (error_to_print != NULL)
+	if (error_to_print != NULL) {
 		genius_display_error (plot_dialog, error_to_print);
+		g_free (error_to_print);
+	}
 }
 
 static void
@@ -4943,7 +5474,7 @@ plot_from_dialog_slopefield (void)
 	double x1, x2, y1, y2;
 	gboolean last_info;
 	gboolean last_error;
-	const char *error_to_print = NULL;
+	char *error_to_print = NULL;
 	gboolean ex = FALSE;
 
 	plot_mode = MODE_LINEPLOT_SLOPEFIELD;
@@ -4953,12 +5484,18 @@ plot_from_dialog_slopefield (void)
 	genius_setup.info_box = TRUE;
 	genius_setup.error_box = TRUE;
 
+	init_var_names ();
+
 	ex = FALSE;
-	funcp = get_func_from_entry2 (slopefield_entry, slopefield_status, &ex);
+	funcp = get_func_from_entry2 (slopefield_entry, slopefield_status, 
+				      lp_x_name,
+				      lp_y_name,
+				      lp_z_name,
+				      &ex);
 
 	if (funcp == NULL) {
-		error_to_print = _("No functions to plot or no functions "
-				   "could be parsed");
+		error_to_print = g_strdup(_("No functions to plot or no functions "
+					    "could be parsed"));
 		goto whack_copied_funcs;
 	}
 
@@ -4980,12 +5517,14 @@ plot_from_dialog_slopefield (void)
 	}
 
 	if (x1 == x2) {
-		error_to_print = _("Invalid X range");
+		error_to_print = g_strdup_printf (_("Invalid %s range"),
+						  lp_x_name);
 		goto whack_copied_funcs;
 	}
 
 	if (y1 == y2) {
-		error_to_print = _("Invalid Y range");
+		error_to_print = g_strdup_printf (_("Invalid %s range"),
+						  lp_y_name);
 		goto whack_copied_funcs;
 	}
 
@@ -5002,7 +5541,8 @@ plot_from_dialog_slopefield (void)
 	slopefield_func = funcp;
 	slopefield_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (slopefield_entry)));
 
-	plot_functions (TRUE /* do_window_present */);
+	plot_functions (TRUE /* do_window_present */,
+			TRUE /* from_gui */);
 
 	if (gel_interrupted)
 		gel_interrupted = FALSE;
@@ -5021,8 +5561,10 @@ whack_copied_funcs:
 	genius_setup.info_box = last_info;
 	genius_setup.error_box = last_error;
 
-	if (error_to_print != NULL)
+	if (error_to_print != NULL) {
 		genius_display_error (plot_dialog, error_to_print);
+		g_free (error_to_print);
+	}
 }
 
 static void
@@ -5033,7 +5575,7 @@ plot_from_dialog_vectorfield (void)
 	double x1, x2, y1, y2;
 	gboolean last_info;
 	gboolean last_error;
-	const char *error_to_print = NULL;
+	char *error_to_print = NULL;
 	gboolean ex = FALSE;
 
 	plot_mode = MODE_LINEPLOT_VECTORFIELD;
@@ -5047,13 +5589,17 @@ plot_from_dialog_vectorfield (void)
 		vectorfield_normalize_arrow_length_cb;
 
 	ex = FALSE;
-	funcpx = get_func_from_entry2 (vectorfield_entry_x, vectorfield_status_x, &ex);
+	funcpx = get_func_from_entry2 (vectorfield_entry_x,
+				       vectorfield_status_x, 
+				       lp_x_name, lp_y_name, lp_z_name, &ex);
 	ex = FALSE;
-	funcpy = get_func_from_entry2 (vectorfield_entry_y, vectorfield_status_y, &ex);
+	funcpy = get_func_from_entry2 (vectorfield_entry_y,
+				       vectorfield_status_y,
+				       lp_x_name, lp_y_name, lp_z_name, &ex);
 
 	if (funcpx == NULL || funcpy == NULL) {
-		error_to_print = _("No functions to plot or no functions "
-				   "could be parsed");
+		error_to_print = g_strdup (_("No functions to plot or no functions "
+					     "could be parsed"));
 		goto whack_copied_funcs;
 	}
 
@@ -5075,12 +5621,14 @@ plot_from_dialog_vectorfield (void)
 	}
 
 	if (x1 == x2) {
-		error_to_print = _("Invalid X range");
+		error_to_print = g_strdup_printf (_("Invalid %s range"),
+						  lp_x_name);
 		goto whack_copied_funcs;
 	}
 
 	if (y1 == y2) {
-		error_to_print = _("Invalid Y range");
+		error_to_print = g_strdup_printf (_("Invalid %s range"),
+						  lp_y_name);
 		goto whack_copied_funcs;
 	}
 
@@ -5099,7 +5647,8 @@ plot_from_dialog_vectorfield (void)
 	vectorfield_name_x = g_strdup (gtk_entry_get_text (GTK_ENTRY (vectorfield_entry_x)));
 	vectorfield_name_y = g_strdup (gtk_entry_get_text (GTK_ENTRY (vectorfield_entry_y)));
 
-	plot_functions (TRUE /* do_window_present */);
+	plot_functions (TRUE /* do_window_present */,
+			TRUE /* from_gui */);
 
 	if (gel_interrupted)
 		gel_interrupted = FALSE;
@@ -5120,8 +5669,10 @@ whack_copied_funcs:
 	genius_setup.info_box = last_info;
 	genius_setup.error_box = last_error;
 
-	if (error_to_print != NULL)
+	if (error_to_print != NULL) {
 		genius_display_error (plot_dialog, error_to_print);
+		g_free (error_to_print);
+	}
 }
 
 static void
@@ -5549,7 +6100,8 @@ SlopefieldPlot_op (GelCtx *ctx, GelETree * * a, int *exception)
 	plotHtick = plot_sf_Htick;
 
 	plot_mode = MODE_LINEPLOT_SLOPEFIELD;
-	plot_functions (FALSE /* do_window_present */);
+	plot_functions (FALSE /* do_window_present */,
+			FALSE /* from gui */);
 
 	if (gel_interrupted)
 		return NULL;
@@ -5668,7 +6220,8 @@ VectorfieldPlot_op (GelCtx *ctx, GelETree * * a, int *exception)
 	plotHtick = plot_vf_Htick;
 
 	plot_mode = MODE_LINEPLOT_VECTORFIELD;
-	plot_functions (FALSE /* do_window_present */);
+	plot_functions (FALSE /* do_window_present */,
+			FALSE /* from_gui */);
 
 	if (gel_interrupted)
 		return NULL;
@@ -5785,7 +6338,8 @@ LinePlot_op (GelCtx *ctx, GelETree * * a, int *exception)
 	reset_ploty2 = ploty2 = y2;
 
 	plot_mode = MODE_LINEPLOT;
-	plot_functions (FALSE /* do_window_present */);
+	plot_functions (FALSE /* do_window_present */,
+			FALSE /* from_gui */);
 
 	if G_UNLIKELY (gel_interrupted)
 		return NULL;
@@ -5928,7 +6482,8 @@ LinePlotParametric_op (GelCtx *ctx, GelETree * * a, int *exception)
 	plottinc = tinc;
 
 	plot_mode = MODE_LINEPLOT_PARAMETRIC;
-	plot_functions (FALSE /* do_window_present */);
+	plot_functions (FALSE /* do_window_present */,
+			FALSE /* from_gui */ );
 
 	if G_UNLIKELY (gel_interrupted)
 		return NULL;
@@ -6067,7 +6622,8 @@ LinePlotCParametric_op (GelCtx *ctx, GelETree * * a, int *exception)
 	plottinc = tinc;
 
 	plot_mode = MODE_LINEPLOT_PARAMETRIC;
-	plot_functions (FALSE /* do_window_present */);
+	plot_functions (FALSE /* do_window_present */,
+			FALSE /* from_gui */);
 
 	if G_UNLIKELY (gel_interrupted)
 		return NULL;
@@ -6094,7 +6650,8 @@ LinePlotClear_op (GelCtx *ctx, GelETree * * a, int *exception)
 
 	/* This will just clear the window */
 	plot_mode = MODE_LINEPLOT;
-	plot_functions (FALSE /* do_window_present */);
+	plot_functions (FALSE /* do_window_present */,
+			FALSE /* from_gui */);
 
 	if G_UNLIKELY (gel_interrupted)
 		return NULL;
@@ -6611,7 +7168,6 @@ static GelETree *
 set_SlopefieldTicks (GelETree * a)
 {
 	int v, h;
-	gboolean update = FALSE;
 
 	if G_UNLIKELY (plot_in_progress != 0) {
 		gel_errorout (_("%s: Plotting in progress, cannot call %s"),
@@ -6638,7 +7194,6 @@ static GelETree *
 set_VectorfieldTicks (GelETree * a)
 {
 	int v, h;
-	gboolean update = FALSE;
 
 	if G_UNLIKELY (plot_in_progress != 0) {
 		gel_errorout (_("%s: Plotting in progress, cannot call %s"),
@@ -6662,6 +7217,93 @@ get_VectorfieldTicks (void)
 }
 
 static GelETree *
+set_LinePlotVariableNames (GelETree * a)
+{
+	GelETree *t;
+	char *sx, *sy, *sz, *st;
+
+	if G_UNLIKELY (plot_in_progress != 0) {
+		gel_errorout (_("%s: Plotting in progress, cannot call %s"),
+			      "set_LinePlotVariableNames", "set_LinePlotVariableNames");
+		return NULL;
+	}
+
+	if (a->type != GEL_MATRIX_NODE ||
+	    gel_matrixw_elements (a->mat.matrix) != 4) {
+		gel_errorout (_("Variable names not given in a 4-vector"));
+		return NULL;
+	}
+
+	t = gel_matrixw_vindex (a->mat.matrix, 0);
+	if (t->type == GEL_IDENTIFIER_NODE) {
+		sx = t->id.id->token;
+	} else if (t->type == GEL_STRING_NODE) {
+		sx = t->str.str;
+	} else {
+		gel_errorout (_("Variable names should be strings"));
+		return NULL;
+	}
+	t = gel_matrixw_vindex (a->mat.matrix, 1);
+	if (t->type == GEL_IDENTIFIER_NODE) {
+		sy = t->id.id->token;
+	} else if (t->type == GEL_STRING_NODE) {
+		sy = t->str.str;
+	} else {
+		gel_errorout (_("Variable names should be strings"));
+		return NULL;
+	}
+	t = gel_matrixw_vindex (a->mat.matrix, 2);
+	if (t->type == GEL_IDENTIFIER_NODE) {
+		sz = t->id.id->token;
+	} else if (t->type == GEL_STRING_NODE) {
+		sz = t->str.str;
+	} else {
+		gel_errorout (_("Variable names should be strings"));
+		return NULL;
+	}
+	t = gel_matrixw_vindex (a->mat.matrix, 3);
+	if (t->type == GEL_IDENTIFIER_NODE) {
+		st = t->id.id->token;
+	} else if (t->type == GEL_STRING_NODE) {
+		st = t->str.str;
+	} else {
+		gel_errorout (_("Variable names should be strings"));
+		return NULL;
+	}
+	if ( ! is_identifier (sx) ||
+	     ! is_identifier (sy) ||
+	     ! is_identifier (sz) ||
+	     ! is_identifier (st)) {
+		gel_errorout (_("Variable names must be valid identifiers"));
+		return NULL;
+	}
+	if (strcmp (sx, sy) == 0 ||
+	    strcmp (sx, sz) == 0 ||
+	    strcmp (sx, st) == 0 ||
+	    strcmp (sy, sz) == 0 ||
+	    strcmp (sy, st) == 0 ||
+	    strcmp (sz, st) == 0) {
+		gel_errorout (_("Variable names must be mutually distinct"));
+		return NULL;
+	}
+
+	lp_x_name = g_strdup (sx);
+	lp_y_name = g_strdup (sy);
+	lp_z_name = g_strdup (sz);
+	lp_t_name = g_strdup (st);
+
+	set_lineplot_labels ();
+
+	return make_matrix_from_lp_varnames ();
+}
+
+static GelETree *
+get_LinePlotVariableNames (void)
+{
+	return make_matrix_from_lp_varnames ();
+}
+
+static GelETree *
 set_VectorfieldNormalized (GelETree * a)
 {
 	if G_UNLIKELY (plot_in_progress != 0) {
@@ -6748,6 +7390,7 @@ gel_add_graph_functions (void)
 
 	PARAMETER (SlopefieldTicks, N_("Number of slopefield ticks as a vector [vertical,horizontal]."));
 	PARAMETER (VectorfieldTicks, N_("Number of vectorfield ticks as a vector [vertical,horizontal]."));
+	PARAMETER (LinePlotVariableNames, N_("Default names used by all 2D plot functions.  Should be a 4 vector of strings or identifiers [x,y,z,t]."));
 
 	PARAMETER (VectorfieldNormalized, N_("Normalize vectorfields if true.  That is, only show direction and not magnitude."));
 	PARAMETER (LinePlotDrawLegends, N_("If to draw legends or not on line plots."));



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