From 1903c5b9a2ad9542b5886da570e42b788b46b940 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Sun, 8 Mar 1998 20:56:38 +0000 Subject: [PATCH] plotting routines git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@605 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/gnome/graph/Makefile | 8 ++ src/gnome/graph/design.txt | 49 ++++++++++++ src/gnome/graph/plot-test.c | 147 ++++++++++++++++++++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 src/gnome/graph/Makefile create mode 100644 src/gnome/graph/design.txt create mode 100644 src/gnome/graph/plot-test.c diff --git a/src/gnome/graph/Makefile b/src/gnome/graph/Makefile new file mode 100644 index 0000000000..6df649ac6d --- /dev/null +++ b/src/gnome/graph/Makefile @@ -0,0 +1,8 @@ +### Makefile + +CFLAGS := -Wall -O2 -g -I../../engine -I ../../../ + +GTK_LIBS := -lgtk -lgdk -lglib +LOADLIBES := -lplot -L/usr/X11R6/lib ${GTK_LIBS} -lXaw -lXt -lXext -lX11 -lm + +plot-test: ../../libengine.a plot-test.o diff --git a/src/gnome/graph/design.txt b/src/gnome/graph/design.txt new file mode 100644 index 0000000000..b55588631b --- /dev/null +++ b/src/gnome/graph/design.txt @@ -0,0 +1,49 @@ +* From: Rob Browning + + +For those of you interested, below is an extremely simple example of a +tiny standalone program that can read an .xac file (specified as the +first argument and then let you select accounts to plot from a Gtk +window. The plot is just a per-transaction running balance, but it's +a start. You need Gtk and plotutils 2.0 installed for this to work. +I just put these files in a new directory src/graph. There's a +Makefile and plot-test.c. + +Issues: + +This program is trivial, and it only works via a Gtk GUI, but I think +that in the end we should support both interactive and non-interactive +operation of our graphing and reporting tools. Whether this happens +via special arguments to xacc, or by providing separate standalone +programs that link to a common library (libxaccplot?) I don't know, +but either way, I think we need both. + +This little program generates the graph by launching a child "graph" +process (graph is part of the plotutils package). I don't set any +axis labels or anything. This could obviously be improved, but there +are limits to how flexible the graph program is. It can't, for +example, do pie or bar charts at the moment. + +However, the lower level library (libplot) that it's based on will +allow us to do whatever we want. In that case, though, we have to do +the scaling, drawing, etc, ourselves, so I think we're better off to +use "graph" for now, and go back and re-implement things in libplot, +adding bells and whistles and other types of graphs later. I did +create libplot code for simple bars in a bargraph just to make sure I +though it would be feasible. + +The other disadvantage to calling graph (as opposed to using libplot +directly) is that it brings up it's own independent X window on each +invocation. This can also be overcome by switching to the more +primitive libplot, where you can specify your own X drawable as the +output device. + +I've actually contacted the plotutils author about providing the more +sophisticated "graph" level plotting behaviors (autoscaling, etc.) as +part of a library (libplotutils) rather than only as a standalone +program. My guess is that this will happen, but I haven't heard back +yet. + +-- +Rob Browning +PGP fingerprint = E8 0E 0D 04 F5 21 A0 94 53 2B 97 F5 D6 4E 39 30 diff --git a/src/gnome/graph/plot-test.c b/src/gnome/graph/plot-test.c new file mode 100644 index 0000000000..899f29b828 --- /dev/null +++ b/src/gnome/graph/plot-test.c @@ -0,0 +1,147 @@ +/* File: plot-test.c */ + +#include +#include +#include +#include + +#include +#include +#include + +static int +graph_balance(Split **splits) { + + FILE *child = popen("graph -T X", "w"); + int i = 0; + + assert(child != NULL); + + while(*splits) { + const double split_balance = xaccGetBalance(*splits); + fprintf(child, "%d %f\n", i, split_balance); + i++; + splits++; + } + pclose(child); + return 0; +} + +void +destroy() { + gtk_main_quit (); +} + +static void +graph_account_balance_per_transaction(gpointer item, gpointer user_data) { + Account *acct = (Account *) + gtk_object_get_data(GTK_OBJECT(item), "acct_ptr"); + + fprintf(stderr, "%s\n", acct->accountName); + + xaccRecomputeBalance(acct); + { + Account *list[] = { acct, NULL }; + Split **splits = accListGetSortedSplits(list); + graph_balance(splits); + } +} + +static void +plot(GtkButton *button, gpointer data) { + GtkWidget *list = GTK_WIDGET(data); + GList *selection = GTK_LIST(list)->selection; + g_list_foreach(selection, mangle_account, NULL); +} + +static GtkWidget * +make_main_window(GtkWidget **list) { + + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *quit_button; + GtkWidget *plot_button; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + *list = gtk_list_new(); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (destroy), NULL); + gtk_container_border_width (GTK_CONTAINER (window), 3); + + quit_button = gtk_button_new_with_label ("Quit"); + + gtk_signal_connect_object (GTK_OBJECT (quit_button), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (window)); + + plot_button = gtk_button_new_with_label ("Plot"); + + gtk_signal_connect (GTK_OBJECT (plot_button), "clicked", + GTK_SIGNAL_FUNC (plot), *list); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_add (GTK_CONTAINER(window), vbox); + + gtk_box_pack_start(GTK_BOX(vbox), *list, FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(vbox), quit_button, FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(vbox), plot_button, FALSE, FALSE, 0); + + gtk_widget_show (*list); + gtk_widget_show (plot_button); + gtk_widget_show (quit_button); + gtk_widget_show(vbox); + gtk_widget_show (window); + + return(window); +} + +static void +add_accounts_to_list(GtkWidget *list, const char *filename) { + AccountGroup *db = xaccReadAccountGroup(filename); + if(!db) { + fprintf(stderr, "db: %p error: %d\n", db, xaccGetFileIOError()); + exit(1); + } + + { + int count = xaccGetNumAccounts(db); + int i; + GtkWidget *item; + + for(i=0; iaccountName); + gtk_object_set_data(GTK_OBJECT(item), "acct_ptr", acc); + gtk_container_add(GTK_CONTAINER(list), item); + gtk_widget_show(item); + } + } +} + +int +main(int argc, char *argv[]) { + + int handle; + char *filename; + GtkWidget *main_win; + GtkWidget *display_area; + GtkWidget *list = NULL; + + + gtk_init(&argc, &argv); + + if(argc != 2) { + fprintf(stderr, "usage: plot-test filename\n"); + exit(1); + } + filename = argv[1]; + + main_win = make_main_window(&list); + add_accounts_to_list(list, filename); + + gtk_main(); + + return(0); +}