def _create_co2_plot(self): max = None min = 0 co2, max, min = self._create_plot(max, min, self.co2, "CO2 production (in carbon)") container = GridContainer(co2, Plot(), Plot(), Plot()) container.shape = (2, 2) self.co2_plot = container
def _create_plot_component(): # Create a GridContainer to hold all of our plots container = GridContainer(padding=20, fill_padding=True, bgcolor="lightgray", use_backbuffer=True, shape=(3,3), spacing=(12,12)) # Create the initial series of data x = linspace(-5, 15.0, 100) pd = ArrayPlotData(index = x) # Plot some bessel functions and add the plots to our container for i in range(9): pd.set_data("y" + str(i), jn(i,x)) plot = Plot(pd) plot.plot(("index", "y" + str(i)), color=tuple(COLOR_PALETTE[i]), line_width=2.0, bgcolor = "white", border_visible=True) # Tweak some of the plot properties plot.border_width = 1 plot.padding = 10 # Set each plot's aspect ratio based on its position in the # 3x3 grid of plots. n,m = divmod(i, 3) plot.aspect_ratio = float(n+1) / (m+1) # Attach some tools to the plot plot.tools.append(PanTool(plot)) zoom = ZoomTool(plot, tool_mode="box", always_on=False) plot.overlays.append(zoom) # Add to the grid container container.add(plot) return container
def _create_plot_component(): # Create a GridContainer to hold all of our plots: 2 rows, 3 columns: container = GridContainer(padding=40, fill_padding=True, bgcolor="lightgray", use_backbuffer=True, shape=(2, 3), spacing=(20, 20)) # Create the initial series of data x = linspace(-5, 15.0, 100) pd = ArrayPlotData(index=x) # Plot some bessel functions and add the plots to our container for i in range(6): pd.set_data("y" + str(i), jn(i, x)) plot = Plot(pd) plot.plot(("index", "y" + str(i)), color=tuple(COLOR_PALETTE[i]), line_width=2.0, bgcolor="white", border_visible=True) # Tweak some of the plot properties plot.border_width = 1 plot.padding = 0 plot.padding_top = 30 # Attach some tools to the plot plot.tools.append(PanTool(plot)) zoom = ZoomTool(plot, tool_mode="box", always_on=False) plot.overlays.append(zoom) # Add to the grid container ( container.add(plot) # Set the upper-left plot to only be resizable vertically, and to have a # fixed horizontal width. This also constrains the width of the first column. ul_plot = container.components[0] ul_plot.set(resizable="v", width=200) ul_plot.overlays.append( PlotLabel("Not horizontally resizable", component=ul_plot)) # Set the bottom center plot to have a fixed width and height. # This also constrains the height of the bottom row and the width of # the middle column. cplot = container.components[4] cplot.set(resizable="", bounds=[400, 400]) cplot.overlays.append(PlotLabel("Not resizable", component=cplot)) container.padding_top = 50 container.overlays.append( PlotLabel( 'Resize the window - some plots resize, others cannot ' '(see source code)', component=container, font="swiss 16", overlay_position="top")) return container
def _create_change_plots(self, common_scale=False): max = None min = 0 ctom, max, min = self._create_plot(max, min, self.change_tom, 'Total organic matter') cwoody, max, min = self._create_plot(max, min, self.change_woody, 'Woody matter') cnonwoody, max, min = self._create_plot(max, min, self.change_non_woody, 'Non-woody matter') ca, max, min = self._create_plot(max, min, self.change_acid, 'A') cw, max, min = self._create_plot(max, min, self.change_water, 'W') ce, max, min = self._create_plot(max, min, self.change_ethanol, 'E') cn, max, min = self._create_plot(max, min, self.change_non_soluble, 'N') ch, max, min = self._create_plot(max, min, self.change_humus, 'H') if common_scale: for pl in (ctom, cwoody, cnonwoody, ca, cw, ce, cn, ch): pl.value_range.set_bounds(min, max) container = GridContainer(ctom, cwoody, cnonwoody, ca, cw, ce, cn, ch) container.shape = (3,3) container.spacing = (-15,-15) self.change_plots = container
def _plot_default(self): # Create a GridContainer to hold all of our plots: 2 rows, 4 columns: container = GridContainer(fill_padding=True, bgcolor="lightgray", use_backbuffer=True, shape=(2, 4)) arrangements = [('top left', 'h'), ('top right', 'h'), ('top left', 'v'), ('top right', 'v'), ('bottom left', 'h'), ('bottom right', 'h'), ('bottom left', 'v'), ('bottom right', 'v')] orientation_name = {'h': 'horizontal', 'v': 'vertical'} pd = ArrayPlotData(image=lena()) # Plot some bessel functions and add the plots to our container for origin, orientation in arrangements: plot = Plot(pd, default_origin=origin, orientation=orientation) plot.img_plot('image') # Attach some tools to the plot plot.tools.append(PanTool(plot)) zoom = ZoomTool(plot, tool_mode="box", always_on=False) plot.overlays.append(zoom) title = '{0}, {1}' plot.title = title.format(orientation_name[orientation], origin.replace(' ', '-')) # Add to the grid container container.add(plot) return container
def get_plots(self): #return [p.plothandle for p in self.plots] gc = GridContainer(padding=20, fill_padding=True, bgcolor='lightgray', use_backbuffer=True, shape=(3,3), spacing=(10,10)) [gc.add(p.plothandle) for p in self.plots] return gc
def _create_stock_plots(self, common_scale=False): max = None min = 0 stom, max, min = self._create_plot(max, min, self.stock_tom, 'Total organic matter') swoody, max, min = self._create_plot(max, min, self.stock_woody, 'Woody matter') snonwoody, max, min = self._create_plot(max, min, self.stock_non_woody, 'Non-woody matter') sa, max, min = self._create_plot(max, min, self.stock_acid, 'A') sw, max, min = self._create_plot(max, min, self.stock_water, 'W') se, max, min = self._create_plot(max, min, self.stock_ethanol, 'E') sn, max, min = self._create_plot(max, min, self.stock_non_soluble, 'N') sh, max, min = self._create_plot(max, min, self.stock_humus, 'H') if common_scale: for pl in (stom, swoody, snonwoody, sa, sw, se, sn, sh): pl.value_range.set_bounds(min, max) container = GridContainer(stom, swoody, snonwoody, sa, sw, se, sn, sh) container.shape = (3,3) container.spacing = (-8,-8) self.stock_plots = container
def test_nonresizable_container(self): cont = GridContainer(shape=(1,1), resizable="") comp1 = StaticPlotComponent([200,300]) cont.add(comp1) cont.do_layout() self.assert_tuple(comp1.position, (0,0)) self.assert_tuple(comp1.bounds, (200,300)) return
def _create_co2_plot(self): max = None min = 0 co2, max, min = self._create_plot(max, min, self.co2, 'CO2 production (in carbon)') container = GridContainer(co2, Plot(), Plot(), Plot()) container.shape= (2,2) self.co2_plot = container
def test_single_cell(self): cont = GridContainer(shape=(1,1)) comp1 = StaticPlotComponent([200,300]) cont.add(comp1) cont.do_layout() # it would be nice to make all boolean tests here trigger # assert failures, maybe using Pypy? self.assert_tuple(comp1.position, (0,0)) self.assert_tuple(comp1.bounds, (200,300)) return
def test_non_resizable(self): cont = GridContainer(shape=(2, 2), spacing=(10, 10), halign="center", valign="center") ul = StaticPlotComponent([100, 100], resizable="") ur = StaticPlotComponent([100, 100], resizable="") ll = StaticPlotComponent([100, 100], resizable="") lr = StaticPlotComponent([100, 100], resizable="") cont.component_grid = [[ul, ur], [ll, lr]] cont.bounds = [240, 240] cont.do_layout() self.assert_tuple(ul.position, (10, 130)) self.assert_tuple(ul.bounds, (100, 100)) self.assert_tuple(ur.position, (130, 130)) self.assert_tuple(ur.bounds, (100, 100)) self.assert_tuple(ll.position, (10, 10)) self.assert_tuple(ll.bounds, (100, 100)) self.assert_tuple(lr.position, (130, 10)) self.assert_tuple(lr.bounds, (100, 100)) cont.bounds = [280, 280] cont.do_layout() self.assert_tuple(ul.position, (20, 160)) self.assert_tuple(ul.bounds, (100, 100)) self.assert_tuple(ur.position, (160, 160)) self.assert_tuple(ur.bounds, (100, 100)) self.assert_tuple(ll.position, (20, 20)) self.assert_tuple(ll.bounds, (100, 100)) self.assert_tuple(lr.position, (160, 20)) self.assert_tuple(lr.bounds, (100, 100))
def _create_plot_component(): # Create a GridContainer to hold all of our plots: 2 rows, 3 columns: container = GridContainer(padding=40, fill_padding=True, bgcolor="lightgray", use_backbuffer=True, shape=(2,3), spacing=(20,20)) # Create the initial series of data x = linspace(-5, 15.0, 100) pd = ArrayPlotData(index = x) # Plot some bessel functions and add the plots to our container for i in range(6): pd.set_data("y" + str(i), jn(i,x)) plot = Plot(pd) plot.plot(("index", "y" + str(i)), color=tuple(COLOR_PALETTE[i]), line_width=2.0, bgcolor = "white", border_visible=True) # Tweak some of the plot properties plot.border_width = 1 plot.padding = 0 plot.padding_top = 30 # Attach some tools to the plot plot.tools.append(PanTool(plot)) zoom = ZoomTool(plot, tool_mode="box", always_on=False) plot.overlays.append(zoom) # Add to the grid container ( container.add(plot) # Set the upper-left plot to only be resizable vertically, and to have a # fixed horizontal width. This also constrains the width of the first column. ul_plot = container.components[0] ul_plot.set(resizable="v", width=200) ul_plot.overlays.append(PlotLabel("Not horizontally resizable", component=ul_plot)) # Set the bottom center plot to have a fixed width and height. # This also constrains the height of the bottom row and the width of # the middle column. cplot = container.components[4] cplot.set(resizable="", bounds=[400,400]) cplot.overlays.append(PlotLabel("Not resizable", component=cplot)) container.padding_top = 50 container.overlays.append( PlotLabel('Resize the window - some plots resize, others cannot ' '(see source code)', component=container, font = "swiss 16", overlay_position = "top")) return container
def test_non_resizable(self): cont = GridContainer(shape=(2,2), spacing=(10,10), halign="center", valign="center") ul = StaticPlotComponent([100,100], resizable="") ur = StaticPlotComponent([100,100], resizable="") ll = StaticPlotComponent([100,100], resizable="") lr = StaticPlotComponent([100,100], resizable="") cont.component_grid = [[ul, ur], [ll, lr]] cont.bounds = [240, 240] cont.do_layout() self.assert_tuple(ul.position, (10,130)) self.assert_tuple(ul.bounds, (100,100)) self.assert_tuple(ur.position, (130,130)) self.assert_tuple(ur.bounds, (100, 100)) self.assert_tuple(ll.position, (10,10)) self.assert_tuple(ll.bounds, (100,100)) self.assert_tuple(lr.position, (130,10)) self.assert_tuple(lr.bounds, (100,100)) cont.bounds = [280, 280] cont.do_layout() self.assert_tuple(ul.position, (20,160)) self.assert_tuple(ul.bounds, (100,100)) self.assert_tuple(ur.position, (160,160)) self.assert_tuple(ur.bounds, (100, 100)) self.assert_tuple(ll.position, (20,20)) self.assert_tuple(ll.bounds, (100,100)) self.assert_tuple(lr.position, (160,20)) self.assert_tuple(lr.bounds, (100,100))
def test_empty_container(self): # FIXME: # This test is failing when run with nosetests and coverage. # Therefore, it is skipped when coverage is imported. # If you want to fix this, please look at: # https://svn.enthought.com/enthought/ticket/1618 # where I posted more details about this problem. if 'coverage' in sys.modules: raise nose.SkipTest cont = GridContainer(shape=(1, 1)) cont.bounds = [100, 100] cont.do_layout() return
def _create_stock_plots(self, common_scale=False): max = None min = 0 stom, max, min = self._create_plot(max, min, self.stock_tom, "Total organic matter") swoody, max, min = self._create_plot(max, min, self.stock_woody, "Woody matter") snonwoody, max, min = self._create_plot(max, min, self.stock_non_woody, "Non-woody matter") sa, max, min = self._create_plot(max, min, self.stock_acid, "Acid soluble") sw, max, min = self._create_plot(max, min, self.stock_water, "Water soluble") se, max, min = self._create_plot(max, min, self.stock_ethanol, "Ethanol soluble") sn, max, min = self._create_plot(max, min, self.stock_non_soluble, "Non soluble") sh, max, min = self._create_plot(max, min, self.stock_humus, "Humus") if common_scale: for pl in (stom, swoody, snonwoody, sa, sw, se, sn, sh): pl.value_range.set_bounds(min, max) container = GridContainer(stom, swoody, snonwoody, sa, sw, se, sn, sh) container.shape = (3, 3) container.spacing = (-8, -8) self.stock_plots = container
def _create_change_plots(self, common_scale=False): max = None min = 0 ctom, max, min = self._create_plot(max, min, self.change_tom, "Total organic matter") cwoody, max, min = self._create_plot(max, min, self.change_woody, "Woody matter") cnonwoody, max, min = self._create_plot(max, min, self.change_non_woody, "Non-woody matter") ca, max, min = self._create_plot(max, min, self.change_acid, "Acid soluble") cw, max, min = self._create_plot(max, min, self.change_water, "Water soluble") ce, max, min = self._create_plot(max, min, self.change_ethanol, "Ethanol soluble") cn, max, min = self._create_plot(max, min, self.change_non_soluble, "Non soluble") ch, max, min = self._create_plot(max, min, self.change_humus, "Humus") if common_scale: for pl in (ctom, cwoody, cnonwoody, ca, cw, ce, cn, ch): pl.value_range.set_bounds(min, max) container = GridContainer(ctom, cwoody, cnonwoody, ca, cw, ce, cn, ch) container.shape = (3, 3) container.spacing = (-15, -15) self.change_plots = container
def test_all_empty_cells(self): cont = GridContainer(shape=(2, 2), spacing=(0, 0)) cont.component_grid = [[None, None], [None, None]] size = cont.get_preferred_size() self.assert_tuple(size, (0, 0)) cont.bounds = (100, 100) cont.do_layout() return
def updateImageContainer(self): container = GridContainer(bgcolor="transparent", shape=(1,1), use_backbuffer=True) self.imagecontainer = container cont = getattr(self.pyxda, 'imageplot') if cont in container._components: container.remove(cont) container.add(cont) container.get_preferred_size() container.invalidate_draw() return
def test_resizable_mixed_h(self): # Tests the layout of a non-resizable component, a resizable with a # preferred size, and a fully resizable component in a horizontal # GridContainer cont = GridContainer(shape=(3,1), spacing=(0,0), halign="center", valign="center") left = StaticPlotComponent([50,10], resizable="") middle = ResizablePlotComponent([100,10]) right = StaticPlotComponent([0,0], resizable="hv") cont.component_grid = [[left, middle, right]] cont.bounds = [200, 10] cont.do_layout() self.assert_tuple(left.position, (0,0)) self.assert_tuple(left.bounds, (50,10)) self.assert_tuple(middle.position, (50,0)) self.assert_tuple(middle.bounds, (100,10)) self.assert_tuple(right.position, (150,0)) self.assert_tuple(right.bounds, (50,10))
def test_spacing(self): cont = GridContainer(shape=(2,2), spacing=(10,10), halign="center", valign="center") ul = StaticPlotComponent([50,50]) # upper-left component lr = StaticPlotComponent([100,100]) # lower-right component top = StaticPlotComponent([0,0], resizable="hv") left = StaticPlotComponent([0,0], resizable="hv") cont.component_grid = [[ul, top], [left, lr]] cont.bounds = [190, 190] cont.do_layout() self.assert_tuple(ul.position, (10,130)) self.assert_tuple(ul.bounds, (50,50)) self.assert_tuple(top.position, (80,130)) self.assert_tuple(top.bounds, (100, 50)) self.assert_tuple(left.position, (10,10)) self.assert_tuple(left.bounds, (50,100)) self.assert_tuple(lr.position, (80,10)) self.assert_tuple(lr.bounds, (100,100)) return
def test_resizable2(self): # Tests a resizable component that also has a preferred size cont = GridContainer(shape=(2,2), spacing=(0,0), halign="center", valign="center") ul = StaticPlotComponent([150,150], resizable="hv") lr = StaticPlotComponent([0,0], resizable="hv") top = StaticPlotComponent([0,0], resizable="hv") left = StaticPlotComponent([0,0], resizable="hv") cont.component_grid = [[ul, top], [left, lr]] cont.bounds = [200, 200] cont.do_layout() self.assert_tuple(ul.position, (0,100)) self.assert_tuple(ul.bounds, (100,100)) self.assert_tuple(top.position, (100,100)) self.assert_tuple(top.bounds, (100,100)) self.assert_tuple(left.position, (0,0)) self.assert_tuple(left.bounds, (100,100)) self.assert_tuple(lr.position, (100,0)) self.assert_tuple(lr.bounds, (100,100))
def test_two_by_two(self): """ Tests a 2x2 grid of components """ cont = GridContainer(shape=(2,2), halign="center", valign="center") ul = StaticPlotComponent([50,50]) # upper-left component lr = StaticPlotComponent([100,100]) # lower-right component top = StaticPlotComponent([0,0], resizable="hv") left = StaticPlotComponent([0,0], resizable="hv") cont.component_grid = [[ul, top], [left, lr]] cont.bounds = [150, 150] cont.do_layout() self.assert_tuple(ul.position, (0,100)) self.assert_tuple(ul.bounds, (50,50)) self.assert_tuple(top.position, (50,100)) self.assert_tuple(top.bounds, (100, 50)) self.assert_tuple(left.position, (0,0)) self.assert_tuple(left.bounds, (50,100)) self.assert_tuple(lr.position, (50,0)) self.assert_tuple(lr.bounds, (100,100)) return
def _create_plot_component(): # Create a GridContainer to hold all of our plots container = GridContainer(padding=40, fill_padding=True, bgcolor="lightgray", use_backbuffer=True, shape=(2,3), spacing=(20,20)) # Create the initial series of data x = linspace(-5, 15.0, 100) pd = ArrayPlotData(index = x) # Plot some bessel functions and add the plots to our container for i in range(6): pd.set_data("y" + str(i), jn(i,x)) plot = Plot(pd) plot.plot(("index", "y" + str(i)), color=tuple(COLOR_PALETTE[i]), line_width=2.0, bgcolor = "white", border_visible=True) # Tweak some of the plot properties plot.border_width = 1 plot.padding = 0 # Attach some tools to the plot plot.tools.append(PanTool(plot)) zoom = ZoomTool(plot, tool_mode="box", always_on=False) plot.overlays.append(zoom) # Add to the grid container container.add(plot) # Set the upper-left plot to only be resizable vertically, and to have # a fixed horizontal width ul_plot = container.components[0] ul_plot.set(resizable="v", padding_top=30, width=200) ul_plot.overlays.append(PlotLabel("Vertically resizable", component=ul_plot)) # Set the bottom center plot to have a fixed width and height cplot = container.components[4] cplot.set(resizable="", padding_top = 30, bounds=[400,400]) cplot.overlays.append(PlotLabel("Not resizable", component=cplot)) return container
def test_resizable_mixed(self): """ Tests mixing resizable and non-resizable components """ cont = GridContainer(shape=(2,2), spacing=(10,10), halign="center", valign="center") ul = StaticPlotComponent([0,0], resizable="hv") lr = StaticPlotComponent([0,0], resizable="hv") top = StaticPlotComponent([0,0], resizable="hv") left = StaticPlotComponent([100,100], resizable="") cont.component_grid = [[ul, top], [left, lr]] cont.bounds = [240, 240] cont.do_layout() self.assert_tuple(ul.position, (10,130)) self.assert_tuple(ul.bounds, (100,100)) self.assert_tuple(top.position, (130,130)) self.assert_tuple(top.bounds, (100, 100)) self.assert_tuple(left.position, (10,10)) self.assert_tuple(left.bounds, (100,100)) self.assert_tuple(lr.position, (130,10)) self.assert_tuple(lr.bounds, (100,100)) return
def test_resizable_mixed2(self): # Tests laying out resizable components with preferred # sized alongside non-resizable components. cont = GridContainer(shape=(2,2), spacing=(0,0), halign="center", valign="center") ul = ResizablePlotComponent([150,150]) lr = StaticPlotComponent([50,50], resizable="") top = StaticPlotComponent([0,0], resizable="hv") left = StaticPlotComponent([0,0], resizable="hv") cont.component_grid = [[ul, top], [left, lr]] cont.bounds = [200, 200] cont.do_layout() self.assert_tuple(ul.position, (0,50)) self.assert_tuple(ul.bounds, (150,150)) self.assert_tuple(top.position, (150,50)) self.assert_tuple(top.bounds, (50,150)) self.assert_tuple(left.position, (0,0)) self.assert_tuple(left.bounds, (150,50)) self.assert_tuple(lr.position, (150,0)) self.assert_tuple(lr.bounds, (50,50))
def _create_plot_component(): # Create a GridContainer to hold all of our plots container = GridContainer(padding=20, fill_padding=True, bgcolor="lightgray", use_backbuffer=True, shape=(3, 3), spacing=(12, 12)) # Create the initial series of data x = linspace(-5, 15.0, 100) pd = ArrayPlotData(index=x) # Plot some bessel functions and add the plots to our container for i in range(9): pd.set_data("y" + str(i), jn(i, x)) plot = Plot(pd) plot.plot(("index", "y" + str(i)), color=tuple(COLOR_PALETTE[i]), line_width=2.0, bgcolor="white", border_visible=True) # Tweak some of the plot properties plot.border_width = 1 plot.padding = 10 # Set each plot's aspect ratio based on its position in the # 3x3 grid of plots. n, m = divmod(i, 3) plot.aspect_ratio = float(n + 1) / (m + 1) # Attach some tools to the plot plot.tools.append(PanTool(plot)) zoom = ZoomTool(plot, tool_mode="box", always_on=False) plot.overlays.append(zoom) # Add to the grid container container.add(plot) return container
def test_all_empty_cells(self): cont = GridContainer(shape=(2,2), spacing=(0,0)) cont.component_grid = [[None, None], [None, None]] size = cont.get_preferred_size() self.assert_tuple(size, (0,0)) cont.bounds = (100,100) cont.do_layout() return
def test_nonresizable_container(self): cont = GridContainer(shape=(1, 1), resizable="") comp1 = StaticPlotComponent([200, 300]) cont.add(comp1) cont.do_layout() self.assert_tuple(comp1.position, (0, 0)) self.assert_tuple(comp1.bounds, (200, 300)) return
def test_some_empty_cells(self): cont = GridContainer(shape=(2, 2), spacing=(0, 0)) a = StaticPlotComponent([100, 30]) b = StaticPlotComponent([50, 40]) cont.component_grid = [[a, None], [None, b]] size = cont.get_preferred_size() self.assert_tuple(size, (150, 70)) cont.bounds = size cont.do_layout() self.assert_tuple(a.outer_position, (0, 40)) self.assert_tuple(a.outer_bounds, (100, 30)) self.assert_tuple(b.outer_position, (100, 0)) self.assert_tuple(b.outer_bounds, (50, 40))
def test_row(self): cont = GridContainer(shape=(1,3), halign="center", valign="center") c1 = StaticPlotComponent([50,50]) c2 = StaticPlotComponent([30,30]) c3 = StaticPlotComponent([0,0], resizable="hv") cont.add(c1, c2, c3) cont.bounds = list(cont.get_preferred_size()) cont.do_layout() self.assert_tuple(c1.position, (0,0)) self.assert_tuple(c1.bounds, (50,50)) self.assert_tuple(c2.position, (50,10)) self.assert_tuple(c2.bounds, (30,30)) self.assert_tuple(c3.position, (80,0)) self.assert_tuple(c3.bounds, (0,50)) cont.bounds = [100, 50] cont.do_layout() self.assert_tuple(c1.position, (0,0)) self.assert_tuple(c1.bounds, (50,50)) self.assert_tuple(c2.position, (50,10)) self.assert_tuple(c2.bounds, (30,30)) self.assert_tuple(c3.position, (80,0)) self.assert_tuple(c3.bounds, (20,50)) return
def test_single_cell(self): cont = GridContainer(shape=(1, 1)) comp1 = StaticPlotComponent([200, 300]) cont.add(comp1) cont.do_layout() # it would be nice to make all boolean tests here trigger # assert failures, maybe using Pypy? self.assert_tuple(comp1.position, (0, 0)) self.assert_tuple(comp1.bounds, (200, 300)) return
def test_some_empty_cells(self): cont = GridContainer(shape=(2,2), spacing=(0,0)) a = StaticPlotComponent([100,30]) b = StaticPlotComponent([50,40]) cont.component_grid = [[a, None], [None, b]] size = cont.get_preferred_size() self.assert_tuple(size, (150, 70)) cont.bounds = size cont.do_layout() self.assert_tuple(a.outer_position, (0, 40)) self.assert_tuple(a.outer_bounds, (100, 30)) self.assert_tuple(b.outer_position, (100,0)) self.assert_tuple(b.outer_bounds, (50, 40))
def test_two_by_two(self): """ Tests a 2x2 grid of components """ cont = GridContainer(shape=(2, 2), halign="center", valign="center") ul = StaticPlotComponent([50, 50]) # upper-left component lr = StaticPlotComponent([100, 100]) # lower-right component top = StaticPlotComponent([0, 0], resizable="hv") left = StaticPlotComponent([0, 0], resizable="hv") cont.component_grid = [[ul, top], [left, lr]] cont.bounds = [150, 150] cont.do_layout() self.assert_tuple(ul.position, (0, 100)) self.assert_tuple(ul.bounds, (50, 50)) self.assert_tuple(top.position, (50, 100)) self.assert_tuple(top.bounds, (100, 50)) self.assert_tuple(left.position, (0, 0)) self.assert_tuple(left.bounds, (50, 100)) self.assert_tuple(lr.position, (50, 0)) self.assert_tuple(lr.bounds, (100, 100)) return
def test_resizable2(self): # Tests a resizable component that also has a preferred size cont = GridContainer(shape=(2, 2), spacing=(0, 0), halign="center", valign="center") ul = StaticPlotComponent([150, 150], resizable="hv") lr = StaticPlotComponent([0, 0], resizable="hv") top = StaticPlotComponent([0, 0], resizable="hv") left = StaticPlotComponent([0, 0], resizable="hv") cont.component_grid = [[ul, top], [left, lr]] cont.bounds = [200, 200] cont.do_layout() self.assert_tuple(ul.position, (0, 100)) self.assert_tuple(ul.bounds, (100, 100)) self.assert_tuple(top.position, (100, 100)) self.assert_tuple(top.bounds, (100, 100)) self.assert_tuple(left.position, (0, 0)) self.assert_tuple(left.bounds, (100, 100)) self.assert_tuple(lr.position, (100, 0)) self.assert_tuple(lr.bounds, (100, 100))
def test_resizable_mixed_h(self): # Tests the layout of a non-resizable component, a resizable with a # preferred size, and a fully resizable component in a horizontal # GridContainer cont = GridContainer(shape=(3, 1), spacing=(0, 0), halign="center", valign="center") left = StaticPlotComponent([50, 10], resizable="") middle = ResizablePlotComponent([100, 10]) right = StaticPlotComponent([0, 0], resizable="hv") cont.component_grid = [[left, middle, right]] cont.bounds = [200, 10] cont.do_layout() self.assert_tuple(left.position, (0, 0)) self.assert_tuple(left.bounds, (50, 10)) self.assert_tuple(middle.position, (50, 0)) self.assert_tuple(middle.bounds, (100, 10)) self.assert_tuple(right.position, (150, 0)) self.assert_tuple(right.bounds, (50, 10))
def test_spacing(self): cont = GridContainer(shape=(2, 2), spacing=(10, 10), halign="center", valign="center") ul = StaticPlotComponent([50, 50]) # upper-left component lr = StaticPlotComponent([100, 100]) # lower-right component top = StaticPlotComponent([0, 0], resizable="hv") left = StaticPlotComponent([0, 0], resizable="hv") cont.component_grid = [[ul, top], [left, lr]] cont.bounds = [190, 190] cont.do_layout() self.assert_tuple(ul.position, (10, 130)) self.assert_tuple(ul.bounds, (50, 50)) self.assert_tuple(top.position, (80, 130)) self.assert_tuple(top.bounds, (100, 50)) self.assert_tuple(left.position, (10, 10)) self.assert_tuple(left.bounds, (50, 100)) self.assert_tuple(lr.position, (80, 10)) self.assert_tuple(lr.bounds, (100, 100)) return
def test_resizable_mixed2(self): # Tests laying out resizable components with preferred # sized alongside non-resizable components. cont = GridContainer(shape=(2, 2), spacing=(0, 0), halign="center", valign="center") ul = ResizablePlotComponent([150, 150]) lr = StaticPlotComponent([50, 50], resizable="") top = StaticPlotComponent([0, 0], resizable="hv") left = StaticPlotComponent([0, 0], resizable="hv") cont.component_grid = [[ul, top], [left, lr]] cont.bounds = [200, 200] cont.do_layout() self.assert_tuple(ul.position, (0, 50)) self.assert_tuple(ul.bounds, (150, 150)) self.assert_tuple(top.position, (150, 50)) self.assert_tuple(top.bounds, (50, 150)) self.assert_tuple(left.position, (0, 0)) self.assert_tuple(left.bounds, (150, 50)) self.assert_tuple(lr.position, (150, 0)) self.assert_tuple(lr.bounds, (50, 50))
def test_resizable_mixed(self): """ Tests mixing resizable and non-resizable components """ cont = GridContainer(shape=(2, 2), spacing=(10, 10), halign="center", valign="center") ul = StaticPlotComponent([0, 0], resizable="hv") lr = StaticPlotComponent([0, 0], resizable="hv") top = StaticPlotComponent([0, 0], resizable="hv") left = StaticPlotComponent([100, 100], resizable="") cont.component_grid = [[ul, top], [left, lr]] cont.bounds = [240, 240] cont.do_layout() self.assert_tuple(ul.position, (10, 130)) self.assert_tuple(ul.bounds, (100, 100)) self.assert_tuple(top.position, (130, 130)) self.assert_tuple(top.bounds, (100, 100)) self.assert_tuple(left.position, (10, 10)) self.assert_tuple(left.bounds, (100, 100)) self.assert_tuple(lr.position, (130, 10)) self.assert_tuple(lr.bounds, (100, 100)) return
def _create_plot_component(): container = GridContainer(padding=40, fill_padding=True, bgcolor="lightgray", use_backbuffer=True, shape=(3,3), spacing=(10,10)) x = arange(100) y = arange(100) plot = create_line_plot((x,y), color="red", width=2.0, index_bounds=(-5,100), value_bounds=(-5,90)) plot.padding = 50 plot.fill_padding = True plot.bgcolor = "white" left, bottom = add_default_axes(plot, vtitle="Roll (degrees)", htitle="Time (s)") hgrid, vgrid = add_default_grids(plot) bottom.tick_interval = 20.0 vgrid.grid_interval = 10.0 container.add(plot) x = arange(100) y = arange(100) plot = create_line_plot((x,y), color="red", width=2.0, index_bounds=(-5,100), value_bounds=(-5,90)) plot.padding = 50 plot.fill_padding = True plot.bgcolor = "white" left, bottom = add_default_axes(plot, vtitle="Pitch (degrees)", htitle="Time (s)") hgrid, vgrid = add_default_grids(plot) bottom.tick_interval = 20.0 vgrid.grid_interval = 10.0 container.add(plot) x = arange(100) y = arange(100) plot = create_line_plot((x,y), color="red", width=2.0, index_bounds=(-5,100), value_bounds=(-5,365)) plot.padding = 50 plot.fill_padding = True plot.bgcolor = "white" left, bottom = add_default_axes(plot, vtitle="Yaw (degrees)", htitle="Time (s)") hgrid, vgrid = add_default_grids(plot) bottom.tick_interval = 20.0 vgrid.grid_interval = 10.0 container.add(plot) x = arange(100) y = arange(100) plot = create_line_plot((x,y), color="red", width=2.0, index_bounds=(-5,100), value_bounds=(-100,100)) plot.padding = 50 plot.fill_padding = True plot.bgcolor = "white" left, bottom = add_default_axes(plot, vtitle="Gyro X", htitle="Time (s)") hgrid, vgrid = add_default_grids(plot) bottom.tick_interval = 20.0 vgrid.grid_interval = 10.0 container.add(plot) x = arange(100) y = arange(100) plot = create_line_plot((x,y), color="red", width=2.0, index_bounds=(-5,100), value_bounds=(-100,100)) plot.padding = 50 plot.fill_padding = True plot.bgcolor = "white" left, bottom = add_default_axes(plot, vtitle="Gyro Y", htitle="Time (s)") hgrid, vgrid = add_default_grids(plot) bottom.tick_interval = 20.0 vgrid.grid_interval = 10.0 container.add(plot) x = arange(100) y = arange(100) plot = create_line_plot((x,y), color="red", width=2.0, index_bounds=(-5,100), value_bounds=(-100,100)) plot.padding = 50 plot.fill_padding = True plot.bgcolor = "white" left, bottom = add_default_axes(plot, vtitle="Gyro Z", htitle="Time (s)") hgrid, vgrid = add_default_grids(plot) bottom.tick_interval = 20.0 vgrid.grid_interval = 10.0 container.add(plot) x = arange(100) y = arange(100) plot = create_line_plot((x,y), color="red", width=2.0, index_bounds=(-5,100), value_bounds=(-1,35)) plot.padding = 50 plot.fill_padding = True plot.bgcolor = "white" left, bottom = add_default_axes(plot, vtitle="Battery Voltage (V)", htitle="Time (s)") hgrid, vgrid = add_default_grids(plot) bottom.tick_interval = 20.0 vgrid.grid_interval = 10.0 container.add(plot) return container
def build_plot(self): print 'Building plot...' fitrange = self.fitrange # Just for convenience onearray = Array onearray = sp.ones(self.indata.shape[0]) minuses = onearray * (-1.) # Define index array for fit function: self.mod_x = sp.arange(self.line_center - 50., self.line_center + 50., .01) self.Model = sp.zeros(self.mod_x.shape[0]) # Establish continuum array in a way that opens for other, more # elaborate continua. self.contarray = sp.ones(self.mod_x.shape[0]) * \ self.Components['Contin'][0] self.y = {} for comp in self.CompoList: self.y[comp] = gauss( # x, mu, sigma, amplitude self.mod_x, self.Components[comp][0] + self.line_center, self.Components[comp][1], self.Components[comp][2]) self.Model = self.contarray + self.y[self.select] broca = BroadcasterTool() # Define the part of the data to show in initial view: plotrange = sp.where((self.x > self.line_center - 30) & (self.x < self.line_center + 30)) # Define the y axis max value in initial view (can be panned/zoomed): maxval = float(self.indata[fitrange].max() * 1.2) minval = maxval / 15. minval = abs(np.median(self.indata[fitrange])) * 1.5 maxerr = self.errs[fitrange].max() * 1.3 resmin = max(sp.absolute(self.Resids[self.fitrange]).max(), 5.) * 1.2 cenx = sp.array([self.line_center, self.line_center]) ceny = sp.array([-minval, maxval]) cenz = sp.array([-maxval, maxval]) # Gray shading of ignored ranges rangelist = np.array(self.rangelist) grayx = np.array(rangelist.flatten().repeat(2)) grayx = np.hstack((self.x.min(), grayx, self.x.max())) grayy = np.ones_like(grayx) * self.indata.max() * 2. grayy[1::4] = -grayy[1::4] grayy[2::4] = -grayy[2::4] grayy = np.hstack((grayy[-1], grayy[:-1])) # Build plot of data and model self.plotdata = ArrayPlotData( wl=self.x, data=self.indata, xs=self.mod_x, cont=self.contarray, ones=onearray, minus=minuses, model=self.Model, errors=self.errs, ceny=ceny, cenz=cenz, cenx=cenx, Residuals=self.Resids, grayx=grayx, grayy=grayy, ) # Add dynamically created components to plotdata for comp in self.CompoList: self.plotdata.set_data(comp, self.y[comp]) olplot = GridContainer(shape=(2, 1), padding=10, fill_padding=True, bgcolor='transparent', spacing=(5, 10)) plot = Plot(self.plotdata) plot.y_axis.title = 'Flux density' resplot = Plot(self.plotdata, tick_visible=True, y_auto=True) resplot.x_axis.title = u'Wavelength [Å]' resplot.y_axis.title = u'Residuals/std. err.' # Create initial plot: Spectrum data, default first component, # default total line profile. self.comprenders = [] self.datarender = plot.plot(('wl', 'data'), color='black', name='Data', render_style='connectedhold') self.contrender = plot.plot(('xs', 'cont'), color='darkgray', name='Cont') self.modlrender = plot.plot(('xs', 'model'), color='blue', line_width=1.6, name='Model') self.centrender = plot.plot(('cenx', 'ceny'), color='black', type='line', line_style='dot', name='Line center', line_width=1.) self.rangrender = plot.plot( ('grayx', 'grayy'), type='polygon', face_color='lightgray', edge_color='gray', face_alpha=0.3, alpha=0.3, ) # There may be an arbitrary number of gaussian components, so: print 'Updating model' for comp in self.CompoList: self.comprenders.append( plot.plot( ('xs', comp), type='line', color=Paired[self.Components[comp] [3]], # tuple(COLOR_PALETTE[self.CompNum]), line_color=Paired[self.Components[comp][ 3]], # tuple(COLOR_PALETTE[self.CompNum]), line_style='dash', name=comp)) # Create panel with residuals: resplot.plot(('wl', 'Residuals'), color='black', name='Resids') resplot.plot(('wl', 'ones'), color='green') resplot.plot(('wl', 'minus'), color='green') resplot.plot(('cenx', 'cenz'), color='red', type='line', line_style='dot', line_width=.5) resplot.plot( ('grayx', 'grayy'), # Yes, that one again type='polygon', face_color='lightgray', edge_color='gray', face_alpha=0.3, alpha=0.3, ) plot.x_axis.visible = False # Set ranges to change automatically when plot values change. plot.value_range.low_setting,\ plot.value_range.high_setting = (-minval, maxval) plot.index_range.low_setting,\ plot.index_range.high_setting = (self.line_center - 30., self.line_center + 30.) resplot.value_range.low_setting,\ resplot.value_range.high_setting = (-resmin, resmin) resplot.index_range.low_setting,\ resplot.index_range.high_setting = (plot.index_range.low_setting, plot.index_range.high_setting) #resplot.index_range = plot.index_range # Yes or no? FIXME plot.overlays.append( ZoomTool(plot, tool_mode='box', drag_button='left', always_on=False)) resplot.overlays.append( ZoomTool(resplot, tool_mode='range', drag_button='left', always_on=False)) # List of renderers to tell the legend what to write self.plots['Contin'] = self.contrender self.plots['Center'] = self.centrender self.plots['Model'] = self.modlrender for i in sp.arange(len(self.comprenders)): self.plots[self.CompoList[i]] = self.comprenders[i] # Build Legend: legend = Legend(component=plot, padding=10, align="ur") legend.tools.append(LegendTool(legend, drag_button="right")) legend.plots = self.plots plot.overlays.append(legend) olplot.tools.append(broca) pan = PanTool(plot) respan = PanTool(resplot, constrain=True, constrain_direction='x') broca.tools.append(pan) broca.tools.append(respan) plot.overlays.append(ZoomTool(plot, tool_mode='box', always_on=False)) olplot.add(plot) olplot.add(resplot) olplot.components[0].set(resizable='hv', bounds=[500, 400]) olplot.components[1].set(resizable='h', bounds=[500, 100]) self.plot = plot self.resplot = resplot self.plwin = olplot self.legend = legend self.plotrange = plotrange
def test_empty_container(self): cont = GridContainer(shape=(1, 1)) cont.bounds = [100, 100] cont.do_layout() return
def build_plot(self): global plotdata # FIXME: Don't use global! onearray = Array onearray = sp.ones(self.indata.shape[0]) minuses = onearray * (-1.) # Define index array for fit function: self.mod_x = sp.arange(self.line_center - 50., self.line_center + 50., .01) self.Model = sp.zeros(self.mod_x.shape[0]) # Establish continuum array in a way that opens for other, more # elaborate continua. self.contarray = sp.ones(self.mod_x.shape[0]) * \ self.Components['Contin'] self.y = {} for comp in self.CompoList: self.y[comp] = stats.norm.pdf( self.mod_x, self.Components[comp][0] + self.line_center, self.Components[comp][1] ) * self.Components[comp][1] * sp.sqrt(2. * sp.pi) * \ self.Components[comp][2] self.Model = self.contarray + self.y[self.select] broca = BroadcasterTool() # Define the part of the data to show in initial view: plotrange = sp.where((self.x > self.line_center - 20) & (self.x < self.line_center + 20)) # Define the y axis max value in initial view (can be panned/zoomed): maxval = float(self.indata[plotrange].max() * 1.1) minval = maxval / 15. maxerr = self.errs[plotrange].max() * 1.3 resmin = max(self.Resids[plotrange].max(), 5.) * 1.2 cenx = sp.array([self.line_center, self.line_center]) ceny = sp.array([-minval, maxval]) cenz = sp.array([-maxval, maxval]) # Build plot of data and model plotdata = ArrayPlotData( wl=self.x, data=self.indata, xs=self.mod_x, cont=self.contarray, ones=onearray, minus=minuses, model=self.Model, errors=self.errs, ceny=ceny, cenz=cenz, cenx=cenx, Residuals=self.Resids, ) for comp in self.CompoList: plotdata.set_data(comp, self.y[comp]) olplot = GridContainer(shape=(2, 1), padding=10, fill_padding=True, bgcolor='transparent', spacing=(5, 10)) plot = Plot(plotdata) plot.y_axis.title = 'Flux density' resplot = Plot(plotdata, tick_visible=True, y_auto=True) resplot.x_axis.title = u'Wavelength [Å]' resplot.y_axis.title = u'Residuals/std. err.' # Create initial plot: Spectrum data, default first component, # default total line profile. self.comprenders = [] self.datarender = plot.plot(('wl', 'data'), color='black', name='Data', render_style='connectedhold') self.contrender = plot.plot(('xs', 'cont'), color='darkgray', name='Cont') self.modlrender = plot.plot(('xs', 'model'), color='blue', line_width=1.6, name='Model') self.centrender = plot.plot(('cenx', 'ceny'), color='black', type='line', line_style='dot', name='Line center', line_width=1.) # There may be an arbitrary number of gaussian components, so: for comp in self.CompoList: self.comprenders.append( plot.plot(('xs', comp), type='line', #color='auto', color=tuple(COLOR_PALETTE[self.CompNum]), line_style='dash', name=comp) ) # Create panel with residuals: resplot.plot(('wl', 'Residuals'), color='black', name='Resids') resplot.plot(('wl', 'ones'), color='green') resplot.plot(('wl', 'minus'), color='green') resplot.plot(('cenx', 'cenz'), color='red', type='line', line_style='dot', line_width=.5) plot.x_axis.visible = False # Set ranges to change automatically when plot values change. plot.value_range.low_setting,\ plot.value_range.high_setting = (-minval, maxval) plot.index_range.low_setting,\ plot.index_range.high_setting = (self.line_center - 20., self.line_center + 20.) resplot.value_range.low_setting,\ resplot.value_range.high_setting = (-resmin, resmin) resplot.index_range.low_setting,\ resplot.index_range.high_setting = (plot.index_range.low_setting, plot.index_range.high_setting) #resplot.index_range = plot.index_range # Yes or no? FIXME plot.overlays.append(ZoomTool(plot, tool_mode='box', drag_button='left', always_on=False)) resplot.overlays.append(ZoomTool(resplot, tool_mode='range', drag_button='left', always_on=False)) # List of renderers to tell the legend what to write self.plots['Contin'] = self.contrender self.plots['Center'] = self.centrender self.plots['Model'] = self.modlrender for i in sp.arange(len(self.comprenders)): self.plots[self.CompoList[i]] = self.comprenders[i] # Build Legend: legend = Legend(component=plot, padding=10, align="ur") legend.tools.append(LegendTool(legend, drag_button="right")) legend.plots = self.plots plot.overlays.append(legend) olplot.tools.append(broca) pan = PanTool(plot) respan = PanTool(resplot, constrain=True, constrain_direction='x') broca.tools.append(pan) broca.tools.append(respan) plot.overlays.append(ZoomTool(plot, tool_mode='box', always_on=False)) olplot.add(plot) olplot.add(resplot) olplot.components[0].set(resizable='hv', bounds=[500, 400]) olplot.components[1].set(resizable='h', bounds=[500, 100]) self.plot = plot self.resplot = resplot self.plwin = olplot self.legend = legend self.plotrange = plotrange
def test_empty_container(self): cont = GridContainer(shape=(1,1)) cont.bounds = [100,100] cont.do_layout() return
class Transition(HasTraits): # When based on Pandas, do we even need this class as anything but a viewer # class? I don't think so. # ...but it's a pretty good viewer class, that is something too. """ A Transition-class to keep track of lines/components for a given transition defined by its species and wavelength, with possible common aliases like e.g. H-Alpha """ # We need some information about the spectrum we're working with: spectrum = Instance(Spectrum2D) wavelength = PrototypedFrom('spectrum', prefix='Center') model = PrototypedFrom('spectrum') line_spectra = DelegatesTo('spectrum') Center = DelegatesTo('spectrum') wavl = DelegatesTo('spectrum') CompMarkers = Dict() from_existing = Bool(False) fit_now = Bool(False) transit_list = DelegatesTo('spectrum') select_existing = Str Builddatabutton = Button # For debugging only z = DelegatesTo('spectrum') # Or what? How to handle this? exes = [] wyes = [] cens = [] wids = [] amps = [] def _lookup_nearby_lines(self): ''' Still need to figure out how best to do this. ''' try: from astroquery.atomic import AtomicLineList, Transition except: raise ImportError("Could not find a working `astroquery` install.") labwl = self.wavelength / (1. + self.z) query_range = [(labwl - 5.) * u.AA, (labwl + 5.) * u.AA] try: Q = AtomicLineList.query_object(query_range, 'AIR', transitions=Transition.nebular, nmax=4) except: raise LookupError("Could not perform line lookup or found nothing") Q = pd.DataFrame(Q.as_array()) Q.SPECTRUM += \ '_' + Q['LAMBDA AIR ANG'].map(np.around).astype(int).astype(str) Q['Lambda_0'] = air_to_vacuum(Q['LAMBDA AIR ANG']) Q = Q[['SPECTRUM', 'Lambda_0']] return def _build_trans_list(self): """ When given the Center wavelength value, find the nearby transitions in the system transitions list and let user choose which one to add to the user's transition list. """ lines_srs = load_lines_series() #lookup_success = False #try: # Loclines = self._lookup_nearby_lines() # lines_srs.merge(Loclines, left_index=True, right_on='SPECTRUM') lines_selection = pd.DataFrame(lines_srs, columns=['Lambda_0']) lines_selection['Lambda_obs'] = \ lines_selection['Lambda_0'] * (1. + self.z) lines = lines_selection[sp.absolute(lines_selection['Lambda_obs'] - self.wavelength) <= 35.] # Turn this into a list of strings that Enum understands choices = [ '%s (%.2f)' % (i, lines.ix[i]['Lambda_obs']) for i in lines.index ] if len(choices) > 0: self.add_trait('choices', Enum(choices)) return True else: choices.append('') self.add_trait('choices', Enum(choices)) print 'No lines listed in this neighbourhood.' return False def _z_changed(self): # TODO: Implement! pass def show_trans_model(self): self._build_plot_data() # This to be a conv function rather than a method? I think possibly so. # Main functionality of this can just be a View() in Show2DSpec. But # should it? def __init__(self, spectrum=None, z=0.): if spectrum is not None: super(Transition, self).__init__(spectrum=spectrum) self.Succes = self._build_trans_list() # ========================================================================= # Define the plot that is the main part of the components editor. This # requires an ArrayPlotData object to be defined, which again requires # a bunch of data arrays to be defined and imported from the parent # objects, so this may take a little while to implement. # FIXME: Possibly remove, as most is now in the 2d viewer class. container = GridContainer(padding=30, bgcolor="sys_window", spacing=(15, 15), shape=(3, 1)) transitiondata = ArrayPlotData(wl=wavl, ) # ========================================================================= # This class has two different views called at two different points in # the data reduction - one before and one after fitting. view = View(Item('choices'), Item('wavelength'), Item('line_spectra'), buttons=ModalButtons) Choose = View(Group( HGroup( Item('choices', label='Select line'), Item('from_existing'), Item('select_existing', enabled_when='from_existing', editor=EnumEditor(name='transit_list')), Item('fit_now', enabled_when='from_existing'), ), Item('z', label='Redshift'), show_border=True, ), buttons=LiveButtons, kind='livemodal', title='Pychelle - add new transition')
def test_row(self): cont = GridContainer(shape=(1, 3), halign="center", valign="center") c1 = StaticPlotComponent([50, 50]) c2 = StaticPlotComponent([30, 30]) c3 = StaticPlotComponent([0, 0], resizable="hv") cont.add(c1, c2, c3) cont.bounds = list(cont.get_preferred_size()) cont.do_layout() self.assert_tuple(c1.position, (0, 0)) self.assert_tuple(c1.bounds, (50, 50)) self.assert_tuple(c2.position, (50, 10)) self.assert_tuple(c2.bounds, (30, 30)) self.assert_tuple(c3.position, (80, 0)) self.assert_tuple(c3.bounds, (0, 50)) cont.bounds = [100, 50] cont.do_layout() self.assert_tuple(c1.position, (0, 0)) self.assert_tuple(c1.bounds, (50, 50)) self.assert_tuple(c2.position, (50, 10)) self.assert_tuple(c2.bounds, (30, 30)) self.assert_tuple(c3.position, (80, 0)) self.assert_tuple(c3.bounds, (20, 50)) return