10

I was following this tutorial on how to write a chess program in Python.

It uses the python-chess engine. The functions from that engine apparently return SVG data, that could be used to display a chessboard.

  • Code from the tutorial:
import chess
import chess.svg

from IPython.display import SVG

board = chess.Board()
SVG(chess.svg.board(board=board,size=400))  

but when I run that code, all I see is a line in the terminal and no image.

<IPython.core.display.SVG object>

The tutorial makes a passing reference to Jupyter Notebooks and how they can be used to display SVG images. I have no experience with Jupyter Notebooks and even though I installed the package from pip and I dabbled a little into how to use it, I couldn't make much progress with regards to my original chessboard problem. But what I do have, is, experience with Qt development using C++ and since Qt has Python bindings, I decided to use those bindings.

Here is what I wrote:

import sys
import chess
import chess.svg
from PyQt5 import QtGui, QtSvg
from PyQt5.QtWidgets import QApplication
from IPython.display import SVG, display

app = QApplication(sys.argv);

board = chess.Board(); 
svgWidget = QtSvg.QSvgWidget(chess.svg.board(board=board, size=400));
#svgWidget.setGeometry(50,50,759,668)
svgWidget.show()

sys.exit(app.exec_())

A Qt window opens and shows nothing and in the terminal I see a lot of text - (apparently the SVG data is ending up in the console and not in the Qt window that is opening?).

I figured I have to install some SVG library under python so I installed drawSvg from pip. But it seems that library generates SVG images. And was of no use for me.

What is even more strange is, after seeing this SO question, I tried the following:

import sys
import chess
import chess.svg
from PyQt5 import QtGui, QtSvg
from PyQt5.QtWidgets import QApplication
from IPython.display import SVG, display

app = QApplication(sys.argv);

board = chess.Board(); 
svgWidget = QtSvg.QSvgWidget('d:\projects\python_chess\Zeichen_123.svg');
#svgWidget.setGeometry(50,50,759,668)
svgWidget.show()

sys.exit(app.exec_())

And it showed an image - an SVG image! What is the difference then between my case and this case?

Question: So my question is, what I am doing wrong in the case of the chessboard SVG data? Is the SVG data generated by the python-chess library not compatible with QtSvg?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Duck Dodgers
  • 3,409
  • 8
  • 29
  • 43

2 Answers2

8

I think you are getting confused by the scripting nature of Python. You say, you have experience with Qt development under C++. Wouldn't you create a main window widget there first and add to it your SVG widget within which you would call or load SVG data?

I would rewrite your code something like this.

import chess
import chess.svg

from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtWidgets import QApplication, QWidget


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setGeometry(100, 100, 1100, 1100)

        self.widgetSvg = QSvgWidget(parent=self)
        self.widgetSvg.setGeometry(10, 10, 1080, 1080)

        self.chessboard = chess.Board()

        self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
        self.widgetSvg.load(self.chessboardSvg)

if __name__ == "__main__":
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec()

EDIT

It would be even better if you would add a paint function to the MainWindow class. Because for sure in future, you would want to repaint your board image many times, whenever you would move a piece. So I would do something like this.

     def paintEvent(self, event):
         self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
         self.widgetSvg.load(self.chessboardSvg) 
  • Thanks for the quick reply. Ok. I understand about creating a main parent widget. But this seems still not to work for some reason. – Duck Dodgers Apr 26 '20 at 11:27
  • Ok, I edited my answer now. Try again with the encoding now also specified. – SmartKittie Apr 26 '20 at 11:32
  • Yes this fixes my problem. I can see the chessboard now. I am only confused by one point now. How could I display the SVG image "Zeichen_123.svg" but not the chessboard? – Duck Dodgers Apr 26 '20 at 11:41
  • Something of a late reply, but the issue is that the `QSvgWidget` constructor expects a filename, so when you give it the path to `Zeichen_123.svg` it will display that. The return value of `chess.svg.board` is instead the actual SVG code (i.e. what would be the file content), so `QSvgWidget` doesn't know what to do with it. On the other hand, the `load` method expects to receive SVG data, not a filename, so that works. (This is in fact somewhat orthogonal to the issue of using or not using a "main window"; you don't need the `MainWindow` class to make the chess SVG display.) – Ed Bennett Feb 21 '22 at 00:42
0

this is how i display SVG image with python, no need third party to do that.

First i save SVG image on disk second i just call it like os.Startfile("exemple.svg")

Exemple:

boardsvg = svg.board(board(fen), size=600, coordinates=True)
   with open('temp.svg', 'w') as outputfile:
     outputfile.write(boardsvg)
   time.sleep(0.1)
   os.startfile('temp.svg')

that's it !

  • But, this does not display an SVG with Python - this displays an SVG with whatever application happens to be associated with the .svg file extension on each particular system, which makes the behavior of the program highly non-deterministic AND even more so reliant on third-party software: on one computer it may open in a browser, on another in a vector editor, on a third it may not work at all. – Ronald McFüglethorn Apr 15 '23 at 12:18