In Excel, shapes are often used for process indicators, callouts, dashboard decoration, or turning scattered data into a clear diagram. Compared with plain text and cell borders, shapes express hierarchy and relationships more freely. But when the same shapes need to be added across many worksheets or files, dragging them by hand is slow and hard to keep consistent.
Python can insert shapes into worksheets in batch and with precision, and control properties such as fill, border, shadow, and layer order. Using Spire.XLS for Python, this article covers shape insertion and the management operations you are most likely to need.
Setting Up the Environment
Install the Spire.XLS library:
pip install Spire.XLS
Then import the required modules in your script:
from spire.xls import *
from spire.xls.common import *
Inserting Shapes
A worksheet exposes several shape collections for different kinds of shapes. The most general is PrstGeomShapes, which creates dozens of preset graphics through the PrstGeomShapeType enum. The arguments of AddPrstGeomShape() are the starting row, starting column, width, and height:
workbook = Workbook()
sheet = workbook.Worksheets[0]
# Insert a triangle with a solid fill
triangle = sheet.PrstGeomShapes.AddPrstGeomShape(2, 2, 100, 100, PrstGeomShapeType.Triangle)
triangle.Fill.ForeColor = Color.get_Yellow()
triangle.Fill.FillType = ShapeFillType.SolidColor
# Insert a heart with a gradient fill
heart = sheet.PrstGeomShapes.AddPrstGeomShape(2, 5, 100, 100, PrstGeomShapeType.Heart)
heart.Fill.ForeColor = Color.get_Red()
heart.Fill.FillType = ShapeFillType.Gradient
# Insert an arrow and a cloud
arrow = sheet.PrstGeomShapes.AddPrstGeomShape(10, 2, 100, 100, PrstGeomShapeType.CurvedRightArrow)
cloud = sheet.PrstGeomShapes.AddPrstGeomShape(10, 5, 100, 100, PrstGeomShapeType.Cloud)
workbook.SaveToFile("shapes.xlsx", ExcelVersion.Version2013)
workbook.Dispose()
PrstGeomShapeType includes values such as Triangle, Heart, CurvedRightArrow, Cloud, Ellipse, and RoundRect, covering common needs in flowcharts, callouts, and decoration.
For rectangles and ovals — the two most common shapes — dedicated methods offer simpler arguments:
# Insert a rectangle; RectangleShapeType can be Rect or RoundRect
rect = sheet.RectangleShapes.AddRectangle(11, 2, 60, 100, RectangleShapeType.RoundRect)
rect.Fill.FillType = ShapeFillType.SolidColor
rect.Fill.ForeColor = Color.get_DarkCyan()
# Insert an oval
oval = sheet.OvalShapes.AddOval(11, 5, 100, 100)
oval.Fill.FillType = ShapeFillType.SolidColor
oval.Fill.ForeColor = Color.get_DarkCyan()
Setting Fill, Border, and Shadow
A shape's fill is controlled by Fill.FillType, where ShapeFillType provides values such as SolidColor, Gradient, and Picture. A picture fill requires the image to be supplied through CustomPicture() first, then the type set to Picture:
# Fill a shape with a picture
cloud = sheet.PrstGeomShapes.AddPrstGeomShape(2, 5, 100, 100, PrstGeomShapeType.Cloud)
cloud.Fill.CustomPicture(Stream("logo.png"), "logo.png")
cloud.Fill.FillType = ShapeFillType.Picture
# A file path can also be used directly
oval = sheet.OvalShapes.AddOval(11, 5, 100, 100)
oval.Fill.CustomPicture("logo.png")
Borders are configured through the Line property, which controls weight and dash style:
rect.Line.Weight = 1
oval.Line.DashStyle = ShapeDashLineStyleType.Solid
Shadows add depth, and the Shadow property exposes angle, distance, size, color, blur, and transparency:
ellipse = sheet.PrstGeomShapes.AddPrstGeomShape(5, 5, 150, 100, PrstGeomShapeType.Ellipse)
ellipse.Shadow.Angle = 90
ellipse.Shadow.Distance = 10
ellipse.Shadow.Size = 150
ellipse.Shadow.Color = Color.get_Gray()
ellipse.Shadow.Blur = 30
ellipse.Shadow.Transparency = 1
ellipse.Shadow.HasCustomStyle = True
Note the last step: the custom shadow settings only take effect once HasCustomStyle is set to True.
Grouping Shapes
When several shapes should move or scale as a single unit, group them. Get the group collection with GetGroupShapeCollection(), then pass the list of shapes to group:
shape1 = sheet.PrstGeomShapes.AddPrstGeomShape(1, 3, 50, 50, PrstGeomShapeType.RoundRect)
shape2 = sheet.PrstGeomShapes.AddPrstGeomShape(5, 3, 50, 50, PrstGeomShapeType.Triangle)
groupShapeCollection = sheet.GetGroupShapeCollection()
groupShapeCollection.Group([shape1, shape2])
Once grouped, the shapes share a single bounding box and stay aligned when repositioned.
Adjusting Layer Order
When shapes overlap, their display order is determined by the layer. The ChangeLayer() method accepts the ShapeLayerChangeType enum to move a shape forward or backward:
# Move forward one level
shape.ChangeLayer(ShapeLayerChangeType.BringForward)
# Bring to the very front
shape.ChangeLayer(ShapeLayerChangeType.BringToFront)
# Send backward one level
shape.ChangeLayer(ShapeLayerChangeType.SendBackward)
# Send to the very back
shape.ChangeLayer(ShapeLayerChangeType.SendToBack)
Picture objects support ChangeLayer() as well, with the same usage.
Deleting and Hiding Shapes
Delete a single shape with Remove(). For bulk deletion, iterate backward — otherwise the indices shift as items are removed and elements get skipped:
workbook.LoadFromFile("template.xlsx")
sheet = workbook.Worksheets[0]
# Remove the first shape
sheet.PrstGeomShapes[0].Remove()
# Remove all shapes: iterate backward
for i in range(sheet.PrstGeomShapes.Count - 1, -1, -1):
sheet.PrstGeomShapes[i].Remove()
workbook.SaveToFile("shapes_deleted.xlsx", ExcelVersion.Version2013)
workbook.Dispose()
If a shape should only be hidden temporarily rather than deleted, toggle its visibility instead, so it can be restored later:
sheet.PrstGeomShapes[1].Visible = False
Exporting Shapes and Reading Their Contents
A shape can be exported as an image for reuse elsewhere:
shape = sheet.PrstGeomShapes[0]
img = shape.SaveToImage()
img.Save("shape.png")
Conversely, the Text property reads the text inside a shape, and a picture fill can be extracted as the original image:
# Read the text inside a shape
print(sheet.PrstGeomShapes[2].Text)
# Extract the picture fill of a shape
image = sheet.PrstGeomShapes[1].Fill.Picture
image.Save("extracted.png", ImageFormat.get_Png())
Practical Tips
- The first two arguments of
AddPrstGeomShape()are the row and column position, followed by width and height; the shape anchors near the corresponding cells, so it shifts when the row or column layout changes. - When setting a custom shadow, it is easy to forget
HasCustomStyle = True, which leaves the parameters without effect. - Always delete shapes in reverse order for bulk operations; forward deletion skips elements because the collection indices change in real time.
- Call
Dispose()when finished to release resources.
Conclusion
This article covered the full workflow of working with shapes in Excel using Python: inserting different shapes with AddPrstGeomShape(), AddRectangle(), and AddOval(); controlling appearance through Fill, Line, and Shadow; grouping shapes with Group() and reordering them with ChangeLayer(); and deleting via Remove(), hiding via Visible, and exporting via SaveToImage(). With these operations, repetitive layout work such as dashboard decoration and diagram annotation can be handed off to a script.

Top comments (0)