I have modified the Poly Editor (from the gallery of Matplotlib) to make it able to load several polygons at a time. This works fine except on one point: I don't know how to control the zorder of the polygons.
Here is my code (only interesting lines):
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import polygons # a list of matplotlib.patches.Polygon
import poly_editor
root = tk.Tk()
fig = Figure(figsize=(10, 8))
ax = fig.add_subplot(aspect='equal')
canvas = FigureCanvasTkAgg(fig, root)
poly_editors = []
for poly in polygons:
ax.add_patch(poly)
poly_editors.append(poly_editor.PolygonInteractor(ax, poly, canvas))
With this code, the first polygon is below, the last one above.
I tried to test the use of zorder at this time:
for i,poly in enumerate(polygons):
poly.set_zorder(10 - i)
ax.add_patch(poly)
poly_editors.append(poly_editor.PolygonInteractor(ax, poly, canvas))
Then the result is the same, zorder is not taken into account.
My goal is to put a polygon above all others when pressing the letter 't' inside it. I have written this code in the poly_editor, which obviously does not work.
def on_key_press(self, event):
if event.key == 't':
if self.poly.contains_point((event.x, event.y)):
self.poly.set(zorder=10)
else:
self.poly.set(zorder=0)
self.ax.draw_artist(self.poly)
self.canvas.draw_idle()
I am new to matplotlib, could somebody help me to understand how zorder works ? I saw many questions related to zorder but I don't find any answer to my question.
I finally solved my problem. Since zorder cannot be used, the only way available is to play on the ax.patches list, as the last polygon of this list is the one above all others.
So if I write that to put the first polygon on top:
ax.patches.remove(polygons[0])
ax.add_patch(polygons[0])
It is not sufficient. I have also to recreate the PolygonInteractor
instance:ax.patches.remove(polygons[0])
ax.add_patch(polygons[0])
p = poly_editor.PolygonInteractor(ax, poly, canvas)
canvas.draw_idle()
That test by hand works as expected. But I have to do that from inside the PolygonInteractor instance.
Here is the interesting code of the final solution that implements exactly what I asked for:
### main
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import polygons # a list of matplotlib.patches.Polygon
import poly_editor
root = tk.Tk()
fig = Figure(figsize=(10, 8))
ax = fig.add_subplot(aspect='equal')
canvas = FigureCanvasTkAgg(fig, root)
poly_editors = {}
for poly in polygons:
ax.add_patch(poly)
poly_editors[poly] = poly_editor.PolygonInteractor(ax, poly, poly_editors)
### PolygonInteractor.__init__
def __init__(self, ax, poly, container):
self.ax = ax
self.poly = poly
self.canvas = ax.figure.canvas
self.container = container
### inside PolygonInteractor
def on_key_press(self, event):
if event.key == 't':
if self.poly.contains_point((event.x, event.y)):
self.ax.patches.remove(self.poly)
self.ax.add_patch(self.poly)
self = self.__class__(self.ax, self.poly, self.container)
self.container[self.poly] = self
It is very simple to replace the current instance by a newly created one. It seems a bit hacky and magical... Python will always amaze me, despite my long experience!