2

Is there anyway to set the miterlimit when saving a matplotlib plot to svg? I'd like to programatically get around this bug:https://bugs.launchpad.net/inkscape/+bug/1533058 whereas I am having to manually change this in the ".svg" text file.

aeolus
  • 159
  • 3
  • 11

2 Answers2

1

This parameter is defined as 'stroke-miterlimit': '100000' and is hard-set in backend_svg.py. There is no such parameter in matplotlibrc, so customizing with style sheet is unlikely to be possible.

I used the following code to fix this issue:

def fixmiterlimit(svgdata, miterlimit = 10):
    # miterlimit variable sets the desired miterlimit
    mlfound = False
    svgout = ""
    for line in svgdata:
        if not mlfound:
             # searches the stroke-miterlimit within the current line and changes its value
             mlstring = re.subn(r'stroke-miterlimit:([0-9]+)', "stroke-miterlimit:" + str(miterlimit), line)
        if mlstring[1]: # use number of changes made to the line to check whether anything was found
            mlfound = True
            svgout += mlstring[0] + '\n'
        else:
            svgout += line + '\n'
    else:
        svgout += line + '\n'
return svgout

And then call it like this (with the trick from this post):

import StringIO
...
imgdata = StringIO.StringIO() # initiate StringIO to write figure data to
# the same you would use to save your figure to svg, but instead of filename use StringIO object
plt.savefig(imgdata, format='svg',  dpi=90, bbox_inches='tight')
imgdata.seek(0)  # rewind the data
svg_dta = imgdata.buf  # this is svg data

svgoutdata = fixmiter(re.split(r'\n', svg_dta)) # pass as an array of lines
svgfh = open('figure1.svg', 'w')
svgfh.write(svgoutdata)
svgfh.close()

The code basically changes the stroke-miterlimit parameter in SVG output before writing it to file. Worked for me.

Community
  • 1
  • 1
drYG
  • 11
  • 1
1

Thanks to drYG for the nice answer and to aeolus for the question. I have a similar issue due to this inkscape bug and the lack of a easy way to change the setting in matplotlib. However, the answer from drYG seems not to work for python3. I've updated it and changed what seemed to be some typos (irrespective of the python version). Hopefully it will save someone else some time as I try to make up what I've lost!

def fixmiterlimit(svgdata, miterlimit = 10):
    # miterlimit variable sets the desired miterlimit
    mlfound = False
    svgout = ""
    for line in svgdata:
        if not mlfound:
            # searches the stroke-miterlimit within the current line and changes its value
            mlstring = re.subn(r'stroke-miterlimit:([0-9]+)', "stroke-miterlimit:" + str(miterlimit), line)
        #if mlstring[1]: # use number of changes made to the line to check whether anything was found
            #mlfound = True
            svgout += mlstring[0] + '\n'
        else:
            svgout += line + '\n'
    return svgout

import io, re
imgdata = io.StringIO() # initiate StringIO to write figure data to
# the same you would use to save your figure to svg, but instead of filename use StringIO object
plt.gca()
plt.savefig(imgdata, format='svg',  dpi=90, bbox_inches='tight')
imgdata.seek(0)  # rewind the data
svg_dta = imgdata.getvalue()  # this is svg data
svgoutdata = fixmiterlimit(re.split(r'\n', svg_dta)) # pass as an array of lines
svgfh = open('test.svg', 'w')
svgfh.write(svgoutdata)
svgfh.close()
guygma
  • 11
  • 1