Thanks to visit codestin.com
Credit goes to github.com

Skip to content

DOC: Revive Irregularly spaced data contour example #11180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions examples/images_contours_and_fields/irregulardatagrid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"""
=======================================
Contour plot of irregularly spaced data
=======================================

Comparison of a contour plot of irregularly spaced data interpolated
on a regular grid versus a tricontour plot for an unstructured triangular grid.

Since :meth:`~.axes.Axes.contour` and :meth:`~.axes.Axes.contourf` expect the
data to live on a regular grid, plotting a contour plot of irregularly spaced
data requires different methods. The two options are:

* Interpolate the data to a regular grid first. This can be done with on-borad
means, e.g. via `~.tri.LinearTriInterpolator` or using external functionality
e.g. via `scipy.interpolate.griddata`. Then plot the
interpolated data with the usual :meth:`~.axes.Axes.contour`.
* Directly use :meth:`~.axes.Axes.tricontour` or
:meth:`~.axes.Axes.tricontourf` which will perform a triangulation
internally.

This example shows both methods in action.
"""

import matplotlib.pyplot as plt
import matplotlib.tri as tri
import numpy as np

np.random.seed(19680801)
npts = 200
ngridx = 100
ngridy = 200
x = np.random.uniform(-2, 2, npts)
y = np.random.uniform(-2, 2, npts)
z = x * np.exp(-x**2 - y**2)

fig, (ax1, ax2) = plt.subplots(nrows=2)

# -----------------------
# Interpolation on a grid
# -----------------------
# A contour plot of irregularly spaced data coordinates
# via interpolation on a grid.

# Create grid values first.
xi = np.linspace(-2.1, 2.1, ngridx)
yi = np.linspace(-2.1, 2.1, ngridy)

# Perform linear interpolation of the data (x,y)
# on a grid defined by (xi,yi)
triang = tri.Triangulation(x, y)
interpolator = tri.LinearTriInterpolator(triang, z)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, Hmmmm. I'm not 100% convinced that we should suggest people use the in-house triangular and interpolator. In the same vein that mlab is going away, my guess is that tri will go away. I'd rather we tell people the "best practice" and I'm not sure our sparsely documented in-house triangulation routine is that. Happy to be corrected, but I'd lean towards the scipy reference.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jklymak I assure you that tri is not going to "go away". What on earth possessed you to assert such a guess?

I am 100% convinced that we should suggest people use the in-house triangulator and interpolator, and unlike yourself I am an expert in the area. Consider yourself corrected, and in future kindly refrain from expressing derogatory opinions on functionality you have no knowledge of.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn’t meaning to be offensive about the actual algorithm, any more that I would be about mlab.psd. Just that it does something that scipy also does. Do we need to be providing duplicate functionality, and more importantly do we want to guide users to this code?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think what @jklymak said was particularly derogatory...

Is there a reason Matplotlib runs a custom triangulator, and doesn't use an upstream one? And if ours is better than what is available in either numpy or scipy, should we try and push the mpl triangulation code upstream? It feels to me like that's where good triangulation code should live.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is about triangulation. It's about the interpolators from tri.triinterpolate.
I cannot judge on whether they are needed or not, but here are the timings from the example:

* LinearTriInterpolator   0.0444 s
* scipy griddata          0.0728 s
* matplotlib tricontour   0.0301 s

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm totally in favor of sharing the love in any stream direction.
In this particular case the motivation is to share the love with users looking for ways to plot irregularly spaced data.
One way of doing so is to inform them about the in-built option for interpolation. Since this in-built option will not vanish from the 2.2 branch with 110% certainty, there is nothing wrong with using that for now. And it would prevent the necessity to include a new large dependecy for the docs during the final stage of this branch.
For the development branch, one may sure discuss if it's useful to change the example and include scipy (a 12 Mb package, 40 Mb extracted) as documentation dependency.
I do not have a clear opinion on that, but I wouldn't want to wait to include this example until someone may or may not have shared their love for tri upstream (and got their love returned).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no 'upstream', no de facto standard library for representing and manipulating triangular grids in python. If there was, we should certainly use it. Until then, we are one of the gathering places for such functionality. It started as just rendering triangular grids, which is clearly within our remit, and when interpolation and mesh refinement were implemented they were added to our code as the best (least bad?) place to put them as our code is actively maintained and will be around for a long time.

Numpy isn't the place for such functionality, scipy would be more appropriate but I don't think it is as suitable as a specific tri grids library (named tripy perhaps?). Every so often there is an interest in such as library, but after lots of chat my summary is that there are plenty of people who want to use such a library, nobody wants to write it. From my point of view, even if a tripy existed the rendering of tri grids, which is what I am mostly interested it, would still reside within mpl.

Without delving too deeply into the workings of our tri code, there are three use cases for creating and using a triangulation object:

  1. User specifies the 2D points and requests a Delaunay triangulation is calculated for them.
  2. The same as 1, and then the user masks out some of the unwanted triangles.
  3. User specifies both the 2D points and the triangulation.

scipy.griddata can only deal with use case 1, our code deals with all three. Unfortunately use case 1 is the one that most examples refer to as it is the entry point to triangular grids for those not used to them. But nearly all serious tri grid work uses the other 2 use cases.

Hence we should not recommend using scipy.griddata, it simply doesn't include the functionality that our code requires and has. But unfortunately we can't just ignore it and not mention it in such examples; we need to keep it as there are lots of historical web pages mentioning griddata, and we need to catch the attention of people looking for it so that we can point out our alternatives. Keeping it in this example but just within a comment is an approach that I like.

Unfortunately griddata have been around for years and people are familiar with it, so anyone who asks about tri grids receives a well-intended but sub-optimal answer to interpolate to a regular grid. It is simply unnecessary. Everyone should use tricontour for optimal results: the boundaries and masked areas are correct, it has higher resolution where the grid has higher resolution. If higher resolution is required, there is an excellent TriRefiner that creates a new triangulation, keeping sensible boundaries, etc and can avoid badly-formed triangles (e.g. long and thin); it is featured in the tricontour_smooth_delaunay and tricontour_smooth_user examples.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quite a bit of useful information. I think it shouldn't stay hidden inside the review section of a PR; but is there any good place for such meta information to be stored?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking the time to explain, and sorry for all of our questions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ianthomas23 Thanks for the explanations. I agree that the tri-mesh plotting utilities that I assume you have developed are very impressive. Having the ability to plot directly from a tessellation is hugely useful, particularly in fields where a finite-volume modelling approach has been used. I certainly never meant that those capabilities should be curtailed or go away. OTOH I agree w/ @ImportanceOfBeingErnest that they should get their own tutorial. Unless you are looking for tri-grid solutions, the examples in the examples directory are clearly labeled, but obscure.

Unfortunately griddata have been around for years and people are familiar with it, so anyone who asks about tri grids receives a well-intended but sub-optimal answer to interpolate to a regular grid. It is simply unnecessary. Everyone should use tricontour for optimal results: the boundaries and masked areas are correct, it has higher resolution where the grid has higher resolution.

gridding data sets is often necessary for reasons other than direct data presentation, usually in the context of comparing to another data set that is supplied on a regular grid.

Xi, Yi = np.meshgrid(xi, yi)
zi = interpolator(Xi, Yi)

# Note that scipy.interpolate provides means to interpolate data on a grid
# as well. The following would be an alternative to the four lines above:
#from scipy.interpolate import griddata
#zi = griddata((x, y), z, (xi[None,:], yi[:,None]), method='linear')


ax1.contour(xi, yi, zi, 14, linewidths=0.5, colors='k')
cntr1 = ax1.contourf(xi, yi, zi, 14, cmap="RdBu_r")

fig.colorbar(cntr1, ax=ax1)
ax1.plot(x, y, 'ko', ms=3)
ax1.axis((-2, 2, -2, 2))
ax1.set_title('grid and contour (%d points, %d grid points)' %
(npts, ngridx * ngridy))


# ----------
# Tricontour
# ----------
# Directly supply the unordered, irregularly spaced coordinates
# to tricontour.

ax2.tricontour(x, y, z, 14, linewidths=0.5, colors='k')
cntr2 = ax2.tricontourf(x, y, z, 14, cmap="RdBu_r")

fig.colorbar(cntr2, ax=ax2)
ax2.plot(x, y, 'ko', ms=3)
ax2.axis((-2, 2, -2, 2))
ax2.set_title('tricontour (%d points)' % npts)

plt.subplots_adjust(hspace=0.5)
plt.show()

#############################################################################
#
# ------------
#
# References
# """"""""""
#
# The use of the following functions and methods is shown in this example:

import matplotlib
matplotlib.axes.Axes.contour
matplotlib.pyplot.contour
matplotlib.axes.Axes.contourf
matplotlib.pyplot.contourf
matplotlib.axes.Axes.tricontour
matplotlib.pyplot.tricontour
matplotlib.axes.Axes.tricontourf
matplotlib.pyplot.tricontourf
2 changes: 1 addition & 1 deletion lib/matplotlib/mlab.py
Original file line number Diff line number Diff line change
Expand Up @@ -3312,7 +3312,7 @@ def newfunc(val, mask, mval):
fh.close()


@cbook.deprecated('2.2')
@cbook.deprecated('2.2', alternative='scipy.interpolate.griddata')
def griddata(x, y, z, xi, yi, interp='nn'):
"""
Interpolates from a nonuniformly spaced grid to some other grid.
Expand Down