I have one Chart and three ChartArea that are aligned in view, zoom, cursor:
this is my related previous post. All things works well except that the three ChartArea are not aligned at the beginning. Following an image of the problem:
I think it depends from the digit's number of Y values axis. From some research I try the following configuration:
// selezione e zoom
dlChart.ChartAreas[VOLTAGE_AREA].CursorX.Interval = 1;
dlChart.ChartAreas[VOLTAGE_AREA].CursorX.IsUserEnabled = true;
dlChart.ChartAreas[VOLTAGE_AREA].CursorX.IsUserSelectionEnabled = true;
// generale
dlChart.ChartAreas[VOLTAGE_AREA].AxisX.LabelStyle.Format = "dd/MM/yy - HH:mm:ss.fff";
dlChart.ChartAreas[VOLTAGE_AREA].AxisX.ScaleView.Zoomable = true;
dlChart.ChartAreas[VOLTAGE_AREA].AxisY.LabelStyle.Format = "D5";
In witch the last row:
dlChart.ChartAreas[VOLTAGE_AREA].AxisY.LabelStyle.Format = "D5";
should specifies always five digits. This mitigate in some way the problem but it doesn't desappers. Furthermore with this row the program starts to throws very lots exceptions of form below any time I scroll the graph:
Generate exception: 'System.FormatException' in mscorlib.dll
Does anyone knows the solution for this problem? Thanks in advance.
You may want to take control of the size of the InnerPlotPosition.
(But Baddack's solution is simpler and more flexible!)
Here is an example:
After setting up a Chart with three CharAreas, setting Minima and Maxima as well as adding one DataPoint to each we get this :
Your issue is showing clearly.
After setting the InnerPlotPosition to a fixed percentage it looks like this:
Here is how to set the InnerPlotPosition size:
ca1.InnerPlotPosition = new ElementPosition(10, 5, 80, 90);
ca2.InnerPlotPosition = new ElementPosition(10, 5, 80, 90);
ca3.InnerPlotPosition = new ElementPosition(10, 5, 80, 90);
Note that both ChartArea.Position and ChartArea.InnerPlotPosition are called 'Position' but really are areas of percentages referring to the respective containers!
So my example has a Left distance of 10%, a Top space of 5% and Width of 80% and Height of 90%. Which leaves 10% space at the Bottom and 5% at the Right. Note: All are referring to the ChartAreas not the ClientArea of the Chart! (Which are still at Auto, which maximizes the size.)
This was my initial setup:
ChartArea ca1 = chart.ChartAreas[0];
ChartArea ca2 = chart.ChartAreas[1];
ChartArea ca3 = chart.ChartAreas[2];
Series s1 = chart.Series[0];
Series s2 = chart.Series.Add("Series2");
Series s3 = chart.Series.Add("Series3");
s2.ChartArea = ca2.Name;
s3.ChartArea = ca3.Name;
s1.Points.AddXY(1, 7);
s2.Points.AddXY(1, 777);
s3.Points.AddXY(1, Math.PI);
Have you tried using the chart area alignment options? I would try something like:
//define inner plot position of the chart areas
dlChart.ChartAreas[0].InnerPlotPosition.Auto = true;
dlChart.ChartAreas[1].InnerPlotPosition.Auto = true;
dlChart.ChartAreas[2].InnerPlotPosition.Auto = true;
//set our second chart area's alignments to match our first chart area
dlChart.ChartAreas[1].AlignmentOrientation = AreaAlignmentOrientations.Vertical;
dlChart.ChartAreas[1].AlignmentStyle = AreaAlignmentStyles.All;
dlChart.ChartAreas[1].AlignWithChartArea = dlChart.ChartAreas[0].Name;
//set our third chart area's alignments to match our first chart area
dlChart.ChartAreas[2].AlignmentOrientation = AreaAlignmentOrientations.Vertical;
dlChart.ChartAreas[2].AlignmentStyle = AreaAlignmentStyles.All;
dlChart.ChartAreas[2].AlignWithChartArea = dlChart.ChartAreas[0].Name;
Related
I have an application that have 2 charts as follows:
Is it possible to programatically show the tooltip of the second chart when hovering on the first chart - via chart 1's DataHover event?
EDIT
The info on the second chart is for Relative Strength Index. It is usually presented at the bottom of the chart. For this reason I made it a separate chart.
Although not an answer to my question, here is what I did. A now deleted comment asked why there are two charts. When I did it like that initially, the charts were over each other.
So I simply went back to that, and applied a scaling factor. 20% of the chart are is fine for the RSI, and as RSI is always calculated out of 100, I set the axis max value to 500% as follows:
chartMain.AxisY.Add(new Axis
{
MaxValue = 500,
MinValue = 0,
IsMerged = true,
Position = AxisPosition.RightTop,
ShowLabels = false,
Sections = new SectionsCollection
{
new AxisSection
{
SectionWidth = m_TradeManager.Settings.RSIThreshold,
Fill = new System.Windows.Media.SolidColorBrush
{
Color = System.Windows.Media.Color.FromRgb(254,132,132),
Opacity = .4
}
}
}
});
The end result is this:
I had added Polyline annotation to graph control. But it is not aligned properly in given datapoint in Addline() method.
PolylineAnnotation annotation = new PolylineAnnotation();
annotation.AxisX = chart1.ChartAreas[0].AxisX;
annotation.AxisY = chart1.ChartAreas[0].AxisY;
annotation.AnchorX = 0;
annotation.AnchorY = 0;
annotation.Height = 30;
annotation.Width = -30;
annotation.LineWidth = 3;
annotation.StartCap = LineAnchorCapStyle.None;
annotation.EndCap = LineAnchorCapStyle.None;
annotation.Alignment = ContentAlignment.BottomLeft;
annotation.AnchorAlignment = ContentAlignment.BottomRight;
annotation.AnchorDataPoint = new DataPoint(this.chart1.Series[0]);
annotation.AllowAnchorMoving = true;
annotation.AllowMoving = true;
annotation.AllowPathEditing = true;
annotation.AllowResizing = true;
annotation.AllowSelecting = true;
annotation.GraphicsPath.AddLine(10, 20, 30, 30);
chart1.Annotations.Add(annotation);
Annotations are complex and anchoring them is too.
It starts rather simple: To anchor an Annotation you need to set its AnchorDataPoint to an existing DataPoint.
This line does nothing like that:
annotation.AnchorDataPoint = new DataPoint(this.chart1.Series[0]);
as the newly created DataPoint is empty. Its has been added and it has values of (0d, 0d), but you probably want to keep the Annotation aligned to a real DataPoint, maybe like this..:
annotation.AnchorDataPoint = chart1.Series[0].Points[someIndex];
But there is more: There actually are two ways to anchor an Annotation:
Anchor it to a DataPoint or
Anchor it with fixed AnchorX and AnchorY values.
(And then you can set them to fixed X & Y values, too.)
Your code actually does both! But: anchoring the coordinates takes precedence over anchoring to a DataPoint.
This is nice as you can combine them and first anchor to a DataPoint and then anchor one of the coordinates to a fixed value: say, x-value stays with the point but the y-value is maybe always at 0..
Also note that you are adding only one line to your polyline and you don't start it at (0,0) but at (10,20) which may be quite some way off the anchor..
And then there is the issue of size and alignment of the polyline itself!
It has a size which MSDN claims is given in pixels. This is nonsense. Instead it is given in value units of the two respective Axes. You can see this when you resize the Chart the Annotation will resize as well; see the screenshot!
Now for the GraphicsPath and its points: Those are given in percent of the Size of the Annotation. To get a feeling for this add a test annotation path that encloses the whole area:
annotation.GraphicsPath.AddRectangle(new Rectangle(0, 0, 100, 100));
Here is a screenshot of what we have got:
As you can see the most logical alignment is TopLeft and after translating the line to (0,0) it would stick right into the point.
Note that I have added a 2nd Series to make the anchor data point stand out.. - Also note that while the Annotation size is a square (10,10) is is stretched horizontally along with the whole chart.
This is the full code I used:
PolylineAnnotation annotation = new PolylineAnnotation();
annotation.AxisX = chart1.ChartAreas[0].AxisX;
annotation.AxisY = chart1.ChartAreas[0].AxisY;
annotation.Height = 10;
annotation.Width = 10;
annotation.LineWidth = 3;
annotation.StartCap = LineAnchorCapStyle.None;
annotation.EndCap = LineAnchorCapStyle.None;
annotation.Alignment = ContentAlignment.TopLeft;
annotation.AnchorAlignment = ContentAlignment.TopLeft;
annotation.X = annotation.Y = annotation.AnchorX = annotation.AnchorY = double.NaN;
DataPoint dp = chart1.Series[0].Points[33];
annotation.AnchorDataPoint = dp;
chart1.Series[1].Points.AddXY(dp.XValue, dp.YValues[0]); // my red points series
annotation.AllowAnchorMoving = true;
annotation.AllowMoving = true;
annotation.AllowPathEditing = true;
annotation.AllowResizing = true;
annotation.AllowSelecting = true;
annotation.GraphicsPath.AddLine(10, 20, 30, 30);
Rectangle r = new Rectangle(0, 0, 100, 100);
annotation.GraphicsPath.AddRectangle(r);
chart1.Annotations.Add(annotation);
Also note that just to make sure no wrong anchors are active I have reset the X/Y and the AnchorX/Y values by setting them to double.NaN! This is not really needed here, as those are the defaults anyway..
Here btw is another post on the topic!
I have 2 series (2016 and 2017) in column chart and all datapoints values are showing fine. but I need to differentiate two series values by showing thick border line between two series.
because , now it seems to combining the 2017 values with 2016 series values since no separator line not there.
FYI.
EDIT:
After used vertical line in my column chart the output as like below,
But i need only one Line that should present between the two series .
how do i remove other lines.
Finally , Got the expected Output.
Thanks in advance.
var series = Mainchart.Series[0]; //series object
var chartArea = Mainchart.ChartAreas[series.ChartArea];
chartArea.AxisX.StripLines.Add(new StripLine
{
BorderDashStyle = ChartDashStyle.Solid,
BorderColor = Color.Black,
Interval = 0, // to show only one vertical line
IntervalOffset = 1.5, // for showing Vertical line between 2 series
IntervalType = DateTimeIntervalType.Years // for me years
});
You may use StripLine:
StripLine limit_lower_strip = new StripLine();
limit_lower_strip.Interval = 0;
limit_lower_strip.IntervalOffset = v1_lower;
limit_lower_strip.StripWidth = 0.0;
limit_lower_strip.BorderColor = Color.FromArgb(100, Color.Red);
limit_lower_strip.BorderDashStyle = ChartDashStyle.Solid;
limit_lower_strip.BorderWidth = 5;
chart1.ChartAreas[0].AxisX.StripLines.Add(limit_lower_strip);
I am trying to add an additional data series to the chart this shows CPU threshold, I can get the range and create the graph with out the threshold on it, but I don't know how to add the threshold value to the chart.
do I need to create another chart object? can I use the existing and just add teh new range in?
How are you creating the chart? -- see code below.
Is this chart already created in the excel file, and you want to modify the chart in the excel file? yes the chart is already in a Excel file.
Excel.ChartObjects sCPUChart;
Excel.ChartObject sCPUChartObjects;
sCPUChart = sDBSheet.ChartObjects(Type.Missing);
sCPUChartObjects = sCPUChart.Add(49, 15, 360, 215);
Excel.Chart sChartCPU;
sChartCPU = sCPUChartObjects.Chart;
sChartCPU.SetSourceData(cpuChartRange, Missing.Value);
sChartCPU.ChartWizard(Source: cpuChartRange, Gallery: Excel.XlChartType.xlLine, Format: 2, HasLegend: true);
sChartCPU.Location(Excel.XlChartLocation.xlLocationAsObject, sDBSheet.Name);
//CPU Chart Axis
Excel.Axis xSChartCPUAxis;
xSChartCPUAxis = sChartCPU.Axes(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary);
Excel.Axis ySChartCPUAxis;
ySChartCPUAxis = syChartCPU.Axes(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlPrimary);
ySChartCPUAxis.HasMajorGridlines = true;
ySChartCPUAxis.MaximumScaleIsAuto = true;
//Set Summary CPU Series
Excel.Series sCPUSeries = sChartCPU.SeriesCollection(1);
sCPUSeries.Name = "CPU";
//-------
// this is where I am having my issue
//I don't know how to add the threshold line to the graph with the existing graph being displayed
//sChartCPU.set_HasAxis(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlSecondary, true);
//summaryChartCPU.SetSourceData(summaryMemThreshold, Type.Missing); -- things break
//-------
I have now done the following:
Excel.SeriesCollection threshold = sChartCPU.sseriesCollection();
Excel.Series line = threshold.NewSeries();
line.Formula = "=SERIES(Summ!$D$54,Summ!$C$55:$C$56,Summ!$D$55:$D$56)";
line.ChartType = Excel.XlChartType.xLScatterLinesNoMarkers;
when the threshold line is created I have the following
the values I have in cells D54 - threshold
C55 = 0
C56 = 1
D55 = 75
D56 = 75
I don't know how to remove the 2 additional axis that appear in chart
If I comment out the line.ChartType, then the axis is correct but I only get one threshold data point ?? I don't understand why.
var series = (SeriesCollection) yourChart.SeriesCollection();
var line = series.NewSeries();
line.Name = "CPU Threshhold";
//line.Values = ...;
//line.XValues = ...;
//formatting
Here's the solution I found to the OP's question of how to remove the secondary axes:
Excel.SeriesCollection threshold = sChartCPU.sseriesCollection();
Excel.Series line = threshold.NewSeries();
// line.Formula = "=SERIES(Summ!$D$54,Summ!$C$55:$C$56,Summ!$D$55:$D$56)";
// instead of setting the Formula, I set the series values
line.Values = "='Summ!'$D$55:$D$56";
line.XValues = "='Summ!'$C$55:$C$56";
line.ChartType = Excel.XlChartType.xlXYScatterLinesNoMarkers;
// creates Axis objects for the secondary axes
Excel.Axis YAxis2 = (Excel.Axis)sChartCPU.Axes(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlSecondary);
Excel.Axis XAxis2 = (Excel.Axis)sChartCPU.Axes(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlSecondary);
// remove the major and minor tick marks from the secondary (top) x-axis
XAxis2.MajorTickMark = Excel.XlTickMark.xlTickMarkNone;
XAxis2.MinorTickMark = Excel.XlTickMark.xlTickMarkNone;
// change the secondary x-axis max range to 1.0 so the bar will go all the way to the right side
XAxis2.MaximumScale = 1.0;
// delete the secondary x-axis labels
XAxis2.TickLabels.Delete();
// I chose to delete the secondary y-axis so the line would graph on the primary axis scale
YAxis2.Delete();
I have a C# windows form with a simple 2D line chart that I want to add custom X or Y axis markers to, and draw a custom grid line (in a highlighted color, dotted line for example). I have looked at the customLabels property, but this seems to override the default grid, which I still want to display. This is to illustrate something like a threshold or a cutoff. How can I do this with the MSChart control?
Many thanks
Could you achieve what you want with striplines?
In the ms chart samples (get it here http://archive.msdn.microsoft.com/mschart), inside the "Using Custom Labels" section, they use striplines on the Y axis which are quite effective at highlighting ranges of values. They also do not affect the grid ... I checked that by changing the sample code a little so I could easily move the boundaries of the striplines around (see below).
double low_med = 17; // was 30
double med_hi = 92; // was 70
// Set Y axis custom labels
axisY.CustomLabels.Add(0, low_med, "Low");
axisY.CustomLabels.Add(low_med, med_hi, "Medium");
axisY.CustomLabels.Add(med_hi, 100, "High");
StripLine stripLow = new StripLine();
stripLow.IntervalOffset = 0;
stripLow.StripWidth = low_med;
stripLow.BackColor = Color.FromArgb(64, Color.Green);
StripLine stripMed = new StripLine();
stripMed.IntervalOffset = low_med;
stripMed.StripWidth = med_hi - low_med;
stripMed.BackColor = Color.FromArgb(64, Color.Orange);
StripLine stripHigh = new StripLine();
stripHigh.IntervalOffset = med_hi;
stripHigh.StripWidth = 100 - med_hi;
stripHigh.BackColor = Color.FromArgb(64, Color.Red);
axisY.StripLines.Add(stripLow);
axisY.StripLines.Add(stripMed);
axisY.StripLines.Add(stripHigh);