2

In MATLAB, filled polygons can be plotted with colors defined in the nodes using the fill command as (example with 2 triangles):

x = [0 1 1; 0 1 0]';
y = [0 0 1; 0 1 1]';
z = [0 1 2; 0 2 3]';

fill(x,y,z)

Is there an equivalent command, or another convenient way, to do the same in matplotlib?

fredrikekre
  • 10,413
  • 1
  • 32
  • 47
  • 1
    How about [`matplotlib.patches.Polygon`](http://matplotlib.org/api/patches_api.html?highlight=patches.polygon#matplotlib.patches.Polygon)? See also [this question](http://stackoverflow.com/questions/26935701/ploting-filled-polygons-in-python) – Andras Deak -- Слава Україні Nov 11 '15 at 01:02
  • I saw, that question. However, as I understand it that function plots the whole polygon in the same color? In MATLAB it is possible to specify the colors of the corners, so that the color inbetween is a gradient, as in the example. – fredrikekre Nov 11 '15 at 13:05
  • So what are your real data actually like? I only found `matplotlib.imshow` that can do interpolation inside your faces, but that assumes a rectangular grid as `x` and `y`... – Andras Deak -- Слава Україні Nov 11 '15 at 19:24
  • Basically I have elements in a mesh (in this case triangles) with nodal values. Much like the example above. It is possible to convert the data to coordinate data for each node (say in vectors `X,Y`) with nodal values in a vector `Z`. Maybe this can be plotted more easily? It is not necessary to plot the actual elements. – fredrikekre Nov 11 '15 at 22:13
  • Very much so. If `x` and `y` are on a mesh, as in `x,y=numpy.meshgrid(xarr,yarr)`, and `z` is again defined on that mesh, possibly as a function of `x` and `y`, then `matplotlib.imshow(z,interpolation='bilinear',extent=...` will do something very similar. But you need an equidistant grid, since [`imshow`](http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.imshow) is designed for plotting images, and interprets your data as pixels (and might flip the coordinate axes). I couldn't find another function capable of intrafacet interpolation, unfortunately. – Andras Deak -- Слава Україні Nov 11 '15 at 22:20
  • The problem is that my points are more or less randomly distributed in space. So definitely not in an equidistant meshgrid. I worked around my problem by calling `MATLAB` and using its `fill` function, but this is not optimal in any way. – fredrikekre Nov 11 '15 at 22:55
  • Your problem sounds ideal to me for use with [`plot_trisurf`](http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#tri-surface-plots) as that will do the triangulation for you, however that also can't interpolate inside facets. – Andras Deak -- Слава Україні Nov 12 '15 at 05:46
  • I might have found what you're looking for. [This question](http://stackoverflow.com/questions/19836199/interpolating-a-3d-surface-known-by-its-corner-nodes-and-coloring-it-with-a-colo) has an accepted answer telling you that `shading interp` is not available in python, and the second (low-voted, bountied) answer will show you how to use `tri.LinearTriInterpolator` with `plot_trisurf` to refine your mesh:) So far this sounds best to me. – Andras Deak -- Слава Україні Nov 12 '15 at 05:49

1 Answers1

1

I managed to get a solution based on this question and the answers therein. It seems that intrafacet interpolation is not built into pyplot, so you need a workaround by creating a finer interpolating mesh on your data.

Using your example data in MATLAB:

x = [0 1 1; 0 1 0]';
y = [0 0 1; 0 1 1]';
z = [0 1 2; 0 2 3]';

fill(x,y,z);

produces this plot (which will be a control for us): matlabfill_control

First you have to determine how your data are represented in python. The natural inputs to the functions I'm going to use are 1d arrays, so you might throw away the multiplicities in your data. If you don't actually care for the triangles, but only the z landscape, then you can let python do the triangulation for you:

from matplotlib import tri, cm
import matplotlib.pyplot as plt

x=[0, 1, 1, 0]
y=[0, 0, 1, 1]
z=[0, 1, 2, 3]

triang=tri.Triangulation(x,y) #Delaunay triangulation of input
refiner=tri.UniformTriRefiner(triang)
interp=tri.LinearTriInterpolator(triang,z) #linear interpolator
new,new_z=refiner.refine_field(z,interp,subdiv=6) #refined mesh; uses 4**subdiv!

fig = plt.figure()
plt.tripcolor(new.x,new.y,new_z,cmap=cm.jet)

The result: python, automatic triangulation

You can see that the result is different from the control, because matplotlib chose another triangulation as we did in MATLAB. If your triangles are small, and you only need a smooth figure, then this should suffice.

However, it is possible to provide the triangulation manually. It would be less then trivial to convert your MATLAB input to a format that is palatable by python, so it's up to how desperate you are. For our small example I can choose the triangles manually:

x=[0, 1, 1, 0]
y=[0, 0, 1, 1]
z=[0, 1, 2, 3]
tridat=[[0,3,2],[0,2,1]] # 2 triangles in counterclockwise order

triang=tri.Triangulation(x,y,tridat) #this has changed
refiner=tri.UniformTriRefiner(triang)
interp=tri.LinearTriInterpolator(triang,z) #linear interpolator
new,new_z=refiner.refine_field(z,interp,subdiv=6) #refined mesh

fig = plt.figure()
plt.tripcolor(new.x,new.y,new_z,cmap=cm.jet)

Result: python manual triangulation

This is clearly comparable to the MATLAB version. For a smoother interpolation you can increase subdiv in the code, but do so carefully: each triangle is split into 4^subdiv parts, so the memory need of plotting grows very rapidly with this parameter.

Community
  • 1
  • 1