2

I am plotting a collection of rectangles with matplotlib.patches. My code is:

import matplotlib.pyplot as plt
import matplotlib.patches as patches

fig = plt.figure(figsize=(14, 10))

for i in rectangles_list:

    ax1 = fig.add_subplot(111, aspect='equal')
    ax1.add_patch(patches.Rectangle(
                 (x[i], y[i]),
                  width[i],
                  height[i],
                  alpha = 1.0,
                  facecolor = colors_list[i]
                 )
                 )

plt.show()

The rectangles may be overlapping, therefore some of them may be completely hidden. Do you know if it is possible to get the colors of the visible rectangles? I mean the colors of the rectangles that are not completely hidden and therefore that can be actually viewed by the user. I was thinking to some function that returns the color of the pixels, but more intelligent ideas are welcome. If possible, I'd prefer to not use PIL. Unfortunately I cannot find any solution on the internet.

5
  • 1
    I don't think there are builtin methods to do this with matplotlib. You might find shapely useful, however. (See union and contains.) Commented Nov 5, 2016 at 0:25
  • Unable to run your code, missing rectangles_list. How about reducing the alpha value so that you can have a view of anything behind the top rectangle. Commented Nov 5, 2016 at 11:14
  • I think it should be possible to wrap fig.canvas.tostring_argb() into an ARGB array via numpy to get all the on-screen colors. Not sure now to proceed but may be a start. Commented Nov 5, 2016 at 12:58
  • I think it would help to know the purpose of this. There might be a better solution than getting colors for whatever is wanted. Commented Nov 5, 2016 at 14:43
  • Many thanks for all your comments. I have to say that I've followed unutbu's suggestion and I've implemented a complicated formula for the intersection of several rectangles. I don't go into details, but you need a formula similar to that shown here for the probability of the union of several sets statistics.about.com/od/Formulas/a/… I'm also going to try the Jean-Sébastien's code. Commented Nov 7, 2016 at 11:39

1 Answer 1

3

Following Vlass Sokolov comment and this Stackoverflow post by Joe Kington, here is how you could get a numpy array containing all the unique colors that are visible on a matplotlib figure:

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

plt.close('all')

# Generate some data :

N = 1000
x, y = np.random.rand(N), np.random.rand(N)
w, h = np.random.rand(N)/10 + 0.05, np.random.rand(N)/10 + 0.05
colors = np.vstack([np.random.random_integers(0, 255, N),
                    np.random.random_integers(0, 255, N),
                    np.random.random_integers(0, 255, N)]).T

# Plot and draw the data :

fig = plt.figure(figsize=(7, 7), facecolor='white')
ax = fig.add_subplot(111, aspect='equal')
for i in range(N):
    ax.add_patch(Rectangle((x[i], y[i]), w[i], h[i], fc=colors[i]/255., ec='none'))
ax.axis([0, 1, 0, 1])
ax.axis('off')
fig.canvas.draw()

# Save data in a rgb string and convert to numpy array :

rgb_data = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
rgb_data = rgb_data.reshape((int(len(rgb_data)/3), 3))

# Keep only unique colors :

rgb_data = np.vstack({tuple(row) for row in rgb_data})

# Show and save figure :

fig.savefig('rectangle_colors.png')
plt.show()

enter image description here

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

5 Comments

Wow that's beautiful! By following unutbu's suggestion I did it geometrically, but 'll check your code as well later today and I'll definitely use it since it looks much more elegant and straightforward than mine!
@user2983638 you are quite welcome, I'm glad it worked.
I'm sorry, just one question. I'm trying to determine the indexes of the colors in colors corresponding to the colors in rgb_data. Since rgb_data is in the [0, 255] format and colors is in the [0, 1] format, I divided rgb_data by 255. Unfortunately Python cannot match the colors in the two lists, because they are slightly different. I'm trying to round the numbers, but this works only if I round them at the second decimal, which is not very good. Do you know how this could be fixed?
@user2983638 This is interesting. That's because we are losing information along the way... If it is possible for your application, maybe a solution would be to feed matplotlib with colors that are defined in the [0, 255] range with np.random.random_integers(0, 255, N), instead of np.random.rand(N). You would then be able to easily determine the indexes from the resulting 0-255 integers in rgb_data? I've updated my answer to illustrate that.
Yes, now it determines the indexes perfectly without rounding the random numbers! Many thanks again Jean-Sébastien!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.