-
Notifications
You must be signed in to change notification settings - Fork 862
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
Contour Plot #4296
Contour Plot #4296
Conversation
…the only change being the addition of a Z attribute to Point. Added TINPlot and Coordinate3d classes to create TIN diagrams, Voronoi Diagrams, and draw contours.
Hi @jon-rizzo,
|
was hoping that someone could contribute a meaningful example. my data is all proprietary and cannot be shared. random points with random elevations do not make a meaningful example.
scott expressed a desire not to make a dependency. I included the code to avoid a dependency & added the license agreement.
I had to make changes to DelaunatorSharp so that it would build against the null handling requirements. Not sure how to resolve the build failure. it is saying that I need to install various workloads. not sure how this is done or why it is required. |
All PR's are susceptible to this error for now. It appears to be a broken pipeline. You don't have to worry about this particular error, it is not up to you. |
Hi @jon-rizzo, thanks for this PR! I'm just now starting to take a closer look at it. However, I think @StendProg and I are having trouble evaluating this PR because it's not clear what the intended visual output is supposed to be. Proprietary sample data is not required to demonstrate how this plot type works if we can communicate the main idea using generated sample data. I modified this PR to add a cookbook page demonstrating how this plot type works. When the test runs is generates the following output. Is this the output you would expect given the sample data generated here? Do you have a recommendation for a better way to generate sample data? I'm a bit confused because the output looks very different from what I'd expect to see (plots like the demonstration ones at the top of #2230 and #3795) Coordinates3d[] cs = new Coordinates3d[500];
for (int i = 0; i < 500; i++)
{
double x = Generate.RandomNumber(0, Math.PI * 2);
double y = Generate.RandomNumber(0, Math.PI * 2);
double z = Math.Sin(x) + Math.Cos(y);
cs[i] = new(x, y, z);
}
TINSourceCoordinates3dArray data = new(cs.ToArray());
ScottPlot.Plottables.TINPlot contour = new(data);
myPlot.PlottableList.Add(contour); Thanks for your feedback! Additional Resources: |
I probably won't put too much more time into researching this at the moment, but highly relevant information is that Python's matplotlib has |
So, the contouring algorithm that I implemented is admittedly very naiive. It draws straight line contours on each triangle. As a result, large data sets (such as the one that I had originally cited) will show more "pleasing" contours than small ones. there are other contouring algorithms that will result in smoother (more visually pleasing, but technically less precise) contours. there are both contour smoothing algorithms and surface (TIN) smoothing algorithms that can do this so I don't think there is one "right answer". I think your data set did not generate contours because all of the values would be between 0 and 1. try changing the contouring interval to something smaller, like 0,1. Contours currently render in a single color. the colorized triangles that you showed (or other colorization options) should be easy enough to implement in the future, but I may have to leave that to others. Mostly, I wanted to get more eyes on this before I went too far. |
Sorry for the confusion - I have the defaults set differently than I was expecting. By default, the contours are not shown. you have to set the ContourLineWidth to at least 1, and your data set works best with the MinorInterval set to 0.1 (or some other value smaller than 1). If you modify your example as follows. you should get the results below.
or, even better, you can turn off the display of the triangles and points, add more points, and increase the contour interval slightly
|
This looks very interesting, you should have started with something like this, at the beginning it was really unclear what it was for. If we take a Heatmap with a regular grid, and put these isolines on top of it, it should be even more beautiful. int N = 100;
Coordinates3d[] cs = new Coordinates3d[N * N];
double[,] heatmapData = new double[N, N];
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
{
double x = 2.0 * Math.PI * i / N;
double y = 2.0 * Math.PI * j / N;
double z = Math.Sin(x) + Math.Cos(y);
cs[i * N + j] = new(x, y, z);
heatmapData[j, i] = z;
}
var heatmap = myPlot.Add.Heatmap(heatmapData);
heatmap.CellAlignment = Alignment.LowerLeft;
heatmap.CellWidth = 2.0 * Math.PI / N;
heatmap.CellHeight = 2.0 * Math.PI / N;
TINSourceCoordinates3dArray data = new(cs.ToArray());
ScottPlot.Plottables.TINPlot contour = new(data);
contour.MinorInterval = 0.2;
contour.ContourLineWidth = 1;
contour.LineWidth = 0;
contour.MarkerStyle = MarkerStyle.None;
myPlot.PlottableList.Add(contour); |
The first example that I posted is an elevation contour map of a real place on the earth. these are rarely, if ever, described as beautiful, but this is the context with which I am most familiar. I think the triangles were making it difficult to see the contours, but can have other uses, as scott pointed out in his images. my previous attempts with random points used random elevations, and the results were far from 'beautiful' because that type of data is not very meaningful. It did not occur to me to use a trig function based on X & Y to calculate Z. There are many more features that can be added in the future - the triangles themselves could be colored based a heatmap (like scott is showing on the left) or the space between the contours can be colored based on a heatmap (like scott is showing on the right). the contours could also be colored based on a heatmap. the most useful feature to most folks, however, would probably be adding labels to each index contour, each intermediate contour, or both. The plot control can also draw Voronoi diagrams of the resulting TIN, but I do not know the practical applications of those diagrams, or if any such applications even exist. |
Hi @jon-rizzo, thanks for the clarification - that helps a lot! The path forward is now a lot easier to see. Also @StendProg I love your example showing the contour lines over the heatmap! I'll continue to work on this PR and create cookbook examples as I go. I'll probably work toward moving as much logic as possible out of the Presently a lot of math is performed in the render loop, but it seems unlikely that users will be creating plots like this from "live data", so that work could probably be done up front. I'm even thinking that, when given a collection of 3d points, users may want to get different things to create different types of plots (perhaps leveraging existing plottables):
I'll keep experimenting and commit changes to this PR as I go. |
unlikely, but not unreasonable or impossible. I have seen several dynamic "grading optimizers" (in the civil engineering world) that adjusts elevations of all of the points and re-renders the tin and contours continuously while the optimizer converges on a solution . There are also simple widgets like this one: https://www.geogebra.org/m/Bkn8sw7v |
Still working on this, but I'll precalculate all the lines when the plottable is constructed, but expose an I greatly simplified |
As you mentioned, the benefit is speed. That, and simplicity of implementation. a spatial index could easily be created if the desire is for continuous, connected paths. There are more advanced algorithms for contouring to achieve smoother contours. There are many established algorithms for doing all of these things. Delaunay Triangulation is one very common solution, particularly with points that have irregular or random distribution. as a bonus, the resulting triangles can also be rendered quickly in 3D or displayed with different colors based on the elevation or slope to perform various analyses. if the points are on a grid, other solutions might be faster and/or more elegant. For example, the CONREC algorithm. but, my need is specifically for random points. I don't think there is one "best" way to draw contours for all situations, so I don't view this as an either/or choice. more solutions = more better. |
Okay, I brought this forward to a place where I'm happy to merge. This works now: myPlot.Add.ContourLines(coordinates); Limitations / ImprovementsThe Also every I don't intend to put time into these improvements right now (I wish to focus on some other open high priority issues) but if one of you wants to add this enhancement and create a PR I would be happy to review it! New Cookbook RecipesContour Lines from a Irregular Points (
|
Added DelaunatorSharp code with license agreement on each file, with a few minor changes: the addition of a Z attribute to Point, and changes that were necessary to support nullable references types. Added TINPlot and Coordinate3d classes to create TIN diagrams, Voronoi Diagrams, and draw contours.
A TINPlot is a class representing a Triangular Irregular Network, or TIN. A TIN is a 2d triangulation of points that will allow you to interpolate the value of a third dimension on a straight line between neighboring points. This class also allows you to draw a Voronoi diagram as well as the contours resulting from this interpolation. Each diagram has its own point and line style settings. Future work could include smoothing and could also be used to render a 3d surface, since the result is a set of 3d triangles.
#2230 #3795
Example: surface.csv
Data taken from this location:
https://cmgds.marine.usgs.gov/data/field-activity-data/2016-030-FA/