From e0f93656233b730f7aa29410813dc6032ba7ebf2 Mon Sep 17 00:00:00 2001 From: Yan Wong Date: Sat, 7 Jun 2025 10:28:08 +0100 Subject: [PATCH 1/4] Make SVG standard widths and heights available in the class definition --- python/tskit/drawing.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python/tskit/drawing.py b/python/tskit/drawing.py index 1d186d6c5a..1dfc37a627 100644 --- a/python/tskit/drawing.py +++ b/python/tskit/drawing.py @@ -860,6 +860,8 @@ class SvgPlot: text_height = 14 # May want to calculate this based on a font size line_height = text_height * 1.2 # allowing padding above and below a line + default_width = 200 # for a single tree + default_height = 200 def __init__( self, @@ -1361,7 +1363,7 @@ def __init__( use_skipped = np.append(np.diff(self.tree_status & OMIT_MIDDLE == 0) == 1, 0) num_plotboxes = np.sum(np.logical_or(use_tree, use_skipped)) if size is None: - size = (200 * int(num_plotboxes), 200) + size = (self.default_width * int(num_plotboxes), self.default_height) if max_time is None: max_time = "ts" if min_time is None: @@ -1674,7 +1676,7 @@ def __init__( stacklevel=4, ) if size is None: - size = (200, 200) + size = (self.default_width, self.default_height) if symbol_size is None: symbol_size = 6 self.symbol_size = symbol_size From c8f8ca1a05b549bb27dfe7b3519140848b718da7 Mon Sep 17 00:00:00 2001 From: Yan Wong Date: Sat, 7 Jun 2025 11:59:55 +0100 Subject: [PATCH 2/4] Remove code duplication by moving the draw function into the drawing module --- python/tskit/drawing.py | 7 +++++++ python/tskit/trees.py | 16 ++++------------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/python/tskit/drawing.py b/python/tskit/drawing.py index 1dfc37a627..2ebfb6ff43 100644 --- a/python/tskit/drawing.py +++ b/python/tskit/drawing.py @@ -894,6 +894,13 @@ def __init__( self.dwg_base = dwg.add(dwg.g(class_=svg_class)) self.drawing = dwg + def draw(self, path=None): + output = self.drawing.tostring() + if path is not None: + # TODO remove the 'pretty' when we are done debugging this. + self.drawing.saveas(path, pretty=True) + return SVGString(output) + def get_plotbox(self): """ Get the svgwrite plotbox, creating it if necessary. diff --git a/python/tskit/trees.py b/python/tskit/trees.py index c05fd6ca44..e11942a3b8 100644 --- a/python/tskit/trees.py +++ b/python/tskit/trees.py @@ -1964,7 +1964,7 @@ def draw_svg( :return: An SVG representation of a tree. :rtype: SVGString """ - draw = drawing.SvgTree( + svgtree = drawing.SvgTree( self, size, time_scale=time_scale, @@ -1995,11 +1995,7 @@ def draw_svg( preamble=preamble, **kwargs, ) - output = draw.drawing.tostring() - if path is not None: - # TODO: removed the pretty here when this is stable. - draw.drawing.saveas(path, pretty=True) - return drawing.SVGString(output) + return svgtree.draw(path) def draw( self, @@ -7599,7 +7595,7 @@ def draw_svg( strictly within an empty region then that tree will not be plotted on the right hand side, and the X axis will end at ``empty_tree.interval.left`` """ - draw = drawing.SvgTreeSequence( + svgtreesequence = drawing.SvgTreeSequence( self, size, x_scale=x_scale, @@ -7629,11 +7625,7 @@ def draw_svg( preamble=preamble, **kwargs, ) - output = draw.drawing.tostring() - if path is not None: - # TODO remove the 'pretty' when we are done debugging this. - draw.drawing.saveas(path, pretty=True) - return drawing.SVGString(output) + return svgtreesequence.draw(path) def draw_text( self, From 8ccd2499a8852efc3425f45648501c42b23f61bc Mon Sep 17 00:00:00 2001 From: Yan Wong Date: Sat, 7 Jun 2025 20:08:01 +0100 Subject: [PATCH 3/4] Remove unused `debug` param This currently does nothing anyway. --- python/tskit/drawing.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/python/tskit/drawing.py b/python/tskit/drawing.py index 2ebfb6ff43..3f1df0a38b 100644 --- a/python/tskit/drawing.py +++ b/python/tskit/drawing.py @@ -134,7 +134,7 @@ def tostring(self): class Drawing: - def __init__(self, size=None, debug=False, preamble=None, **kwargs): + def __init__(self, size=None, preamble=None, **kwargs): kwargs = { "version": "1.1", "xmlns": "http://www.w3.org/2000/svg", @@ -881,9 +881,7 @@ def __init__( root_svg_attributes = {} if canvas_size is None: canvas_size = size - dwg = Drawing( - size=canvas_size, debug=True, preamble=preamble, **root_svg_attributes - ) + dwg = Drawing(size=canvas_size, preamble=None, **root_svg_attributes) self.image_size = size self.plotbox = Plotbox(size) From dcb9cff441d9268d83410191595b952d4a3abd4a Mon Sep 17 00:00:00 2001 From: Yan Wong Date: Sat, 7 Jun 2025 12:36:49 +0100 Subject: [PATCH 4/4] Change when preamble is inserted Put a placeholder in, then actually place it on `draw`. This allows the preamble to be (re)set after init but before actually drawing, which can be useful for complex composite drawings. --- python/tskit/drawing.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/python/tskit/drawing.py b/python/tskit/drawing.py index 3f1df0a38b..6a093e4076 100644 --- a/python/tskit/drawing.py +++ b/python/tskit/drawing.py @@ -134,7 +134,7 @@ def tostring(self): class Drawing: - def __init__(self, size=None, preamble=None, **kwargs): + def __init__(self, size=None, **kwargs): kwargs = { "version": "1.1", "xmlns": "http://www.w3.org/2000/svg", @@ -148,8 +148,7 @@ def __init__(self, size=None, preamble=None, **kwargs): kwargs["height"] = size[1] self.root = Element("svg", **kwargs) - if preamble is not None: - self.root.add(preamble) + self.root.add("") # First root elem is a blank preamble self.defs = Element("defs") self.root.add(self.defs) @@ -881,8 +880,9 @@ def __init__( root_svg_attributes = {} if canvas_size is None: canvas_size = size - dwg = Drawing(size=canvas_size, preamble=None, **root_svg_attributes) + dwg = Drawing(size=canvas_size, **root_svg_attributes) + self.preamble = preamble self.image_size = size self.plotbox = Plotbox(size) self.root_groups = {} @@ -893,6 +893,8 @@ def __init__( self.drawing = dwg def draw(self, path=None): + if self.preamble is not None: + self.drawing.root.children[0] = self.preamble output = self.drawing.tostring() if path is not None: # TODO remove the 'pretty' when we are done debugging this.