0

When making a scatter plot in matplotlib, I found that when I change the size of the dots, they become transparent. How can I prevent this from happening?

I've already tried alpha=1, facecolor='k' but none of these seem to work

Example code

X = np.random.normal(0,1,5000) Y = np.random.normal(0,1,5000) fig, ax = plt.subplots(1,2, figsize=(6,3), dpi=288) ax[0].scatter(X,Y, s=.01, c='k') ax[1].scatter(X,Y, s=1, c='k') plt.show() 

Result:

Result

Notice how the larger dots are opaque and filled in, whilst the smaller ones seem transparent, and have a white facecolor. How do I get the smaller ones to be filled in as well?

1 Answer 1

2

If you want the size to scale correctly, and print down to the pixel limit, the dpi and figure size need to be adjusted. Then s will behave correctly, starting with the smallest pixel being s=1. You also probably want to change the marker from the default. Try this:

#divide dpi by four, multiply figsize components by four to keep same area fig, ax = plt.subplots(1,2, figsize=(24,12), dpi=72) ax[0].scatter(X,Y, s=1, marker=".", c='k') ax[1].scatter(X,Y, s=100, marker=".", c='k') 

This will make the axes labels smaller, however.

Edit: We can also ensure that the s-value is never sub-minimal-pixel size, as pointed out in comments. Here's a function that allows one to play around with these settings using this:

def scat_rand(size=(24,12), scale=72, smin=1, smax=100, sedge=True, min_pix=1): X = np.random.normal(0,1,5000) Y = np.random.normal(0,1,5000) fig, ax = plt.subplots(1,2, figsize=(size), dpi=scale) slimit = (min_pix * 72 / fig.dpi) ** 2 if smin < slimit + .0001: smin = slimit print(f"smin too small, reset to {slimit}") if sedge: ax[0].scatter(X,Y, s=smin, c='k') ax[1].scatter(X,Y, s=smax, c='k') else: ax[0].scatter(X,Y, s=smin, c='k', edgecolor='none') ax[1].scatter(X,Y, s=smax, c='k', edgecolor='none') plt.suptitle(f"Pixel= {size[0] * scale} x {size[1] * scale}", fontsize=14) plt.show() 

Here's a little driver if you want to play around with it:

if __name__ == "__main__": temp = int(input("Enter size(1-24): ")) size = (2 * temp, temp) scale = int(input("Enter dpi scale (72, 144, 288, 576, 1152): ")) limit = (72 / scale) ** 2 smin = float(input(f"Enter smallest point (limit = {limit}): ")) smax = float(input("Enter largest point: ")) edge = input("edgecolor (y/n): ") if edge == 'y': sedge = True else: sedge = False scat_rand(size, scale, smin, smax, sedge) 

See also: Relationship between dpi and figure size

Sign up to request clarification or add additional context in comments.

2 Comments

This is a bit confusing. You don't need to set the dpi to 72 to get the desired result. Rather the first problem is that the points have an edgecolor. So set that to edgecolor="none". Then make sure the size of the scatter can actually be rendered, meaning it needs to be at least one pixel large. That would result in scatter(X,Y, s=(1*72/fig.dpi)**2, marker="o", c='k', edgecolor="none")
@ImportanceOfBeingErnest, thanks that does provide a nice way of finding the correct one-pixel limit. Edited the answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.