August 2008 - Posts

Since I'm new to this blogging thing, it has taken me awhile to figure out what tools to use to make writing and publishing posts easy to do. After reading what others have to say on the topic, and talking to my co-workers at SRT, I have hit upon Windows Live Writer with the Code Snippet plugin. But it hasn't been straightforward getting these tools to cooperate with Community Server 2007.1, the server SRT uses for blogs. Here are two tricks to make things work right.

Windows Live Writer makes writing a post and including things such as images and videos and bits of code very easy. One of the big advantages is that it can go to your blog site and grab your template, so that as you compose your post you can see just what it will look like when it is published. I could have used that feature when I wrote my last post on ZedGraph and made the images too wide for the main text column. To get the template, WLW creates a temporary post, publishes it to the server, then goes to that post and downloads the CSS. Seems straightforward...except that it failed the first and second and third and fourth times I asked it to do this. Then I went searching for a solution. What I figured out is that in Community Server Dashboard, under Global Settings -> Default Post Settings, there is an option called "Auto Name Posts". If set to "Yes", CS tries to name each post based on the title, rather than use the de facto standard blog post naming convention, which is based on the date the post was created. After I disabled this option, WLW successfully located its post and downloaded my template to my local machine. Success!

My second problem that I've been struggling with is coming up with a quick and easy way to insert formatted, colored code into posts. Before I had WLW, I would cut and paste code and then go and manually add <div> and <span> tags with with embedded CSS styles using the horrible Community Server interface with the TinyMCE editor. Death seemed preferable. If I specified colors like this:

<span style="color: blue;">

things worked just fine. I would get blue text. But if instead I specified:

<span style="color: #0000FF;">

then the TinyMCE editor would modify the tag to look like this:

<span style="color: rgb(0,0,255);">, which would then turn into:

<span>

by the time it was published. I would not get blue text. Argh!

By using WLW with the Code Snippet plugin, as long as I never open up the post in the TinyMCE editor before it's published, everything is fine and my span tags with their color styles are left untouched. Stay away from TinyMCE!

I haven't worked out all of my blog problems just yet. For instance, Code Snippet supports C# code, but not Matlab. But I got two big problems solved, so I will declare success for the moment.

Previously I wrote about choosing ZedGraph as my graphing tool in a C#.Net project for a client. Today I'd like to give an update on how it's going. I have been very pleased with this graphing library, and it has been relatively straightforward to figure out how to make it do what I want it to do.

I'm plotting X-Y data that represents the shape of an airfoil on a 2D plot with grid lines, axes, and axes labels. One of my main concerns was having the ability to force the scales of the X and Y axes to be the same value. If they are locked, my plot will show the airfoil with the right proportions. If not, the airfoil appears to be a lot fatter than it really is.

Figure 1. Airfoil with axis scales locked

airfoil_with_axes_locked

 

Figure 2. Airfoil with axis scales determined independently of one another

airfoil_with_axes_unlocked

 

The ZedGraph library comes with a ZedGraph control, which contains of a collection of one or more GraphPane objects. The GraphPane holds all of the plotting information for a single plot, including settings and options in addition to the actual plotting data. For my particular problem I only need one GraphPane, which is the default. My first step is to initialize my GraphPane object.

public MainForm()
{
InitializeComponent();

// Initialize ZedGraph
GraphPane graphPane = zedGraphControl1.GraphPane;
graphPane.XAxis.Title.Text = "Chord";
graphPane.YAxis.Title.Text = "Thickness";
graphPane.XAxis.MajorGrid.IsVisible = true;
graphPane.YAxis.MajorGrid.IsVisible = true;
graphPane.Legend.IsVisible = false;
graphPane.Title.IsVisible = false;
//graphPane.Title.Text = "ZedGraph";
zedGraphControl1.Resize += new System.EventHandler(this.zedGraphControl1_Resize);
graphPane.AxisChangeEvent += new GraphPane.AxisChangeEventHandler(graphPane_AxisChangeEvent);

}

The key here is the last line of initialization, where I add an event handler for the AxisChangeEvent. This event is invoked by calling the AxisChange() method in the ZedGraphControl object. One generally calls this method whenever new plotting data is added to a GraphPane; it takes care of adjusting the minimum and maximum axes values and the grid spacing. AxisChangeEvents are also generated whenever the user zooms or pans a GraphPane. It is not invoked, however, when the user resizes the ZedGraphControl, so I added an event handler for the Resize event that calls the AxisChange() method. The Resize event handler looks like this:

private void zedGraphControl1_Resize(object sender, EventArgs e)
{
zedGraphControl1.AxisChange();
}

The AxisChange event handler is called after the the ZedGraphControl has recomputed the minimum and maximum axis values and the grid spacing. It adjusts the minimum and maximum values so that the scale in the X and Y directions are equal, and then it recomputes the grid spacing to ensure that the grid does not have too many or too few lines.

private void graphPane_AxisChangeEvent(GraphPane target)
{
GraphPane graphPane = zedGraphControl1.GraphPane;

// Correct the scale so that the two axes are 1:1 aspect ratio
double scalex2 = (graphPane.XAxis.Scale.Max - graphPane.XAxis.Scale.Min) / graphPane.Rect.Width;
double scaley2 = (graphPane.YAxis.Scale.Max - graphPane.YAxis.Scale.Min) / graphPane.Rect.Height;
if (scalex2 > scaley2)
{
double diff = graphPane.YAxis.Scale.Max - graphPane.YAxis.Scale.Min;
double new_diff = graphPane.Rect.Height * scalex2;
graphPane.YAxis.Scale.Min -= (new_diff - diff) / 2.0;
graphPane.YAxis.Scale.Max += (new_diff - diff) / 2.0;
}
else if (scaley2 > scalex2)
{
double diff = graphPane.XAxis.Scale.Max - graphPane.XAxis.Scale.Min;
double new_diff = graphPane.Rect.Width * scaley2;
graphPane.XAxis.Scale.Min -= (new_diff - diff) / 2.0;
graphPane.XAxis.Scale.Max += (new_diff - diff) / 2.0;
}

// Recompute the grid lines
float scaleFactor = graphPane.CalcScaleFactor();
Graphics g = zedGraphControl1.CreateGraphics();
graphPane.XAxis.Scale.PickScale(graphPane, g, scaleFactor);
graphPane.YAxis.Scale.PickScale(graphPane, g, scaleFactor);
}

Having the ZedGraph source control was extremely useful in figuring all of this out, particularly for resizing the grid after I have adjust the minimum and maximum axes values. In the end, I did not need to modify any of the ZedGraph source code, but because it is fairly clean and readable, I was able to use it in place of documentation when I needed more explanation than what was provided in the basic tutorial and class descriptions.

So I still feel good about ZedGraph, and my customer is happy, too!