Skip to content

Modifying existing objects

Scott Pakin edited this page Oct 10, 2025 · 24 revisions

In addition to adding new objects to an image, Simple Inkscape Scripting provides a few mechanisms for modifying existing objects, even those not created using Simple Inkscape Scripting.

Acquiring lists of shapes

The following two functions return lists of shapes appearing in the image, including shapes not created using Simple Inkscape Scripting.

Function: all_shapes()

This function returns a list of all shapes in the image as Simple Inkscape Scripting objects.

Function: selected_shapes()

This function returns a list of all selected shapes in the image as Simple Inkscape Scripting objects.

For both all_shapes and selected_shapes, groups count as shapes, but layers do not.

Example:

for obj in selected_shapes():
    obj.rotate(uniform(-45, 45), 'center', first=True)

The preceding example rotates each selected shape around its center by a random angle from −45° to +45°.

The following property on all Simple Inkscape Scripting shape objects can be used to filter the lists returned by all_shapes and selected_shapes:

Property: tag (type str)

tag returns the underlying SVG element's tag. For example, an ellipse's tag is ellipse; a rectangle's tag is rect; a group's tag is g; and a clone of any element is use. Most Inkscape-specific shapes such as regular polygons, stars, and spirals have a tag of path; 3‑D boxes comprise multiple path elements.

Applying shape transformations

Simple Inkscape Scripting provides a number of mechanisms for modifying the transformation applied to a shape object.

Applying individual transformations

Individual transformations operations can be applied using the following methods:

Method: translate((x, y), first, relocate)

Method: rotate(angle, anchor, first)

Method: scale(factor, anchor, first)

Method: skew((sx, sy), anchor, first)

We demonstrate usage of these methods using the following base shapes:

Example:

blue = rect((90, 0), (170, 50), fill='#55ddff')
red = rect((0, 0), (80, 50), fill='#ff5555')

Two rectangles with no transformations applied

Dashed lines were added to the above to serve as a visual reference point for the transformations.

rotate, scale, and skew each take an optional anchor argument that specifies the point around which the object rotates, scales, or skews. anchor can be either an (x, y) coordinate or one of the following strings:

  • c or center. Transform around the shape's center.
  • ul or nw. Transform around the shape's upper-left (northwest) corner.
  • ur or ne. Transform around the shape's upper-right (northeast) corner.
  • ll or sw. Transform around the shape's lower-left (southwest) corner.
  • lr or se. Transform around the shape's lower-right (southeast) corner.
  • n. Transform around the shape's top-center (north) point.
  • e. Transform around the shape's middle-right (east) point.
  • s. Transform around the shape's bottom-center (south) point.
  • w. Transform around the shape's middle-left (west) point.

Note that all of those positions are computed using the shape's bounding box, not necessarily points on the shape itself:

Named anchors on a shape's bounding box

At the time of this writing, Inkscape does not compute proper bounding boxes for text objects.

anchor defaults to "center".

All four transformation methods take an optional first parameter that, if True, causes the transformation to be applied before all existing transformations. In the default, False, case, the transformation is applied after all existing transformations. See the advice below on when to use first=True and when to use first=False.

The translate method moves the shape x units to the right and y units down.

Example:

blue = rect((90, 0), (170, 50), fill='#55ddff')
red = rect((0, 0), (80, 50), fill='#ff5555')
red.translate((50, 30))

Translating the red rectangle

Unlike the other three transformation methods, translate additionally takes an optional relocate parameter. If relocate is False (the default), a transformation is applied to the otherwise unmodified object. If relocate is True, the object's coordinates are rewritten to translate the object to a new location. In essence, this operation is like a "super" first=True in that the translation occurs before any transformations are applied.

To contrast relocate=False and relocate=True, consider the SVG corresponding to the original, blue rectangle:

<rect
   x="90"
   y="0"
   width="80"
   height="50"
   id="rect1509" />

Moving the rectangle 100 pixels to the right with

blue.translate((100, 0), relocate=False)

(where the relocate=False can be omitted) leaves the rectangle's upper-left corner at (90, 0) but adds a transformation to render the rectangle 100 pixels to the right of its natural location:

<rect
   x="90"
   y="0"
   width="80"
   height="50"
   style="stroke:black;fill:#55ddff"
   id="rect1509"
   transform="translate(100, 0)" />

Moving the rectangle 100 pixels to the right instead with

blue.translate((100, 0), relocate=True)

actually changes the rectangle's upper-left corner from (90, 0) to (190, 0):

<rect
   x="190"
   y="0"
   width="80"
   height="50"
   id="rect1509" />

Any transformations subsequently applied will translate, rotate, scale, or skew the rectangle relative to these new coordinates.

The rotate method rotates the shape clockwise by a given number of degrees.

Example (rotation around the object's center):

blue = rect((90, 0), (170, 50), fill='#55ddff')
red = rect((0, 0), (80, 50), fill='#ff5555')
red.rotate(30)

Rotating the red rectangle around its center

Example (rotation around an arbitrary point):

blue = rect((90, 0), (170, 50), fill='#55ddff')
red = rect((0, 0), (80, 50), fill='#ff5555')
red.rotate(30, (85, 25))

Rotating the red rectangle around an arbitrary point

A dot was added to the above to label the center of rotation.

Example (rotation around the shape's lower-left corner):

blue = rect((90, 0), (170, 50), fill='#55ddff')
red = rect((0, 0), (80, 50), fill='#ff5555')
red.rotate(30, 'll')

Rotating the red rectangle around its lower-left corner

The scale method multiplies the shape's size by a given factor, factor. If factor is a 2-tuple, it scales horizontally and vertically by different factors.

Example (uniform scaling):

blue = rect((90, 0), (170, 50), fill='#55ddff')
red = rect((0, 0), (80, 50), fill='#ff5555')
red.scale(1.5)

Scaling the red rectangle uniformly from its center

Example (nonuniform scaling):

blue = rect((90, 0), (170, 50), fill='#55ddff')
red = rect((0, 0), (80, 50), fill='#ff5555')
red.scale((0.75, 1.5))

Scaling the red rectangle non-uniformly

Example (uniform scaling relative to the shape's upper-right corner):

blue = rect((90, 0), (170, 50), fill='#55ddff')
red = rect((0, 0), (80, 50), fill='#ff5555')
red.scale(1.5, 'ur')

Scaling the red rectangle uniformly from its upper-right corner

The skew method skews the shape by a given number of degrees along the x axis and a given number of degrees along the y axis.

Example (skew x only):

blue = rect((90, 0), (170, 50), fill='#55ddff')
red = rect((0, 0), (80, 50), fill='#ff5555')
red.skew((10, 0))

Skewing the red rectangle horizontally from its center

Example (skew y only):

blue = rect((90, 0), (170, 50), fill='#55ddff')
red = rect((0, 0), (80, 50), fill='#ff5555')
red.skew((0, 10))

Skewing the red rectangle vertically from its center

Example (skew y only, with the skewing anchored at the shape's lower-right corner):

blue = rect((90, 0), (170, 50), fill='#55ddff')
red = rect((0, 0), (80, 50), fill='#ff5555')
red.skew((0, 10), 'lr')

Skewing the red rectangle vertically from its lower-right corner

The translate, rotate, scale, and skew methods can be chained, as in the following example.

Example (chained scaling and rotation):

blue = rect((90, 0), (170, 50), fill='#55ddff')
red = rect((0, 0), (80, 50), fill='#ff5555')
red.scale(1.5, 'ul').rotate(14, 'ul')

Scaling then rotating the red rectangle

Advice for the use of first

The following are some general guidelines for the use of the optional first parameter to the translate, rotate, scale, and skew methods:

  • When constructing an object from scratch, consider using first=False (the default).

  • When modifying an existing object, consider specifying first=True.

Constructing. As an example of constructing an object from scratch and applying transformations to it, consider the following base shape:

p = polygon([(0, 0), (-100, 0), (-80, -55), (-20, -55)], fill='#37abc8', opacity=0.8)

A polygon with no transformations applied

(A grid was added to the above to clarify the polygon's position.)

For our set of transformations, we first scale the shape by a factor of 0.75:

p = polygon([(0, 0), (-100, 0), (-80, -55), (-20, -55)], fill='#37abc8', opacity=0.8)
p.scale(0.75)

A polygon scaled to 75% of its original size

Then we rotate the scaled shape by 60°:

p = polygon([(0, 0), (-100, 0), (-80, -55), (-20, -55)], fill='#37abc8', opacity=0.8)
p.scale(0.75)
p.rotate(60)

A polygon first scaled then rotated

Finally, we translate the scaled, rotated shape by (150, 130) units:

p = polygon([(0, 0), (-100, 0), (-80, -55), (-20, -55)], fill='#37abc8', opacity=0.8)
p.scale(0.75)
p.rotate(60)
p.translate((150, 130))

A polygon scaled then rotated then translated

The above are all based on the default of first=False. Had we instead specified first=True for each transformation, the shape would have wound up in a very different location:

p = polygon([(0, 0), (-100, 0), (-80, -55), (-20, -55)], fill='#37abc8', opacity=0.8)
p.scale(0.75, first=True)
p.rotate(60, first=True)
p.translate((150, 130), first=True)

A polygon scaled, rotated, and translated with first=True, thereby reversing the order these transformations are applied

This is because the first=True flags cause the transformations to be applied in the reverse of program order: translate is applied first, then rotate (around the translated origin), and finally scale.

Modifying. As an example of modifying an existing object, assume we are given the following shape, which has an arbitrary tranformation applied to it. (It happens to be matrix(0.919785 0.978952 -0.865874 0.448312 198.685 220.311), but that's not important to this example.)

A shape with a pre-existing transformation applied

Now suppose we want to rotate that shape counterclockwise by 20° around its center. rotate(-20, 'center') (or, equivalently, rotate(-20, 'center', first=False)) does not behave as one might expect:

Rotating a shape after its pre-existing transformation

This is because the rotation is being applied in a transformed coordinate system. Applying the rotation with rotate(-20, 'center', first=True) ensures the rotation is applied in the original coordinate system:

Rotating a shape before its pre-existing transformation

All of the previously applied transformations are reapplied after the rotation.

Replacing the entire transformation

An alternative to the translate, rotate, scale, and skew methods is the following property, which can be both read and assigned:

Property: transform (type inkex.Transform)

For convenience, a string assigned to transform will be converted automatically to an inkex.Transform. The following examples present equivalent means for drawing a rectangle around the origin then rotating it by 30° and translating it to the center of the page:

Example (providing a string for the transform argument):

rect((-200, -200), (200, 200), fill='#d7f4ee',
     transform='translate(%g, %g) rotate(30)' % (canvas.width/2, canvas.height/2))

Specifying a complete transformation as a string

Example (assigning a string to the transform property):

r = rect((-200, -200), (200, 200), fill='#d7f4ee')
r.transform = 'translate(%g, %g) rotate(30)' % (canvas.width/2, canvas.height/2)

Example (invoking methods on the transform property):

r = rect((-200, -200), (200, 200), fill='#d7f4ee')
r.transform = r.transform.add_translate(canvas.width/2, canvas.height/2)
r.transform = r.transform.add_rotate(30)

Note that transformations are applied left-to-right. Therefore, even though the above invokes add_translate before add_rotate, the effect is first to rotate the rectangle then translate it.

Example (applying inkex.Transforms to the existing transform property):

r = rect((-200, -200), (200, 200), fill='#d7f4ee')
r.transform = inkex.Transform('rotate(30)') * r.transform
r.transform = inkex.Transform('translate(%g, %g)' % (canvas.width/2, canvas.height/2)) * r.transform

With explicit use of the * operator, transformations can be specified in the order they will be applied, as in the above.

Transforming a path

The methods described thus far associate transformations with an arbitrary, unmodified shape. In the specific case of path objects (e.g., those created with the path command), Simple Inkscape Scripting additionally provides methods to transform the path's control points themselves:

Method: translate_path((x, y))

Method: rotate_path(angle, anchor)

Method: scale_path(factor, anchor)

Method: skew_path((sx, sy), anchor)

Each of those methods returns the transformed path object itself. This enables chaining of transformations, e.g., with p = path(…).rotate_path(…).scale_path(…). See the descriptions of translate, rotate, scale, and skew in Applying individual transformations for explanations of the various arguments.

We demonstrate usage of the path-transforming methods using the following base path:

Example:

S = path([Move(57, 13),
          Vert(28),
          Quadratic(52, 25, 46, 24),
          Quadratic(41, 23, 36, 23),
          Quadratic(29, 23, 26, 25),
          Quadratic(23, 26, 23, 30),
          Quadratic(23, 33, 25, 35),
          Quadratic(27, 36, 33, 37),
          Line(40, 39),
          Quadratic(52, 41, 57, 46),
          Quadratic(62, 51, 62, 60),
          Quadratic(62, 71, 55, 77),
          Quadratic(48, 82, 34, 82),
          Quadratic(27, 82, 21, 81),
          Quadratic(14, 80, 7, 77),
          Vert(62),
          Quadratic(14, 66, 20, 68),
          Quadratic(26, 69, 32, 69),
          Quadratic(38, 69, 41, 67),
          Quadratic(44, 65, 44, 62),
          Quadratic(44, 58, 42, 57),
          Quadratic(40, 55, 34, 53),
          Line(27, 52),
          Quadratic(16, 50, 11, 45),
          Quadratic(7, 40, 7, 31),
          Quadratic(7, 21, 13, 15),
          Quadratic(20, 10, 33, 10),
          Quadratic(39, 10, 45, 11),
          Quadratic(51, 12, 57, 13),
          ZoneClose()],
         fill='#decd87', stroke_width=5)

A complex path with no transformation applied

The translate_path method moves the adjusts the path's control points x units to the right and y units down.

The rotate_path method rotates the path's control points clockwise by a given number of degrees.

Example:

S.rotate_path(-22)

A complex path with path coordinates rotated

The scale_path method multiplies the path's control-point coordinates by a given factor, factor. If factor is a 2-tuple, it scales horizontally and vertically by different factors.

Example:

S.scale_path((3, 1), 'ul')

A complex path with path coordinates scaled non-uniformly

Scaling a path provides a clear contrast with applying a scale transformation:

Example:

S.scale((3, 1), 'ul')

A complex path scaled non-uniformly as a complete object, not as individual coordinates

With (3, 1) path scaling, the stroke retains its constant thickness throughout the object. Applying a (3, 1) scale transformation, however, makes the stroke three times as wide as it is tall. A distinction can also be observed in the generated SVG code:

Original:

<path
   d="M 57 13 V 28 Q 52 25 46 24 Q 41 23 36 23 Q 29 23 26 25 Q 23 26 23 30 Q 23 33 25 35 Q 27 36 33 37 L 40 39 Q 52 41 57 46 Q 62 51 62 60 Q 62 71 55 77 Q 48 82 34 82 Q 27 82 21 81 Q 14 80 7 77 V 62 Q 14 66 20 68 Q 26 69 32 69 Q 38 69 41 67 Q 44 65 44 62 Q 44 58 42 57 Q 40 55 34 53 L 27 52 Q 16 50 11 45 Q 7 40 7 31 Q 7 21 13 15 Q 20 10 33 10 Q 39 10 45 11 Q 51 12 57 13 Z"
   style="stroke:black;fill:#decd87;stroke-width:5"
   id="path1" />

Path scaling:

<path
   d="M 171 13 L 171 28 Q 156 25 138 24 Q 123 23 108 23 Q 87 23 78 25 Q 69 26 69 30 Q 69 33 75 35 Q 81 36 99 37 L 120 39 Q 156 41 171 46 Q 186 51 186 60 Q 186 71 165 77 Q 144 82 102 82 Q 81 82 63 81 Q 42 80 21 77 L 21 62 Q 42 66 60 68 Q 78 69 96 69 Q 114 69 123 67 Q 132 65 132 62 Q 132 58 126 57 Q 120 55 102 53 L 81 52 Q 48 50 33 45 Q 21 40 21 31 Q 21 21 39 15 Q 60 10 99 10 Q 117 10 135 11 Q 153 12 171 13 Z"
   style="stroke:black;fill:#decd87;stroke-width:5"
   id="path1" />

Scale transformation:

   d="M 57 13 V 28 Q 52 25 46 24 Q 41 23 36 23 Q 29 23 26 25 Q 23 26 23 30 Q 23 33 25 35 Q 27 36 33 37 L 40 39 Q 52 41 57 46 Q 62 51 62 60 Q 62 71 55 77 Q 48 82 34 82 Q 27 82 21 81 Q 14 80 7 77 V 62 Q 14 66 20 68 Q 26 69 32 69 Q 38 69 41 67 Q 44 65 44 62 Q 44 58 42 57 Q 40 55 34 53 L 27 52 Q 16 50 11 45 Q 7 40 7 31 Q 7 21 13 15 Q 20 10 33 10 Q 39 10 45 11 Q 51 12 57 13 Z"
   style="stroke:black;fill:#decd87;stroke-width:5"
   transform="matrix(3 0 0 1 -14 0)"
   id="path1" />

The Original and Scale transformation code use the same path specification (d attribute), but the Scale transformation code includes an additional transform attribute. In contrast, the Path scaling code contains a modified path specification but no transform attribute.

The skew_path method skews the coordinate of the path's control points by a given number of degrees along the x axis and a given number of degrees along the y axis.

Example:

S.skew_path((-30, 0), 'll')

A complex path with path coordinates skewed horizontally

Aligning shapes

A Simple Inkscape Scripting script can mimic the alignment operations from Inkscape's ObjectAlign and Distribute… dialog box using the methods presented in Applying individual transformations, the per-object bounding_box method, and some distance calculations. However, for greater convenience, Simple Inkscape Scripting provides the following function for aligning a collection of shapes:

Function: align([obj, …], alignment, anchor, transform)

where [obj, …] is a list of shape objects to align (or, less commonly, a single shape object), alignment specifies the desired horizontal and/or vertical alignment, anchor indicates the anchor relative to which the shape objects in the list should be aligned, and transform causes Simple Inkscape Scripting to align objects by applying translate transformations instead of by modifying each object's coordinates.

The following strings are valid values for alignment:

Direction String Synonym Meaning
horizontal left w Align left (west) sides.
horizontal right e Align right (east) sides.
vertical top n Align top (north) sides.
vertical bottom s Align bottom (south) sides.
horizontal center center_x Align horizontal centers.
vertical middle center_y Align vertical centers.
both ul nw Align upper-left (northwest) corners.
both ur ne Align upper-right (northeast) corners.
both ll sw Align lower-left (southwest) corners.
both lr se Align lower-right (southeast) corners.
both centroid Align both horizontal and vertical centers.

While not commonly needed, a pair of strings can be provided for alignment, specifying one horizontal alignment and one vertical alignment. For example, alignment=('center', 'bottom') aligns all shapes' horizontal centers and bottom edges.

The anchor argument accepts a variety of types. It can be any of

  • a Simple Inkscape Scripting shape object—either a member of [obj, …] or not,
  • a collection of shape objects,
  • an inkex.BoundingBox,
  • a single coordinate, expressed as a tuple of two numbers,
  • a single coordinate, expressed as an inkex.Vector2d, or
  • one of the strings from the following table:
String Synonym Aligns to the bounding box surrounding…
page the page's viewbox
drawing all objects on the page
selection all selected objects
objects shapes all objects in [obj, …]
biggest largest the object in [obj, …] whose bounding box encloses the greatest area
littlest smallest the object in [obj, …] whose bounding box encloses the least area

While Inkscape always aligns objects by altering their coordinates, the align function gives the caller a choice. If transform is False (the default) then align behaves like Inkscape. If transform is True then align applies a shape transformation (viz. translate) individually to each object in [obj, …]. Alignments are visually identical whether transform is False or True; the differences lie in the generated SVG code. See the discussion of the translate method's relocate option under Applying individual transformations for an example of coordinate modification versus transform application.

To demonstrate the align function, we start by placing a set of arbitrary objects on the page:

Example:

style(stroke='none')
my_rect = rect((315, 200), (450, 275), fill='#800080').rotate(-27)
my_ellipse = ellipse((160, 525), (40, 75), fill='#d40000')
my_star = star(5, (584.28571, 350), (46.860626, 20.800316), angles=(0.65569563, 1.2924963), transform='translate(-10, 30)', stroke='none', fill='#668000', stroke_width=2, stroke_linecap='round', stroke_linejoin='round')
my_path = path([
    Move(440, 540),
    Curve(415, 540, 393, 546, 418, 571),
    Curve(458, 611, 448, 601, 418, 641),
    Curve(388, 681, 438, 691, 488, 691),
    Curve(496, 691, 504, 687, 511, 682),
    Curve(502, 669, 494, 654, 488, 641),
    Curve(471, 607, 468, 602, 514, 572),
    Curve(506, 559, 494, 549, 478, 541),
    Curve(470, 541, 454, 539, 440, 540),
    ZoneClose()
], fill='#006680')
my_text = text('', (311, 750), font_size='24px', line_height=1, font_family='FreeSerif', font_weight='bold', fill='#44aa00', text_align='center', text_anchor='middle')
my_text.add_text('Simple Inkscape', (311, 750))
my_text.add_text('Scripting', (311, 775))

Initial set of shapes to align

Starting with that code, we can align the bottom of all shapes to the bottom of the page by appending the following:

Example:

shapes = [my_rect, my_ellipse, my_star, my_path, my_text]
align(shapes, 'bottom', 'page')

Aligning shapes to the bottom of the page

Starting again from the original code, we can align all shapes in a vertical line with their right sides aligned with the path shape's right side:

Example:

shapes = [my_rect, my_ellipse, my_star, my_path, my_text]
align(shapes, 'right', my_path)

Aligning shapes to the right of the path object

Here we translate a single object (the star) to the horizontal and vertical center of all the other objects:

Example:

align(my_star, 'centroid', [my_rect, my_ellipse, my_path, my_text])

Aligning the star to the centroid of the bounding box surrounding all other objects

Finally, we translate each object's upper-right corner to coordinates (300, 200):

Example:

shapes = [my_rect, my_ellipse, my_star, my_path, my_text]
align(shapes, 'ur', (300, 200))

Aligning shapes's upper-right corner with the point (300, 200)

Altering a shape's style

A shape object's style can be read and modified via the following method:

Method: style(key=value, …)

The key=value arguments are as one would pass to a shape-creation function. style returns the shape's current style as a Python dict. Passing no arguments to style is also allowed and is useful for reading a shape's style without modifying it.

The following examples present equivalent means of applying a style to a shape object:

Example (specifying the complete style when creating the object):

polygon([(16, 16), (16, 112), (64, 80), (112, 112), (112, 16), (64, 48)],
        fill='#c8377a', stroke_width=3)

A shape with its style specified upon creation

Example (specifying the complete style after creating the object):

p = polygon([(16, 16), (16, 112), (64, 80), (112, 112), (112, 16), (64, 48)])
p.style(fill='#c8377a', stroke_width=3)

Example (specifying the style in multiple steps after creating the object):

p = polygon([(16, 16), (16, 112), (64, 80), (112, 112), (112, 16), (64, 48)])
p.style(fill='#c8377a')
p.style(stroke_width=3)

The style method can be used to copy a style from one object to another:

Example (copying a style):

# First object
down = -3*pi/2
a = arc((75, 75), 50, (down + pi/5, down - pi/5), arc_type='chord',
        stroke='#677821', fill='#abc837', stroke_width=3)

# Second object, which copies the first object's style
path([Move(224, 112),
      Curve(176,64, 192,32, 256,32),
      Curve(320,32, 336,64, 288,112),
      ZoneClose()],
     **a.style())

Copying one object's style to another object

Because the style method returns a dict, it is easy to alter the style before applying it:

Example (copying and modifying a style):

# First object
down = -3*pi/2
a = arc((75, 75), 50, (down + pi/5, down - pi/5), arc_type='chord',
        stroke='#677821', fill='#abc837', stroke_width=3)

# Second object, which copies the first object's style but triples the
# stroke width
sty = a.style()
sty['stroke_width'] *= 3
path([Move(224, 112),
      Curve(176,64, 192,32, 256,32),
      Curve(320,32, 336,64, 288,112),
      ZoneClose()],
     **sty)

Extracting an object's style and applying a modified version to another object

Removing an existing object

Method: remove()

Invoking remove on any shape object removes the object from the set of objects displayed in the document.

Method: unremove()

Invoking unremove on any object that previously had been removed with remove re-adds it to the top level of the document.

Example:

c = circle((75, 75), 38, fill='darkturquoise', stroke_width=2)
rect((0, 0), (75, 75), fill='aquamarine', stroke_width=2)
c.remove()
c.unremove()

Removing a circle then unremoving it, which puts it on top

The preceding example draws a circle with a square on top of it. It then removes the circle from the image, leaving only the square. Finally, it un-removes the circle, placing it back in the image as if it had just been created. The resulting image is therefore the same as if the script had been,

rect((0, 0), (75, 75), fill='aquamarine', stroke_width=2)
c = circle((75, 75), 38, fill='darkturquoise', stroke_width=2)

SVG-level attribute modifications

Attributes of the SVG element underlying a Simple Inkscape Scripting object can be read and written respectively with the following two methods:

Method: svg_get(attr, as_str)

Method: svg_set(attr, val)

svg_get returns the current value of a named attribute, attr, or None if the element does not define a value for that attribute. If the optional as_str argument is False (the default), the value is returned as an appropriate Python data type. If as_str is True, the value is always returned as a string.

svg_set assigns a value to a named attribute. The value is converted implicitly to a string.

There exist a few special cases for svg_get and svg_set:

  • If val is None, svg_set removes the attribute from the object.

  • If attr is 'transform', svg_get returns an inkex.Transform object. An inkex.Transform provides methods for conversion to a string, conversion to a hexad matrix, composition with other inkex.Transforms, interpolation with other inkex.Transforms, application of additional transformations, and more.

  • If attr is 'transform', svg_set accepts either an inkex.Transform or a string for val.

  • If attr is 'style', svg_get returns a Python dictionary. Hyphens are replaced with underscores in all keys. For example, the SVG style fill:#d45500;stroke:#000000;stroke-width:4;stroke-dasharray:4,8;stop-color:#000000 is returned as {'fill': '#d45500', 'stroke': '#000000', 'stroke_width': 4, 'stroke_dasharray': [4, 8], 'stop_color': '#000000'}. (Note also in this example that stroke_dasharray conveniently maps to a Python list.)

  • If attr is 'style', svg_set accepts for val either a string, a Python dictionary, or an inkex.Style. Either underscores or hyphens can be used as keys; underscores will be converted to hyphens when generating SVG. An inkex.Style provides methods for composing, modifying, interpolating, and performing other operations on styles.

In many cases, the methods and properties described above in Applying shape transformations and Altering a shape's style are a more convenient way of manipulating transforms and styles, respectively.

Changing stacking order

Simple Inkscape Scripting stacks shape objects from back to front. That is, more recently created objects within a layer or level of grouping are drawn on top of less recently created objects in the same layer/group. If Simple Inkscape Scripting is used to modify an existing diagram (using, e.g., with svg_root.selection—see Direct SVG access) or in the rare cases in which it is more convenient to draw objects in a different order from their target Z-order, the following shape-object method can be used:

Method: z_order(target, n)

n is an optional integer. target must be one of the following strings:

  • top. Raise the object above all of its siblings. Equivalent to Inkscape's ObjectRaise to Top.

  • bottom. Lower the object below all of its siblings. Equivalent to Inkscape's ObjectLower to Bottom.

  • raise. Raise the object above its next-higher sibling. Equivalent to Inkscape's ObjectRaise. If n is specified, repeat this operation n times.

  • lower. Lower the object below its next-lower sibling. Equivalent to Inkscape's ObjectLower. If n is specified, repeat this operation n times.

  • to. Make the object the nth lowest of its siblings. Specifying n is required in this case. If n is negative, make the object the (−n)th highest of its siblings.

As examples of the above we start with the following base image of five stacked rectangles, with beige on the bottom, maroon, medium slate blue, and medium sea green in the middle, and tan on top:

Example:

boxes = []
ul = inkex.Vector2d()
for c in ['beige', 'maroon', 'mediumslateblue', 'mediumseagreen', 'tan']:
    boxes.append(rect(ul, ul + (100, 60), fill=c, opacity=0.9))
    ul += (10, 10)

Original stacking order

By invoking the z_order method we can hoist the bottom rectangle to the top:

Example:

boxes = []
ul = inkex.Vector2d()
for c in ['beige', 'maroon', 'mediumslateblue', 'mediumseagreen', 'tan']:
    boxes.append(rect(ul, ul + (100, 60), fill=c, opacity=0.9))
    ul += (10, 10)
boxes[0].z_order('top')

Beige rectangle raised to the top

We can lower the top rectangle to the bottom:

Example:

boxes = []
ul = inkex.Vector2d()
for c in ['beige', 'maroon', 'mediumslateblue', 'mediumseagreen', 'tan']:
    boxes.append(rect(ul, ul + (100, 60), fill=c, opacity=0.9))
    ul += (10, 10)
boxes[-1].z_order('bottom')

Tan rectangle lowered to the bottom

We can raise the medium slate blue rectangle by one position:

Example:

boxes = []
ul = inkex.Vector2d()
for c in ['beige', 'maroon', 'mediumslateblue', 'mediumseagreen', 'tan']:
    boxes.append(rect(ul, ul + (100, 60), fill=c, opacity=0.9))
    ul += (10, 10)
boxes[2].z_order('raise')

Slate-blue rectangle raised by one position

We can lower the medium sea green rectangle by two positions:

Example:

boxes = []
ul = inkex.Vector2d()
for c in ['beige', 'maroon', 'mediumslateblue', 'mediumseagreen', 'tan']:
    boxes.append(rect(ul, ul + (100, 60), fill=c, opacity=0.9))
    ul += (10, 10)
boxes[3].z_order('lower', 2)

Green rectangle lowered by two positions

We can put the maroon rectangle in position 3 so that three other rectangles are beneath it:

Example:

boxes = []
ul = inkex.Vector2d()
for c in ['beige', 'maroon', 'mediumslateblue', 'mediumseagreen', 'tan']:
    boxes.append(rect(ul, ul + (100, 60), fill=c, opacity=0.9))
    ul += (10, 10)
boxes[1].z_order('to', 3)

Maroon rectangle moved to position 3

SVG objects do not maintain an absolute z-index. Rather, the Z-order is defined hierarchically: layers are drawn from bottom to top, with all items in one layer appearing above the items in all preceding layers; within a layer, groups are drawn from bottom to top, with all shapes in one group appearing above the shapes in all preceding groups; within a group, shapes are drawn from bottom to top, with each shape appearing above all preceding shapes. Groups containing other groups or mixtures of shapes and groups follow the same pattern: the last thing drawn at some level appears atop everything preceding it at the same level.

It nevertheless is sometimes useful to be able to query the order in which a set of shapes will be drawn. The following function provides that capability:

Function: z_sort([obj, …])

Given a list of objects, even those appearing in different groups and/or layers, z_sort returns that list sorted in bottom-to-top drawing order. For example, because all of the rectangles in our example lie at the same level we can reverse their stacking order by lowering each rectangle in turn, from the bottommost through the topmost, to the bottom of the stack:

Example:

boxes = []
ul = inkex.Vector2d()
for c in ['beige', 'maroon', 'mediumslateblue', 'mediumseagreen', 'tan']:
    boxes.append(rect(ul, ul + (100, 60), fill=c, opacity=0.9))
    ul += (10, 10)
shuffle(boxes)    # Demonstrate that z_sort really is sorting by Z-order.
for box in z_sort(boxes):
    box.z_order('bottom')

Rectangles after sequential, reversed-order lowering to the bottom

Clone this wiki locally