Commit ae48b751 authored by Yori Fournier's avatar Yori Fournier
Browse files

Merge branch '77-add-weighted-grids' into 'dev-tools'

Resolve "FEATURE: Add Vertical/HorizontalWeightedGrid in mytool"

See merge request !58
parents 32a980db 5672808f
Pipeline #484 passed with stage
in 4 minutes and 18 seconds
......@@ -15,6 +15,7 @@ myplotlib_import_local_latex_tkagg:
- ./setup_test_folder.sh -r latex-tkagg
- python import_test.py
- python -m tests
- python -m tutorials
- ./clean_test_folder.sh
myplotlib_test_mytool:
......
......@@ -138,10 +138,8 @@ elif D_HIERARCHY in ('LOCAL', 'local'):
from .myAxes import MyAxes
# MyFig: Overlay on matplotlib.Figure class
from .myFig import MyFig
from .mplGrid import Grid, VerticalGrid, HorizontalGrid
from .myFig import MyFig
from .empty_fig import EmptyFig
from .empty_axes import EmptyAxes
......
......@@ -14,9 +14,13 @@ class Grid(object):
self.height = height
self.items = []
self.fig = None
self.grids = []
def layout(self):
pass
if self.contains_a_grid():
for grid in self.getGrids():
grid.layout()
def appendAxes(self, ax, axlabel, rawdata):
self.items.append(ax)
......@@ -25,6 +29,7 @@ class Grid(object):
def appendGrid(self, grid):
self.items.append(grid)
self.grids.append(grid)
self.items[-1].fig = self.fig
def getItem(self, index):
......@@ -33,6 +38,12 @@ class Grid(object):
def getItems(self):
return(self.items)
def getGrids(self):
return(self.grids)
def contains_a_grid(self):
return(len(self.grids) > 0)
def set_position(self, pos):
left, bottom, width, height = pos
self.left = left
......@@ -43,25 +54,35 @@ class Grid(object):
class VerticalGrid(Grid):
def layout(self):
nbr_axes = len(self.items)
axes_height = (self.height - (nbr_axes-1)*self.padding - 2.*self.margin)/nbr_axes
for index in range(0, nbr_axes):
new_left = self.margin + self.left
new_bottom = self.margin + self.bottom + index*axes_height + index*self.padding
new_width = self.width - 2.*self.margin
new_height = axes_height
new_frame = [new_left, new_bottom, new_width, new_height]
self.items[index].set_position(new_frame)
if nbr_axes > 0:
axes_height = (self.height - (nbr_axes-1)*self.padding - 2.*self.margin)/nbr_axes
for index in range(0, nbr_axes):
new_left = self.margin + self.left
new_bottom = self.margin + self.bottom + index*axes_height + index*self.padding
new_width = self.width - 2.*self.margin
new_height = axes_height
new_frame = [new_left, new_bottom, new_width, new_height]
self.items[index].set_position(new_frame)
Grid.layout(self)
class HorizontalGrid(Grid):
def layout(self):
nbr_axes = len(self.items)
axes_width = (self.width - (nbr_axes-1)*self.padding - 2.*self.margin)/nbr_axes
for index in range(0, nbr_axes):
new_left = self.margin + self.left + index*axes_width + index*self.padding
new_bottom = self.margin + self.bottom
new_width = axes_width
new_height = self.height - 2.*self.margin
new_frame = [new_left, new_bottom, new_width, new_height]
self.items[index].set_position(new_frame)
if nbr_axes > 0:
axes_width = (self.width - (nbr_axes-1)*self.padding - 2.*self.margin)/nbr_axes
for index in range(0, nbr_axes):
new_left = self.margin + self.left + index*axes_width + index*self.padding
new_bottom = self.margin + self.bottom
new_width = axes_width
new_height = self.height - 2.*self.margin
new_frame = [new_left, new_bottom, new_width, new_height]
self.items[index].set_position(new_frame)
Grid.layout(self)
......@@ -74,6 +74,7 @@ from . import DBUG, SEVR, INFO, SPCE, WARN
from . import MyData
from . import MyAxes
from . import Figure
from . import HorizontalGrid
# Class MyFig Overwriting Matplotlib.figure.Figure
......@@ -104,6 +105,9 @@ class MyFig(Figure):
# it ensures that a figure can not be bounded
# to several windows and prevent the loss of canvas.
self.boundedToWin = False
# add a default Grid to the figure
self.setGrid(HorizontalGrid())
# initialise
self._initialize(*args, **kwargs)
......@@ -211,9 +215,13 @@ class MyFig(Figure):
return None
# SET LAYOUT -------------------------------------------------------
def setLayout(self, grid):
self.layout = grid
self.layout.fig = self
def setGrid(self, grid):
self.grid = grid
self.grid.fig = self
# LAYOUT -----------------------------------------------------------
def layout(self):
self.grid.layout()
# SET RAW DATA -----------------------------------------------------
def set_rawdata(self, rawdata):
......
......@@ -16,4 +16,9 @@ from .figOneAxes import FigOneAxes
from .formatter import FormatterListToLine
from .formatter import FormatterArrayToLines
from .formatter import FormatterAppendToLines
from .mplWeightedGrid import WeightedGrid
from .mplWeightedGrid import VerticalWeightedGrid
from .mplWeightedGrid import HorizontalWeightedGrid
from .ax2dPlots import Ax2dPlots
from itertools import repeat
class Formatter(object):
def __init__(self):
......@@ -69,7 +71,7 @@ class FormatterAppendToLines(Formatter):
iindex = 1
else:
iindex = 0
labels = None
labels = []
for item in rawdata.data[iindex]:
ydatas.append([item])
......@@ -81,11 +83,13 @@ class FormatterAppendToLines(Formatter):
if self.xdataIndex is not None:
xdata = ydatas.pop(self.xdataIndex)
if labels is not None:
if labels != []:
if self.xlabel is None:
self.xlabel = labels.pop(self.xdataIndex)
else:
labels.pop(self.xdataIndex)
else:
labels = repeat(None)
else:
xdata = range(0, len(ydatas[0])) # generic xdata
......
_D_MARGIN = 0.05
_D_PADDING = 0.05
_D_POS = [0.0, 0.0, 1.0, 1.0]
from myplotlib import Grid
from myplotlib import WARN, INFO, SEVR, SPCE
class WeightedGrid(Grid):
def __init__(self, pos=_D_POS, margin=_D_MARGIN, padding=_D_PADDING, weights=None):
Grid.__init__(self, pos=pos, margin=margin, padding=padding)
# This has to be done that way because putting "weights=[]" as optional argument in the constructor
# would results into a global variable. Indeed "weights=[]" means create an array while importing.
# and since it is an array its pointer will be transmitted to "self.weights". So for any WeightedGrid
# and also for all its childs, the value self.weights will point toward the same object.
# Therefore we initialise "self.weights" within the constructor.
if weights is None:
self.weights = []
else:
self.weights = weights
def appendAxes(self, ax, axlabel, rawdata, weight=None, weights=None):
Grid.appendAxes(self, ax, axlabel, rawdata)
if weights is not None:
self.weights = weights
else:
if weight is not None:
self.weights.append(weight)
else:
self.weights.append(1.)
def appendGrid(self, grid, weight=None, weights=None):
Grid.appendGrid(self, grid)
if weights is not None:
self.weights = weights
else:
if weight is not None:
self.weights.append(weight)
else:
self.weights.append(1.)
def getItemWeight(self, index):
return(self.weights[index])
def getWeights(self):
return(self.weights)
class VerticalWeightedGrid(WeightedGrid):
def layout(self):
nbr_axes = len(self.items)
sum_of_weights = sum(self.weights)
if sum_of_weights > 1.:
print(WARN + "The weights you have given are larger than 100% your axes will overcross the Figure's borders")
height_avail_for_axes = self.height - (nbr_axes-1)*self.padding - 2.*self.margin
current_height = 0.0
for index in range(0, nbr_axes):
axes_height = self.weights[index] * height_avail_for_axes
new_left = self.margin + self.left
new_bottom = self.margin + self.bottom + current_height + index*self.padding
new_width = self.width - 2.*self.margin
new_height = axes_height
new_frame = [new_left, new_bottom, new_width, new_height]
self.items[index].set_position(new_frame)
current_height = current_height + axes_height
WeightedGrid.layout(self)
class HorizontalWeightedGrid(WeightedGrid):
def layout(self):
nbr_axes = len(self.items)
sum_of_weights = sum(self.weights)
if sum_of_weights > 1.:
print(WARN + "The weights you have given are larger than 100% your axes will overcross the Figure's borders")
width_avail_for_axes = self.width - (nbr_axes-1)*self.padding - 2.*self.margin
current_width = 0.0
for index in range(0, nbr_axes):
axes_width = self.weights[index] * width_avail_for_axes
new_left = self.margin + self.left + current_width + index*self.padding
new_bottom = self.margin + self.bottom
new_width = axes_width
new_height = self.height - 2.*self.margin
new_frame = [new_left, new_bottom, new_width, new_height]
self.items[index].set_position(new_frame)
current_width = current_width + axes_width
WeightedGrid.layout(self)
......@@ -3,3 +3,5 @@ import unittest
from test_formatter import FormatterListToLineTestCase
from test_formatter import FormatterArrayToLinesTestCase
from test_formatter import FormatterAppendToLinesTestCase
from test_weighted_grid import WeightedGridTestCase
......@@ -16,6 +16,10 @@ states.update({'FormatterArrayToLines': unittest.TextTestRunner(verbosity=verbos
suite_append_to_lines = unittest.TestLoader().loadTestsFromTestCase(FormatterAppendToLinesTestCase)
states.update({'FormatterAppendToLines': unittest.TextTestRunner(verbosity=verbose).run(suite_append_to_lines).wasSuccessful()})
# Weighted Grid
suite_weighted_grid = unittest.TestLoader().loadTestsFromTestCase(WeightedGridTestCase)
states.update({'WeightedGrid': unittest.TextTestRunner(verbosity=verbose).run(suite_weighted_grid).wasSuccessful()})
for success in states.items():
if not success[1]:
failed.append(success[0])
......
#!/usr/bin/env python
import os, sys
import unittest
sys.path.append('../../')
from myplotlib import MyData
from myplotlib.mytool import FormatterListToLine, FormatterArrayToLines, FormatterAppendToLines
class FormatterListToLineTestCase(unittest.TestCase):
def setUp(self):
self.data_line = MyData(data=[0., 1., 2., 3., 4., 5.,],
name='data_line')
def test_formatter_list_to_line(self):
formatter = FormatterListToLine()
data = formatter.shape(self.data_line)
self.assertIsNone(formatter.xlabel)
self.assertIsNone(formatter.ylabel)
correctdata = {'ydatas': [[0., 1., 2., 3., 4., 5.,]],
'xdata': [0., 1., 2., 3., 4., 5.,],
'xlabel': None,
'ylabel': None,
'name': 'data_line'}
self.assertEqual(data, correctdata)
def test_formatter_list_to_line_with_kw(self):
formatter = FormatterListToLine(xlabel=r'x-axis', ylabel=r'y-axis')
data = formatter.shape(self.data_line)
self.assertEqual(formatter.xlabel, r'x-axis')
self.assertEqual(formatter.ylabel, r'y-axis')
correctdata = {'ydatas': [[0., 1., 2., 3., 4., 5.]],
'xdata': [0., 1., 2., 3., 4., 5.],
'xlabel': r'x-axis',
'ylabel': r'y-axis',
'name': 'data_line'}
self.assertEqual(data, correctdata)
class FormatterArrayToLinesTestCase(unittest.TestCase):
def setUp(self):
self.data_lines = MyData(data=[[0., 1., 2., 3., 4., 5.],
[0., 2., 4., 6., 8., 10.],
[0., 3., 6., 9., 12., 15.]],
name='data_lines')
def test_formatter_array_to_lines(self):
formatter = FormatterArrayToLines()
data = formatter.shape(self.data_lines)
self.assertIsNone(formatter.xlabel)
self.assertIsNone(formatter.ylabel)
self.assertIsNone(formatter.xdataIndex)
correctdata = {'ydatas': [[0., 1., 2., 3., 4., 5.],
[0., 2., 4., 6., 8., 10.],
[0., 3., 6., 9., 12., 15.]],
'xdata': [0., 1., 2., 3., 4., 5.],
'xlabel': None,
'ylabel': None,
'name': 'data_lines'}
self.assertEqual(data, correctdata)
def test_formatter_array_to_lines_with_kw(self):
formatter = FormatterArrayToLines(xlabel=r'x-axis', ylabel=r'y-axis', xdataIndex=1)
data = formatter.shape(self.data_lines)
self.assertEqual(formatter.xlabel, r'x-axis')
self.assertEqual(formatter.ylabel, r'y-axis')
self.assertEqual(formatter.xdataIndex, 1)
correctdata = {'ydatas': [[0., 1., 2., 3., 4., 5.],
[0., 3., 6., 9., 12., 15.]],
'xdata': [0., 2., 4., 6., 8., 10.],
'xlabel': r'x-axis',
'ylabel': r'y-axis',
'name': 'data_lines'}
self.assertEqual(data, correctdata)
class FormatterAppendToLinesTestCase(unittest.TestCase):
def setUp(self):
self.data_cols = MyData(data=[[0., 0., 0.],
[1., 2., 3.],
[2., 4., 6.],
[3., 6., 9.],
[4., 8., 12.],
[5., 10., 15.]],
name='data_cols')
self.data_labeled_cols = MyData(data=[['y0', 'y1', 'y2'],
[0., 0., 0.],
[1., 2., 3.],
[2., 4., 6.],
[3., 6., 9.],
[4., 8., 12.],
[5., 10., 15.]],
name='data_labeled_cols')
def test_formatter_append_to_lines(self):
formatter = FormatterAppendToLines()
data = formatter.shape(self.data_cols)
self.assertIsNone(formatter.xlabel)
self.assertIsNone(formatter.ylabel)
self.assertIsNone(formatter.xdataIndex)
correctdata = {'ydatas': [[0., 1., 2., 3., 4., 5.,],
[0., 2., 4., 6., 8., 10.],
[0., 3., 6., 9., 12., 15.]],
'xdata': [0., 1., 2., 3., 4., 5.],
'xlabel': None,
'ylabel': None,
'labels': [],
'name': 'data_cols'}
self.assertEqual(data, correctdata)
def test_formatter_append_to_lines_with_kw(self):
formatter = FormatterAppendToLines(with_label=True, xdataIndex=0)
data = formatter.shape(self.data_labeled_cols)
self.assertEqual(formatter.xlabel, 'y0')
self.assertIsNone(formatter.ylabel)
self.assertEqual(formatter.xdataIndex, 0)
self.assertTrue(formatter.with_label)
correctdata = {'ydatas': [[0., 2., 4., 6., 8., 10.],
[0., 3., 6., 9., 12., 15.]],
'xdata': [0., 1., 2., 3., 4., 5.],
'xlabel': 'y0',
'ylabel': None,
'labels': ['y1', 'y2'],
'name': 'data_labeled_cols'}
self.assertEqual(data, correctdata)
def test_formatter_append_to_lines_with_kw_2(self):
formatter = FormatterAppendToLines(xlabel=r'x-axis', ylabel=r'y-axis', xdataIndex=1, with_label=True)
data = formatter.shape(self.data_labeled_cols)
self.assertEqual(formatter.xlabel, r'x-axis')
self.assertEqual(formatter.ylabel, r'y-axis')
self.assertEqual(formatter.xdataIndex, 1)
correctdata = {'ydatas': [[0., 1., 2., 3., 4., 5.],
[0., 3., 6., 9., 12., 15.]],
'xdata': [0., 2., 4., 6., 8., 10.],
'xlabel': r'x-axis',
'ylabel': r'y-axis',
'labels': ['y0', 'y2'],
'name': 'data_labeled_cols'}
self.assertEqual(data, correctdata)
def test_formatter_append_to_lines_with_kw_3(self):
formatter = FormatterAppendToLines(xlabel=r'x-axis', ylabel=r'y-axis', with_label=True)
data = formatter.shape(self.data_labeled_cols)
self.assertEqual(formatter.xlabel, r'x-axis')
self.assertEqual(formatter.ylabel, r'y-axis')
self.assertIsNone(formatter.xdataIndex)
correctdata = {'ydatas': [[0., 1., 2., 3., 4., 5.],
[0., 2., 4., 6., 8., 10.],
[0., 3., 6., 9., 12., 15.]],
'xdata': [0., 1., 2., 3., 4., 5.],
'xlabel': r'x-axis',
'ylabel': r'y-axis',
'labels': ['y0', 'y1', 'y2'],
'name': 'data_labeled_cols'}
self.assertEqual(data, correctdata)
if __name__ == '__main__':
unittest.main()
......@@ -121,7 +121,7 @@ class FormatterAppendToLinesTestCase(unittest.TestCase):
'xdata': [0., 1., 2., 3., 4., 5.],
'xlabel': None,
'ylabel': None,
'labels': None,
'labels': [],
'name': 'data_cols'}
self.assertEqual(data, correctdata)
......
#!/usr/bin/env python
import os, sys
import unittest
sys.path.append('../../')
from myplotlib import EmptyFig, MyData
from myplotlib.mytool import WeightedGrid, Ax2dPlots
class WeightedGridTestCase(unittest.TestCase):
def setUp(self):
self.rawdata = MyData(data=[-1., 1.])
self.fooFig = EmptyFig()
self.fooGrid = WeightedGrid()
self.fooGrid2 = WeightedGrid()
self.fooAxes = Ax2dPlots(self.fooFig)
self.fooAxes2 = Ax2dPlots(self.fooFig)
def test_default_constructor(self):
wgrid = WeightedGrid()
self.assertEqual(wgrid.weights, [])
def test_constructor_with_weights(self):
wgrid = WeightedGrid(weights=[0.2, 0.2, 0.4, 0.15, 0.05])
self.assertEqual(wgrid.weights, [0.2, 0.2, 0.4, 0.15, 0.05])
def test_append_axes(self):
wgrid = WeightedGrid(margin=0.15, padding=0.05)
self.fooFig.setGrid(wgrid)
wgrid.appendAxes(self.fooAxes, 'fooAxes', self.rawdata)
self.assertEqual(wgrid.weights, [1.])
wgrid.appendAxes(self.fooAxes2, 'fooAxes2', self.rawdata)
self.assertEqual(wgrid.weights, [1., 1.])
def test_append_axes_with_weight(self):
wgrid = WeightedGrid(margin=0.15, padding=0.05)
self.fooFig.setGrid(wgrid)
wgrid.appendAxes(self.fooAxes, 'fooAxes', self.rawdata, weight=0.6)
self.assertEqual(wgrid.weights, [0.6])
wgrid.appendAxes(self.fooAxes2, 'fooAxes2', self.rawdata, weight=0.4)
self.assertEqual(wgrid.weights, [0.6, 0.4])
def test_append_axes_with_weights(self):
wgrid = WeightedGrid(margin=0.15, padding=0.05)
self.fooFig.setGrid(wgrid)
wgrid.appendAxes(self.fooAxes, 'fooAxes', self.rawdata)
self.assertEqual(wgrid.weights, [1.])
wgrid.appendAxes(self.fooAxes2, 'fooAxes2', self.rawdata, weights=[0.4, 0.6])
self.assertEqual(wgrid.weights, [0.4, 0.6])
def test_append_grid(self):
wgrid = WeightedGrid(margin=0.15, padding=0.05)
self.fooFig.setGrid(wgrid)
wgrid.appendGrid(self.fooGrid)
self.assertEqual(wgrid.weights, [1.])
wgrid.appendGrid(self.fooGrid2)
self.assertEqual(wgrid.weights, [1., 1.])
def test_append_grid_with_weight(self):
wgrid = WeightedGrid(margin=0.15, padding=0.05)
self.fooFig.setGrid(wgrid)
wgrid.appendGrid(self.fooGrid, weight=0.6)
self.assertEqual(wgrid.weights, [0.6])
wgrid.appendGrid(self.fooGrid2, weight=0.4)
self.assertEqual(wgrid.weights, [0.6, 0.4])
def test_append_grid_with_weights(self):
wgrid = WeightedGrid(margin=0.15, padding=0.05)
self.fooFig.setGrid(wgrid)
wgrid.appendGrid(self.fooGrid)
self.assertEqual(wgrid.weights, [1.])
wgrid.appendGrid(self.fooGrid2, weights=[0.4, 0.6])
self.assertEqual(wgrid.weights, [0.4, 0.6])
def test_get_item_weight(self):
wgrid = WeightedGrid(margin=0.15, padding=0.05, weights=[0.5, 0.3, 0.6])
self.assertEqual(wgrid.getItemWeight(1), 0.3)
def test_get_weights(self):
wgrid = WeightedGrid(margin=0.15, padding=0.05, weights=[0.5, 0.3, 0.6])
self.assertEqual(wgrid.getWeights(), [0.5, 0.3, 0.6])
def test_looping_grids(self):
wgrid = WeightedGrid(margin=0.15, padding=0.05)
wgrid2 = WeightedGrid(margin=0.15, padding=0.05)
self.fooFig.setGrid(wgrid)
wgrid.appendGrid(wgrid2)
wgrid2.appendGrid(wgrid)
with self.assertRaises(RuntimeError):
self.fooFig.layout()