Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Treemap

33 views
Skip to first unread message

Eric

unread,
May 6, 2005, 11:40:47 AM5/6/05
to
Is there a way to manipulate the color of a node outside the ColorMetric
property using the TreemapControl?

For example, I am interested in changing the background color of values of 0
from white to another color.

I've noted that the TreemapGenerator class has a DrawItem Event, but the
TreemapControl is lacking one.

Is there a way to force equal size subnodes within a parent node -
whitespace as a placeholder is acceptable if neccessary to keep the subnodes
the same size - the data is only 2 levels... I figure the EmptySpace object
might work in this case. Is it easy to determine the proper SizeMetric on
the fly after the layout?

Thanks,
Eric


Tony Capone

unread,
May 9, 2005, 8:33:17 PM5/9/05
to
Eric:

You have control over the maximum and minimum colors, which are green and
red by default, but a Node.ColorMetric value of 0 is always white. (It
would have been possible to make the 0 color programmable also, but the
resulting color gradients would be meaningless in most cases. Would a
gradient of green-to-purple, and then purple-to-red make visual sense, for
example?)

TreemapGenerator supports custom drawing via the DrawItem event, but
TreemapControl does not. That is a requested feature that has not yet been
implemented.

I'm not sure I understand your last question. The size of each node is
determined by its Node.SizeMetric property. If you want all children of a
parent node to be the same size, you would set the children's SizeMetric
properties all to the same value. If this isn't what you're asking, please
let me know.

-- Tony Capone

"Eric" <elongatdontspammegetcollccom> wrote in message
news:Ogzt6Hl...@TK2MSFTNGP15.phx.gbl...

Eric

unread,
May 10, 2005, 11:21:07 AM5/10/05
to
Tony,
I'm posting inline...

"Tony Capone" <msr_n...@microsoft.com> wrote in message
news:%23Cf4cfP...@tk2msftngp13.phx.gbl...


> Eric:
>
> You have control over the maximum and minimum colors, which are green and
> red by default, but a Node.ColorMetric value of 0 is always white. (It
> would have been possible to make the 0 color programmable also, but the
> resulting color gradients would be meaningless in most cases. Would a
> gradient of green-to-purple, and then purple-to-red make visual sense, for
> example?)

I think that being able to define the zero point is useful, perhaps not as
purple. The ability to define the zero point as say a greyscale centerpoint
- be it black or some other shade - allows flexibility on the coloring of
the
overall layout while still providing a neutral color.

Which, my solution may be in your second point...

> TreemapGenerator supports custom drawing via the DrawItem event, but
> TreemapControl does not. That is a requested feature that has not yet
been
> implemented.

Maybe the way to create a different coloring scheme is to wrap the
TreeGenerator in a custom control and take the information from the DrawItem
event to draw the leafs with custom coloring using the Draw method
with a rectangle in conjuntion with the DrawItem event.

> I'm not sure I understand your last question. The size of each node is
> determined by its Node.SizeMetric property. If you want all children of a
> parent node to be the same size, you would set the children's SizeMetric
> properties all to the same value. If this isn't what you're asking,
please
> let me know.

I was trying - unsuccessfully - to describe a QuantumTreemap:
http://iv.slis.indiana.edu/sw/images/quantumtreemap.jpg

What I was trying to ask was if there was a way to manipulate the EmptySpace
class for the leaf node at some point in the layout calculation to provide
the whitespace padding which would allow me to create a QuantumTreemap.

Thanks,
Eric

Tony Capone

unread,
May 10, 2005, 2:45:05 PM5/10/05
to
Eric:

Your idea for wrapping the TreemapGenerator in a custom control and taking
advantage of TreemapGenerator's custom drawing facility is a good one. It's
actually quite easy to do. I'll attach some sample code in a separate
posting.

You can manipulate the EmptySpace object to provide empty space in each
node, but the layout algorithm we use is not going to give you the perfectly
square nodes I see in the QuantamTreemap. You can do this yourself if
you're using custom drawing and your drawing code uses its own layout
algorithm for the level-2 nodes, but it's not going to be as easy as letting
our component compute its default layout.

-- Tony Capone

"Eric" <elongatdontspammegetcollccom> wrote in message

news:uoKFrPXV...@tk2msftngp13.phx.gbl...

Tony Capone

unread,
May 10, 2005, 2:50:35 PM5/10/05
to
Here is some sample code I wrote to draw a photo in each treemap node. It
shows how to wrap the
TreemapGenerator in a custom control and use owner (custom) drawing.

-- Tony Capone

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;
using Microsoft.Research.CommunityTechnologies.Treemap;

namespace Microsoft.Research.CommunityTechnologies.CustomTreemapPanel
{
//*****************************************************************************
// Class: TreemapPanel
//
/// <summary>
/// Represents a custom panel that displays an owner-drawn treemap. The
/// treemap nodes represent people. Each person's image is drawn in the
node's
/// rectangle.
/// </summary>
//*****************************************************************************

public class TreemapPanel : Panel
{
//*************************************************************************
// Constructor: TreemapPanel()
//
/// <summary>
/// Initializes a new instance of the TreemapPanel class.
/// </summary>
//*************************************************************************

public TreemapPanel()
{
// Create the treemap drawing engine.

m_oTreemapGenerator = new TreemapGenerator();

// We want to do owner drawing, so handle the DrawItem event.

m_oTreemapGenerator.DrawItem +=
new TreemapGenerator.TreemapDrawItemEventHandler(DrawItem);

m_oGraphics = null;

// Populate the treemap with Person objects.

PopulateTreemap();

// Avoid flicker while drawing. According to "Windows Forms
// Programming in C#," the following three styles are all required.

this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);

// Force the panel to be redrawn when it's resized.

this.ResizeRedraw = true;

AssertValid();
}

//*************************************************************************
// Method: PopulateTreemap()
//
/// <summary>
/// Populates the treemap with Person objects.
/// </summary>
//*************************************************************************

protected void
PopulateTreemap()
{
// Load some images to use for the Person objects.

Image oImage1 = Image.FromFile("..\\..\\Images\\Follow.jpg");
Image oImage2 = Image.FromFile("..\\..\\Images\\RedMoonDesert.jpg");
Image oImage3 = Image.FromFile("..\\..\\Images\\Tulips.jpg");

Nodes oNodes;
Node oNode;

// Get the collection of top-level nodes.

oNodes = m_oTreemapGenerator.Nodes;

// Create a Person object.

Person oPerson1 = new Person("Person1", oImage1);

// Add a top-level node to the collection. The treemap will be
owner-
// drawn, so the text and colorMetric arguments to the Add() method
// won't be used and can be set to anything.

oNode = oNodes.Add("", 25F, 0F);

// Store the Person object in the node's Tag.

oNode.Tag = oPerson1;

// Repeat for two more Person objects.

Person oPerson2 = new Person("Person2", oImage2);
oNode = oNodes.Add("", 50F, 0F);
oNode.Tag = oPerson2;

Person oPerson3 = new Person("Person3", oImage3);
oNode = oNodes.Add("", 75F, 0F);
oNode.Tag = oPerson3;
}

//*************************************************************************
// Method: OnPaint()
//
/// <summary>
/// Handles the Paint event on the Panel.
/// </summary>
///
/// <param name="e">
/// Standard event argument.
/// </param>
//*************************************************************************

protected override void
OnPaint
(
PaintEventArgs e
)
{
AssertValid();

// Save the Graphics object so it can be accessed by OnDrawItem().

m_oGraphics = e.Graphics;

// Tell the TreemapGenerator to draw the treemap using owner-
// implemented code. This causes the DrawItem event to get fired
for
// each node in the treemap.

m_oTreemapGenerator.Draw(this.ClientRectangle);

// All DrawItem events have been fired. Make sure the Graphics
object
// doesn't get used again.

m_oGraphics = null;
}

//*************************************************************************
// Method: OnClick()
//
/// <summary>
/// Handles the Click event on the Panel.
/// </summary>
///
/// <param name="e">
/// Standard event argument.
/// </param>
//*************************************************************************

protected override void
OnClick
(
EventArgs e
)
{
AssertValid();

// The coordinates are not provided in the event arguments, so we
have
// to get them from a static Control method.

Point oMousePositionScreen = Control.MousePosition;

// Convert the screen coordinates to this panel's client
coordinates.

Point oMousePositionClient =
this.PointToClient(oMousePositionScreen);

// Get the node under this point, if there is one.

Node oClickedNode;

if ( m_oTreemapGenerator.GetNodeFromPoint(
oMousePositionClient.X, oMousePositionClient.Y,
out oClickedNode) )
{
// Retrieve the Person object from the clicked node's tag.

Debug.Assert(oClickedNode.Tag is Person);
Person oPerson = (Person)oClickedNode.Tag;

MessageBox.Show( String.Format(
"{0} node was clicked.",
oPerson.Name
) );
}
}

//*************************************************************************
// Method: DrawItem()
//
/// <summary>
/// Handles the DrawItem event on the TreemapGenerator.
/// </summary>
///
/// <param name="sender">
/// Standard event argument.
/// </param>
///
/// <param name="e">
/// Standard event argument.
/// </param>
//*************************************************************************

protected void
DrawItem
(
Object sender,
TreemapDrawItemEventArgs e
)
{
AssertValid();

// Retrieve the node that needs to be drawn.

Node oNode = e.Node;

// Retrieve the Person object from the node's tag.

Debug.Assert(oNode.Tag is Person);
Person oPerson = (Person)oNode.Tag;

// Make sure the Graphics object was properly set in the OnPaint()
// handler.

Debug.Assert(m_oGraphics != null);

// Draw the person's image in the specified rectangle. (This
version
// of DrawImage() distorts the image.)

m_oGraphics.DrawImage(oPerson.Image, e.Bounds);
}


//*************************************************************************
// Method: AssertValid()
//
/// <summary>
/// Asserts if the object is in an invalid state. Debug-only.
/// </summary>
//*************************************************************************

[Conditional("DEBUG")]

public void
AssertValid()
{
Debug.Assert(m_oTreemapGenerator != null);
}


//*************************************************************************
// Protected fields
//*************************************************************************

/// Treemap drawing engine.

protected TreemapGenerator m_oTreemapGenerator;

/// Graphics object for drawing the panel. Valid only within the
OnPaint()
/// call.

protected Graphics m_oGraphics;
}

}


"Tony Capone" <msr_n...@microsoft.com> wrote in message
news:%23Cf4cfP...@tk2msftngp13.phx.gbl...

Eric

unread,
May 10, 2005, 5:37:05 PM5/10/05
to
Tony,
I appreciate your assistance.

I agree that the DrawItem solution seems to be the best direction for
attempting the coloring that we've discussed.

I've executed the code and I am looking forward to seeing how I can
best manipulate the output from the engine.

I'm not certain that I will persue the adventure of manipulating the
engine's output into a QuantumTreemap. It appears that the
Squarified Treemap will naturally tend towards a similar pattern
in large datasets when the SizeMetric is equally weighted among
all child leafs.

Thanks,
Eric


"Tony Capone" <msr_n...@microsoft.com> wrote in message

news:eg%23nlBZV...@TK2MSFTNGP14.phx.gbl...

0 new messages