Move layout rows/columns to class LayoutConfig

pull/357/head
nyanpasu64 2018-08-14 06:10:40 -07:00
rodzic 2f4ebece70
commit 21d739cd4f
3 zmienionych plików z 84 dodań i 34 usunięć

Wyświetl plik

@ -5,7 +5,7 @@ from typing import Optional, List
from ovgenpy import outputs from ovgenpy import outputs
from ovgenpy.channel import Channel, ChannelConfig from ovgenpy.channel import Channel, ChannelConfig
from ovgenpy.config import register_config from ovgenpy.config import register_config
from ovgenpy.renderer import MatplotlibRenderer, RendererConfig from ovgenpy.renderer import MatplotlibRenderer, RendererConfig, LayoutConfig
from ovgenpy.triggers import ITriggerConfig, CorrelationTriggerConfig from ovgenpy.triggers import ITriggerConfig, CorrelationTriggerConfig
from ovgenpy.utils import keyword_dataclasses as dc from ovgenpy.utils import keyword_dataclasses as dc
from ovgenpy.utils.keyword_dataclasses import field from ovgenpy.utils.keyword_dataclasses import field
@ -30,6 +30,7 @@ class Config:
trigger: ITriggerConfig # Maybe overriden per Wave trigger: ITriggerConfig # Maybe overriden per Wave
amplification: float amplification: float
layout: LayoutConfig
render: RendererConfig render: RendererConfig
outputs: List[outputs.IOutputConfig] outputs: List[outputs.IOutputConfig]
@ -60,10 +61,8 @@ def default_config(**kwargs):
), ),
amplification=1, amplification=1,
render=RendererConfig( layout=LayoutConfig(ncols=1),
1280, 720, render=RendererConfig(1280, 720),
ncols=1
),
outputs=[ outputs=[
# outputs.FFmpegOutputConfig(output), # outputs.FFmpegOutputConfig(output),
@ -100,7 +99,7 @@ class Ovgen:
nframes = fps * self.waves[0].get_s() nframes = fps * self.waves[0].get_s()
nframes = int(nframes) + 1 nframes = int(nframes) + 1
renderer = MatplotlibRenderer(self.cfg.render, self.nchan) renderer = MatplotlibRenderer(self.cfg.render, self.cfg.layout, self.nchan)
if RENDER_PROFILING: if RENDER_PROFILING:
begin = time.perf_counter() begin = time.perf_counter()

Wyświetl plik

@ -1,4 +1,4 @@
from typing import Optional, List, Tuple, TYPE_CHECKING, TypeVar, Callable from typing import Optional, List, TYPE_CHECKING, TypeVar, Callable
import matplotlib import matplotlib
import numpy as np import numpy as np
@ -22,24 +22,8 @@ class RendererConfig:
width: int width: int
height: int height: int
nrows: Optional[int] = None
ncols: Optional[int] = None
orientation: str = 'h'
create_window: bool = False create_window: bool = False
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:
""" """
@ -64,10 +48,10 @@ class MatplotlibRenderer:
DPI = 96 DPI = 96
def __init__(self, cfg: RendererConfig, nplots: int): def __init__(self, cfg: RendererConfig, lcfg: 'LayoutConfig', nplots: int):
self.cfg = cfg self.cfg = cfg
self.nplots = nplots self.nplots = nplots
self.layout = RendererLayout(cfg, nplots) self.layout = RendererLayout(lcfg, nplots)
# Flat array of nrows*ncols elements, ordered by cfg.rows_first. # Flat array of nrows*ncols elements, ordered by cfg.rows_first.
self.fig: 'Figure' = None self.fig: 'Figure' = None
@ -162,13 +146,33 @@ class MatplotlibRenderer:
return buffer_rgb return buffer_rgb
@register_config
class LayoutConfig:
nrows: Optional[int] = None
ncols: Optional[int] = None
orientation: str = 'h'
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
Region = TypeVar('Region') Region = TypeVar('Region')
RegionFactory = Callable[[int, int], Region] # f(row, column) -> Region RegionFactory = Callable[[int, int], Region] # f(row, column) -> Region
class RendererLayout: class RendererLayout:
VALID_ORIENTATIONS = ['h', 'v'] VALID_ORIENTATIONS = ['h', 'v']
def __init__(self, cfg: 'RendererConfig', nplots: int): def __init__(self, cfg: LayoutConfig, nplots: int):
self.cfg = cfg self.cfg = cfg
self.nplots = nplots self.nplots = nplots

Wyświetl plik

@ -2,25 +2,28 @@ from unittest.mock import patch
import pytest import pytest
from ovgenpy.renderer import RendererConfig, MatplotlibRenderer from ovgenpy.renderer import RendererConfig, MatplotlibRenderer, LayoutConfig, \
RendererLayout
WIDTH = 640 WIDTH = 640
HEIGHT = 360 HEIGHT = 360
def test_config(): def test_config():
with pytest.raises(ValueError): with pytest.raises(ValueError):
RendererConfig(WIDTH, HEIGHT, nrows=1, ncols=1) LayoutConfig(nrows=1, ncols=1)
one_col = RendererConfig(WIDTH, HEIGHT, ncols=1) one_col = LayoutConfig(ncols=1)
assert one_col assert one_col
one_row = RendererConfig(WIDTH, HEIGHT, nrows=1) one_row = LayoutConfig(nrows=1)
assert one_row assert one_row
default = RendererConfig(WIDTH, HEIGHT) default = LayoutConfig()
assert default.ncols == 1 # Should default to single-column layout assert default.ncols == 1 # Should default to single-column layout
assert default.nrows is None assert default.nrows is None
assert default.orientation == 'h'
def test_renderer(): def test_renderer():
@ -33,15 +36,59 @@ def test_renderer():
""" """
# 2 columns # 2 columns
cfg = RendererConfig(WIDTH, HEIGHT, ncols=2) cfg = RendererConfig(WIDTH, HEIGHT)
lcfg = LayoutConfig(ncols=2)
nplots = 15 nplots = 15
r = MatplotlibRenderer(cfg, nplots) r = MatplotlibRenderer(cfg, lcfg, nplots)
# 2 columns, 8 rows # 2 columns, 8 rows
assert r.layout.ncols == 2 assert r.layout.ncols == 2
assert r.layout.nrows == 8 assert r.layout.nrows == 8
@pytest.mark.parametrize('lcfg', [
LayoutConfig(ncols=2),
LayoutConfig(nrows=8),
])
def test_layout(lcfg):
nplots = 15
layout = RendererLayout(lcfg, nplots)
assert layout.ncols == 2
assert layout.nrows == 8
# holy shit, passing tuples into a numpy array breaks things spectacularly, and it's
# painfully difficult to stuff tuples into 1D array.
# http://wesmckinney.com/blog/performance-quirk-making-a-1d-object-ndarray-of-tuples/
regions = layout.arrange(lambda row, col: str((row, col)))
assert len(regions) == nplots
assert regions[0] == '(0, 0)'
assert regions[1] == '(0, 1)'
assert regions[2] == '(1, 0)'
m = nplots - 1
assert regions[m] == str((m // 2, m % 2))
@pytest.mark.parametrize('lcfg', [
LayoutConfig(ncols=3, orientation='v'),
LayoutConfig(nrows=3, orientation='v'),
])
def test_layout(lcfg):
nplots = 7
layout = RendererLayout(lcfg, nplots)
assert layout.ncols == 3
assert layout.nrows == 3
regions = layout.arrange(lambda row, col: str((row, col)))
assert len(regions) == nplots
assert regions[0] == '(0, 0)'
assert regions[2] == '(2, 0)'
assert regions[3] == '(0, 1)'
assert regions[6] == '(0, 2)'
# TODO: test get_frame() # TODO: test get_frame()
# (integration test) ensure rendering to output works # (integration test) ensure rendering to output works