Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically updating a plot in Haskell

Tags:

plot

haskell

I have a program which performs a long-going calculation where the result is shown as a plot. I am currently using Chart-0.14 for this. I want to show the partial results, and update during calculations. Graphics.Rendering.Chart.Gtk.updateCanvas :: Renderable a -> DrawingArea -> IO Bool seems to do that, but I do not find any way to get a DrawingArea from the plot. The function renderableToWindow :: Renderable a -> Int -> Int -> IO () does not return anything (and furthermore it does not return before the window is closed).

I would like to do something like the following:

main = do
drawingArea = forkRenderableToWindow (toRenderable $ plotLayout $
                     plot [0,0.1..10] sin "sin(x)") 640 480
updateCanvas  (toRenderable $ plotLayout $  plot [0,0.1..10] sin "sin(x)") drawingArea

How should I do this? Would I need to reimplement the functions in Graphics.Rendering.Chart.Gtk with a version that returns the DrawingArea and in some way (how would I do this? forkIO?) returns immediately without closing the window?

like image 586
Hjulle Avatar asked Nov 04 '22 13:11

Hjulle


1 Answers

You are looking for createRenderableWindow and then you need to use the GTK operations to work on the given Window - I don't think the Chart package exports any higher level operations on Windows.

EDIT2: So ignore the below - it doesn't work even with GUI initilization. My comment was a guess based on types. EDIT: Here is some example code. Understand, I'm just piecing things together based on the types. There might be better ways to do things if you ask someone who actually knows the library.

Below we use:

  1. createRenderableWindow - this was the crux of my answer
  2. castToDrawingArea - This is needed to get a DrawingArea from the Window type provided by GTK. These casts are taking place of C++ OO inheritance, I think.
  3. widgetShowAll - because we haven't actually displayed the window, we best do that. I stole this function after looking at the source for renderableToWindow.
  4. updateCanvas - I just saw this in the haddock documentation and figured it is why you wanted a DrawingArea in the first place.

Now for the code:

import Graphics.Rendering.Chart.Gtk
import Graphics.Rendering.Chart.Renderable
import Graphics.UI.Gtk.Misc.DrawingArea
import qualified Graphics.UI.Gtk as G

main = do
        win  <- createRenderableWindow emptyRenderable 400 400
        let draw = castToDrawingArea win
        G.widgetShowAll win
        updateCanvas emptyRenderable draw
like image 192
Thomas M. DuBuisson Avatar answered Nov 09 '22 07:11

Thomas M. DuBuisson