简体   繁体   中英

matplotlib custom path markers not displaying correctly

just wondering if anybody has experience with matplotlib custom markers

I want each marker in my plot to be a pie chart. To achieve this, my strategy was to create custom markers using the path class, method wedge.

https://matplotlib.org/stable/api/path_api.html

However is not displaying correctly, in particular with wedges defined with angles in the left quadrants. However, the path defined by the wedge class method seems to be correct and wedges are displayed correctly if using PathPatch and.add_patch()

See example below

import numpy as np
import math
import matplotlib.path as mpath
import matplotlib.cm
import matplotlib.pyplot as plt
import matplotlib.patches as patches

#Create wedges from angles
angles = np.array( [0,140,160,360] ) #Wedges angles
wedges=[]
for i in range(len(angles)-1):
    angle0= angles[i]
    angle1= angles[i+1]
    
    dangle = angle1-angle0

    wedge0=None
    if dangle>0:
        wedge0= mpath.Path.wedge(angle0, angle1)
    wedge0= mpath.Path.wedge(angle0, angle1)
    wedges.append(wedge0)

fig = plt.figure(figsize=(10,5))
ax1 = fig.add_subplot(121)
ax1.set_xlim(-1, 1)
ax1.set_ylim(-1, 1)

ax2 = fig.add_subplot(122)
ax2.set_xlim(-2, 2)
ax2.set_ylim(-2, 2)

tab10 = matplotlib.cm.get_cmap('tab10')

for i, w0 in enumerate(wedges):
    ax1.scatter(0,0, marker=w0, c = [tab10(i)], s=20000) #Use path markers
    
    patch = patches.PathPatch(w0, color=tab10(i)) #Use patch
    ax2.add_patch(patch)

plt.show()

情节产生

Notice that the wedge on the left plot is sticking out, which is not supposed to.

Is this a bug in the matplotlib markers' code?

I managed to get the pie charts to display correctly.

Scaling by doing affine transforms does not help because the path markaers are all resized, as in line 495 of markers.py .

def _set_custom_marker(self, path):
    rescale = np.max(np.abs(path.vertices))  # max of x's and y's.
    self._transform = Affine2D().scale(0.5 / rescale)
    self._path = path

My solution is to modify the vertices in the created wedges by inserting new vertices that define a bounding box, slightly larger than the circle with radius 1.

Here is the modified code

import numpy as np
import matplotlib.path as mpath
import matplotlib.cm
import matplotlib.pyplot as plt
import matplotlib.patches as patches

def getBoundedWedge(angle0, angle1):
    wedge0= mpath.Path.wedge(angle0, angle1)
    #print(f"wedge0:{wedge0}")

    vertices = wedge0.vertices
    codes = wedge0.codes

    #Add ghost vertices to define bounding box
    vertices= np.insert( vertices, 0, [[1.1,1.1], [-1.1,1.1] , [-1.1,-1.1], [1.1,-1.1]] , axis=0)
    codes = np.insert( codes, 0, [1,1,1,1])

    wedgeextra = mpath.Path(vertices, codes)
    
    return wedgeextra

#Create wedges from angles
angles = np.array( [0,140,160,360] ) #Wedges angles
wedges=[]
for i in range(len(angles)-1):
    angle0= angles[i]
    angle1= angles[i+1]
    
    dangle = angle1-angle0

    wedge0=None
    if dangle>0:
        wedge0= getBoundedWedge(angle0, angle1)
    wedges.append(wedge0)

fig = plt.figure(figsize=(10,5))
ax1 = fig.add_subplot(121)
ax1.set_xlim(-1, 1)
ax1.set_ylim(-1, 1)

ax2 = fig.add_subplot(122)
ax2.set_xlim(-2, 2)
ax2.set_ylim(-2, 2)

tab10 = matplotlib.cm.get_cmap('tab10')

for i, w0 in enumerate(wedges):
    ax1.scatter(0,0, marker=w0, c = [tab10(i)], s=20000) #Use path markers
    
    patch = patches.PathPatch(w0, color=tab10(i)) #Use patch
    ax2.add_patch(patch)

plt.show()

And the output is as follows

输出

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM