I need to create a graph that have the following properties:
The X Axis is for schools names.
The Y Axis is for classes names.
In Point (x,y) I need to put a dot that it's color will represent the number of students (darker means more students).
I'm using ZedGraph (using that sample: http://zedgraph.org/wiki/index.php?title=Gradient-By-Value_Demo), but I don't know how to put the dot (and to determine it's dark-level) in the correct position (compare it to school's name and class's name).
Also, I don't know how to make the X and Y axis to show the school's name and the class's name.
How can I do that? (It's NOT have to be in zedGraph).
many thanks!
The problem is that ZedGraph is treating a Text-type scale in a little bit strange way. So it's almost impossible to display correctly data when you have both scales of Text type.
But you can fool ZG a little bit.
The whole trick is to display the data using coordinates of hidden scale, while displaying second, fake scale.
string[] schools = { "A", "B", "C" };
string[] classes = { "cl. 1", "cl. 2", "cl. 3" };
var pane = zg1.GraphPane;
Random x = new Random();
// Hide the basic scale, show the second with text labels
pane.X2Axis.Type = AxisType.Text;
pane.X2Axis.IsVisible = true;
pane.Y2Axis.Type = AxisType.Text;
pane.Y2Axis.IsVisible = true;
pane.XAxis.Scale.IsVisible = false;
pane.YAxis.Scale.IsVisible = false;
pane.X2Axis.Scale.TextLabels = schools;
pane.Y2Axis.Scale.TextLabels = classes;
// Main problem - synchronize the scales correctly
pane.XAxis.Scale.Min = -0.5;
pane.XAxis.Scale.Max = schools.Count() - 0.5;
pane.YAxis.Scale.Min = -0.5;
pane.YAxis.Scale.Max = classes.Count() - 0.5;
pane.YAxis.MajorGrid.IsZeroLine = false;
// generate some fake data
PointPairList list = new PointPairList();
for(int i=0;i<schools.Count();i++)
for (int j = 0; j < classes.Count(); j++)
{
list.Add(new PointPair(i, j, x.Next(30)));
}
var pointsCurve = pane.AddCurve("", list, Color.Transparent);
pointsCurve.Line.IsVisible = false;
// Create your own scale of colors.
pointsCurve.Symbol.Fill = new Fill(new Color[] { Color.Blue, Color.Green, Color.Red });
pointsCurve.Symbol.Fill.Type = FillType.GradientByZ;
pointsCurve.Symbol.Fill.RangeMin = 0;
pointsCurve.Symbol.Fill.RangeMax = 30;
pointsCurve.Symbol.Type = SymbolType.Circle;
pane.AxisChange();
zg1.Refresh();
I don't do quite this in my project, but I do change the color based on some criteria. It should be pretty easy for you to modify. Look at the svn depot in stochfit.sourceforge.net at the graphing classes. You may also want to take a look at the version of zedgraph I have in my depot, some image capture and a scaling bug were fixed.
Related
What I want to achieve?
I'm working on an evolutionary algorithm finding min/max of non-linear functions. I have fully functional WPF application, but there's one feature missing: 3D plots.
What is the problem?
To accomplish this I've started with free trial of ilNumerics which provide 3D data visualisation. It works completely fine with examples from documentation, but there's something what prevents me from plotting properly my own 3D graphs.
Visualising problem:
So, here is how it behaves at the moment
Those are graphs of non-linear function: x1^4+x2^4-0.62*x1^2-0.62*x2^2
Left side: Contour achieved with OxyPlot
Right side: 3D graph achieved with ilNumerics
As you can see, OxyPlot contour is completely fine and 3D graph which I'm trying to plot with exactly same data is not proper at all.
How actual (not working) solution is done?
I'm trying to visualise 3D surface using points in space. ILNumerics has class called Surface which object I have to create in order to plot my graph. It has following constructor:
public Surface(InArray<float> ZXYPositions, InArray<float> C = null, Tuple<float, float> colorsDataRange = null, Colormap colormap = null, object tag = null);
where as you can see ZXYPositions is what I actually have problem with. Before instantiating Surface object I'm creating an Array like this:
int m = 0;
for (int i = 0; i < p; ++i)
{
for (int j = 0; j < p; ++j)
{
sigma[m, 0] = (float)data[i, j];
sigma[m, 1] = (float)xy[0][i];
sigma[m, 2] = (float)xy[1][j];
m++;
}
}
where sigma[m, 0] = Z; sigma[m, 1] = X; sigma[m, 2] = Y;
And here's the problem. I cannot find any logical error in this approach.
Here is code responsible for creating object which I'm passing to ilNumerics plot panel:
var scene = new PlotCube(twoDMode: false) {
// add a surface
new Surface(sigma) {
// make thin transparent wireframes
Wireframe = { Color = Color.FromArgb(50, Color.LightGray) },
// choose a different colormap
Colormap = Colormaps.Jet,
}
};
Additionaly I want to say that sigma array is constructed properly, because I've printed out its values and they're definitely correct.
Plot only data points.
At the end I need to add, that when I'm not creating surface object and plot only data points it looks much more reasonable:
But sadly it's not what I'm looking for. I want to create a surface with this data.
Good News!
I found the answer. Oddly almost evereything was fine.. I missunderstood just one thing. When I'm passing ZXYPositions argument to surface it can actually expect only Z data from me to plot graph correctly.
What did I changed to make it work
Two first for loops now looks like that:
sigma = data;
As you can see they're no longer loops, because sigma now contains only "solution" coordinates (which are Z coords), so I need to just assign data array to sigma.
Second part, where I'm creating Surface now looks like this:
var B = ILMath.tosingle(sigma);
var scene = new PlotCube(twoDMode: false) {
// add a surface
new Surface(B) {
// make thin transparent wireframes
Wireframe = { Color = Color.FromArgb(50, Color.LightGray) },
// choose a different colormap
Colormap = Colormaps.Jet,
}
};
scene.Axes.XAxis.Max = (float)arguments[0].Maximum;
scene.Axes.XAxis.Min = (float)arguments[0].Minimum;
scene.Axes.YAxis.Max = (float)arguments[1].Maximum;
scene.Axes.YAxis.Min = (float)arguments[1].Minimum;
scene.First<PlotCube>().Rotation = Matrix4.Rotation(new Vector3(1f, 0.23f, 1), 0.7f);
Basically one thing which changed is scaling XY axes to proper values.
Final results
Here you have final results:
i got a Little "Problem", i want to create a Chart looking like this:
So basically
Series 1 = Normal bar Chart. Color green if it Ends before the "time max" (series2) Series 2 = just a DataPoint / Marker on top of series 1 items.
I am struggling with this though...
my Code:
chart_TimeChart.Series.Clear();
string series_timeneeded = "Time Needed";
chart_TimeChart.Series.Add(series_timeneeded);
chart_TimeChart.Series[series_timeneeded]["PixelPointWidth"] = "5";
chart_TimeChart.ChartAreas[0].AxisY.ScrollBar.Size = 10;
chart_TimeChart.ChartAreas[0].AxisY.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
chart_TimeChart.ChartAreas[0].AxisY.ScrollBar.IsPositionedInside = true;
chart_TimeChart.ChartAreas[0].AxisY.ScrollBar.Enabled = true;
chart_TimeChart.Series[series_timeneeded].BorderWidth = 2;
chart_TimeChart.Series[series_timeneeded].ChartType = SeriesChartType.StackedBar;
chart_TimeChart.Series[series_timeneeded].YValueType = ChartValueType.Time;
chart_TimeChart.ChartAreas[0].AxisY.LabelStyle.Format = "HH:mm:ss";
chart_TimeChart.Series[series_timeneeded].XValueType = ChartValueType.String;
for (int i = 0; i < MaxNumber; i++)
{
chart_TimeChart.Series[series_timeneeded].Points.AddXY("item"+ " " + (i + 1).ToString(), DateTime.Now.Add(Timespans[i]));
}
chart_TimeChart.Series.Add(series_FinishTime);
chart_TimeChart.Series[series_FinishTime].ChartType = SeriesChartType.StackedBar;
chart_TimeChart.Series[series_FinishTime].BorderWidth = 0;
chart_TimeChart.Series[series_FinishTime].MarkerSize = 15;
chart_TimeChart.Series[series_FinishTime].MarkerStyle = MarkerStyle.Square;
chart_TimeChart.Series[series_FinishTime].MarkerColor = Color.Black;
chart_TimeChart.Series[series_FinishTime].YValueType = ChartValueType.DateTime;
chart_TimeChart.Series[series_FinishTime].XValueType = ChartValueType.String;
for (int i = 0; i < MaxNumber; i++)
{
DateTime YPosition = GetFinishTime(i);
chart_TimeChart.Series[series_FinishTime].Points.AddXY("item"+ " " +(i+1).ToString(), YPosition);
}
but this only Displays the 2nd series on top of the first one but the first one isnt visible anymore. The Maker of series 2 isnt shown but instead the bar is (eventhough i made borderwidth to 0). In my opinion/thinking i just have to make the "bar" of series 2 invisible and just Show the marker Points for series 2.
Any ideas?
Update:
string seriesname = Name+ i.ToString();
chart_TimeChart.Series.Add(seriesname);
chart_TimeChart.Series[seriesname].SetCustomProperty("DrawSideBySide", "false");
chart_TimeChart.Series[seriesname].SetCustomProperty("StackedGroupName", seriesname);
chart_TimeChart.Series[seriesname].ChartType = SeriesChartType.StackedBar; //Y and X are exchanged
chart_TimeChart.Series[seriesname].YValueType = ChartValueType.Time;
chart_TimeChart.ChartAreas[0].AxisY.LabelStyle.Format = "HH:mm:ss";
chart_TimeChart.Series[seriesname].XValueType = ChartValueType.String;
DateTime TimeNeeded = DateTime.Now.Add(List_AllLiniengroupsTimespans[k][i]);
DateTime TimeMax = GetFinishTime(k, i);
TimeSpan TimeDifference = TimeNeeded - TimeMax;
if (TimeNeeded > TimeMax) //All good
{
chart_TimeChart.Series[seriesname].Points.AddXY(seriesname, TimeNeeded); //Time till finish
chart_TimeChart.Series[seriesname].Points[0].Color = Color.Blue;
chart_TimeChart.Series[seriesname].Points[0].SetCustomProperty("StackedGroupName", seriesname);
chart_TimeChart.Series[seriesname].Points.AddXY(seriesname, TimeNeeded.Add(TimeDifference)); //time left
chart_TimeChart.Series[seriesname].Points[1].Color = Color.Red;
chart_TimeChart.Series[seriesname].Points[1].SetCustomProperty("StackedGroupName", seriesname);
}
else if (TimeMax > TimeNeeded) //wont make it in time
{
chart_TimeChart.Series[seriesname].Points.AddXY(seriesname, TimeNeeded); //time till still okay
chart_TimeChart.Series[seriesname].Points[0].Color = Color.Blue;
chart_TimeChart.Series[seriesname].Points[0].SetCustomProperty("StackedGroupName", seriesname);
chart_TimeChart.Series[seriesname].Points.AddXY(seriesname, TimeNeeded.Add(TimeDifference)); //Time that is too much
chart_TimeChart.Series[seriesname].Points[1].Color = Color.Green;
chart_TimeChart.Series[seriesname].Points[1].SetCustomProperty("StackedGroupName", seriesname);
}
else if (TimeMax == TimeNeeded) //fits exactly
{
chart_TimeChart.Series[seriesname].Points.AddXY(seriesname, TimeNeeded);
chart_TimeChart.Series[seriesname].Points[0].Color = Color.DarkOrange;
chart_TimeChart.Series[seriesname].Points[0].SetCustomProperty("StackedGroupName", seriesname);
}
the Code will be displayed as:
but i want it to look like this:
!! See the update below !!
If you really want to create a StackedBar chart, your chart has two issues:
If you want to stack datapoints they need to have meaningful x-values; without them how can it know what to stack on each other?
You add strings, which look fine but simply don't work. That is because the DataPoint.XValue field is double and when you add string into it it is set to 0 !! Your string is copied to the Label but otherwise lost.
So you need to come up with a suitable numeric value you use for the x-values..
And you also need to group the series you want to stack. For this there is a special property called StackedGroupName which serves to group those series that shall be stacked.
Here is how you can use it:
yourSeries1.SetCustomProperty("StackedGroupName", "Group1");
For a full example see this post !
It also shows one way of setting the Labels with string values of your choice..
This is the way to go for real StackedBar charts. Your workaround may or may not work. You could try to make the colors transparent or equal to the chart's backcolor; but it won't be more than a hack, imo.
Update
I guess I have misread the question. From what I see you do not really want to create a stacked chart.
Instead you struggle with these issues:
displaying bars at the same y-spot
making some bars invisible
displaying a vertical line as a marker
Let's tackle each:
Some column types including all Bars, Columns and then some have a little known special property called DrawSideBySide.
By default is is set to Auto, which will work like True. This is usually fine as we don't want bars to sit upon each other, effectively hiding all or part of the overlaid points.
But here we do want them to share the same y-position, so we need to set the property to false for at least one Series; the others (on Auto) will follow..:
You can do it either like this:
aSeries["DrawSideBySide"] = "false";
or like this:
aSeries.SetCustomProperty("DrawSideBySide", "false");
Next we hide the overlaid Series; this is simple:
aSeries.Color = Color.Transparent;
The last issue is displaying a line marker. There is no such MarkerStyle, so we need to use a custom style. For this we need to create a suitable bitmap and add it as a NamedImage to the chart's Images collection.
This sounds more complicated than it is; however the MarkerImage will not be scaled, so we need to created suitable sizes whenever we resize the Chart or add/remove points. I will ignore this complication for now..
int pointCount = 10;
Bitmap bmp = new Bitmap(2, chart.ClientSize.Height / pointCount - 5);
using (Graphics g = Graphics.FromImage(bmp)) g.Clear(Color.Black);
NamedImage marker = new NamedImage("marker", bmp);
chart.Images.Clear(); // quick & dirty
chart.Images.Add(marker);
Here is the result:
A few notes:
I would recommend to use variables for all chart elements you refer to repeatedly instead of using indexed references all the time. Less code, easier to read, a lot easier to maintain, and probably better performance.
Since your code called for the visible datapoints to be either red or green the Legend will not show a good representation. See here for an example of drawing a multi-colored legend item..
I used the chart height; this is not really recommended as there may be Titles or Legends or even more ChartAreas; instead you should use the height of the ChartArea, or even more precise, the height of the InnerPlotPosition. You would need to convert those from percentages to pixels. Not too hard, see below or see here
or here for more examples!
The markers should be adapted from the Resize and probably from the AxisViewChanged events. Putting it in a nice function to call (e.g. void setMarkerImage(Chart chart, Series s, string name, int width, Color c)) is always a good idea.
If you need to adapt the size of the marker image repeatedly, you may want to write better code for clearing the old one; this should include disposing of the Bitmap that was used before..
Here is an example:
var oldni = chart.Images.FindByName("marker");
if (oldni != null)
{
oldni.Image.Dispose();
chart.Images.Remove(oldni);
oldni.Dispose();
}
In some situations one needs to nudge the Chart to update some of its properties; RecalculateAxesScale is one such nudge.
Example for calculating a suitable marker height:
ChartArea ca = chart.ChartAreas[0];
ca.RecalculateAxesScale();
float cah = ca.Position.Height;
float iph = ca.InnerPlotPosition.Height;
float h = chart3.ClientSize.Height * cah / 100f * iph / 100f;
int mh = (int)(h / s.Points.Count);
Final note: The original answer stressed the importance of using meaningful x-values. Strings are useless! This was important for stacking bars; but it is equally important now, when we want bars to sit at the same vertical positions! Adding the x-values as strings is again resulting in nonsense..
(Since we have Bars the x-values go along the vertical axis and vice versa..)
I have a Winforms chart in which I have temperature readings arriving and displaying every second. I like the way the chart works automatically handling the display of the values, but I want to change one simple thing.
I want to increase the minimum displayed y axis range, so it displays a range of 20. At the moment it only displays around 5. I have tried a few things:
//(when new data arrives...)
//Does not work, I think because by default, Size is always NaN?
if (chart1.ChartAreas[0].AxisY.ScaleView.Size < 20)
{
chart1.ChartAreas[0].AxisY.ScaleView.Size = 20;
}
None of these work either:
chart1.ChartAreas[0].AxisY.ScaleView.SmallScrollMinSize = 20;
chart1.ChartAreas[0].AxisY.ScaleView.SmallScrollSize = 20;
chart1.ChartAreas[0].AxisY.ScaleView.MinSize = 20;
chart1.ChartAreas[0].AxisY.Minimum //doesn't seem to have any effect
chart1.ChartAreas[0].AxisY.Maximum //doesn't seem to have any effect
I'm sure I've missed something simple. I hope I have anyway.
The 'minimum display range' is not something built-in in the MSChart control.
But you can easily fake it:
Add a dummy Series which contains only two points to make sure the display range will not go below the range of their y-values..:
int rangeMin = -10;
int rangeMax = 20;
sDummy = chart.Series.Add("dummy");
sDummy.Color = Color.Transparent;
sDummy.IsVisibleInLegend = false;
sDummy.ChartType = SeriesChartType.Point;
sDummy.Points.AddXY(0, rangeMin + 1);
sDummy.Points.AddXY(0, rangeMax - 1);
Style your y-axis as you like:
Axis ay = chart.ChartAreas[0].AxisY;
ay.MajorGrid.Interval = 5;
And add one or more data Series:
sData = chart.Series.Add("data");
sData.LegendText = "Temperature";
sData.ChartType = SeriesChartType.Line;
Now as you add data points with a larger range of values the y-axis will grow its display range to accommodate them. And if you remove the larger points it will shrink back, but not below the range needed for the dummy series..:
Note that since the Chart automatically adds some slack I reduce the range on both sides by 1; with other Intervals etc other numbers are needed..
The code to remove the larger values, btw:
var toRemove = sData.Points.Cast<DataPoint>()
.Where(x => x.YValues[0] >= rangeMax).ToList();
foreach (var dp in toRemove) sData.Points.Remove(dp);
I am working on my own graph drawing application. I have got the graph and the updating mechanisme working like i want to. Now I am trying to draw a grid, So i need some lines on the axis of my graph, so I came up with this little loop:
Gridx = new Line();
while (x <= _XAxisSize)
{
gridx.X1 = x;
gridx.X2 = x;
gridx.Y1 = _YAxisSize - 20;
gridx.Y2 = _YAxisSize + 20;
x = x + XgridSize;
gridx.UpdateLayout();
}
This doesn't work, because it only draws one line (the last point of the loop). So i need to draw multiple lines on that axes. How dow i accomplish something like that, using either the line() from the system.Windows.Shapes library, or any other shape in that library
Thanks
If you want multiple lines, you need to create multiple lines:
while (x <= _XAxisSize)
{
var gridx = new Line();
gridx.X1 = x;
gridx.X2 = x;
gridx.Y1 = _YAxisSize - 20;
gridx.Y2 = _YAxisSize + 20;
//need to add gridx to your view here
x = x + XgridSize;
}
However, for such static lines you might be better off looking at using a GeometryDrawing which has much less overhead than the Line shape. See here for details about the differences.
I'm building a chart to show items by volume by category. So far I've been succcessful in showing items by volume as it's a simple x/y chart, however I'd like to show y2 and I know MS Chart Controls has a built in AxisY2 however when I try anything with it the Chart get's all funky.
Here's what I'm looking for (in ascii art):
item1 |[][][][][].............| cat1
item2 |[][]...................| cat2
item3 |[][....................| cat1
item4 |[][][][][][][][........| cat1
|_______________________|
0 1 2 3 4 5
Like previously mentioned I can get Items and counts to show fine as that's relatively easy, it's the Categories that I can't seem to place.
Thanks
Here's what did it for me- after I created the chart I added the following lines:
chrtMain.Series[0].YAxisType = AxisType.Primary;
chrtMain.Series[1].YAxisType = AxisType.Secondary;
chrtMain.ChartAreas[0].AxisY2.LineColor = Color.Transparent;
chrtMain.ChartAreas[0].AxisY2.MajorGrid.Enabled = false;
chrtMain.ChartAreas[0].AxisY2.Enabled = AxisEnabled.True;
chrtMain.ChartAreas[0].AxisY2.IsStartedFromZero = chrtMain.ChartAreas[0].AxisY.IsStartedFromZero;
There was no need to superimpose two charts or anything!
It gets even better:
For using the second Y axis, there is no need for a second chart area. You can decide per serie which axis you want to use with the Series.YAxisType property.
Take a look at the documentation on http://msdn.microsoft.com/en-us/library/dd489216.aspx
Martijn
Short Answer first : According to MS Examples, there is no straight way to do that, but just a workaround trick : Plot your series on a second chartArea matching exactly your existing area position, (by performing a copy of your Series) having invisible primary X/Y Axis and a visible secondary Y Axis (AxisY2). And set the chartArea and the copied series's backcolors to transparent. (This can be applied to secondary X axis in case of column graphs rather that bars)
//Suppose you already have a ChartArea with the series plotted and the left Y Axis
//Add a fake Area where the only appearent thing is your secondary Y Axis
ChartArea area1 = chart.ChartAreas.Add("ChartAreaCopy_" + series.Name);
area1.BackColor = Color.Transparent;
area1.BorderColor = Color.Transparent;
area1.Position.FromRectangleF(area.Position.ToRectangleF());
area1.InnerPlotPosition.FromRectangleF(area.InnerPlotPosition.ToRectangleF());
area1.AxisX.MajorGrid.Enabled = false;
area1.AxisX.MajorTickMark.Enabled = false;
area1.AxisX.LabelStyle.Enabled = false;
area1.AxisY.MajorGrid.Enabled = false;
area1.AxisY.MajorTickMark.Enabled = false;
area1.AxisY.LabelStyle.Enabled = false;
area1.AxisY2.Enabled = AxisEnabled.True;
area1.AxisY2.LabelStyle.Enabled = true;
// Create a copy of specified series, and change Y Values to categories
Series seriesCopy = chart.Series.Add(series.Name + "_Copy");
seriesCopy.ChartType = series.ChartType;
foreach(DataPoint point in series.Points)
{
double category = getYourItemCategory(point.XValue);
seriesCopy.Points.AddXY(point.XValue, category);
}
// Hide copied series
seriesCopy.IsVisibleInLegend = false;
seriesCopy.Color = Color.Transparent;
seriesCopy.BorderColor = Color.Transparent;
//Drop it in the chart to make the area show (only the AxisY2 should appear)
seriesCopy.ChartArea = area1.Name;
PS : I've spent two nights awake messing with MS chart controls, trying to put two different Y axis on a Chart Area. I wanted to put two differently scaled series (same X scale, different Y Scales : one on the left for Series A , the other on the right for Series B).
In fact, this proved to be a real nightmare, when one could expect this to be pretty straightforward. The truth is that MS Chart Controls are definitely NOT adapted for this particular use case IMHO. The multiple Y axis sample suggested in the MSCC sample examples is an awful and very ugly workaround, which requires two chartareas on top of the default one, playing with visibility and transparency, to achieve the desired effect (which sounds like a very bad illusion magic trick).
While hoping for this to be enriched and fixed in a proper way in future versions, if you really need an efficient way to manage multiple Y-Axis, sitck to ZedGraph
You can add as many series on the Y axis as you want, below code is an extract from a chart I use that has more than 2 secondary y axes, code is for vb.net but i'm sure you can work it out:
ChartKPI.Series.Clear()
ChartKPI.Series.Add("Series1")
ChartKPI.Series("Series1").XValueMember = "Date"
ChartKPI.Series("Series1").YValueMembers = "HSDPA_Vol_MBy"
ChartKPI.Series("Series1").Name = "HSDPA_Vol_MBy"
ChartKPI.Series("HSDPA_Vol_MBy").ChartType = SeriesChartType.Column
ChartKPI.Series("HSDPA_Vol_MBy").ToolTip = "HSDPA MBytes: #VAL"
ChartKPI.Series.Add("Series2")
ChartKPI.Series("Series2").YAxisType = AxisType.Secondary
ChartKPI.Series("Series2").XValueMember = "Date"
ChartKPI.Series("Series2").YValueMembers = "cs_voice_traffic"
ChartKPI.Series("Series2").Name = "cs_voice_traffic"
ChartKPI.Series("cs_voice_traffic").ChartType = SeriesChartType.Line
ChartKPI.Series("cs_voice_traffic").BorderWidth = 3
ChartKPI.Series("cs_voice_traffic").ToolTip = "CS Voice Traffic: #VAL"
ChartKPI.Series.Add("Series3")
ChartKPI.Series("Series3").YAxisType = AxisType.Secondary
ChartKPI.Series("Series3").XValueMember = "Date"
ChartKPI.Series("Series3").YValueMembers = "cs_conv_traffic"
ChartKPI.Series("Series3").Name = "cs_conv_traffic"
ChartKPI.Series("cs_conv_traffic").ChartType = SeriesChartType.Line
ChartKPI.Series("cs_conv_traffic").BorderWidth = 3
ChartKPI.Series("cs_conv_traffic").ToolTip = "CS Conv Traffic: #VAL"
ChartKPI.Series.Add("Series4")
ChartKPI.Series("Series4").YAxisType = AxisType.Secondary
ChartKPI.Series("Series4").XValueMember = "Date"
ChartKPI.Series("Series4").YValueMembers = "ps_backg_traffic_ul"
ChartKPI.Series("Series4").Name = "ps_backg_traffic_ul"
ChartKPI.Series("ps_backg_traffic_ul").ChartType = SeriesChartType.Line
ChartKPI.Series("ps_backg_traffic_ul").BorderWidth = 3
ChartKPI.Series("ps_backg_traffic_ul").ToolTip = "PS Backg Traffic UL: #VAL"
ChartKPI.Series.Add("Series5")
ChartKPI.Series("Series5").YAxisType = AxisType.Secondary
ChartKPI.Series("Series5").XValueMember = "Date"
ChartKPI.Series("Series5").YValueMembers = "ps_backg_traffic_dl"
ChartKPI.Series("Series5").Name = "ps_backg_traffic_dl"
ChartKPI.Series("ps_backg_traffic_dl").ChartType = SeriesChartType.Line
ChartKPI.Series("ps_backg_traffic_dl").BorderWidth = 3
ChartKPI.Series("ps_backg_traffic_dl").ToolTip = "PS Backg Traffic DL: #VAL"
ChartKPI.ChartAreas("ChartArea1").AxisX.Title = "HSDPA Traffic (MB)"
ChartKPI.ChartAreas("ChartArea1").AxisX.MajorGrid.Interval = 1
ChartKPI.ChartAreas("ChartArea1").AxisX.LabelStyle.Interval = 1
ChartKPI.ChartAreas("ChartArea1").AxisY.Title = "RRC Attempts"
ChartKPI.ChartAreas("ChartArea1").AxisY2.Title = "R99 Traffic (Erlang)"
ChartKPI.DataBind()
Solution:
chart1.ChartAreas[1].AlignWithChartArea = chart1.ChartAreas[0].Name;
chart1.ChartAreas[1].AlignmentOrientation = AreaAlignmentOrientations.All;