Colored maps / surface

Sep 9, 2009 at 10:04 PM

I was wondering if the D3 components could be used to generate a colored map, kind of a filled contour map.  Where the data is specified as a list of (x,y,z) values and z is mapped in a color scale like the HSB palette.  This is a sample image of what I am trying to do:

photo link

Thank you in advance.

Sep 9, 2009 at 11:47 PM

You could propbably use IsoPlot for this purpose since it accepts data in that format easily...

You'll probably have to modify IsoPlot itself a bit.

I need this for a project of mine also so if I find something I'll post here...

Sep 10, 2009 at 12:31 AM

I gave things a try: I have an app that collects 2D intensity data for a sample. I want to plot this data exactly in the way you describe. The data is originally collected as a double[] (so a 1D array) with the X and Y dimensions of the image known. Therefore it is easy to construct a 2D array of the data. Use this crude code as an example:

public void Plot()
        {
            double[,] data = new double[this.m_iWidth, this.m_iHeight];
            for (int row = 0; row < this.m_iHeight; row++)
            {

                for (int column = 0; column < this.m_iWidth; column++)
                {
                    data[column, row] = this.m_dData[row * this.m_iWidth + column];
                }
            }

            Point[,] gridData = new Point[this.m_iWidth, this.m_iHeight];
            for (int row = 0; row < this.m_iHeight; row++)
            {
                for (int column = 0; column < this.m_iWidth; column++)
                {
                    gridData[column, row] = new Point(row, column);
                }
            }

            WarpedDataSource2D<double> dataSource = new WarpedDataSource2D<double>(data, gridData);
            isolineGraph.DataSource = dataSource;
            trackingGraph.DataSource = dataSource;

            Rect visible = dataSource.GetGridBounds();
            plotter.Viewport.Visible = visible;
        }

This is backing code for the following XAML:

<d3:ChartPlotter Name="plotter">
                    <d3:IsolineGraph Name="isolineGraph"/>
                    <d3:IsolineTrackingGraph Name="trackingGraph"/>
                    <d3:CursorCoordinateGraph/>
</d3:ChartPlotter>

Taken directly from the IsoPlot example.

 

This actually works and I can clearly see a 2D plot of my data. However, for a 400 by 400 point dataset the performance when scrolling is horrible. Probably because the IsoPlot tries to do some interpolation/coloring on the points. This control is probably not meant for this kind of use...

 

Maybe this helps but indeed it would be nice to have the kind of "heatmap" functionality you describe...

 

Sep 10, 2009 at 12:58 AM

Just checked the nightlies... There is apparently an IntensityPlot now that seems to do what you want...

Question to the developer: Will the cross section be available for both axes?

 

Sep 10, 2009 at 2:38 AM

Hi Kris,

 

I just saw your posts. I went and checked the nightlies.  You are absolutly right.  It looks like that would do.  I will be trying tomorrow and will let you know how it goes.

 

Thanks.

Sep 10, 2009 at 6:47 PM

No problem!

I checked out this control and it is absolutely awesome! I have been tinkering with it a bit and was able to implement a cross section graph for the other dimension as well. If you want, I also implemented some extra colormaps...

 

Good luck!

 

Editor
Sep 10, 2009 at 7:30 PM

Hello gentlemen, sorry for interrupting your discussion)

I'm developer of DynamicDataDisplay. I'm not sure tha I have understood your requirements right, so can you please describe them in more details? Or you have already got what you wanted from D3?

 

By the way - IntensitySample is just a sample, it doesn't belong to our library, so there is no infrastructure around it. We are now creating a fully-functional color map.

Best regards,

Mikhail Brinchuk.

Sep 10, 2009 at 7:47 PM

Hi Mikhail,

Thanks for stepping in and letting us know there is a color map in the making.

The data I showed previously represents Iron concentration on the surface of a solar cell.  This data is stored as a set of (X,Y,Z), where X,Y are a point on the surface of the cell and Z is the corresponding iron concentration.  I was looking to have a colored map this data, and the NativeColorMap seems to be a basic but efficient way to display it.

I understand that what we talked about in this thread is not a "real" solution to displaying this kind of data, but at least it helps me to get out of the hole where I was.  It allows me to display some data.  Although it is based on generating a bitmap and just showing the image as part of the plot, it lets you do basic things as zooming and panning.  So, it is not that bad.

I would love to try the color map once it is out.

Thanks.

Carlos Almeida.

 

Sep 10, 2009 at 8:55 PM

Privet Mikhail :)

Personally I am developing a software package for the purpose of my phD project that would allow me to do 2D imaging of samples under a microscope.

My data are being stored by my software as an array of Int32. This array is 1D. Each Int32 represents the amount of photons emitted for a pixel in a set timeframe. Because I also know imagewidth and height I can convert this to double[,] easily.

What I needed was to have this XY color map plotted and also to have "cross section" views for both axes. The IntensitySample offers all these things.

The only two things I would need to solve is to somehow get both axes to display the physical measurements of my sample instead of the pixel value -> Suppose the image I record is 512 by 512 px than this can correspond to an area of 1000 by 1000 nm or some other values. I think this is easy by just manipulating the axisdata a bit.

The second thing that would be really good to have is some kind of ROI or POI selection on the plot so that I could mark a certain area and/or a list of points and be able to retrieve these points from the graph control do measure at these coordinates...

You talk about a more specialized color map... in what way would it be different from the IntensitySample (which uses bitmaps, which suits my purposes just fine).

Thanks already for creating these wonderful bits of code!

 

 

Sep 11, 2009 at 3:28 PM

Hello Mikhail,

I have a quick question about the IntensityPlot sample...

How do I align the "cross section" plots perfectly with the 2D plot? As you can see in the screenshot they are not really aligned. I tried setting a Height="(Binding Elementname=plotter, Path=Height}" on the cross section plotter, but this has no effect...

From RIS

 

Cheers,

Kris

 

Editor
Sep 11, 2009 at 5:15 PM

Hello Kris,

a quick answer for a quick question - I've uploaded new version of source code, it is changeset 28717, where I've used the following binding in IntensitySample:

Height="{Binding ElementName=plotter, Path=CentralGrid.ActualHeight}"

This is a binding to a layout part of Plotter, which is a host for all charts, so it is the very element which size should be useв in such bindings.

Regards,

Mikhail.

 

Editor
Sep 11, 2009 at 7:02 PM

By the way, Kris, you wrote:

This actually works and I can clearly see a 2D plot of my data. However, for a 400 by 400 point dataset the performance when scrolling is horrible. Probably because the IsoPlot tries to do some interpolation/coloring on the points. This control is probably not meant for this kind of use...

Though you've mentioned some IsoPlot, which is not known to me, it seems to me that you were speaking our IsolineGraph. Actually, it should be not very slow on such dataset you've mentioned. The slowest part of isoline drawing is a drawing of labels, so if you don't need them, you can switch them off by assigning false to isolineGraph.DrawLabels. This greatly improves pan and zoom performance.

Best regards,

Mikhail. 

Sep 11, 2009 at 8:18 PM

Hi Mikhail,

The modification you did to the IntensityPlot example indeed gives better results. It seems this was the binding I needed. I also had some succes by modifying the viewport directly (by assigning a new DataRect to the View property).

This actually brings me to a new question. By setting the binding to CentralGrid.ActualHeight somehow the viewport of the SectionGraph coinsides directly with the ends of the data (there is no "gap" beteween the graphed data and the border of the sectiongraph. In the prevous version the viewport was slightly bigger than the displayed data. Why is this? I have been looking a bit at the code but some subtle interactions between the different poperties are not always clear to me...

To answer you last question: Before I found out about the IntensityPlot in the nightly I initially tried the IsoPlot to display my data by just changing the datasource for the supplied IsoPlot example by my data. This dataset was 400*400 points but for some reason it was really slow. I will have a look again to see if the DrawLabels have something to do with this.

Your library is really an amazing set of controls. I will surely be looking at it more closely the coming days. Do you think it might be useful for your product if people would assist in documenting the functionality some more? (Things like the problem I had, etc...) Maybe writing a more detailed manual about the different features?

Cheers,

KrisJ

 

 

Sep 12, 2009 at 12:17 AM

 

Me Again,

Playing with IntensityPlot I think I discoverd some minor bugs;

If you change the dataset that is plotted in this way;

 

private double[,] BuildSampleData(int size)
{
    double[,] data = new double[size, size];

    for (int ix = 0; ix < size; ix++)
   {
	//double coeff = 0.0005 * ix;
	for (int iy = 0; iy < size; iy++)
	    {
		//double value = Math.Sin(coeff * iy);
                double value = Math.Sin(0.01 * iy);
		data[ix, iy] = value;
	     }
    }

    return data;
}

 

You will now have a simpler sine that is variable only in the Y dimension and constant in X (for all values of X, the values of Y are the same). The sine is also a bit asymmetric in relation to the viewport.

When I run Intensityplot like this you will see that:

a) The displayed image is oriented "the wrong way", the variation in intensity is displayed in the X dimension and not in Y as expected.

b) If the displayed image was correct then the SectionGraph should be a flat line at all times, yet it is not.

You can see both these things in the screenshot;

From RIS

When I look at the data array then I think that indeed the Sectiongraph is ALMOST correct since the data array holds a range of Y values for each value of X

From RIS

So I think that the NaiveColorMap BuildImage() method has an implementation error. The data[,] array holds X data in dimension 0 and Y in dim 1. It is not specified in the MSDN documentation but I suspect the WritableBitmap.WritePixels(...)  method will write an array of pixels to the BMP line per line (with lines being "horizontal" lines or lines of constant Y. However, in the NaiveColorMap implementation the data[,] is read in vertical lines that are being stuck after each other in the 1D array of pixels. This would actually mean that the image is flipped 90 degrees.

When I change the code in NaiveColorMap.BuildImage like this;

int pointer = 0;
for (int iy = 0; iy < height; iy++) // Read line per line in Y!!!!
{
      for (int ix = 0; ix < width; ix++)
	{
           double value = Data[ix, iy];
           double ratio = (value - min) / rangeDelta;
           Color color = Palette.GetColor(ratio);
           int argb = color.ToArgb();
           pixels[pointer++] = argb;
        }
}

Then the image looks a bit better already;

From RIS

However, the sectiongraph is also flipped the wrong way in relation to the image! The black area in the image is the lowest intensity, which is not the lowest point in the SectionGraph!

From RIS

In the second image this is also solved by changing CreateSection() in Window1.xaml.cs with this;

section[iy] = interpolatedValue; should become section[imageSize - 1 - iy] = interpolatedValue;

Could you confirm this (or tell me where I am wrong?).

Cheers,

KrisJ

Sep 20, 2009 at 11:12 AM

Hi guys,

 

Could anyone confirm my assumptions regarding NaiveColorMap BuildImage()?

 

Cheers,

 

Kris

 

Editor
Sep 25, 2009 at 4:22 PM
Edited Sep 25, 2009 at 7:42 PM

Hi Kris,

you are right, there were some bugs in this class, sorry for long waiting for answer.

Version of DynamicDataDisplay with fixes in this class will be uploaded to source code page in the nearest time.

Best regards,

Mikhail.

Editor
Sep 25, 2009 at 7:43 PM

Hi Kris,

I've uploaded fixed NaiveColorMap in changeset 28841.

Regards,

Mikhail.

Editor
Sep 25, 2009 at 7:47 PM

By the way, Kris, you've mentioned that you need control to select POIs - the latest changeset contains a first version of such control. It is PointSelector, you can find a sample with it DevSamples/PointSelectorSample.csproj

Mikhail.

Sep 25, 2009 at 7:50 PM

Hi Mikhail,

 

Thanks a lot, I'll check it out right now :)

 

Dec 10, 2009 at 7:03 PM

Hi,

Are there any news about colormap? I'd like to use it to plot a polar graphic with data defined by an triangular mesh. Is it possible to use NaiveColormap to do it (polar coordinate)?

 

Thanks

Rafael Albuquerque

Dec 11, 2009 at 5:37 PM

Hi,

I added this code to IsolineGraph to generate the graph that I wished.

          public void DoPaintAll()
        {
            DrawLabels = false;
            double step = (Collection.Max - Collection.Min) / 100000;
            for (double level = Collection.Min; level < Collection.Max; level += step)
            {
                Collection.AddCollection(IsolineBuilder.BuildIsoline(level));
            }
        }

It' s ok, but quite slow. Any suggestions?

 

 

 

Editor
Dec 13, 2009 at 4:25 PM

Hi Rafael,

your code with isoline is slow because you are making WPF to draw hundreds thousand lines, which is over the WPF's abilities.

Our color map is almost ready and will be released soon.

Best regards,

Mikhail.

May 11, 2010 at 2:21 PM

Mikhail,

     Have the color maps been released? If so, are there specific examples in the nightlies that you could refer me to? Thanks.

 

Jun 1, 2010 at 8:45 PM

KrisJ, were you ever able to find a solution to your question earlier in this thread?

"The only two things I would need to solve is to somehow get both axes to display the physical measurements of my sample instead of the pixel value -> Suppose the image I record is 512 by 512 px than this can correspond to an area of 1000 by 1000 nm or some other values. I think this is easy by just manipulating the axisdata a bit."

I am looking for a combination of the IsolineGraph example and the IntensityGraph. I would like the look of the IntensityGraph, with the synchronized sections. However, I want my x,y axis to be displayed in feet, not pixels. I would also like the value displayed to be my true z value, not the ratio. Thanks in advance.

 

PS. Does anyone ever check these boards? I've posted numerous questions with not much of a response. Thanks again.

Editor
Jun 4, 2010 at 2:44 PM

Please wait for June 20 or like that. Now I simply have important exams, so I have no time to spend for D3)

Editor
Jun 20, 2010 at 2:26 PM

Answering to Brian Bauer:

to change bounds rectangle of NaiveColorMap, please set you own value to d3:ViewportPanel.ViewportBounds in the following code region

<d3:ChartPlotter Name="plotter" Grid.Row="0" Grid.Column="1">
	<d3:ViewportHostPanel>
		<Image Name="image" d3:ViewportPanel.ViewportBounds="0,0,1,1" Stretch="Fill"/>
	</d3:ViewportHostPanel>
...
</d3:ChartPlotter>

in IntensityChart sample.

 

Mikhail.

Jun 23, 2010 at 4:34 PM

This does not work as expected. I have tried various ViewportBounds and the visible area displayed after the chart is populated does not match the ViewportBounds DataRect. The displayed visible area is inconsistent. Also, by changing the ViewportBounds, the two additional plots associated with the chartPlotter no longer update correctly. When you drag the cursor around it still picks up underlying data as if the image ViewportBounds are still "0,0,1,1". I believe this is a bug.

Jun 23, 2010 at 4:40 PM

Also, when changing the bounds of the image, the bounds of the two synchronized X & Y slices do not change. I have yet to figure out how to get the XY axis of the intensity plot to show my data range, as well as the X plot and Y plot to show the actual data range. Right now the intensity plot shows a pixel value or ratio (0,0,1,1) and the associated X & Y plots have data point numbers as their x axis.

 

Apr 3, 2012 at 3:58 PM

I am confused by this thread!  I too would like a version of IsolineGraph that can "shade" inbetween the lines.  However, I cannot locate the sample "IntensityChart" anywhere.

Can somebody point me in the right direction? 

Thanks

Craig