'Is there a way to improve the line quality when exporting streamplots from matplotlib?

I am drawing streamplots using matplotlib, and exporting them to a vector format. However, I find the streamlines are exported as a series of separate lines - not joined objects. This has the effect of reducing the quality of the image, and making for an unwieldy file for further manipulation. An example; the following images are of a pdf generated by exportfig and viewed in Acrobat Reader:

This is the entire plot

Bad streamlines

and this is a zoom of the center.

Bad streamlines zoomed

Interestingly, the length of these short line segments is affected by 'density' - increasing the density decreases the length of the lines. I get the same behavior whether exporting to svg, pdf or eps.

Is there a way to get a streamplot to export streamlines as a single object, preferably as a curved line?

MWE

import matplotlib.pyplot as plt
import numpy as np

square_size = 101

x = np.linspace(-1,1,square_size)
y = np.linspace(-1,1,square_size)

u, v = np.meshgrid(-x,y)

fig, axis = plt.subplots(1, figsize = (4,3))
axis.streamplot(x,y,u,v)
fig.savefig('YourDirHere\\test.pdf')


Solution 1:[1]

In the end, it seemed like the best solution was to extract the lines from the streamplot object, and plot them using axis.plot. The lines are stored as individual segments with no clue as to which line they belong, so it is necessary to stitch them together into continuous lines.

Code follows:

import matplotlib.pyplot as plt
import numpy as np

def extract_streamlines(sl):
    
    # empty list for extracted lines, flag
    new_lines = []
    
    for line in sl:

        #ignore zero length lines
        if np.array_equiv(line[0],line[1]):
            continue

        ap_flag = 1

        for new_line in new_lines:
            
            #append the line segment to either start or end of exiting lines, if either the star or end of the segment is close.
            if np.allclose(line[0],new_line[-1]):
                new_line.append(list(line[1]))
                ap_flag = 0
                break

            elif np.allclose(line[1],new_line[-1]):
                new_line.append(list(line[0]))
                ap_flag = 0
                break
            
            elif np.allclose(line[0],new_line[0]):
                new_line.insert(0,list(line[1]))
                ap_flag = 0
                break

            elif np.allclose(line[1],new_line[0]):
                new_line.insert(0,list(line[0]))
                ap_flag = 0
                break
                
        # otherwise start a new line
        if ap_flag:
            new_lines.append(line.tolist())

    return [np.array(line) for line in new_lines]

square_size = 101

x = np.linspace(-1,1,square_size)
y = np.linspace(-1,1,square_size)

u, v = np.meshgrid(-x,y)

fig_stream, axis_stream = plt.subplots(1, figsize = (4,3))
stream = axis_stream.streamplot(x,y,u,v)

np_new_lines = extract_streamlines(stream.lines.get_segments())

fig, axis = plt.subplots(1, figsize = (4,4))

for line in np_new_lines:
    axis.plot(line[:,0], line[:,1])

fig.savefig('YourDirHere\\test.pdf')

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 NLambert