class PlanDVHGraphTestCase(ConradTestCase): @classmethod def setUpClass(self): self.beams = 50 self.anatomy = Anatomy([ Structure(0, 'PTV', True, A=np.random.rand(100, self.beams)), Structure(1, 'OAR1', False, A=np.random.rand(300, self.beams)), Structure(2, 'OAR2', False, A=np.random.rand(250, self.beams)) ]) self.anatomy['PTV'].constraints += D(80) > 40 * Gy self.anatomy['PTV'].constraints += D(20) < 45 * Gy def test_plandvh_graph_init(self): # explicit initialization pd = self.anatomy.plotting_data() pdg = PlanDVHGraph(pd) self.assertIsInstance(pdg.structure_DVHs, dict) for structure in self.anatomy: self.assertIn(structure.label, pdg.structure_DVHs) self.assertIn(structure.label, pdg.structure_labels) self.assertIn(structure.label, pdg.structure_colors) self.assertIsInstance(pdg[structure.label], StructureDVHGraph) for _, s_dvh in pdg: self.assertIsInstance(s_dvh, StructureDVHGraph) # implicit initialization pdg = PlanDVHGraph(self.anatomy) for structure in self.anatomy: self.assertIsInstance(pdg[structure.label], StructureDVHGraph) for _, s_dvh in pdg: self.assertIsInstance(s_dvh, StructureDVHGraph) def test_plandvh_graph_maxdose(self): self.anatomy.calculate_doses(np.random.rand(self.beams)) pd = self.anatomy.plotting_data() dmax = dmaxdc = 0 for label in pd: sdata = pd[label] dmax = max(dmax, sdata['curve']['dose'][-1]) dmaxdc = max(dmaxdc, dmax) for _, constr in sdata['constraints']: dmaxdc = max(dmaxdc, max(constr['dose'])) pdg = PlanDVHGraph(pd) self.assertEqual(dmaxdc, pdg.maxdose()) self.assertEqual(dmax, pdg.maxdose(exclude_constraints=True))
class PlanConstraintsGraphTestCase(ConradTestCase): @classmethod def setUpClass(self): self.beams = 50 self.anatomy = Anatomy([ Structure(0, 'PTV', True, A=np.random.rand(100, self.beams)), Structure(1, 'OAR1', False, A=np.random.rand(300, self.beams)), Structure(2, 'OAR2', False, A=np.random.rand(250, self.beams)) ]) self.anatomy['PTV'].constraints += D(80) > 40 * Gy self.anatomy['PTV'].constraints += D(20) < 45 * Gy def test_plan_constraints_graph_init(self): # # explicit initialization pd = self.anatomy.plotting_data(constraints_only=True) pcg = PlanConstraintsGraph(pd) self.assertIsInstance(pcg.structure_constraints, dict) for structure in self.anatomy: self.assertIn(structure.label, pcg.structure_constraints) self.assertIn(structure.label, pcg.structure_labels) self.assertIn(structure.label, pcg.structure_colors) self.assertIsInstance(pcg[structure.label], StructureConstraintsGraph) for _, s_constr in pcg: self.assertIsInstance(s_constr, StructureConstraintsGraph) # implicit initialization pcg = PlanConstraintsGraph(self.anatomy) for structure in self.anatomy: self.assertIsInstance(pcg[structure.label], StructureConstraintsGraph) for _, s_constr in pcg: self.assertIsInstance(s_constr, StructureConstraintsGraph) def test_plan_constraints_graph_maxdose(self): self.anatomy.calculate_doses(np.random.rand(self.beams)) pd = self.anatomy.plotting_data(constraints_only=True) dmax = 0 for label in pd: for _, constr in pd[label]: dmax = max(dmax, max(constr['dose'])) pcg = PlanConstraintsGraph(pd) self.assertEqual(dmax, pcg.maxdose)
class DVHPlotTestCase(ConradTestCase): @classmethod def setUpClass(self): self.beams = 50 self.anatomy = Anatomy([ Structure(0, 'PTV', True, A=np.random.rand(100, self.beams)), Structure(1, 'OAR1', False, A=np.random.rand(300, self.beams)), Structure(2, 'OAR2', False, A=np.random.rand(250, self.beams)) ]) self.panel_assignments = {0: 0, 1: 0, 2: 0} self.names = {0: 'PTV', 1: 'OAR1', 2: 'OAR2'} self.case = Case(anatomy=self.anatomy) def setUp(self): self.build_call = DVHPlot.build def tearDown(self): DVHPlot.build = self.build_call def test_dvhplot_init_properties(self): DVHPlot.build = lambda arg_self: None d = DVHPlot(self.panel_assignments) self.assertNotIsInstance(d.figure, mpl.figure.Figure) self.assertEqual(d.n_structures, 3) self.assertIsInstance(d.subplots, dict) self.assertEqual(len(d.subplots), 0) self.assertIsInstance(d.panels, list) self.assertEqual(len(d.panels), 0) for k, v in d.subplot_assignments.items(): self.assertEqual(self.panel_assignments[k], v) self.assertEqual(d.cols, 1) self.assertEqual(d.rows, 1) self.assertEqual(d.layout, 'auto') def test_dvhplot_panels_to_cols(self): DVHPlot.build = lambda arg_self: None d = DVHPlot(self.panel_assignments) self.assertEqual(d.subplots_to_cols(1), 1) self.assertEqual(d.subplots_to_cols(2), 2) self.assertEqual(d.subplots_to_cols(3), 2) self.assertEqual(d.subplots_to_cols(4), 2) self.assertEqual(d.subplots_to_cols(5), 3) self.assertEqual(d.subplots_to_cols(6), 3) self.assertEqual(d.subplots_to_cols(7), 4) self.assertEqual(d.subplots_to_cols(8), 4) self.assertEqual(d.subplots_to_cols(12), 4) self.assertEqual(d.subplots_to_cols(15), 4) self.assertEqual(d.subplots_to_cols(25), 4) def test_dvhplot_sift_options(self): DVHPlot.build = lambda arg_self: None d = DVHPlot(self.panel_assignments) options = { 'legend_opt1': 1, 'legend_opt2': 2, 'other_opt1': 3, 'other_opt2': 4 } legend_options = {'opt1': 1, 'opt2': 2} other_options = {'other_opt1': 3, 'other_opt2': 4} o_opt, l_opt = d.sift_options(**options) for k, v in legend_options.items(): self.assertEqual(l_opt[k], v) for k, v in other_options.items(): self.assertEqual(o_opt[k], v) def test_dvhplot_build_clear(self): DVHPlot.build = lambda arg_self: None d = DVHPlot(self.panel_assignments) self.assertNotIsInstance(d.figure, mpl.figure.Figure) self.assertIsInstance(d.subplots, dict) self.assertEqual(len(d.subplots), 0) self.assertIsInstance(d.panels, list) self.assertEqual(len(d.panels), 0) # test calculate panels d.calculate_panels() self.assertEqual(d.n_subplots, 1) self.assertEqual(d.rows, 1) self.assertEqual(d.cols, 1) d._DVHPlot__subplot_assignments_by_structure = {0: 0, 1: 1, 2: 2} d.calculate_panels() self.assertEqual(d.n_subplots, 3) self.assertEqual(d.rows, 2) self.assertEqual(d.cols, 2) d._DVHPlot__layout = 'vertical' d.calculate_panels() self.assertEqual(d.n_subplots, 3) self.assertEqual(d.rows, 3) self.assertEqual(d.cols, 1) d._DVHPlot__layout = 'horizontal' d.calculate_panels() self.assertEqual(d.n_subplots, 3) self.assertEqual(d.rows, 1) self.assertEqual(d.cols, 3) # test build/clear DVHPlot.build = self.build_call d._DVHPlot__layout = 'auto' d.subplot_assignments = {0: 0, 1: 0, 2: 0} d.build() self.assertIsInstance(d.figure, mpl.figure.Figure) self.assertEqual(len(d.subplots), 3) for sp in d.subplots.values(): self.assertIsInstance(sp, DVHSubplot) self.assertIsInstance(d.panels, list) self.assertEqual(len(d.panels), 1) for sp in d.panels: self.assertIsInstance(sp, DVHSubplot) d.clear() self.assertNotIsInstance(d.figure, mpl.figure.Figure) self.assertIsInstance(d.subplots, dict) self.assertEqual(len(d.subplots), 0) self.assertIsInstance(d.panels, list) self.assertEqual(len(d.panels), 0) def test_dvhplot_panels_layout(self): d = DVHPlot(self.panel_assignments) self.assertIsInstance(d.figure, mpl.figure.Figure) self.assertEqual(d.n_subplots, 1) self.assertEqual(d.rows, 1) self.assertEqual(d.cols, 1) self.assertEqual(len(d.subplots), 3) self.assertEqual(len(d.panels), 1) for i in xrange(3): self.assertEqual(d.subplots[i], d.panels[0]) self.assertTrue(d.subplots[i].bottom) self.assertTrue(d.subplots[i].left) d.subplot_assignments = {0: 0, 1: 1, 2: 2} d.build() self.assertEqual(d.n_subplots, 3) self.assertEqual(d.rows, 2) self.assertEqual(d.cols, 2) self.assertEqual(len(d.subplots), 3) self.assertEqual(len(d.panels), 3) for i in xrange(3): self.assertEqual(d.subplots[i], d.panels[i]) self.assertEqual(d.subplots[i].bottom, bool(i >= d.cols)) self.assertEqual(d.subplots[i].left, bool(i % d.cols == 0)) d.layout = 'vertical' self.assertEqual(d.n_subplots, 3) self.assertEqual(d.rows, 3) self.assertEqual(d.cols, 1) self.assertEqual(len(d.subplots), 3) self.assertEqual(len(d.panels), 3) for i in xrange(3): self.assertEqual(d.subplots[i], d.panels[i]) self.assertEqual(d.subplots[i].bottom, bool(i == d.n_subplots - 1)) self.assertTrue(d.subplots[i].left) d.layout = 'horizontal' self.assertEqual(d.n_subplots, 3) self.assertEqual(d.rows, 1) self.assertEqual(d.cols, 3) self.assertEqual(len(d.subplots), 3) self.assertEqual(len(d.panels), 3) for i in xrange(3): self.assertEqual(d.subplots[i], d.panels[i]) self.assertTrue(d.subplots[i].bottom) self.assertEqual(d.subplots[i].left, bool(i == 0)) with self.assertRaises(ValueError): d.layout = 'not a valid layout string' def test_dvhplot_getitem(self): d = DVHPlot(self.panel_assignments) for key in [0, 1, 2, 'upper right']: self.assertIsInstance(d[key], DVHSubplot) self.assertEqual(d[key], d.panels[0]) d.subplot_assignments = {0: 0, 1: 1, 2: 2} d.build() for key in [0, 1, 2, 'upper right']: self.assertIsInstance(d[key], DVHSubplot) if isinstance(key, int): self.assertEqual(d[key], d.panels[key]) else: self.assertEqual(d[key], d.panels[1]) d.layout = 'horizontal' self.assertEqual(d['upper right'], d.panels[-1]) def test_dvhplot_drawlegend(self): d = DVHPlot(self.panel_assignments) series = [mpl.lines.Line2D([], []) for i in xrange(3)] names = ['first', 'second', 'third'] self.assertEqual(len(d.figure.legends), 0) d.draw_legend(series, names) self.assertEqual(len(d.figure.legends), 1) self.assertEqual(len(d.figure.legends[-1].get_lines()), len(series)) for text in d.figure.legends[-1].get_texts(): self.assertTrue(text.get_text() in names) # coordinates width = d.figure.legends[-1].get_bbox_to_anchor().x1 height = d.figure.legends[-1].get_bbox_to_anchor().y1 coords = [0.5, 0.6] d.draw_legend(series, names, coordinates=coords) origin_x = d.figure.legends[-1].get_bbox_to_anchor().x0 origin_y = d.figure.legends[-1].get_bbox_to_anchor().y0 self.assertTrue(coords[0] * width == origin_x) self.assertTrue(coords[1] * height == origin_y) # location d.draw_legend(series, names, coordinates=coords, alignment='right') d.draw_legend(series, names, coordinates=coords, alignment='center') self.assertNotEqual(d.figure.legends[-2]._loc, d.figure.legends[-1]._loc) def test_dvhplot_drawtitle(self): d = DVHPlot(self.panel_assignments) d.draw_title('test title') self.assertEqual(d.figure.texts[-1].get_text(), 'test title') def test_dvhplot_format_subplots(self): d = DVHPlot(self.panel_assignments) xmax = 50. d.format_subplots(xmax) for subplot in d.panels: self.assertEqual(subplot.xmax, xmax) def test_check_figure(self): DVHPlot.build = lambda arg_self: None d = DVHPlot(self.panel_assignments) with self.assertRaises(AttributeError): d.check_figure() DVHPlot.build = self.build_call d = DVHPlot(self.panel_assignments) d.check_figure() d.clear() with self.assertRaises(AttributeError): d.check_figure() def test_dvhplot_plotvirtual(self): d = DVHPlot(self.panel_assignments) series_names = ['first', 'second', 'third'] series_aesthetics = [LineAesthetic() for i in xrange(3)] d.plot_virtual(series_names, series_aesthetics) self.assertEqual(len(d.figure.legends), 1) self.assertEqual(len(d.figure.legends[-1].get_lines()), 3) for text in d.figure.legends[-1].get_texts(): self.assertIn(text.get_text(), series_names) def test_dvhplot_plotlabels(self): d = DVHPlot(self.panel_assignments) coords = (0.5, 0.6) d.plot_labels({1: coords}, self.anatomy.plotting_data()) self.assertEqual(len(d.subplots[1].axes.texts), 1) t = d.subplots[1].axes.texts[-1] self.assertEqual(t.get_text(), self.anatomy[1].name) self.assertEqual(t.get_unitless_position(), coords) with self.assertRaises(KeyError): d.plot_labels({4: coords}, self.anatomy.plotting_data()) def test_dvhplot_plotconstraints(self): d = DVHPlot(self.panel_assignments) LABEL = 0 self.anatomy[LABEL].constraints += D(30) < 20 * Gy pc = PlanConstraintsGraph(self.anatomy) d.plot_constraints(pc) for constr in pc[LABEL]: self.assertIs(constr.axes, d.subplots[LABEL].axes) def test_dvhplot_plot(self): d = DVHPlot({i: i for i in xrange(3)}) d.layout = 'horizontal' LABEL = 0 self.anatomy.calculate_doses(np.random.rand(self.beams)) self.anatomy[LABEL].constraints += D(30) < 20 * Gy pd = PlanDVHGraph(self.anatomy.plotting_data()) # vanilla plot + self-title subplots d.plot(self.anatomy.plotting_data(), self_title_subplots=True) for structure in self.anatomy: self.assertEqual(d.subplots[structure.label].title, structure.name) # individual legends d.plot(self.anatomy.plotting_data(), legend='each') for structure in self.anatomy: self.assertIsNotNone(d.subplots[structure.label].legend) self.assertEqual( len(d.subplots[structure.label].legend.get_lines()), 1) self.assertEqual(len(d.figure.legends), 0) # overall legend d.plot(self.anatomy.plotting_data(), legend=True) for structure in self.anatomy: self.assertIsNone(d.subplots[structure.label].legend) self.assertEqual(len(d.figure.legends), 1) # self-title for multiple structures on single subplot d.subplot_assignments = {i: 0 for i in xrange(3)} d.build() d.plot(pd, self_title_subplots=True) title = '' for label, _ in pd: title += self.anatomy[label].name title += ', ' title = title[:-2] # trim terminal ", " self.assertEqual(d.panels[0].title, title) # def test_dvhplot_show(self): # pass def test_dvhplot_save(self): d = DVHPlot(self.panel_assignments) filename = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'test.pdf') self.assertFalse(os.path.exists(filename)) d.build() d.save(filename) self.assertTrue(os.path.exists(filename)) os.remove(filename) self.assertFalse(os.path.exists(filename))