|
| 1 | +""" |
| 2 | +Demonstrates high-resolution tricontouring of a random set of points ; |
| 3 | +a matplotlib.tri.TriAnalyzer is used to improve the plot quality. |
| 4 | +
|
| 5 | +The initial data points and triangular grid for this demo are: |
| 6 | + - a set of random points is instantiated, inside [-1, 1] x [-1, 1] square |
| 7 | + - A Delaunay triangulation of these points is then computed, of which a |
| 8 | + random subset of triangles is masked out by the user (based on |
| 9 | + *init_mask_frac* parameter). This simulates invalidated data. |
| 10 | +
|
| 11 | +The proposed generic procedure to obtain a high resolution contouring of such |
| 12 | +a data set is the following: |
| 13 | + 1) Compute an extended mask with a matplotlib.tri.TriAnalyzer, which will |
| 14 | + exclude badly shaped (flat) triangles from the border of the |
| 15 | + triangulation. Apply the mask to the triangulation (using set_mask). |
| 16 | + 2) Refine and interpolate the data using a |
| 17 | + matplotlib.tri.UniformTriRefiner. |
| 18 | + 3) Plot the refined data with tricontour. |
| 19 | +
|
| 20 | +""" |
| 21 | +from matplotlib.tri import Triangulation, TriAnalyzer, UniformTriRefiner |
| 22 | +import matplotlib.pyplot as plt |
| 23 | +import matplotlib.cm as cm |
| 24 | +import numpy as np |
| 25 | + |
| 26 | + |
| 27 | +#----------------------------------------------------------------------------- |
| 28 | +# Analytical test function |
| 29 | +#----------------------------------------------------------------------------- |
| 30 | +def experiment_res(x, y): |
| 31 | + """ An analytic function representing experiment results """ |
| 32 | + x = 2.*x |
| 33 | + r1 = np.sqrt((0.5-x)**2 + (0.5-y)**2) |
| 34 | + theta1 = np.arctan2(0.5-x, 0.5-y) |
| 35 | + r2 = np.sqrt((-x-0.2)**2 + (-y-0.2)**2) |
| 36 | + theta2 = np.arctan2(-x-0.2, -y-0.2) |
| 37 | + z = (4*(np.exp((r1/10)**2)-1)*30. * np.cos(3*theta1) + |
| 38 | + (np.exp((r2/10)**2)-1)*30. * np.cos(5*theta2) + |
| 39 | + 2*(x**2 + y**2)) |
| 40 | + return (np.max(z)-z)/(np.max(z)-np.min(z)) |
| 41 | + |
| 42 | +#----------------------------------------------------------------------------- |
| 43 | +# Generating the initial data test points and triangulation for the demo |
| 44 | +#----------------------------------------------------------------------------- |
| 45 | +# User parameters for data test points |
| 46 | +n_test = 200 # Number of test data points, tested from 3 to 5000 for subdiv=3 |
| 47 | + |
| 48 | +subdiv = 3 # Number of recursive subdivisions of the initial mesh for smooth |
| 49 | + # plots. Values >3 might result in a very high number of triangles |
| 50 | + # for the refine mesh: new triangles numbering = (4**subdiv)*ntri |
| 51 | + |
| 52 | +init_mask_frac = 0.0 # Float > 0. adjusting the proportion of |
| 53 | + # (invalid) initial triangles which will be masked |
| 54 | + # out. Enter 0 for no mask. |
| 55 | + |
| 56 | +min_circle_ratio = .01 # Minimum circle ratio - border triangles with circle |
| 57 | + # ratio below this will be masked if they touch a |
| 58 | + # border. Suggested value 0.01 ; Use -1 to keep |
| 59 | + # all triangles. |
| 60 | + |
| 61 | +# Random points |
| 62 | +random_gen = np.random.mtrand.RandomState(seed=127260) |
| 63 | +x_test = random_gen.uniform(-1., 1., size=n_test) |
| 64 | +y_test = random_gen.uniform(-1., 1., size=n_test) |
| 65 | +z_test = experiment_res(x_test, y_test) |
| 66 | + |
| 67 | +# meshing with Delaunay triangulation |
| 68 | +tri = Triangulation(x_test, y_test) |
| 69 | +ntri = tri.triangles.shape[0] |
| 70 | + |
| 71 | +# Some invalid data are masked out |
| 72 | +mask_init = np.zeros(ntri, dtype=np.bool) |
| 73 | +masked_tri = random_gen.randint(0, ntri, int(ntri*init_mask_frac)) |
| 74 | +mask_init[masked_tri] = True |
| 75 | +tri.set_mask(mask_init) |
| 76 | + |
| 77 | + |
| 78 | +#----------------------------------------------------------------------------- |
| 79 | +# Improving the triangulation before high-res plots: removing flat triangles |
| 80 | +#----------------------------------------------------------------------------- |
| 81 | +# masking badly shaped triangles at the border of the triangular mesh. |
| 82 | +mask = TriAnalyzer(tri).get_flat_tri_mask(min_circle_ratio) |
| 83 | +tri.set_mask(mask) |
| 84 | + |
| 85 | +# refining the data |
| 86 | +refiner = UniformTriRefiner(tri) |
| 87 | +tri_refi, z_test_refi = refiner.refine_field(z_test, subdiv=subdiv) |
| 88 | + |
| 89 | +# analytical 'results' for comparison |
| 90 | +z_expected = experiment_res(tri_refi.x, tri_refi.y) |
| 91 | + |
| 92 | +# for the demo: loading the 'flat' triangles for plot |
| 93 | +flat_tri = Triangulation(x_test, y_test) |
| 94 | +flat_tri.set_mask(~mask) |
| 95 | + |
| 96 | + |
| 97 | +#----------------------------------------------------------------------------- |
| 98 | +# Now the plots |
| 99 | +#----------------------------------------------------------------------------- |
| 100 | +# User options for plots |
| 101 | +plot_tri = True # plot of the base triangulation |
| 102 | +plot_masked_tri = True # plot of the excessively flat excluded triangles |
| 103 | +plot_refi_tri = False # plot of the refined triangulation |
| 104 | +plot_expected = False # plot of the analytical function values for comparison |
| 105 | + |
| 106 | + |
| 107 | +# Graphical options for tricontouring |
| 108 | +levels = np.arange(0., 1., 0.025) |
| 109 | +cmap = cm.get_cmap(name='Blues', lut=None) |
| 110 | + |
| 111 | +plt.figure() |
| 112 | +plt.gca().set_aspect('equal') |
| 113 | +plt.title("Filtering a Delaunay mesh\n" + |
| 114 | + "(application to high-resolution tricontouring)") |
| 115 | + |
| 116 | +# 1) plot of the refined (computed) data countours: |
| 117 | +plt.tricontour(tri_refi, z_test_refi, levels=levels, cmap=cmap, |
| 118 | + linewidths=[2.0, 0.5, 1.0, 0.5]) |
| 119 | +# 2) plot of the expected (analytical) data countours (dashed): |
| 120 | +if plot_expected: |
| 121 | + plt.tricontour(tri_refi, z_expected, levels=levels, cmap=cmap, |
| 122 | + linestyles='--') |
| 123 | +# 3) plot of the fine mesh on which interpolation was done: |
| 124 | +if plot_refi_tri: |
| 125 | + plt.triplot(tri_refi, color='0.97') |
| 126 | +# 4) plot of the initial 'coarse' mesh: |
| 127 | +if plot_tri: |
| 128 | + plt.triplot(tri, color='0.7') |
| 129 | +# 4) plot of the unvalidated triangles from naive Delaunay Triangulation: |
| 130 | +if plot_masked_tri: |
| 131 | + plt.triplot(flat_tri, color='red') |
| 132 | + |
| 133 | +plt.show() |
0 commit comments