Re: Using fixed-size data buffer with GtkPlot [solved]
"Nickolai Dobrynin" <[email protected]> Wed, 1 Mar 2006 20:03:38 -0600
| Newsgroups | gmane.comp.scigraphica.gtkextra |
|---|---|
| Message-ID | <[email protected]> |
Thanks to all who replied to my post, as I finally was able to do what I
intended
to. Since there is no doubt people would want to do something similar to
what I've done, I decided to post the code snippet that does the job.
Once again, my original problem was: suppose I want to plot data in real
time,
by using GtkPlot. Each data point is only displayed once and then
discarded.
Given that the number of data points grows dynamically, I theoretically
could
use a dynamically expanding buffer associated with the GtkPlotData
object attached to the plot. However, this would eventually run my system
out of
memory because the data buffer would just keep on expanding. So, the main
question
was: is it possible to keep the amount of memory used to store data points
constant,
so that I would keep using the same fixed-size buffer over and over?
Just in case someone has the same problem, here is the code:
#include <gtk/gtk.h>
#include <gtkextra/gtkplot.h>
#include <gtkextra/gtkplotcanvas.h>
#include <gtkextra/gtkplotcanvasplot.h>
#include <gtkextra/gtkplotdata.h>
#include <math.h>
#define NPOINTS 5000
gint runningCount;
gdouble px[NPOINTS];
gdouble py[NPOINTS];
gint dialationFactor = 10;
GtkWidget *canvas;
GtkPlot *plot;
GtkPlotData *dataset;
gdouble getPoint(gdouble x) { return 10.0 * sin(dialationFactor*x); }
bool firstRun; /* Is this the first time we poll or not? */
double xDisplacement;
/*
* This is added to every value of 'x' we get. Thus,
* 'x' itself can stay within a fixed range and doesn't have to be between
* xmin and xmax. (Doing it this way is convenient when used in combination
* with runningCount).
*/
gboolean update(gpointer)
{
if (runningCount >= NPOINTS && !firstRun) {
gdouble xmin, xmax; /* [xmin,xmax) */
gtk_plot_get_xrange(plot, &xmin, &xmax);
gtk_plot_set_xrange(plot, xmin + 2*M_PI, xmax + 2*M_PI);
xDisplacement += 2*M_PI;
gtk_plot_data_set_numpoints(dataset, 0);
gtk_plot_canvas_paint(GTK_PLOT_CANVAS(canvas));
gtk_widget_queue_draw(GTK_WIDGET(canvas));
runningCount = 0;
}
else {
const gdouble x = runningCount * (2*M_PI) / NPOINTS + xDisplacement;
const gdouble y = getPoint(x);
px[runningCount] = x; py[runningCount] = y;
gtk_plot_data_set_numpoints(dataset, runningCount + 1);
gtk_plot_data_draw_points(dataset, 1);
gtk_plot_refresh(plot, NULL);
++runningCount;
}
firstRun = false;
return TRUE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkPlotCanvasChild *child;
runningCount = 0;
gtk_init(&argc, &argv);
/* main window */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Plot");
gtk_container_border_width(GTK_CONTAINER(window), 8);
gtk_widget_show(GTK_WIDGET(window));
g_signal_connect(GTK_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit),
NULL);
/* canvas */
canvas = gtk_plot_canvas_new(700, 600, 1.0);
GTK_PLOT_CANVAS_UNSET_FLAGS(GTK_PLOT_CANVAS(canvas),
GTK_PLOT_CANVAS_DND_FLAGS);
gtk_container_add(GTK_CONTAINER(window), canvas);
gtk_widget_show(GTK_WIDGET(canvas));
/* plot */
plot = GTK_PLOT(gtk_plot_new(NULL));
gtk_plot_set_range(plot, 0, 2*M_PI, -10, 10);
gtk_plot_set_ticks(plot, GTK_PLOT_AXIS_X, 1, 4);
gtk_plot_set_ticks(plot, GTK_PLOT_AXIS_Y, 5, 4);
gtk_plot_axis_hide_title(gtk_plot_get_axis(plot, GTK_PLOT_AXIS_TOP));
gtk_plot_axis_hide_title(gtk_plot_get_axis(plot, GTK_PLOT_AXIS_RIGHT));
gtk_plot_axis_set_title(gtk_plot_get_axis(plot, GTK_PLOT_AXIS_BOTTOM),
"x");
gtk_plot_axis_set_title(gtk_plot_get_axis(plot, GTK_PLOT_AXIS_LEFT),
"sin(x)");
gtk_plot_hide_legends(plot);
/* canvas plot */
child = gtk_plot_canvas_plot_new(plot);
gtk_plot_canvas_put_child(GTK_PLOT_CANVAS(canvas), child, 0.15, 0.15, 0.85,
0.85);
gtk_widget_show(GTK_WIDGET(plot));
/* plot dataset */
dataset = GTK_PLOT_DATA(gtk_plot_data_new());
gtk_plot_data_dimension_set_points(dataset, "x", px);
gtk_plot_data_dimension_set_points(dataset, "y", py);
gtk_plot_add_data(plot, dataset);
gtk_widget_show(GTK_WIDGET(dataset));
gtk_widget_show_all(window);
gtk_plot_canvas_paint(GTK_PLOT_CANVAS(canvas));
gtk_plot_canvas_refresh(GTK_PLOT_CANVAS(canvas));
gtk_plot_clip_data(GTK_PLOT(plot), TRUE);
firstRun = true;
xDisplacement = 0;
g_timeout_add(10, update, NULL);
gtk_main();
return 0;
}
Regards,
Nickolai
On 2/27/06, Fabio da Silva <[email protected]> wrote:
>
> Nickolai,
>
> I understand your concerns and yes, it is no fun to run out of RAM when
> you are doing dynamic allocation. In fact, the first time it happened to
> me was when I left testrealtime.c from GTKExtra running for one full
> day. You can still do a dynamically allocated scheme where you specify
> your maximum amount of memory to be allocated. One you reach that limit
> you dump the results in a file that you can access later (granted that
> hard disks are also a limited memory pool and you should limit the
> amount of files you want to create.) If you are running an application
> with real-time characteristics you may think about creating a thread to
> save the data and not overload the CPU with hard disk access overhead.
>
> Take care,
>
> Fabio
>
> On Mon, 2006-02-27 at 15:26 -0600, Nickolai Dobrynin wrote:
> > Fabio,
> >
> > Thanks for your response.
> >
> > On 2/27/06, Fabio da Silva <[email protected]> wrote:
> > Hi there,
> >
> > I agree with Al. allocating points dynamically is not that
> > painful or
> > computer intensive.
> >
> > The cost of allocating points dynamically is not what I'm worried
> > about at all.
> > My problem is far more basic and newbie-like. Assume you allocate
> > your
> > data point array dynamically and assume your program runs for days and
> > days uninterrupted. Would you be OK about your system running out of
> > memory because you keep allocating memory on and on and on, to store
> > all the data points you receive at runtime, even though you only need
> > to
> > plot each once and discard? Is there no way to keep the memory usage
> > bounded?
> >
> >
> > However if you absolutely don't want to change the
> > size of your array dynamically and are plotting points that
> > are
> > connected somehow, you will have to fill up the memory area
> > that is not
> > used with the x-y values of the latest measurement point. This
> > is to
> > avoid the annoyance of seeing the connecting line go to some
> > random
> > place in the screen after the last point is measured. Now,
> > realize that
> > this means you will have to access the memory to write your
> > points N*N
> > times for every cycle. N is the number of points you are
> > statically
> > allocating. Soon enough you will find out that this solution
> > will bog
> > your application down quite a bit.
> >
> > This sounds true, but, once again, this is not the level I am at right
> > now.
> > I am asking about something that, no doubt, was done by every single
> > programmer who wants to plot things in real time and is not OK about
> > the
> > operating system running out of memory because his data set grows
> > indefinitely in size.
> >
> >
> >
> > Best regards,
> >
> > Nickolai
>
>