I have a Van der Waal's gas simulation where we are showing real time collisions between gas molecules. I am doing that using Pygame and it works fine. However, I want one half of the Pygame window to show the real time collisions while the other half plots a dynamic histogram for every time step. Till now, I haven't come across any such code which allows plotting in the same Pygame window where some other simulation is going on.
-
I have a code which can plot it separately. I frankly couldn't figure out a way to plot it in the same window. @blckbirdDiptanil Roy– Diptanil Roy2016-11-30 21:08:45 +00:00Commented Nov 30, 2016 at 21:08
-
Are you explicitely asking about matplotlib here? Matplotlib has several backends, to PyQt/PySide or Tkinter. So once you find a way to include your pygame into one of them, it's easy. I'm not sure however, if integration is possible. There are some questions about it, here or here. At the end, it might just be easier to build the histogram from scratch in pygame (this is only a few bars next to each other).ImportanceOfBeingErnest– ImportanceOfBeingErnest2016-11-30 21:34:02 +00:00Commented Nov 30, 2016 at 21:34
-
@ImportanceOfBeingErnest Thanks, that would help. This is what we are employing now.Diptanil Roy– Diptanil Roy2016-12-01 05:39:09 +00:00Commented Dec 1, 2016 at 5:39
-
for Pygame it aways one window so there is no difference if you draw only simulation or simulation with histogram - you have to do it in one mainloop.furas– furas2016-12-01 11:13:46 +00:00Commented Dec 1, 2016 at 11:13
1 Answer
Using custom ipywidget to display incremental simulation image display
I have been using jupyter technology for all my needs to displaying results from simulations, and I have had reasonable succeesses. Here is what I would do in your case.
I am not an expert at the capabilities of pygame. Looks like in each loop, you are running a simulation step, get the simulation state, and feed it to the pygame scene building to update and render the state for that step (loop).
Assume that, MyPyGameRenderer is your python class object whose MyPyGameRenderer.produce_rendering( simul_state=None) is the one that cause the rendering. I would alter this routine as follows
class MyPyGameRenderer(object)
def produce_rendering_as_a_png_img(self, simul_state=None):
myRenderPngByteData=None
#using pygame, interpret the simulation state and produce rendering
#as a png image byte data and set it to myRenderPngByteData
return myRenderPngByteData
I would install jupyter, make a notebook with python2.7 kernel, and put the above code, and the code for simulation there, and show my png image produced.
If what I said above is what you are doing and your objective is to arrange GUI elements, (in your case it is displaying two windows side by side), I would be tempted to use ipywidgets. ipywidgets enable you in some rudimentary way to assemble GUI elements. The GUI composition capabilities of ipywidgets are cruder than a sophisticated javascript renderings of GUI elements that you see in a webpage, but in my experience they are sufficient for demonstrating scientific results. Here are the steps that I would do.
In achieving what you are saying, for each simulation step, I would still use pygame to do the scene compositing and rendering.
I would construct a custom ipywidget called MyCustomIncrementalImageWidget with a value element which is supposed to hold a png as a dataurl image to display. The rendering routine of the custom ipywidget, just displays the png image which is set as a dataurl. I can display any random png image in my MyCustomIncrementalImageWidget as follows
import base64
#read a random png image and set its byte-data here
my_random_png_img_byte_data = None
myImage = MyCustomIncrementalImageWidget()
dataurl = "data:image/png;base64" + base64.b64encode(my_random_png_img_byte_data
myImage.value = dataurl
display(myImage)
Now the above code will show your png image in the ipywidget framework. You can have the following advantages.
You can compose this myImage with other extensive GUI elements available from ipywidget framework and construct more complex GUI here. In your case, I would have two instances of
MyCustomIncrementalImageWidget-es one for holding the rendering of the scene and the other for holding the histogram. You can compose these two custom ipywidet-s usingwidget.HBox, which should render them horizontally side by side.You need only one call for the display of your GUI elements. And this can be outside your simulation loop. In short, the GUI display is detached from your simulation code, All you need to do in your simulation step is to update the
valueelement of each of the two custom widgets in your simulation step.
Putting it together, here is my high level code.
import b64encode
from ipywidgets import widgets
class MyCustomIncrementalImageWidget(widgets.DOMWidget):
#your implementation of custom ipywidget
pass
def get_dataurl_from_imagedata(img_png_byte_data=None):
dataurl = "data:image/png;base64" + base64.b64encode(img_png_byte_data)
return dataurl
class MyPyGameRenderer(object)
def produce_rendering_as_a_png_img(self, simul_state=None):
myRenderPngByteData=None
#using pygame, interpret the simulation state and produce rendering
#as a png image and set the byte-data to myRenderPngByteData
return myRenderPngByteData
def produce_histogram_as_a_png_img(self, simul_state=None):
myHistPngByteData=None
#interpret the simulation data and produce the histigram as a png image
# set the image byte-data to myHistPngByteData
return myHistPngByteData
def update(self, simul_state=None):
r=self.produce_rendering_as_a_png_img(simul_state=simul_state)
h=self.produce_histogram_as_a_png_img(simul_state=simul_state)
return r, h
my_renderer=MyPyGameRenderer()
my_collision_render_widget=MyCustomIncrementalImageWidget()
my_histogram_widget=MyCustomIncrementalImageWidget()
top_level_hbox=widgets.HBox(children=tuple([my_collision_render_widget,
my_histogram_widget]))
My simulation code will be as follows
whle(True):
simul_state=None
#do your simulation and get simulation state and set it to simul_state
r, h= my_pygame_renderer.update(simul_state=simul_state)
my_collision_render_widget.value = get_dataurl_from_imagedata(r)
my_histogram_widget.value=get_daturl_from_imagedata(h)
And wherever I want to display this widget combination, I would do.
from IPython import display
display(top_level_hbox)
Please take a look at my custom ipywidget implementation here. My class is called ProgressImageWidget.