10

I have a big question here - one that I imagine the majority of people will not like and I will probably be flamed for being a noob but here goes anyway.

I am trying to use matplotlib to implement a barchart into my pygame program. I managed to do it pretty simply but not using pygame.

I have managed to make a bar chart but I am not able to put it into pygame:

names = ['a', 'b', 'c']
values = [1, 10, 100]
plt.figure(1, figsize=(9, 3))
plt.bar(names, values)
plt.show()

I want to implement this to my game in pygame but I honestly have no idea where to start. It is for a project due next week. Thanks.

4 Answers 4

7

matplotlib as default uses tkinter to display graph. It can also use PyQt or wxPython - they are called "backends" - but it doesn't have methods to use PyGame as backend.

The only what I found (using Google) is example in PyGame wiki

It renders matplotlib graph to bitmap and then converts this bitmap to string which can be used to create Surface with image.

import matplotlib
matplotlib.use("Agg")

import matplotlib.backends.backend_agg as agg


import pylab

fig = pylab.figure(figsize=[4, 4], # Inches
                   dpi=100,        # 100 dots per inch, so the resulting buffer is 400x400 pixels
                   )
ax = fig.gca()
ax.plot([1, 2, 4])

canvas = agg.FigureCanvasAgg(fig)
canvas.draw()
renderer = canvas.get_renderer()
raw_data = renderer.tostring_rgb()

import pygame
from pygame.locals import *

pygame.init()

window = pygame.display.set_mode((600, 400), DOUBLEBUF)
screen = pygame.display.get_surface()

size = canvas.get_width_height()

surf = pygame.image.fromstring(raw_data, size, "RGB")
screen.blit(surf, (0,0))
pygame.display.flip()

crashed = False
while not crashed:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            crashed = True

enter image description here

Fankly I wouldn't use matplotlib to create graph - escpecially it is not interactive. It could be easy to create own graph in PyGame.

Sign up to request clarification or add additional context in comments.

6 Comments

How would you create your own graph in pygame? Thanks for the quick response - I found this too on google but honestly I didn't understand how it worked. Thanks for explaining it.
you can use pygame.draw.rect() to draw bars. PyGame has other methods to draw objects and text. You will have to draw every element separately but you have control and it can be animated or interactive.
see future GUI with PyGame - there are animated bars - youtu.be/_5qFQvuHrXg
code for Future GUI example.
I know this is old but I'll add what I think is an important distinction: Pygame doesn't yet have good anti-aliased drawing capabilities. This makes lines and other shapes look really jagged and generally not as clean as what matplotlib can generate. I am dealing with a similar need for an application. After coding using pygame I decided to look into using matplotlib to render to a buffer and display the graphic through pygame. The smoothness of lines and other shapes produced this way, as far as I know, cannot be matched by pygame. BTW, I am using this for a simulation, not a game.
|
4

You might want to take a look to this library that attempts to create a proper pygame backend for matplotlib. https://pypi.org/project/pygame-matplotlib/

It is under beta developpement for the moment, but looks promising.

Comments

3

The accepted answer doesn't explain how to set the line-color, line-style and some more. So this is what I found and hope it will be useful to some else.

You will need a working python-tk and install pygame and matplotlib with pip. The following code was tested with python3, pygame 2.0.1 and matplotlib 3.3.4 on a Ubuntu 18.04.

Some links on how to customize the code:

Result

import matplotlib
import matplotlib.pyplot as plt
import matplotlib.backends.backend_agg as agg
import pygame
from pygame.locals import *
import pylab

matplotlib.use("Agg")

plt.rcParams.update({
    "lines.marker": "o",         # available ('o', 'v', '^', '<', '>', '8', 's', 'p', '*', 'h', 'H', 'D', 'd', 'P', 'X')
    "lines.linewidth": "1.8",
    "axes.prop_cycle": plt.cycler('color', ['white']),  # line color
    "text.color": "white",       # no text in this example
    "axes.facecolor": "black",   # background of the figure
    "axes.edgecolor": "lightgray",
    "axes.labelcolor": "white",  # no labels in this example
    "axes.grid": "True",
    "grid.linestyle": "--",      # {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
    "xtick.color": "white",
    "ytick.color": "white",
    "grid.color": "lightgray",
    "figure.facecolor": "black", # color surrounding the plot
    "figure.edgecolor": "black",
})

fig = pylab.figure(figsize=[4, 2], # Inches
                   dpi=100)        # 100 dots per inch, so the resulting buffer is 400x200 pixels
fig.patch.set_alpha(0.1)           # make the surrounding of the plot 90% transparent to show what it does

ax = fig.gca()
ax.plot([1, 2, 4])

canvas = agg.FigureCanvasAgg(fig)
canvas.draw()
renderer = canvas.get_renderer()
raw_data = renderer.buffer_rgba()

pygame.init()
window = pygame.display.set_mode((600, 210), DOUBLEBUF)
screen = pygame.display.get_surface()

size = canvas.get_width_height()
surf = pygame.image.frombuffer (raw_data, size, "RGBA")

bg_color = (255, 0, 0)   # fill red as background color
screen.fill(bg_color)
screen.blit(surf, (100, 5)) # x, y position on screen
pygame.display.flip()

stop = False
while not stop:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            stop = True
    pygame.time.Clock().tick(30)  # Avoid 100% CPU usage

2 Comments

This works but is awfully slow at more than 200 points, due to the canvas to buffer transformation. Is there a more straightforward way to load the fig in pygame.image ?
I have invested many hours trying to improve performance without success. Someone with more mathplotlib+pygame knowledge might still improve it. What I want to say, that I was having this problem with my attempts too.
1

I spent all day today trying to extend upon @furas's answer, in order to get rid of that blasted white background. I'll put this here for posterity's sake. Use his answer, but replace these two lines to use the alpha component, so the background is transparent:

raw_data = renderer.buffer_rgba ()
surf     = pygame.image.frombuffer (raw_data, size, "RGBA")

I also tweaked some settings with the figure:

dims = pygame2matplotlib (w, h)
fig  = plt.figure (**dims, facecolor='none', edgecolor='none')
fig.patch.set_visible (False)

2 Comments

From where do you take pygame2matplotlib and plt? Can you please post your full code? As a pygame and matplotlib newbie I have problems getting your additions to compile.
pygame2matplotlib is a one-liner defined here: link plt is an alias for matplotlib's pyplot module. import matplotlib.pyplot as plt

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.