Intensity Type SurfaceGridSeries3D ??
Moderator: Queue Moderators
Intensity Type SurfaceGridSeries3D ??
How would I go about colouring a SurfaceGridSeries3D based on values other than the values used for the Y axis?
As an example I have the following data for a rectangular grid:
- depth
- temperature
- pressure
I want to plot the SurfaceGridSeries3D using my depth values for the Y axis, then use a gradient Palette from the temperature values I have for each XZ. I then might even like to show contour lines based on the pressure values I have. Is this possible?
Thanks
Greg.
As an example I have the following data for a rectangular grid:
- depth
- temperature
- pressure
I want to plot the SurfaceGridSeries3D using my depth values for the Y axis, then use a gradient Palette from the temperature values I have for each XZ. I then might even like to show contour lines based on the pressure values I have. Is this possible?
Thanks
Greg.
- ArctionPasi
- Posts: 1367
- Joined: Tue Mar 26, 2013 10:57 pm
- Location: Finland
- Contact:
Re: Intensity Type SurfaceGridSeries3D ??
The palette-coloring is made only by Y value. There's no separate Intensity field in the points, that's a difference to 2D view's Intensity series.
You can however give a color for your data Surface data points.
Set surface.Fill = FromSurfacePoints.
In the data filling loop, set Color field for every point. You can use the ContourPalette to convert the intensity values into colors.
surface.Data[i,j].Y = yValue;
surface.ContourPalette.GetColorByValue(intensityValue, out surface.Data[i,j].Color);
You may want to add another SurfaceGridSeries3D with Fill = Paletted to show the legend palette, because setting Fill.FromSurfacePoints legend will be meaningless.
Contour lines is available based on Y value only.
Another approach:
Set surface.Fill = Bitmap. Then create a bitmap based on your intensity colors. The resolution of the bitmap can be different from your surface.SizeX and SizeY. Set the bitmap to surface.BitmapFill.Image property. Bitmap will be stretched to fit.
You may even want to use ViewXY's IntensityGridSeries with contours, and use chart.SaveToFile/SaveToStream methods to export the bitmap. You can use output size parameters with these methods, if you want higher-resolution bitmap than your screen is.
You can however give a color for your data Surface data points.
Set surface.Fill = FromSurfacePoints.
In the data filling loop, set Color field for every point. You can use the ContourPalette to convert the intensity values into colors.
surface.Data[i,j].Y = yValue;
surface.ContourPalette.GetColorByValue(intensityValue, out surface.Data[i,j].Color);
You may want to add another SurfaceGridSeries3D with Fill = Paletted to show the legend palette, because setting Fill.FromSurfacePoints legend will be meaningless.
Contour lines is available based on Y value only.
Another approach:
Set surface.Fill = Bitmap. Then create a bitmap based on your intensity colors. The resolution of the bitmap can be different from your surface.SizeX and SizeY. Set the bitmap to surface.BitmapFill.Image property. Bitmap will be stretched to fit.
You may even want to use ViewXY's IntensityGridSeries with contours, and use chart.SaveToFile/SaveToStream methods to export the bitmap. You can use output size parameters with these methods, if you want higher-resolution bitmap than your screen is.
LightningChart Support Team, PT
Re: Intensity Type SurfaceGridSeries3D ??
Any chance of adding support for this native to Lightning Chart say with a IntensitySurfaceGridSeries3D type?
This type of visualization is very common in scientific applications, specifically for geology where the user wants to see their data on a surface. In the oil and gas world this is the main type of 3D surface plot made. The "surface" is depth and the colouring is data (temperature, pressure, water saturation, facies (rock type), etc...).
Do you have a code example for your second example above (Intensity data as bitmap fill of SurfaceGrid3D)?
Thanks.
Greg.
This type of visualization is very common in scientific applications, specifically for geology where the user wants to see their data on a surface. In the oil and gas world this is the main type of 3D surface plot made. The "surface" is depth and the colouring is data (temperature, pressure, water saturation, facies (rock type), etc...).
Do you have a code example for your second example above (Intensity data as bitmap fill of SurfaceGrid3D)?
Thanks.
Greg.
- ArctionPasi
- Posts: 1367
- Joined: Tue Mar 26, 2013 10:57 pm
- Location: Finland
- Contact:
Re: Intensity Type SurfaceGridSeries3D ??
That's definitely in plans during next year or so. It would be very handy.
I'll try to provide you an example by using IntensityGridSeries to compose animated bitmap, and to update that over animated Y-animated SurfaceGridSeries3D.
I'll try to provide you an example by using IntensityGridSeries to compose animated bitmap, and to update that over animated Y-animated SurfaceGridSeries3D.
LightningChart Support Team, PT
- ArctionPasi
- Posts: 1367
- Joined: Tue Mar 26, 2013 10:57 pm
- Location: Finland
- Contact:
Re: Intensity Type SurfaceGridSeries3D ??
Ok, I made an example project.
It's using 2 charts. 2D intensity chart not visible in the back, and 3D surface chart on the front. 2D chart makes the intensity plot, and exports it to bitmap stream.
3D charts reads the bitmap stream.
Both intensity data and surface data are animated, and therefore a bit heavy.
I hope this helps...
It's using 2 charts. 2D intensity chart not visible in the back, and 3D surface chart on the front. 2D chart makes the intensity plot, and exports it to bitmap stream.
3D charts reads the bitmap stream.
Both intensity data and surface data are animated, and therefore a bit heavy.
I hope this helps...
LightningChart Support Team, PT
Re: Intensity Type SurfaceGridSeries3D ??
Hello Pasi,
In March of 2014 you said:
I tried the bitmap method, using your sample from above. However something seems to have changed in the latest version of LC and I get a bitmap with the axis shown, see attached screen shot.
We need to make 4D plots, that is a 3D surface plot that is coloured by another variable. This is very very common plot to make. Colouring by height is almost never done. As mentioned above it would be great if there was a "contour series" so that as with colouring, contours can be added independent of height, based on another variable. Below is a screen shot that we made using commercial plotting software, the colouring and contours are independent of height.
In March of 2014 you said:
Any news on adding Intensity 3D surface? Also contours independent of height (Y)?That's definitely in plans during next year or so. It would be very handy
I tried the bitmap method, using your sample from above. However something seems to have changed in the latest version of LC and I get a bitmap with the axis shown, see attached screen shot.
We need to make 4D plots, that is a 3D surface plot that is coloured by another variable. This is very very common plot to make. Colouring by height is almost never done. As mentioned above it would be great if there was a "contour series" so that as with colouring, contours can be added independent of height, based on another variable. Below is a screen shot that we made using commercial plotting software, the colouring and contours are independent of height.
- ArctionPasi
- Posts: 1367
- Joined: Tue Mar 26, 2013 10:57 pm
- Location: Finland
- Contact:
Re: Intensity Type SurfaceGridSeries3D ??
v.7 and its new DirectX11 engine takes majority of our time. I'm sorry we haven't found time to implement 3D intensity surfaces yet. It's still on our to-do list.
Independent intenisity contours in 3D are not in our to-do list, and can't promise that to be implemented. These kind of features take months of programming time.
About capturing the bitmap from ViewXY, set ViewXY.AxisLayout.AutoAdjustMargins = false, and you should get similar bitmap than before.
Independent intenisity contours in 3D are not in our to-do list, and can't promise that to be implemented. These kind of features take months of programming time.
About capturing the bitmap from ViewXY, set ViewXY.AxisLayout.AutoAdjustMargins = false, and you should get similar bitmap than before.
LightningChart Support Team, PT
Re: Intensity Type SurfaceGridSeries3D ??
Hi,
For colouring the surface from a value other than the Y value I have used your "FromSurfacePoints" method:
I'm running into two problems with the second SurfaceGridSeries3D:
- the background is not transparent, it appears to be Gray. Not sure where that colour is coming from. I've tried saving the image as both TargetImageFormat.Bmp and TargetImageFormat.Png, same result.
- the contour lines look very stretched on the SurfaceGridSeries3D.
Below are some screen shots to show what is happening
First SurfaceGridSeries3D with colouring FromSurfacePoints, this is OK: IntensityGridSeries just to get contours, all backgrounds set to transparent and Fill None: Second SurfaceGridSeries3D surface with BitmapFill.Image from above IntensityGridSeries Finally if I save the IntensityGridSeries to file using _contourChart.SaveToFile("contour.Png"); I get this (which has transparent background) (in next post as I can only post 3 images)
For colouring the surface from a value other than the Y value I have used your "FromSurfacePoints" method:
and this seems acceptable. Now I'm trying to get independent contours (contours not related to Y). To do that I am creating a 2D IntensityGridSeries, with transparent background, and calling SaveToStream. I then create a second SurfaceGridSeries3D surface, with same Y values as the first SurfaceGridSeries3D. Then I fill this second surface with the bitmap created by the IntensityGridSeries.You can however give a color for your data Surface data points.
Set surface.Fill = FromSurfacePoints.
In the data filling loop, set Color field for every point. You can use the ContourPalette to convert the intensity values into colors.
surface.Data[i,j].Y = yValue;
surface.ContourPalette.GetColorByValue(intensityValue, out surface.Data[i,j].Color);
I'm running into two problems with the second SurfaceGridSeries3D:
- the background is not transparent, it appears to be Gray. Not sure where that colour is coming from. I've tried saving the image as both TargetImageFormat.Bmp and TargetImageFormat.Png, same result.
- the contour lines look very stretched on the SurfaceGridSeries3D.
Below are some screen shots to show what is happening
First SurfaceGridSeries3D with colouring FromSurfacePoints, this is OK: IntensityGridSeries just to get contours, all backgrounds set to transparent and Fill None: Second SurfaceGridSeries3D surface with BitmapFill.Image from above IntensityGridSeries Finally if I save the IntensityGridSeries to file using _contourChart.SaveToFile("contour.Png"); I get this (which has transparent background) (in next post as I can only post 3 images)
Re: Intensity Type SurfaceGridSeries3D ??
Finally if I save the IntensityGridSeries to file using _contourChart.SaveToFile("contour.Png"); I get this (which has transparent background)
Code to create Contours:
Code to create second SurfaceGridSeries3D
Any ideas to get this to work?
I will post the project file...
Here is the code to create the first SurfaceGridSeries3D Code: Select all
//Create new chart
m_chart = new LightningChartUltimate(LicenseKeys.LicenseKeyStrings.LightningChartUltimate);
//Disable rendering, strongly recommended before updating chart properties
m_chart.BeginUpdate();
//Set 3D as active view
m_chart.ActiveView = ActiveView.View3D;
//Chart parent must be set
m_chart.Parent = this.splitContainer1.Panel1;
//Fill parent area with chart
m_chart.Dock = DockStyle.Fill;
//Chart name
m_chart.Name = title;
m_chart.Title.Text = title;
//Set x-rotation
// m_chart.View3D.Camera.RotationX = 38;
m_chart.View3D.Camera.OrthographicCamera = true;
//scale X and Y (X and Z on lightning chart) for correct aspect ratio
double lX = ((nY - 1) * dy);
double lZ = ((nX - 1) * dx);
double maxdie = lZ;
if (lX > lZ) maxdie = lX;
m_chart.View3D.Dimensions.X = Convert.ToSingle(lX * 100.0 / maxdie);
m_chart.View3D.Dimensions.Z = Convert.ToSingle(lZ * 100.0 / maxdie);
m_chart.View3D.Dimensions.Y = m_yscale;
//Set transparent walls
List<WallBase> walls = m_chart.View3D.GetWalls();
foreach (WallBase wall in walls)
{
wall.Material.DiffuseColor = Color.FromArgb(30, wall.Material.DiffuseColor);
wall.SetGridStripColor1(Color.FromArgb(60, wall.GetGridStripColor1()));
wall.SetGridStripColor2(Color.FromArgb(60, wall.GetGridStripColor2()));
}
//Lightning Chart coords, our X = their Z, our Y = their X, our Z = their Y on 3D plots
m_chart.View3D.XAxisPrimary3D.SetRange(orgY, orgY + ((nY - 1) * dy));
m_chart.View3D.XAxisPrimary3D.Title.Text = "Y Axis";
m_chart.View3D.XAxisPrimary3D.Reversed = true;
m_chart.View3D.ZAxisPrimary3D.SetRange(orgX, orgX + ((nX - 1) * dx));
m_chart.View3D.ZAxisPrimary3D.Title.Text = "X Axis";
float[] fz = Z.Where(z => !Double.IsNaN(z)).ToArray();//filter out NaNs before getting Z (depth) min/max
m_chart.View3D.YAxisPrimary3D.SetRange(fz.Min(), fz.Max());
//m_chart.View3D.YAxisPrimary3D.Reversed = true;//depths are positive values "Below Sea Level", so reverse
m_chart.View3D.YAxisPrimary3D.Title.Text = "Burial Depth";
//this doesn't seem to work as expected with reversed axis, seems to be lit from bottom
//m_chart.View3D.SetPredefinedLightingScheme(LightingScheme.Default);
m_chart.View3D.ZoomPanOptions.AxisMouseWheelAction = AxisMouseWheelAction.ZoomAll;
//Add 3D surface grid
SurfaceGridSeries3D gridSeries = new SurfaceGridSeries3D(m_chart.View3D, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary);
IntensityGridSeries gridColourSeries = new IntensityGridSeries(m_chart.ViewXY, m_chart.ViewXY.XAxes[0], m_chart.ViewXY.YAxes[0]);
gridSeries.Title.Text = title;
float[] fcz = Z.Where(z => !Double.IsNaN(z)).ToArray();
float[] fcolourz = zColour.Where(z => !Double.IsNaN(z)).ToArray();
gridSeries.ContourPalette = CreatePalette(gridSeries, fcolourz.Min(), fcolourz.Max());
gridSeries.ContourLineType = ContourLineType.None;
gridSeries.ContourPalette.Type = PaletteType.Gradient;
gridSeries.WireframeType = SurfaceWireframeType.None;
gridSeries.Fill = SurfaceFillStyle.FromSurfacePoints;
gridSeries.SetRangesXZ(orgY, orgY + ((nY - 1) * dy), orgX, orgX + ((nX - 1) * dx));
gridSeries.SetSize(nY, nX);
gridColourSeries.SetRangesXY(orgX, orgX + ((nX - 1) * dx), orgY, orgY + ((nY - 1) * dy));
gridColourSeries.SetSize(nY, nX);
gridSeries.ColorSaturation = 65;
m_chart.View3D.SurfaceGridSeries3D.Add(gridSeries);
//Lightning Chart coords, our X = their Z, our Y = their X, our Z = their Y on 3D plots
for (int iNodeX = 0; iNodeX < nY; iNodeX++)
{
for (int iNodeZ = 0; iNodeZ < nX; iNodeZ++)
{
gridSeries.Data[(nY - 1) - iNodeX, iNodeZ].Y = (Z[iNodeZ * nY + iNodeX]);//stored column major
gridSeries.ContourPalette.GetColorByValue(zColour[iNodeZ * nY + iNodeX], out gridSeries.Data[(nY - 1) - iNodeX, iNodeZ].Color);
}
}
//Notify new values are ready
gridSeries.InvalidateData();
Create2DContourChart(gridColourSeries, zContour);
Create3DContourSurfaceChart(m_chart, gridSeries);
//Allow chart rendering
m_chart.EndUpdate();
Code: Select all
private ValueRangePalette CreateContourPalette(Arction.LightningChartUltimate.SeriesXY.SeriesBaseXY ownerSeries, double ymin, double YRange)
{
ValueRangePalette palette = new ValueRangePalette(ownerSeries);
palette.Type = PaletteType.Gradient;
double yRange = YRange - ymin;
palette.Steps.Clear();
palette.MinValue = ymin;
palette.Steps.Add(new PaletteStep(palette, Color.FromArgb(0, 0, 0, 0), ymin));
palette.Steps.Add(new PaletteStep(palette, Color.FromArgb(0, 0, 0, 0), ymin + 33 * yRange / 100.0));
palette.Steps.Add(new PaletteStep(palette, Color.FromArgb(0, 0, 0, 0), ymin + 66 * yRange / 100.0));
palette.Steps.Add(new PaletteStep(palette, Color.FromArgb(0, 0, 0, 0), ymin + 100.0 * yRange / 100.0));
palette.Steps.Add(new PaletteStep(palette, Color.FromArgb(0, 0, 0, 0), ymin - 10)); //Aux step
palette.Steps.Add(new PaletteStep(palette, Color.FromArgb(0, 0, 0, 0), -1E9)); //Aux step
return palette;
}
/// <summary>
/// Intensity chart renders intensity data from given data set, and exports a bitmap image.
/// </summary>
void Create2DContourChart(IntensityGridSeries gridColourSeries, float[] contourData)
{
_contourChart = new LightningChartUltimate();
_contourChart.BeginUpdate();
this.splitContainer1.Panel2.BackColor = Color.Blue;
this.BackColor = Color.Red;
_contourChart.Parent = this.splitContainer1.Panel2;
_contourChart.Dock = DockStyle.Fill;
_contourChart.Width = gridColourSeries.SizeX;
_contourChart.Height = gridColourSeries.SizeY;
_contourChart.RenderOptions.AntiAliasLevel = 4;
_contourChart.Background.Color = Color.Transparent;
//_contourChart.Background.GradientColor = Color.Transparent;
//_contourChart.Background.GradientFill = GradientFill.Solid;
_contourChart.Background.Style = RectFillStyle.None;
//_contourChart.ViewXY.GraphBackground.Color = Color.DarkMagenta;
//_contourChart.ViewXY.GraphBackground.GradientColor = Color.DarkGreen;
_contourChart.ViewXY.GraphBackground.Style = RectFillStyle.None;
_contourChart.ActiveView = ActiveView.ViewXY;
_contourChart.Title.Visible = false;
ViewXY v = _contourChart.ViewXY;
v.LegendBox.Visible = false;
//Remove all margins
v.Margins = new System.Windows.Forms.Padding(0);
v.GraphBorderColor = Color.Transparent;
IntensityGridSeries grid = new IntensityGridSeries(v, v.XAxes[0], v.YAxes[0]);
grid.SetRangesXY(gridColourSeries.RangeMinX, gridColourSeries.RangeMaxX, gridColourSeries.RangeMinY, gridColourSeries.RangeMaxY);
grid.SetSize(gridColourSeries.SizeX, gridColourSeries.SizeY);
grid.ContourLineType = ContourLineType.ColorLine;
grid.ContourLineStyle.Color = Color.Black;
grid.ContourLineStyle.Pattern = LinePattern.Solid;
grid.ContourLineStyle.Width = 2;
v.AxisLayout.AutoAdjustMargins = false;
float[] fz = contourData.Where(z => !Double.IsNaN(z)).ToArray();//filter out NaNs before getting contour data
grid.ValueRangePalette = CreateContourPalette(grid, fz.Min(), fz.Max());
v.IntensityGridSeries.Add(grid);
//Set axis ranges sow that intensity grid fills it. Minimums same and Maximums same.
v.XAxes[0].SetRange(gridColourSeries.RangeMinX, gridColourSeries.RangeMaxX);
v.YAxes[0].SetRange(gridColourSeries.RangeMinY, gridColourSeries.RangeMaxY);
for (int iNodeX = 0; iNodeX < gridColourSeries.SizeX; iNodeX++)
{
for (int iNodeZ = 0; iNodeZ < gridColourSeries.SizeY; iNodeZ++)
{
grid.Data[(gridColourSeries.SizeX - 1) - iNodeX, iNodeZ].Value = (contourData[iNodeZ * gridColourSeries.SizeX + iNodeX]);//stored column major
}
}
_contourChart.EndUpdate();
_contourChart.SaveToStream(_bitmapStream, TargetImageFormat.Png);
_contourChart.SaveToFile("contour.Png");
}
Code: Select all
void Create3DContourSurfaceChart(LightningChartUltimate _surface3DChart, SurfaceGridSeries3D depthSurface)
{
View3D v = _surface3DChart.View3D;
v.LegendBox.Visible = false;
SurfaceGridSeries3D surface = new SurfaceGridSeries3D(v, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary);
surface.SetRangesXZ(depthSurface.RangeMinX, depthSurface.RangeMaxX, depthSurface.RangeMinZ, depthSurface.RangeMaxZ);
surface.SetSize(depthSurface.SizeX, depthSurface.SizeZ);
surface.BitmapFill.Image = Bitmap.FromStream(_bitmapStream);
surface.Fill = SurfaceFillStyle.Bitmap;
//surface.ToneColor = Color.Beige;
surface.ContourLineType = ContourLineType.None;
surface.WireframeType = SurfaceWireframeType.None;
surface.ColorSaturation = 75;
surface.BaseColor = Color.Transparent;
surface.ToneColor = Color.Transparent;
surface.ContourPalette = depthSurface.ContourPalette;
for (int i = 0; i < depthSurface.SizeX; i++)
{
for (int j = 0; j < depthSurface.SizeZ; j++)
{
surface.Data[i, j].Y = depthSurface.Data[i, j].Y + 500.0;//add some constant to Y so this surface is distinct from first, just for testing
}
}
v.SurfaceGridSeries3D.Add(surface);
surface.InvalidateData();
}
Any ideas to get this to work?
I will post the project file...
Re: Intensity Type SurfaceGridSeries3D ??
Attached test project, note I removed my LicenseKeyStrings.cs
- ArctionPasi
- Posts: 1367
- Joined: Tue Mar 26, 2013 10:57 pm
- Location: Finland
- Contact:
Re: Intensity Type SurfaceGridSeries3D ??
We have made a lot of work to get this working in approx 7.1 version, developed new contouring 3D algorithms etc. So eventually it will find its way to final product.
We can provide you a demo application with these contouring algorithms, but we can't put them visible here in the forums. The algorithms are considered proprietary. Please contact our support by e-mail with declaration of confidentiality (pdf), that you won't spread the code or algorithm around and write your signature in there. Also put your company and subscription ID in the document.
Thanks
We can provide you a demo application with these contouring algorithms, but we can't put them visible here in the forums. The algorithms are considered proprietary. Please contact our support by e-mail with declaration of confidentiality (pdf), that you won't spread the code or algorithm around and write your signature in there. Also put your company and subscription ID in the document.
Thanks
LightningChart Support Team, PT