Adding series to Excel chart exception - c#

I have an excel file filled with some data. I am trying to open the second sheet and create a chart. The problem is that the Series are giving me either a System.Runtime.InteropServices.COMException was caught or if I un-comment the commented lines a No overload for method 'SeriesCollection' takes '0' arguments. Here is the code that I have:
Microsoft.Office.Interop.Excel.ChartObjects chartObjs = (Microsoft.Office.Interop.Excel.ChartObjects)ws.ChartObjects(Type.Missing);
Microsoft.Office.Interop.Excel.ChartObject chartObj = chartObjs.Add(100, 20, 300, 300);
Microsoft.Office.Interop.Excel.Chart xlChart = chartObj.Chart;
Range rg1 = ws.get_Range("A1", "D" + rowcount);
rg1.VerticalAlignment = Microsoft.Office.Interop.Excel.XlVAlign.xlVAlignCenter;
xlChart.SetSourceData(rg1, Microsoft.Office.Interop.Excel.XlRowCol.xlColumns);
xlChart.ChartType = XlChartType.xlLine;
xlChart.Legend.Position = XlLegendPosition.xlLegendPositionBottom;
Axis axis = (Axis)xlChart.Axes(Microsoft.Office.Interop.Excel.XlAxisType.xlValue, Microsoft.Office.Interop.Excel.XlAxisGroup.xlPrimary);
axis.MaximumScaleIsAuto = false;
axis.MaximumScale = 3;
Axis Xaxis = (Axis)xlChart.Axes(Microsoft.Office.Interop.Excel.XlAxisType.xlCategory, Microsoft.Office.Interop.Excel.XlAxisGroup.xlPrimary);
Xaxis.TickLabels.Orientation = XlTickLabelOrientation.xlTickLabelOrientationDownward;
//SeriesCollection seriesCollection = (SeriesCollection)xlChart.SeriesCollection();
Series s1 = (Series)xlChart.SeriesCollection(1);
s1.Name = "Serie1";
s1.MarkerStyle = XlMarkerStyle.xlMarkerStyleCircle;
//seriesCollection.NewSeries();
Series s2 = (Series)xlChart.SeriesCollection(2);
s2.Name = "Serie2";
s2.MarkerStyle = XlMarkerStyle.xlMarkerStyleNone;
//seriesCollection.NewSeries();
Series s3 = (Series)xlChart.SeriesCollection(3);
s3.Name = "Serie3";
s3.MarkerStyle = XlMarkerStyle.xlMarkerStyleNone;
If I keep the comments, the error says invalid parameter and is shown on that line:
Series s2 = (Series)xlChart.SeriesCollection(2);
If I remove the comments, I get the second exception on that line:
SeriesCollection seriesCollection = (SeriesCollection)xlChart.SeriesCollection();
If I add 1 as a parameter, then the chart is not displayed properly. Do you have any suggestions how to make it work?

Argh that stuff still gives me nightmares. There was some weirdness around SeriesCollection - but I cannot remember exactly what it was.
Try to re-include that line
//SeriesCollection seriesCollection = (SeriesCollection)xlChart.SeriesCollection();
and refernece the seriesCollection object everywhere.
Alos it could be, that the index for SeriesCollection is zero - based, can you try that?

By Default when you create a new chart it doesn't have any series so you can't select it using chartPage.SeriesCollection(1). You need to create a series first.
In order to add a new series you need to use something like:
SeriesCollection seriesCollection = (SeriesCollection)xlChart.SeriesCollection();
Series s1 = seriesCollection.NewSeries();
s1.Name = "Serie1";
s1.MarkerStyle = XlMarkerStyle.xlMarkerStyleCircle;
Series s2 = seriesCollection.NewSeries();
s2.Name = "Serie2";
s2.MarkerStyle = XlMarkerStyle.xlMarkerStyleNone;
You may also need to add the values to the series rather than to the chart, eg:
Series ser = sc.NewSeries();
ser.XValues = _excelWorksheet.Range[YourRange];
ser.Values = _excelWorksheet.Range[YourRange];

Related

How to add multiple texts on Visio connector shapes using the c#/vba code?

I want to add multiple texts on the connector line as per the image below. I am using c# code to automate the process. Below is my code which I have used. It is not giving the exact output as I had expected. Any help in this regard would be highly appreciated.
Visio.Shape vsoLastShape = visioPage.Shapes.get_ItemFromID(lastshapeID);
vsoLastShape.ConvertToGroup();
Visio.Selection vsoSelections = app.ActiveWindow.Selection;
vsoSelections.Select(vsoLastShape, (short)VisSelectArgs.visSelect);
Visio.Shape vsoGroupShape = vsoSelections.Group();
vsoGroupShape.Text = "Testing 12";
vsoGroupShape.TextStyle.PadLeft(10);
Whatever method (manual, C#, VBA or whatevber) you use, one shape can only contain one text. If you want to add more than one text then you need to convert the shape into a grouped shape. Then you can add a shape to the group and set that sub-shape's text to what you want.
Shape .Characters object used in conjunction with .Text allows for some flexibility.
private string nl = Environment.NewLine;
public void MultiText() {
try {
// using = System.Windows.Forms;
// using Vis = Microsoft.Office.Interop.Visio;
Vis.Application app = Globals.ThisAddIn.Application; // or launch Visio
Vis.Document vDoc = app.Documents.Add(""); // new blank document
Vis.Shape c1 = app.ActivePage.DrawOval(1, 1, 1.5, 1.5);
Vis.Shape s1 = app.ActivePage.DrawLine(1.5, 1.25, 4, 1.25);
s1.Text = $"Shape1{nl}Line2";
Vis.Shape c2 = app.ActivePage.DrawOval(4, 1, 4.5, 1.5);
Vis.Shape c3 = app.ActivePage.DrawOval(1, 3, 1.5, 3.5);
Vis.Shape s2 = app.ActivePage.DrawLine(1.5, 3.25, 4, 3.25);
s2.Text = $"Shape2";
Vis.Shape c4 = app.ActivePage.DrawOval(4, 3, 4.5, 3.5);
app.ActiveWindow.CenterViewOnShape(c4, Vis.VisCenterViewFlags.visCenterViewDefault);
app.ActiveWindow.Zoom = 1.2;
app.ActiveWindow.Selection.DeselectAll();
app.DoCmd((short)VisUICmds.visCmdDeselectAll);
System.Windows.Forms.MessageBox.Show($"2 Shapes with text.", "Continue...");
// reset the Text on Shape #2 and define 2 separate ranges
s2.Text = "";
// alocate a range
Characters range1 = s2.Characters;
range1.Begin = 0;
range1.End = 3;
range1.Text = "Name";
// alocate another
Characters range2 = s2.Characters;
range2.Begin = 4;
//range2.End = 7;
range2.Text = $"{Environment.NewLine}Type";
MessageBox.Show($"Now change Font Size", "Continue...");
// change font size or any of numerous properties
range1.CharProps[(short)Vis.VisCellIndices.visCharacterSize] = 16;
range2.CharProps[(short)Vis.VisCellIndices.visCharacterSize] = 8;
//range2.CharProps[(short)Vis.VisCellIndices.visCharacterStrikethru] = 1; // 1-true 0-false
MessageBox.Show($"Big Name!{nl}little Type.", "OK to continue");
} catch (Exception ex) {
ta.LogIt($"Err {ex.Message} Trace {ex.StackTrace}");
}
}
You may want to check this post and used the uploaded stencil. (Requires registration to see and download the attachment):
http://visguy.com/vgforum/index.php?topic=6318.msg25957#msg25957

How do we assign a Series to a ChartArea?

I have an array of ChartArea area[] and an array of Series series[]
What I need to do is use a different ChartArea for each Series.
This is what is usually done :
Chart Chart0 = new Chart();
ChartArea ChartArea0 = new ChartArea("name");
Chart0.ChartAreas.Add(ChartArea0);
Series Series0 = new Series();
Chart0.Series.Add(Series0);
// link series to area here
Series0.ChartArea = "name";
But in my case, I cannot have a string name for each. It needs to be an array. How can I work around this?
I asked a few clarifying questions in my comment, but if I go off my assumptions of the situation you expressed, here's what I would do:
var sourceStringArray = new string[] { "ChartArea1Name" };
Chart Chart0 = new Chart();
ChartArea ChartArea0 = new ChartArea(sourceStringArray[0]);
Chart0.ChartAreas.Add(ChartArea0);
Series Series0 = new Series();
Chart0.Series.Add(Series0);
// link series to area here
Series0.ChartArea = sourceStringArray[0];
I will edit my answer based on the responses to my comment.
Edit:
Based on your comment:
I need it to be an array as the number of ChartAreas I need is dependant on a variable number of parameters
You would probably want to make a method that does the creation of your ChartArea objects. Something like:
private List<ChartArea> CreateChartAreas(string[] chartAreaNames)
{
var chartAreaInstances = new List<ChartArea>();
foreach (var chartAreaName in chartAreaNames)
{
var tempChart = new Chart();
var tempChartArea = new ChartArea(chartAreaName);
tempChart.ChartAreas.Add(tempChartArea);
var tempSeries = new Series();
tempChart.Series.Add(tempSeries);
tempSeries.ChartArea = chartAreaName;
}
return chartAreaInstances;
}
Then in the main code, do something like:
var sourceStringArray = new string[] { "ChartArea1Name", "ChartArea2Name" };
var chartAreas = CreateChartAreas(sourceStringArray);
foreach (var chartArea in chartAreas)
{
// Do something with your chart area instances.
}
Disclaimer: I haven't tested this code as I don't know what your specific use case is for this.

Add title to my series line [mschart]

I am using Chart control to display my network statistics (download, upload):
chart1.Titles.Add("Test Chart");
Series seriesDownload = new Series("KB/s");
seriesDownload.Color = Color.DarkBlue;
seriesDownload.ChartType = SeriesChartType.Spline;
seriesDownload.BorderWidth = 2;
chart1.Series.Add(seriesDownload);
Series seriesPps = new Series("pps");
seriesPps.Color = Color.Black;
seriesPps.ChartType = SeriesChartType.Spline;
seriesPps.BorderWidth = 2;
chart1.Series.Add(seriesPps);
Is it possible to add text near each line in order to distinguish between both colors ?
private void chartTimer_Tick(object sender, EventArgs e)
{
chart1.Series[1].LegendText = chart1.Series[1].Name = str + " KB/s";
DataPoint Point = chart1.Series[1].Points[chart1.Series[1].Points.Count - 1];
Point.Label = chart1.Series[1].Name;
DataPoint _point = default(DataPoint);
foreach (DataPoint item in chart1.Series[1].Points)
{
item.Label = "";
item.MarkerStyle = MarkerStyle.None;
}
}
Something like this will add a label with the series name to the last point on your series. This is VB.NET but you should be able to parse it to C#
'remove all previous datapoint labels
Dim _point As DataPoint
For Each _point In Chart1.Series(i).Points
_point.Label = ""
_point.MarkerStyle = MarkerStyle.None
Next
'add label to last point
Dim Point As DataPoint = Chart1.Series(i).Points(Chart1.Series(i).Points.Count - 1)
Point.Label = Chart1.Series(i).Name
Point.MarkerStyle = MarkerStyle.Circle
Or are you looking to populate the legend with the series name?? then
Chart1.Series(i).LegendText = Chart1.Series(i).Name
EDIT based on the askee submitted code in C#
private void chartTimer_Tick(object sender, EventArgs e)
{
foreach (DataPoint item in chart1.Series[1].Points)
{
item.Label = "";
}
chart1.Series[1].LegendText = chart1.Series[1].Name = str + " KB/s";
DataPoint Point = chart1.Series[1].Points[chart1.Series[1].Points.Count - 1];
Point.Label = chart1.Series[1].Name;
}
Changing the name of the series is not good practice, as the SeriesCollection can be indexed by name (e.g., chart1.Series["MySeries"]) which might then fail after the name change.
If you're trying to add a static label at the end of the code, you can do it as a smart label. Look into the "#VALX#", "#VAL#" modifiers to use in labels:
DataPoint Point = chart1.Series[1].Points[chart1.Series[1].Points.Count - 1];
Point.Label = "#VAL" + " kB/s";
which will automatically add the current x or y value to the label. See http://msdn.microsoft.com/en-us/library/dd456687(v=vs.110).aspx
As an aside, it's very helpful to put the names of your Series into const variables in the class (or static variables in another class), so you can index them without fear of typos. Makes your code much easier to understand, too.
private const string _downloadSeries = "download";
// in some initialization method
Series seriesDownload = new Series(_downloadSeries);
chart1.Series.Add(seriesDownload);
// Access the series
DataPoint point = chart1.Series[_downloadSeries].Points[0];
for example.
EDIT: If you just want to distinguish the two colors, that's exactly what a legend is for. If you want to show the latest value as well, then this code will do that

Chart control data series

I have a chart control.I am plotting price along y axis and month-year along x axis.
I add series1 1st and then series2 to the same chart area.
Then I plot the points for series 1 and 2 using the below code
curveChart.Series.Add("Series1");
curveChart.Series["Series1"].XValueType = ChartValueType.DateTime;
curveChart.Series["Series1"].Points.DataBind(list1, "MonthYear", "PriceValue", null);
curveChart.Series["Series1"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
curveChart.Series["Series1"].BorderWidth = 3;
curveChart.ChartAreas["0"].AxisX.Interval = 1;
curveChart.Series.Add("Series2");
curveChart.Series["Series2"].XValueType = ChartValueType.DateTime;
curveChart.Series["Series2"].Points.DataBind(list2, "MonthYear", "PriceValue", null);
curveChart.Series["Series2"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
curveChart.Series["Series2"].BorderWidth = 3;
curveChart.ChartAreas["0"].AxisX.Interval = 1;
The problem I am facing is that list2 contains data only till Dec-2015 and list1 contains data till Dec-2016 but when the graph is plotted both the lines in the graph extend upto Dec-2016 though list2 doesnt have data till Dec-2016.How can I solve this?
I tried to simulate your problem. I added two data series one with 3 points, one with 2 points. The chart rendered correctly. This makes me think you are going to have to massage your data before you bind it.
curveChart.Series.Clear();
curveChart.Series.Add("Series1");
curveChart.Series["Series1"].XValueType = ChartValueType.DateTime;
curveChart.Series["Series1"].Points.AddXY(DateTime.Now, 12.00m);
curveChart.Series["Series1"].Points.AddXY(DateTime.Now.AddDays(1), 13m);
curveChart.Series["Series1"].Points.AddXY(DateTime.Now.AddDays(2), 8m);
curveChart.Series["Series1"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
curveChart.Series["Series1"].BorderWidth = 3;
curveChart.ChartAreas["0"].AxisX.Interval = 1;
curveChart.Series.Add("Series2");
curveChart.Series["Series2"].XValueType = ChartValueType.DateTime;
curveChart.Series["Series2"].Points.AddXY(DateTime.Now, 5.00m);
curveChart.Series["Series2"].Points.AddXY(DateTime.Now.AddDays(1), 7m);
curveChart.Series["Series2"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
curveChart.Series["Series2"].BorderWidth = 3;
curveChart.ChartAreas["0"].AxisX.Interval = 1;

Getting Values of other Series through tooltip

I'm having a Chart whose data is coming from a list.
This class has id and count1 and count2 as Properties...
Now, i have a list of class...where the values are...
Id Count1 Count2
1 -10 20
2 -15 15
Now,
i do a simple bind...with multiple series
Chart1.DataSource = ListObjOfThatClass
Chart1.Series[0].XValueMember = "Id";
Chart1.Series[0].YValueMembers = "Count1";
Chart1.Series[1].YValueMembers = "Count2";
Chart1.DataBind();
Now, everthing works fine..
My Que: When i hover over the DataSeries, i show a tooltip for that particular YValueMember as "#VALY";
Chart1.Series[0].ToolTip = "#VALY";
Is there any way that I can show the value present in the other series?
i.e
Count2 value, of the series[1].YValueMember which I initialized earlier...??
Thanks
The easier way is too create your own DataPoint for the series, and not use the datasource. Then you can put whatever you want in the tooltip:
foreach (var o in ListObjOfThatClass)
{
var p1 = new DataPoint();
p1.SetValueXY(o.Id, o.Count1);
p1.ToolTip = string.Format("{0}", o.Count2);
Chart1.Series[0].Points.Add(p1);
var p2 = new DataPoint();
p2.SetValueXY(o.Id, o.Count2);
Chart1.Series[1].Points.Add(p2);
}

Categories