|
Automation error The object invoked has disconnected from its clients. |
Posted by Zev Toledano on Feb-13-2011 19:29 |
|
Hello again Peter,
Regarding the error "Automation error The object invoked has disconnected from its clients."
I get it every once in a while when I call the following line:
Set Graph.Chart = mchart
Where mchart is a Multichart and Graph is a ChartViewer
So far I identified two specific scenarios:
1. Sometimes, when displaying multiple surface charts in a multichart I guess it decides it's just too complex. Interestingly, I worked around this by calling it a few times and then it works. I.e.:
On Error Resume Next
Set Graph.Chart = mchart
' retry 3 times - this usually works
If Err.Number <> 0 Then Set Graph.Chart = mchart
If Err.Number <> 0 Then Set Graph.Chart = mchart
If Err.Number <> 0 Then Set Graph.Chart = mchart
Sorry, I don't have specific code to test here, but just try adding multiple heavy surface charts to a multichart and it may crash for you too.
2. Try the following code and it should instantly crash:
Dim cd As New ChartDirector.API
Dim data1()
data1 = Array(50, 55, 47, 34, 47, 53, 38, 40, 51)
Dim c As XYChart
Set c = cd.XYChart(600, 300, &HFFDDDD, &H0, 1)
Call c.setPlotArea(0, 0, 600, 300, &HFFFFFF, -1, -1, &HCCCCCC, &HCCCCCC)
Dim layer As splineLayer
Set layer = c.addSplineLayer(Array(0))
Call layer.getDataSet(0).SetData(data1)
Set viewer.Picture = c.makePicture()
I fixed it by using addDataSet instead of setting the data twice - don't ask me why I did it like this in the first place but I thought you should know in case it reveals an interesting bug in the chart... It took me many hours to track down. |
Re: Automation error The object invoked has disconnected from its clients. |
Posted by Peter Kwan on Feb-15-2011 08:59 |
|
Hi Zev,
For your case, to diagnose the problem, is it possible to change your code to the followings. This can help to identify which function of the code is generating the error:
Set Graph.Chart = Nothing
Set Graph.Picture = Nothing
Dim temp
Set temp = mchart.makePicture()
Set Graph.Picture = temp
Also, would you mind to inform me how many data points are you using in your surface chart, and is it "gridded" data points (data points that lie on a rectangular grid, with no missing points), or "scatter" data points (data points that line at arbitrary position), and how large is the chart size (in terms of pixels) and the number of charts in a MultiChart? Also, are you using 64-bit Windows or 32-bit Windows?
We are aware there is a bug that ChartDirector will crash if a surface chart contains more than 46341 scattered data points. This problem should have been fixed in the ChartDirector for ASP/COM/VB "chartdir50.dll" that are released on Apr 9, 2010.
The strange feature of your case is that the error is recoverable just by retrying. If the error is due to the 46341 limit, it should not be recoverable. So I am suspecting the error may be due to out of memory issues, or due to using DCOM ("ChartDirector for ASP/COM/VB" on 64-bit Windows by default install itself as a DCOM component). In DCOM, the component access is subjected to network security settings (even if it is not actually going through the network), and the connection can fail if there are network issues.
For the setData issue that crashes ChartDirector, the setData is actually an internal method used by ChartDirector and is never documented. (I think we have set the access level incorrect so it becomes visible using VB Intellisense.) Please do not use this method. Instead, just use:
Set layer = c.addSplineLayer(data1)
Hope this can help.
Regards
Peter Kwan |
Re: Automation error The object invoked has disconnected from its clients. |
Posted by Zev Toledano on Feb-15-2011 14:46 |
|
More about the surface chart issues...
Regarding your questions: If I understood correctly, in some cases there will be missing points so we are dealing also with scatter surface charts. Not only that but some points may be 'empty' using API.NoValue. Each chart could be anywhere between full screen (1920x1024) to tiny (e.g., 80x80) and sometimes I can show up to 50 surface charts in one multichart. We are talking about Windows 32bit, I don't think I passed 46341 points, and I don't know how to test whether it is a DCOM issue or temporary memory issue.
The error (for the scenarios that I reproduced this time) happens in the line:
Set temp = mchart.makePicture()
I worked on it a bit more and narrowed down the following scenarios so far:
1. This one is actually NON-recoverable - i.e. the retry doesn't work:
It seems to be caused when I set ALL data points on one of the scales (the yscale in this case) to ChartDirector.API.NoValue. This happens sometimes because I am using the multichart to display a pivoted grid of graphs and some pivot sections don't have values.
I added a temporary workaround for this but isn't it a bug?
2. Similar to the above but this one happens when there is no combination in two axes that doesn't have a NoValue. E.g. if there are two points, and in plot point 0 the yaxis has a novalue, and in 1 the xaxis has a novalue. At least I think that's the rule - I'm not sure.
I haven't been able to reproduce any 'recoverable' errors yet but my code has changed a lot since then and I am 100% sure I had some of those a few days ago. |
Re: Automation error The object invoked has disconnected from its clients. |
Posted by Peter Kwan on Feb-16-2011 10:12 |
|
Hi Zev,
We apologize very much for this problem. I searched our bug database thoroughly today. I found 3 known bugs that can crash a SurfaceChart, but 2 of them should have already been fixed in the Apr 9, 2010 release. The remaining known bug is:
- SurfaceChart may crash if there are 2 or more data points, but less than 2 distinct data points.
The above can happen if some of the data points are NoValue, or all of the data points are the same point.
To plot a surface, at least 3 non-colinear points are needed. Whereas ChartDirector detects and handles many special cases, it misses the above case.
To work around the problem, you may consider to use the following code to "filter" the data (assuming scattered data in which the length of the x, y and z data arrays are the same):
'Move all valid points to the front the array
count = 0
For i = 0 To UBound(dataX)
If dataX(i) <> cd.NoValue And dataY(i) <> cd.NoValue And dataZ(i) <> cd.NoValue Then
dataX(count) = dataX(i) : dataY(count) = dataY(i) : dataZ(count) = dataZ(i)
count = count + 1
Next
Next
'Check if all points are the same
For i = 1 To count - 1
If dataX(i - 1) <> dataX(i) And dataY(i - 1) <> dataY(i) And dataZ(i - 1) <> dataZ(i) Then Exit For
Next
If i >= count Then count = Min(count, 1) 'all points the same - that means than is only 1 or 0 data point
'Trim off the NoValue points
ReDim dataX(count - 1)
ReDim dataY(count - 1)
ReDim dataZ(count - 1)
You may create a subroutine using the above code and filter the data before passing them to ChartDirector.
Please let me know if the above can solve the problem.
Regards
Peter Kwan |
Re: Automation error The object invoked has disconnected from its clients. |
Posted by Zev Toledano on Feb-17-2011 19:45 |
|
Thanks for the help and the workaround. I also improved my code in several ways and I haven't found any more errors so far.
But I have a new question... I'm trying to figure out how to use a manually set ColorAxis with scatter surface charts: How do I set specific colors for specific points?
Let's use a simplified example... say I set the scatter chart data to be:
point1: 1,3,4
point2: 3,1,8
point3: 2,5,2
...and I want point1 to be red, point2 green and point3 blue.
I can't figure out the code to do this... Even if ColorAxis.SetColors goes according to zaxis values, how do I tell it which value goes with which color? Or, even better, I'd like to simply set the color per point. |
Re: Automation error The object invoked has disconnected from its clients. |
Posted by Peter Kwan on Feb-18-2011 09:36 |
|
Hi Zev,
The colors in a surface chart is determined by the z-coordinate. For the points:
point1: 1,3,4
point2: 3,1,8
point3: 2,5,2
I assume the z-coordinates are 4, 8, 2. These numbers will be used to determine the colors at that point.
Note that even if you only have 3 points, the surface chart, which interpolates the points, will necessarily have all possible z levels between 2 and 8. So instead of setting the colors of 3 points, you would need to set the colors of the entire axis range (2 to 8). The following is an example:
'Normall, the color axis is synchronized to the z-axis. In this example, we set the color
'axis from 2 to 8 without affecting the z-axis. So we need to break the synchronization first.
Call c.colorAxis().syncAxis(c.colorAxis())
'The color axis is from 2 to 8.
Call c.colorAxis().setLinearScale(2, 8)
'Set a 4 color gradient. ChartDirector will spread them evenly on the z-axis, which
'means they will be used for z = 2, 4, 6, 8.
Call c.colorAxis().setColorGradient(false, Array(&H0000ff&, &Hff0000&, &H888800&, &H00ff00&))
Hope this can help.
Regards
Peter Kwan |
Re: Automation error The object invoked has disconnected from its clients. |
Posted by Zev Toledano on Feb-18-2011 13:06 |
|
This seems rather unwieldy...
For starters, what is this &H888800& for point 6? Do I have to calculate appropriate interim colors for values between points? Can't I just skip them somehow, or set them to the same colors as the points on top or below them?
And what if the points for the zaxis were:
5
5000000
301
1000006
Do I then have to create a color array of size 5000000 and calculate 4999996 interim colors?
What if I didn't use a gradient and used discrete colors? Is this possible and would it be easier then?
Also what if the colors were set according to the yaxis values and not the zaxis - is this possible? Can two identical zaxis values have different colors just because they are on different yaxis points? I presume I would then synchronize the coloraxis with another axis, but what happens if I have to give the coloraxis a custom linear scale similar to your code?
Sorry for so many questions but as you can see, I am confused. What I am trying to achieve here is to let the user color code the surface chart according to any axis and any value, for example he may want to see it color-coded by year, or by sales. And he may want 2005 in green, and 2008 in red and the rest in blue.
P.S. I mistakenly added this post to the general forum. Feel free to move it to the support forum if you wish. |
Re: Automation error The object invoked has disconnected from its clients. |
Posted by Peter Kwan on Feb-19-2011 07:41 |
|
Hi Zev,
Unluckily, the coloring of the surface chart is designed to represent the z-axis values. It cannot be used to represent the x or y value or any other value.
The &H888800 at point 6 is arbitrary. You can set it to any color you like, and it still meets color requirement of 2, 4, and 8.
The points on the z-axis are continuous. That means if you have data points at (5
5000000, 301, 1000006), logically you can consider the z-axis to contain all possible values from 5 to 5000000. Although there are only 4 values for the points, the surface itself interpolates the points (the surface chart plots the surface, not the points), and therefore varies continuously from 5 to 5000000. So someone need to enter the colors for the range (5, 5000000).
The ChartDirector API is designed to accept an array of colors, and it will spread it to cover the range (5, 5000000), either using a smooth gradient, or using discrete steps. In the latter case, the number of steps do not need to be the same as the number colors input. For example, you can simply input two colors, and ask ChartDirector to spread it into 16 steps.
If your colors are specified in a different way, you would need to write some code to convert it to the array of colors expected by the ChartDirector API.
Note that there is only 8 bit resolution per color in modern computer. For example, if you set up a gradient from &H123456& to &HFE8745&, there can be at most 256 shades in between. So normally, you do not need to have significantly more than 256 colors, and it can already achieve the desired colors accurately.
For example, for the range (5, 5000000), you may create an array of around 256 colors, then determine which "slot" the values 5, 301, 1000006 and 5000000 falls into, and set the colors for these slots. If two points occupy the same slot, you may consider them to be too close together to be distinguishable on a computer. (You may not be able to distinguish them by looking at the z-axis or color axis, as they probably occupy the same pixel on those axes.)
Hope this can help.
Regards
Peter Kwan |
Re: Automation error The object invoked has disconnected from its clients. |
Posted by Zev Toledano on Feb-21-2011 01:02 |
|
Thanks for your advice. Your suggestion regarding 8 bits per color is only valid if I use completely separated colors per point for red/green/blue - otherwise we are dealing with 24-bit colors. But what I did is make an array based on the maximum amount of pixels in the graph.
I rolled up my sleeves and wrote an algorithm to calculate a gradient based on points, 'combining' multiple colors per point if it has to, the best it can.
The result for surface charts is not always pretty. It keeps changing colors based on values in another scale, sometimes combining them, but with some surface charts it comes out very interesting and it works very well when the colors are based on a scatter zaxis. I attached a screenshot in case you are curious - notice the attempt at coloring based on the yaxis, not the zaxis.
Then I realized I can use this same algorithm to make gradients for line charts. The results for this were much more impressive. See two attached screenshots, one using a 'heatmap' coloring.
Anyways thanks once again for a great product and the support.
|
|