Navdeep Singh
Navdeep Singh

Reputation: 71

Add Bullet list using python-pptx

I am using the python-pptx library for pptx manipulation. I want to add a bullet list in the pptx document.

I am using the following snippet to add list item:

p = text_frame.add_paragraph()
run = p.add_run()
p.level = 0
run.text = "First"

But it does not display bullet points; please guide.

Upvotes: 7

Views: 11841

Answers (4)

Nootaku
Nootaku

Reputation: 419

This question is still up to date on May 27, 2021. Following up on @OD1995's answer I would like to add a little more detail as well as my turn on the problem.

I created a new package with the following code:

from pptx.oxml.xmlchemy import OxmlElement


def getBulletInfo(paragraph, run=None):
    """Returns the attributes of the given <a:pPr> OxmlElement
    as well as its runs font-size.

    *param: paragraph* pptx _paragraph object
    *param: run* [optional] specific _run object
    """
    pPr = paragraph._p.get_or_add_pPr()
    if run is None:
        run = paragraph.runs[0]
    p_info = {
        "marL": pPr.attrib['marL'],
        "indent": pPr.attrib['indent'],
        "level": paragraph.level,
        "fontName": run.font.name,
        "fontSize": run.font.size,
    }
    return p_info


def SubElement(parent, tagname, **kwargs):
    """Helper for Paragraph bullet Point
    """
    element = OxmlElement(tagname)
    element.attrib.update(kwargs)
    parent.append(element)
    return element


def pBullet(
    paragraph,  # paragraph object
    font,  # fontName of that needs to be applied to bullet
    marL='864000',
    indent='-322920',
    size='350000'  # fontSize (in )
):
    """Bullets are set to Arial,
    actual text can be a different font
    """
    pPr = paragraph._p.get_or_add_pPr()
    # Set marL and indent attributes
    # Indent is the space between the bullet and the text.
    pPr.set('marL', marL)
    pPr.set('indent', indent)
    # Add buFont
    _ = SubElement(parent=pPr,
                   tagname="a:buSzPct",
                   val="350000"
                   )
    _ = SubElement(parent=pPr,
                   tagname="a:buFont",
                   typeface=font,
                   # panose="020B0604020202020204",
                   # pitchFamily="34",
                   # charset="0"
                   )
    # Add buChar
    _ = SubElement(parent=pPr,
                   tagname='a:buChar',
                   char="•"
                   )

The reason I did this is because I was frustrated that the bullet character was not of the same size as the original and the text was stuck to the bullet.

getBulletInfo() allows me to retrieve information from an existing paragraph. I use this information to populate the element's attributes (so that it is identical to the template).

Anyways the main add-on is the creation of a sub-element <a:buSzPct> (documentation here and here). This is a size percentage that can go from 25% to 350% (100000 = 100%).

Upvotes: 6

OD1995
OD1995

Reputation: 1777

My solution:

from pptx.oxml.xmlchemy import OxmlElement

def SubElement(parent, tagname, **kwargs):
        element = OxmlElement(tagname)
        element.attrib.update(kwargs)
        parent.append(element)
        return element
    
def makeParaBulletPointed(para):
    """Bullets are set to Arial,
        actual text can be a different font"""
    pPr = para._p.get_or_add_pPr()
    ## Set marL and indent attributes
    pPr.set('marL','171450')
    pPr.set('indent','171450')
    ## Add buFont
    _ = SubElement(parent=pPr,
                   tagname="a:buFont",
                   typeface="Arial",
                   panose="020B0604020202020204",
                   pitchFamily="34",
                   charset="0"
                   )
    ## Add buChar
    _ = SubElement(parent=pPr,
                   tagname='a:buChar',
                   char="•")

Upvotes: 3

Samuel Johansson
Samuel Johansson

Reputation: 47

It is currently not possible to access the bullet property using python-pptx, but I want to share a workaround that has served me well.

This requires the use of a pptx template, in which we exploit the fact that the levels in a slide layout can be customized individually.

For instance, in the slide layout you could set level 0 to be normal text, level 1 to be bullets, and level 2 to be numbers or any other list style you want. You can then modify font size, indentation (using the ruler at the top), and any other property of each level to get the look you want.

For my use-case, I just set levels 1 and 2 to have the same indentation and size as level 0, making it possible to create bullet lists and numbered lists by simply setting the level to the corresponding value.

This is how my slide layout looks in the template file: slide layout example

And this is how I set the corresponding list style in the code:

p.level = 0  # Regular text
p.level = 1  # Bullet
p.level = 2  # Numbers

In theory, you should be able to set it up exactly the way you want, even with indented sub-lists and so on. The only limitation I am aware of is that there seems to be a maximum of 8 levels that can be customized in the slide layout.

Upvotes: 3

Henk van der Laak
Henk van der Laak

Reputation: 299

Try this:

p = text_frame.add_paragraph()
p.level = 0
p.text = "First"

Or if the text_frame already has a paragraph:

p = text_frame.paragraphs[0]
p.level = 0
p.text = "First"

Upvotes: -1

Related Questions