RendererConfig calculates orientation based on nrows or ncols.

- Ensure either nrows or ncols is set.
- If neither, set ncols=1 (single column).
- Remove rows_first flag.

Add test_renderer.py
pull/357/head
nyanpasu64 2018-07-15 23:38:57 -07:00
rodzic 8b71df0bbb
commit 2ad624be03
3 zmienionych plików z 71 dodań i 14 usunięć

Wyświetl plik

@ -50,7 +50,6 @@ def main(wave_dir: str, master_wave: Optional[str], fps: int):
), ),
render=RendererConfig( # todo render=RendererConfig( # todo
1280, 720, 1280, 720,
rows_first=False,
ncols=1 ncols=1
) )
) )

Wyświetl plik

@ -1,6 +1,7 @@
from typing import NamedTuple, Optional, List, Tuple from typing import NamedTuple, Optional, List, Tuple
import numpy as np import numpy as np
from dataclasses import dataclass
from matplotlib import pyplot as plt from matplotlib import pyplot as plt
from matplotlib.axes import Axes from matplotlib.axes import Axes
from matplotlib.figure import Figure from matplotlib.figure import Figure
@ -9,21 +10,29 @@ from matplotlib.lines import Line2D
from ovgenpy.util import ceildiv from ovgenpy.util import ceildiv
class RendererConfig(NamedTuple): @dataclass
class RendererConfig:
width: int width: int
height: int height: int
rows_first: bool nrows: Optional[int] = None
nrows: Optional[int] = None # TODO set to 1
ncols: Optional[int] = None ncols: Optional[int] = None
# TODO backend: FigureCanvasBase = FigureCanvasAgg def __post_init__(self):
if not self.nrows:
self.nrows = None
if not self.ncols:
self.ncols = None
if self.nrows and self.ncols:
raise ValueError('cannot manually assign both nrows and ncols')
if not self.nrows and not self.ncols:
self.ncols = 1
class MatplotlibRenderer: class MatplotlibRenderer:
""" """
TODO disable antialiasing
If __init__ reads cfg, cfg cannot be hotswapped. If __init__ reads cfg, cfg cannot be hotswapped.
Reasons to hotswap cfg: RendererCfg: Reasons to hotswap cfg: RendererCfg:
@ -48,6 +57,8 @@ class MatplotlibRenderer:
self.fig: Figure = None self.fig: Figure = None
# Setup layout # Setup layout
# "ncols=1" is good for vertical layouts.
# But "nrows=X" is good for left-to-right grids.
self.nrows = 0 self.nrows = 0
self.ncols = 0 self.ncols = 0
@ -60,13 +71,14 @@ class MatplotlibRenderer:
def set_layout(self) -> None: def set_layout(self) -> None:
""" """
Inputs: self.cfg, self.waves, self.fig
Outputs: self.nrows, self.ncols, self.axes
Creates a flat array of Matplotlib Axes, with the new layout. Creates a flat array of Matplotlib Axes, with the new layout.
Opens a window showing the Figure (and Axes).
Inputs: self.cfg, self.fig
Outputs: self.nrows, self.ncols, self.axes
""" """
self.nrows, self.ncols = self.calc_layout() self.nrows, self.ncols = self._calc_layout()
# Create Axes # Create Axes
# https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplots.html # https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplots.html
@ -86,7 +98,7 @@ class MatplotlibRenderer:
ax.set_axis_off() ax.set_axis_off()
# if column major: # if column major:
if not self.cfg.rows_first: if self.cfg.ncols:
axes2d = axes2d.T axes2d = axes2d.T
self.axes: List[Axes] = axes2d.flatten().tolist()[:self.nplots] self.axes: List[Axes] = axes2d.flatten().tolist()[:self.nplots]
@ -99,14 +111,14 @@ class MatplotlibRenderer:
) )
plt.show(block=False) plt.show(block=False)
def calc_layout(self) -> Tuple[int, int]: def _calc_layout(self) -> Tuple[int, int]:
""" """
Inputs: self.cfg, self.waves Inputs: self.cfg, self.waves
:return: (nrows, ncols) :return: (nrows, ncols)
""" """
cfg = self.cfg cfg = self.cfg
if cfg.rows_first: if cfg.nrows:
nrows = cfg.nrows nrows = cfg.nrows
if nrows is None: if nrows is None:
raise ValueError('invalid cfg: rows_first is True and nrows is None') raise ValueError('invalid cfg: rows_first is True and nrows is None')

Wyświetl plik

@ -0,0 +1,46 @@
from unittest.mock import patch
import pytest
from matplotlib import pyplot as plt
from ovgenpy.renderer import RendererConfig, MatplotlibRenderer
WIDTH = 640
HEIGHT = 360
def test_config():
with pytest.raises(ValueError):
RendererConfig(WIDTH, HEIGHT, nrows=1, ncols=1)
one_col = RendererConfig(WIDTH, HEIGHT, ncols=1)
assert one_col
one_row = RendererConfig(WIDTH, HEIGHT, nrows=1)
assert one_row
default = RendererConfig(WIDTH, HEIGHT)
assert default.ncols == 1 # Should default to single-column layout
assert default.nrows is None
@patch("ovgenpy.renderer.plt.show")
def test_renderer(mock_show):
"""
TODO check image output using:
https://matplotlib.org/devel/testing.html#writing-an-image-comparison-test
https://stackoverflow.com/a/27950953
"[I]mage comparison tests end up bring more trouble than they are worth"
"""
# monkeypatch.setattr(plt, 'show', lambda *args, **kwargs: None)
# 2 columns
cfg = RendererConfig(WIDTH, HEIGHT, ncols=2)
nplots = 16
r = MatplotlibRenderer(cfg, nplots)
# 2 columns, 8 rows
assert r.ncols == 2
assert r.nrows == 8