PDA

View Full Version : C# Imsl.Chart2D.Chart throws System.OverflowException



efimpechat
12-19-2007, 01:03 PM
Hi,
I'm using evaluation copy of C# library version 4.0. It looks like the class Imsl.Chart2D.Chart has a critical bug which I cannot find work around for. The result of evaluation really depends on success of this piece. Any help will be greatly appreciated.

The application as presented runs fine. When the line
// unlucky date
is uncommented, chart breaks. When the line
// fatal date
is uncommented, application crashes.

The issue exists in the C:\Program Files\VNI\IMSLCS4.0.2\gallery\ImslDemo.sln as well, the author of the demo was lucky enough not to select fatal date to start the sample (the example of fatal date - 7/1/2006)



using System;
using System.Windows.Forms;
using Imsl.Chart2D;

namespace ImslChartTest {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
//----------------------------
int numDays = 100;
DateTime start = new DateTime(2006, 8, 1);

// Uncomment next line - unlucky date - the chart will shrink to one line
// start = new DateTime(2006, 10, 1); // unlucky date

// Uncomment next line - fatal date - the application will crash
// start = new DateTime(2006, 7, 1); // fatal date

double[] date = new double[numDays];
double[] value = new double[numDays];
for(int i = 0; i < numDays; ++i) {
DateTime dt = start.AddDays(i);
date[i] = dt.Ticks;
value[i] = System.Math.Sin(i/10.0);
}
//----------------------------
Imsl.Chart2D.Chart chart = panelChart1.Chart;
Imsl.Chart2D.AxisXY axis = new Imsl.Chart2D.AxisXY(chart);
axis.AxisX.AxisLabel.TextFormat = "d";
axis.AxisX.AxisLabel.TextFormatProvider = axis.AxisX.CultureInfo.DateTimeFormat;
axis.AxisX.CustomTransform = new TransformDate();
axis.AxisX.Transform = AxisXY.TRANSFORM_CUSTOM;
axis.SetUpMapping();


Data data = new Data(axis, date, value);
}
}
}


Exception:


System.OverflowException was unhandled
Message="Overflow error."
Source="System.Drawing"
StackTrace:
at System.Drawing.Graphics.CheckErrorStatus(Int32 status)
at System.Drawing.Graphics.DrawLine(Pen pen, Int32 x1, Int32 y1, Int32 x2, Int32 y2)
at Imsl.Chart2D.Draw.DrawLine(Int32 x0, Int32 y0, Int32 x1, Int32 y1)
at Imsl.Chart2D.MajorTick.Paint(Draw draw)
at Imsl.Chart2D.Axis1D.Paint(Draw draw)
at Imsl.Chart2D.AxisXY.Paint(Draw draw)
at Imsl.Chart2D.Chart.Paint(Draw draw)
at Imsl.Chart2D.Chart.PaintChart(Graphics graphics)
at Imsl.Chart2D.Chart.Paint(Graphics g)
at Imsl.Chart2D.PanelChart.OnPaint(PaintEventArgs painteventargs)
at System.Windows.Forms.Control.PaintWithErrorHandlin g(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Mes sage& m)
at System.Windows.Forms.Control.ControlNativeWindow.O nMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.W ndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallba ck(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchM essageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager. System.Windows.Forms.UnsafeNativeMethods.IMsoCompo nentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.Run MessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.Run MessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at ImslChartTest.Program.Main() in C:\Yefim\Dev\CSharp\ImslChartTest\Program.cs:line 14
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.Run UsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context( Object state)
at System.Threading.ExecutionContext.Run(ExecutionCon text executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

ed
12-19-2007, 04:59 PM
Someone here will have a look at your code tomorrow, but until then I can hopefully lend some insight. Usually when these errors appear its because the system has been asked to draw a line of 0 length or gets an infinite or NaN value. I've noticed .NET fails very ungraciously in such circumstances. We've trapped a lot of these cases in the source, but I won't promise we got all of them. It's likely that the Graphics.DrawLine() is getting a bad value from our Draw.DrawLine() method. The alternative is that an infinite value is showing up in the axis transform - but this usually only happens with log/log plots and not Date/Time plots.

But, we'll have a look tomorrow.

efimpechat
12-20-2007, 06:04 AM
I think throwing an exception on invalid input, like request to draw NaN value, is a right thing to do. It's better though to throw problem specific exception, instead of generic "reference not set to an instance of an object" or "parameter is not valid".

Unfortunately, it is not the case with my sample program. It attempts to draw the same 100 data points starting on 1 Aug 2006, 1 Oct 2006 and 1 Jul 2006. It succeeds in the first case, draws 1D instead of 2D graph in the second case (the whole graph is compressed into one vertical line with ticks), and crashes in the third case. I call dates like 10/1/2006 or 7/1/2006 blackout dates. The fraction of blackout dates is about 20-30%, and it was really difficult to me to avoid them when I was giving a presentation of my application based on C# IMSL library.

ed
12-20-2007, 06:20 AM
Looking more closely, I see you're setting up a Custom Transform for the Date axis. Try removing the following three lines:

axis.AxisX.CustomTransform = new TransformDate();
axis.AxisX.Transform = AxisXY.TRANSFORM_CUSTOM;
axis.SetUpMapping();

Do all your different start date cases work then? There might be something funny going on depending on if the data start/end on a weekend. This would line up with your estimate of 20-30% of the dates going bad. Both 10/1/06 and 7/1/06 are weekends, and weekend start dates should make up 2/7 (28.5%) of cases chosen at random.

Someone will still need to look into this on our end, but do you need to drop weekends from the axis?

ed
12-20-2007, 06:47 AM
Looking at the dates more closely, the problem cases are:
"unlucky" - 10/1/06 (Sunday) to 1/8/07 (Monday)
"fatal" - 7/1/06 (Saturday) to 10/8/06 (Sunday)

I think that we are defining the axis locations based on those values, but then the DateTransform is dropping weekends. For the Unlucky case, 10/1/06 is then unplottable, but the end date is, so everything gets smashed down to that single location. In the Fatal case, both are unplottable, so everything gets null locations.

If you need to use a plot that doesn't include weekends, your data should not include weekends. We use the DateTransform in the Stock Chart example in the demo gallery where financial data are being displayed and it works because no values appear on weekends. Creating the DateTime values as you've done here, weekends are included in the data, and we run into problems when the start date is a weekend.

I think we should fail a little more nicely in this case, but it's very similar to what happens when using a Custom Transform to create a log axis and then try to plot zero. I will file a Change Request to have our developers look into a way of trapping these 'unplottable' cases when using an axis transformation.

efimpechat
12-20-2007, 10:03 AM
First, I noticed only your second post, and tried number of days in July 2006, which turned out to be fatal, and all days in October 2006 I've tried turned out to be unlucky.

Then I've noticed your prior post, and your suggestion worked! I used the 3 lines because your sample used it. So now I know these lines allow skipping weekends, is it true? I need to skip weekends, but if it crashes the application, I can live without it, so your suggestion allows me at least not to crash.

I'm still not sure, where I can find good explanation of the charting - as I saw examples are not perfect.

Thank you for the insight, look forward for having this problem addressed.

ed
12-20-2007, 10:47 AM
Yes, the purpose of the TransformDate custom axis transform is to skip weekends - this is very helpful for plotting financial data, but is not usually needed.

The root cause appears to be that if your data starts with a weekend, and then weekends are skipped when plotting using TransformDate, you will get unpredictable results -- either a smashed axis or an exception. If you need to skip weekends in the plot, it is probably best practice to remove weekends from your data first -- at least until we can figure out how to trap this condition.

The upcoming 5.0 release of IMSL C# will include a Chart Programmers Guide that will greatly enhance our charting documentation. Many more examples and some additional discussion is included in this document.

efimpechat
12-21-2007, 07:13 AM
If you need to skip weekends in the plot, it is probably best practice to remove weekends from your data first -- at least until we can figure out how to trap this condition.
In the following program I'm trying to follow your suggestion above. I construct date[] and value[] arrays to only include values on weekdays. Nevertheless, the chart still displays weekends on the axis X. I tried uncommenting all or some of the 4 lines in the bottom, with no success. Please note, I start my data on Monday, 3 July 2006. I use bar type graph in the program to make the gaps more obvious. Please advise, what do I need to do to skip weekends?


using System;
using System.Windows.Forms;
using Imsl.Chart2D;

namespace ImslChartTest {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();

//----- Define variables
int numDays = 100;
double[] date = new double[numDays];
double[] value = new double[numDays];
DateTime start = new DateTime(2006, 7, 3);
Imsl.Chart2D.Chart chart = panelChart1.Chart;
Imsl.Chart2D.AxisXY axis = new Imsl.Chart2D.AxisXY(chart);

//----- Initialize data
int j = 0;
for(int i = 0; j < numDays; ++i) {
DateTime dt = start.AddDays(i);
if(dt.DayOfWeek == DayOfWeek.Saturday || dt.DayOfWeek == DayOfWeek.Sunday) {
continue;
}
date[j] = dt.Ticks;
value[j] = j;
j++;
}

//----- Prepare the X axis
axis.AxisX.AxisLabel.TextFormatProvider = axis.AxisX.CultureInfo.DateTimeFormat;
axis.AxisX.AxisLabel.TextFormat = "d";

//axis.AxisX.CustomTransform = new TransformDate();
//axis.AxisX.Transform = AxisXY.TRANSFORM_CUSTOM;
//axis.AxisX.SkipWeekends = true;

//axis.SetUpMapping();

//----- Draw the chart
Data data = new Bar(axis, date, value);
data.BarType = Bar.BAR_TYPE_VERTICAL;
}
}
}