Debugging and Devtools

There is a set of debugging- and developer tools that can facilitate the programming of frontend elements in q100viz/ To begin with, there is a bunch of startup flags and key input events can be used to switch modes and change the slider values.

Verbose Mode

There is a verbose mode, that will display additional information right on the interface, and print more information to the console. The verbose mode can be activated using the startup flag -v or toggled by pressing v. Its status is stored in the session.VERBOSE_MODE bool. In verbose mode, buildings will be colored according to their heat consumption, not by their connections status. You’ll see the slider values displayed next to the slider and an ‘x’ indicating the position where the physical slider should be (if not, it is not positioned properly). When verbose mode is on, API messages sent to the infoscreen will be printed to the console.


  • print_verbose: if this function is used to print information to the console, the information will be written to the log, too.

  • mark_random_buildings_for_simulation takes the global list of buildings and selects N random buildings to force-connect them to the heat grid, set a date for refurbishment or enable energy saving options. This function can be enabled using the --select_random startup flag. It will then be called shortly before the simulation is run.

  • mark_buildings_for_simulation: like above, but options can be set for specific buildings, chosen by their ID

  • print_full_df: prints a full pandas DataFrame, not only its head and tail (pandas default)


session.log is a string that logs some Runtime Errors and API messages. When the frontend application terminates, the log file is written to the frontend folder.


The log file will only be written, if the program is closed properly (e.g. Alt+F4, do not close the application using Ctrl+C KeyboardInterrupt.)

Interactive Programming

In the q100viz/sandbox folder there are some files for testing specific parts of the code, and scripts to pre-calculate data (to compare them with the simulation results, for example). For interactive programming we used some Jupyter Notebook Scripts and load the q100viz.session so the Buildings data can be processed without the pygame running in the loop.

In q100viz/sandbox/simulation_demox.ipynb, a batch of simulations is conducted, without loading the pygame frontend:

# --------------- import q100viz libraries we want to use: ----------
path_to_frontend = '..'
print('current working directory:', os.getcwd()) # shall be q100viz root folder
import q100viz.session as session
import q100viz.devtools as devtools
import as graphs

# ------------------------- prepare buildings: ----------------------
session.buildings.df['selected'] = False
session.buildings.df['group'] = -1

# ------------------------- prepare simulation: ---------------------
devtools.mark_random_buildings_for_simulation(session.buildings.df, 4, connection_to_heat_grid=random.randint(2020,2040), refurbished=True)

# ------------------------- start simple simulation: ----------------

# ------------------------- test batch-simulation: ------------------
session.VERBOSE_MODE = True

# 1. 2 specific + 2 random buildings, no decisions
devtools.mark_buildings_for_simulation(session.buildings.df, ['5.11', '6.06'])
            session.buildings.df, 2)

# 2. same buildings, connection=2022
            session.buildings.df[session.buildings.df['selected'] == True], 4, connection_to_heat_grid=2021)

# 2. same buildings, connection=2022 + refurbished
            session.buildings.df[session.buildings.df['selected'] == True], 4, connection_to_heat_grid=2021, refurbished=True)

# 2. same buildings, connection=2022 + save_energy
session.buildings.df['refurbished'] = False  # reset refurbishment

            session.buildings.df[session.buildings.df['selected'] == True], 4, connection_to_heat_grid=2021, save_energy=True)


The projector is positioned above the table and will cast a distorted image onto the physical table. Thus, some calibration has to be done for the projection to match the table dimensions. The process used for this is called “keystone transformation”, meaning that the image is being remapped between four corner points with adjustable position.

Frontend Calibration

  1. The calibration mode can be entered using the c key.

  2. Four corner points are shown as white rectangles, one of which is filled white and , by that, marked active.

  3. The active corner point can be moved using the arrow keys. Make sure these rectangles are positioned at the edges of the physical table, and that the line connecting these points does not leave the table extents.

  4. The active corner point can be selected using one of the keys 1, 2, 3, 4.

  5. The magnitude of moving the corner points can be toggled pressing SPACEBAR. The lines connecting the corner points will be blue for big steps and red for small steps.

  6. Eventually, the settings can be saved to pressing s. This stores a file to the frontend folder that will automatically be loaded next time upon startup.


Combining the calibration view with the grid view (g) can be helpful to also check, if the physical grid is placed properly.


Make sure the backend is calibrated properly, too!

keystone transformation

Transformation Example

adding a new surface, draw on it and transform it:

class SomeClass:
  # session.canvas_size = 1920, 1080
  self.surface = keystone.Surface(session.canvas_size, pygame.SRCALPHA)

  # x_size, y_size = 22, 22
  self.surface.src_points = [[0, 0], [0, y_size], [x_size, y_size], [x_size, 0]]
  self.surface.dst_points = [
      [config['X1'], config['Y1']],
      [config['X1'], config['Y2']],
      [config['X2'], config['Y2']],
      [config['X2'], config['Y1']]]
  # where e.g. X1 = 0, X2 = 50, Y1 = 0, Y2 = 81.818 (%)

  def draw(self, viewport):

    pygame.draw.polygon(self.surface, pygame.Color(255, 255, 255), [[20, 70], [20, 20], [80, 20], [80, 70]])  # render polygon

    viewport.blit(self.surface, (0,0))  # cast it to viewport

slider transformation

  • slider uses the transformation of the grid

  • drawing of polygons and values should be done via self.surface.blit(...). Slider surface is rendered and “blitted” to main canvas.

print(slider.coords_transformed) returns:

[[860.9641723632812, 915.1583862304688],
[863.9833984375, 614.8511352539062],
[1228.917724609375, 622.6510009765625],
[1226.5196533203125, 923.7374267578125]]

with [[bottom-left[x], bottom-left[y]], [upper-left[x], upper-left[y]], [upper-right[x], upper-right[y]], [bottom-right[x], bottom-right[y]]]