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.

user2983638
  • 903
  • 1
  • 13
  • 20
  • 1
    I don't think there are builtin methods to do this with matplotlib. You might find [shapely](https://pypi.python.org/pypi/Shapely) useful, however. (See [union](http://toblerity.org/shapely/manual.html#object.union) and [contains](http://toblerity.org/shapely/manual.html#object.contains).) – unutbu Nov 05 '16 at 00: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. – hashmuke Nov 05 '16 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. – Vlas Sokolov Nov 05 '16 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. – ImportanceOfBeingErnest Nov 05 '16 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 http://statistics.about.com/od/Formulas/a/Probability-Of-The-Union-Of-Three-Or-More-Sets.htm I'm also going to try the Jean-Sébastien's code. – user2983638 Nov 07 '16 at 11:39

1 Answers1

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

Community
  • 1
  • 1
Jean-Sébastien
  • 2,649
  • 1
  • 16
  • 21
  • 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 Nov 07 '16 at 11:33
  • @user2983638 you are quite welcome, I'm glad it worked. – Jean-Sébastien Nov 08 '16 at 02:12
  • 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 Nov 08 '16 at 16:34
  • 1
    @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. – Jean-Sébastien Nov 08 '16 at 17:25
  • Yes, now it determines the indexes perfectly without rounding the random numbers! Many thanks again Jean-Sébastien! – user2983638 Nov 08 '16 at 22:15