1

I'm trying to plot a circle that is enclosed by a matrix cell. Easy enough, right? Everything looks great when I run the code for a square or lower-dimensional matrix:

import matplotlib.pyplot as plt
from matplotlib.patches import Circle
import numpy as np

fig, ax = plt.subplots( )
mat = np.random.random((5,5))
ax.matshow(mat)
ax.add_patch( Circle( (2,2) , .5, color='white') )
print( ax.patches[0].get_width() )

plt.show()

which correctly returns the image:

enter image description here

Note how the width of each cell in data coordinates is equal to 1. This is always true for ax.matshow(). So it makes sense that my circle of diameter 1 seems to perfectly fit within the cell.


However, if I change the number of columns in the matrix to 50 and execute the code:

import matplotlib.pyplot as plt
from matplotlib.patches import Circle
import numpy as np

fig, ax = plt.subplots( dpi=500 )
mat = np.random.random((5,50))
ax.matshow(mat)
ax.add_patch( Circle( (2,2) , .5, color='white') )
print( ax.patches[0].get_width() )

plt.show()

then I get the following plot:

enter image description here


Note that, even though the width of each cell is still equal to 1 in data coordinates, the Patch object that is plotted (the circle of diameter 1) is clearly bigger than the cell it is supposed to fit within. I can't see any reason why this would happen.

  • 2
    The circle is bigger because is consists of two parts: the circle area and the circle outline. The outline is drawn with a thickness of "linewidth" (default 1 "point"), which is measured symmetrically, half outwards, half inwards. Internally, the "color" property are two colors: `facecolor` for the area and `edgecolor` for the outline. You can either set `linewidth=0` or `edgecolor='none'` to suppress the outline. (For scatter plots, `linewidth=` is called `markeredgewidth=` or shortened to `mew=`). The outline is used to get a nice anti-aliased border. – JohanC Nov 12 '21 at 22:10
  • oh my goodness, that worked! So why did the ```linewidth``` not affect it for the larger plot? was there less antialiasing needed or something? – InertialObserver Nov 12 '21 at 22:15
  • 1
    For the larger plot there is the same linewidth (measured in "points"), but it is a much smaller proportion of the circle (measured in "data coordinates"). (Some internal information about matplotlib's transformations at work: [Transformations Tutorial](https://matplotlib.org/stable/tutorials/advanced/transforms_tutorial.html)) – JohanC Nov 12 '21 at 22:23
  • I see, thanks again. I'm still trying to figure out exactly what a "point" is exactly. Do you have a good reference that tackles this question? – InertialObserver Nov 12 '21 at 22:26
  • 1
    Maybe the introduction of [this post](https://stackoverflow.com/a/69860023/12046409)? "points" comes from the printing world, e.g. measuring font size as "12 points". There are 72 points in an inch. And there is "dpi" which tells how many pixels go in an inch. – JohanC Nov 12 '21 at 22:29
  • 1
    Note that [Scale matplotlib.pyplot.Axes.scatter markersize by x-scale](https://stackoverflow.com/questions/48172928/scale-matplotlib-pyplot-axes-scatter-markersize-by-x-scale) explicitly sets the linewidth to zero: `plt.Circle((xi,yi), radius=0.5, linewidth=0)` – JohanC Nov 12 '21 at 22:38

0 Answers0