Search code examples
pythonmatplotlibprecision

Poor precision when plotting small wedge compared to axis size


I am trying to recreate the charts on this website: https://bumps.live/torpids/2022. I am using matplotlib and am running into an issue when drawing the logos, which I have recreated with the MWE below. I am drawing two semicircles next to each other, and the result is as expected when they are around the same size as the axis, but when they are much smaller there is a loss of precision and the semicircles no longer take up the space of half a circle. The radius of both semicircles is 0.1 in the following two figures, but the first figure has axis limits from -0.15 to 0.15 and the second figure has limits from -10 to 10 (I have zoomed in on the right figure). When using plt.show and zooming in, this issue does not occur.

Regular size semicircles compared to axes

Small semicircles compared to axes (zoomed in)

I am guessing that matplotlib has defined the wedges to a suitable degree of accuracy assuming that no one is zooming in a lot, although as I am zooming in, this is not sufficient. I asked ChatGPT and it suggested adding theresolution=100 kwarg to my wedges, but this appears to be deprecated or something as that gives an error. I am using python 3.12.3 and matplotlib 3.9.1.post1. I will need to produce around 350 logos, and I would be willing to add them as SVGs if the performance is good enough as a backup plan, but ideally I would like to understand how to fix this issue.

import matplotlib.pyplot as plt
from matplotlib.patches import Wedge

fig, ax = plt.subplots(figsize=(5, 5))

radius = 0.1
left_semicircle = Wedge((0, 0), radius, 0, 180, color="r")
right_semicircle = Wedge((0, 0), radius, 180, 360, color="b")

ax.add_patch(left_semicircle)
ax.add_patch(right_semicircle)

axis_limit = 0.15
axis_limit = 10
ax.set_xlim((-axis_limit, axis_limit))
ax.set_ylim((-axis_limit, axis_limit))
ax.set_aspect('equal')

plt.savefig(f"TwoSemicircles_{axis_limit}.pdf")

Solution

  • When you set the color, you are setting both facecolor (which is the color of the inside of the shape) and the edgecolor (which is the color of the outline). Matplotlib then draws the outline with a default line width of 1 point. That linewidth is preserved for the interactive zoom in plt.show (so remains too small to notice), but in your pdf the linewidth is a fixed proportion of the page size. Instead you should just set the facecolor

    left_semicircle = Wedge((0, 0), radius, 0, 180, facecolor="r")
    right_semicircle = Wedge((0, 0), radius, 180, 360, facecolor="b")
    

    then Matplotlib does not draw the edge.