MSChart: How to group RangeBar data with text labels instead of indexes? - c#

I'm looking to plot data on a RangeBar chart area (System.Windows.Forms.DataVisualization.Charting) and I'm having issues grouping the data when I have text values for the labels on the vertical axis.
Here's the pertinent code:
var connectedTimeRangeSeries = theChart.Series.Add("ConnectedTimeRangeSeries");
var connectedTimeRangesChartArea = theChart.ChartAreas["PerItemConnectedChartArea"];
connectedTimeRangeSeries.ChartArea = connectedTimeRangesChartArea.Name;
connectedTimeRangeSeries.ChartType = SeriesChartType.RangeBar;
connectedTimeRangeSeries.XValueType = ChartValueType.Auto;
connectedTimeRangeSeries.YValueType = ChartValueType.Auto;
for (int i = 0; i < timeRanges.Count; i++)
{
string theLabel = timeRanges[i].ItemLabel;
connectedTimeRangeSeries.Points.AddXY(timeRanges[i].ItemId + 1, timeRanges[i].StartConnectionTime, timeRanges[i].StopConnectionTime);
}
timeRanges is a list with items having these member types (accessed through public properties with corresponding capitalized names):
private int itemId;
private string itemLabel;
private DateTime startConnectionTime;
private DateTime stopConnectionTime;
When I call DataSeries.Points.AddXY() with the X type as an integer (recall X is the vertical axis on the range bar) it does what I want. The time ranges are grouped according to the index in the bottom graph:
However, when I change to try to use a text label to group them, by replacing AddXY with this:
connectedTimeRangeSeries.Points.AddXY(theLabel, timeRanges[i].StartConnectionTime, timeRanges[i].StopConnectionTime);
the data are no longer grouped:
It's like each one gets its own bin, and I just want them to be combined by label. (Each index has one and only one label.)
Any ideas? Thanks!

Use AxisLabel property of the DataPoint.
One way to do it would be something like this:
for (int i = 0; i < timeRanges.Count; i++)
{
string theLabel = timeRanges[i].ItemLabel;
int pointIndex = connectedTimeRangeSeries.Points.AddXY(timeRanges[i].ItemId + 1, timeRanges[i].StartConnectionTime, timeRanges[i].StopConnectionTime);
connectedTimeRangeSeries.Points[pointIndex].AxisLabel = theLabel;
}

Related

MSVisio Characters custom color

I know, that I can change color of all text in shape this way:
Shape.CellsU["Char.Color"].FormulaForceU = "RGB(255,255,255)";
There is also way to change color of certain characters in shape this way:
Characters.Begin = 2;
Characters.End = 5;
Characters.set_CharProps((short)MSVisio.VisCellIndices.visCharacterColor, (short)MSVisio.VisDefaultColors.visRed;);
But I can't find any way to pass custom RGB (or HEX or any type) value of color to just certain characters in shape. I don't want to cut shape into little shapes.
Can you please help? Thanks
The CharProps property allows you to set an index into the predefined document colors collection. For a custom RGB you can set the corresponding cell formula by first getting the row index with CharPropsRow like this:
var shp = vApp.ActiveWindow.Selection.PrimaryItem;
var shpChars = shp.Characters;
shpChars.Begin = 2;
shpChars.End = 5;
//shpChars.set_CharProps((short)Visio.VisCellIndices.visCharacterColor, (short)Visio.VisDefaultColors.visRed);
var targetRow = shpChars.CharPropsRow[0];
shp.CellsSRC[(short)Visio.VisSectionIndices.visSectionCharacter,
targetRow,
(short)Visio.VisCellIndices.visCharacterColor].FormulaU = "RGB(40,220,40)";
and that should give you similar results to this:
[Update] The above assumes you're targeting existing formating and changing it. To add new runs you can use CharProps first to add the row and then the CharPropsRow to target that new run. So you can run this code against a new page:
var vPag = vApp.ActivePage;
var shp = vPag.DrawRectangle(3,3,5,4);
shp.Text = "GoodMorning";
var shpChars = shp.Characters;
shpChars.Begin = 0;
shpChars.End = 4;
var targetRow = shpChars.CharPropsRow[(short)Visio.VisCharsBias.visBiasLetVisioChoose];
shp.CellsSRC[(short)Visio.VisSectionIndices.visSectionCharacter,
targetRow,
(short)Visio.VisCellIndices.visCharacterColor].FormulaU = "RGB(220,40,40)";
shpChars.Begin = 4;
shpChars.End = 11;
shpChars.set_CharProps((short)Visio.VisCellIndices.visCharacterColor, (short)Visio.VisDefaultColors.visBlack);
targetRow = shpChars.CharPropsRow[(short)Visio.VisCharsBias.visBiasLetVisioChoose];
shp.CellsSRC[(short)Visio.VisSectionIndices.visSectionCharacter,
targetRow,
(short)Visio.VisCellIndices.visCharacterColor].FormulaU = "RGB(40,200,40)";
...and this should result in the following:

c# Fill a listview with items from a richtextbox (each 5 lines into columns)

I have a list view and a richtextbox.
This richtextbox has data like below. And I want to input the first 5 lines in one row and 5 columns like below.
richtextbox example and List view example
I have the below code so far
for ( int i = 0; i < richTextBox1.Lines.Count(); i++)
{
string[] arry = new string[5];
ListViewItem itms;
arry[0] = richTextBox1.Lines[i];
arry[1] = richTextBox1.Lines[i+1];
arry[2] = richTextBox1.Lines[i + 1];
arry[3] = richTextBox1.Lines[i+2];
arry[4] = richTextBox1.Lines[i+3];
itms = new ListViewItem(arry);
listView1.Items.Add(itms);
}
But it is not giving me the desired output, as it repeats itself over and over like seen here
Undesired Output
Kindy let me know where I am going wrong
Your for loop is going line by line, not by groups of 5 lines.
Change it to this:
for ( int i = 0; i < richTextBox1.Lines.Count(); i += 5)

Store results of subtracting 2 series Y values, as new series

I have a chart with two series that share the same X axis values. I want to subtract the Y values and create a new series.
There are two ways I've tried so far:
Convert the points on the chart and put them into an array and subtract them:
double[] arrayX = new double[chart2.Series[0].Points.Count()];
double[] arrayY = new double[chart2.Series[0].Points.Count()];
double[] arrayResult = { };
for (int i = 0; i < chart2.Series[0].Points.Count(); i++)
{
arrayX[i] = chart2.Series[0].Points[i].XValue;
arrayY[i] = chart2.Series[0].Points[i].YValues[0];
}
The issue with this is that this only gets the X Values from the first series and leaves out the second series X Values.
When I add the points to the chart I used this:
chart2.Series[SplitListBox.Items[0].ToString()].Points.AddXY(e, firstval);
chart2.Series[SplitListBox.Items[1].ToString()].Points.AddXY(e, firstval);
Both of which are in separate loops. I was going to use 2 array to catch the points (e,firstval) for each loop but I don't know how to subtract the two from each other and still keep the values that exist in one series but not in the other.
After creating the new Series SDelta to your liking you can call a simple function to fill it like this:
void PlotDelta(Chart chart, Series S1, Series S2, Series SDelta)
{
for (int i = 0; i < S1.Points.Count; i++)
{
if ( i < S2.Points.Count)
{
DataPoint dp1 = S1.Points[i];
DataPoint dp2 = S2.Points[i];
if (!dp1.IsEmpty && !dp2.IsEmpty)
SDelta.Points.AddXY(dp1.XValue, dp2.YValues[0] - dp1.YValues[0]);
}
}
You may want to improve the error handling for cases of different point counts or emtpy points..
Here is a testbed:
private void button1_Click(object sender, EventArgs e)
{
chart1.Series.Clear();
chart1.Series.Add(new Series { Name = "Cos", ChartType = SeriesChartType.Line });
chart1.Series.Add(new Series { Name = "Sin", ChartType = SeriesChartType.Line });
chart1.Series.Add(new Series { Name = "Delta", ChartType = SeriesChartType.Line });
for (int i = 0; i < 100; i++ )
{
chart1.Series["Cos"].Points.AddXY(i, Math.Cos(i / Math.PI));
chart1.Series["Sin"].Points.AddXY(i, Math.Sin(i / Math.PI));
}
PlotDelta(chart1, chart1.Series["Cos"], chart1.Series["Sin"],
chart1.Series["Delta"]);
}
Of course you could integrate the creation of the delta series in the function; but you would have to pass in any properties you may want to vary like Color, ChartType etc..

How to change X-axis datetime value jan-01 to Oct-01 using .net chart control

I am trying to show x axis value in the form of date(MMM-yy) but it is always begin with jan-01. So please provide solution to display other then jan-01, I mean instead of Jan-01 show oct-01.
Please find the simulated function :
private static void drawGraph()
{
List<GraphPoints> listGP = new List<GraphPoints>();
listGP.Add(new GraphPoints()
{
RecordDate = "01/10/1984",
benchmark = "10000.00"
});
listGP.Add(new GraphPoints()
{
RecordDate = "29/06/1987",
benchmark = "30396.00"
});
listGP.Add(new GraphPoints()
{
RecordDate = "31/05/1989",
benchmark = "10000.00"
});
listGP.Add(new GraphPoints()
{
RecordDate = "30/09/1993",
benchmark = "310137.88"
});
listGP.Add(new GraphPoints()
{
RecordDate = "31/12/2015",
benchmark = "440037.28"
});
Graph.Chart chart;
chart = new Graph.Chart();
chart.Location = new System.Drawing.Point(10, 10);
chart.Size = new System.Drawing.Size(800, 300);
chart.ChartAreas.Add("draw");
chart.ChartAreas["draw"].AxisX.IntervalType = Graph.DateTimeIntervalType.Years;
chart.ChartAreas["draw"].AxisX.LabelStyle.Format = "MMM-yyyy";
chart.ChartAreas["draw"].AxisX.MajorGrid.LineColor = Color.Black;
chart.ChartAreas["draw"].AxisX.MajorGrid.LineDashStyle = Graph.ChartDashStyle.NotSet;
chart.ChartAreas["draw"].AxisY.IntervalAutoMode = Graph.IntervalAutoMode.VariableCount;
chart.ChartAreas["draw"].AxisY.MajorGrid.LineColor = Color.Black;
chart.ChartAreas["draw"].AxisY.MajorGrid.LineDashStyle = Graph.ChartDashStyle.NotSet;
chart.ChartAreas["draw"].BackColor = Color.White;
chart.Series.Add("Bench-Mark");
chart.Series["Bench-Mark"].XValueType = Graph.ChartValueType.Date;
chart.Series["Bench-Mark"].ChartType = Graph.SeriesChartType.Line;
chart.Series["Bench-Mark"].Color = Color.Red;
chart.Series["Bench-Mark"].BorderWidth = 1;
foreach (var item in listGP)
{
chart.Series["Bench-Mark"].Points.AddXY(Convert.ToDateTime(item.RecordDate).ToOADate(), item.benchmark);
}
chart.SaveImage("MyImage.jpg", Graph.ChartImageFormat.Jpeg);
}
See Graph axis points are showing from jan 1988.
There is a nice page on MSDN on various types of labels.
It explains three types of labelling:
Using the Label of the AxisX.LabelStyle.Format and Axis.Interval property to create a regular grid of labels not really connected to the data points
Using the DataPoint.AxisLabel property to label each DataPoint individually
Using CustomLabels to set labels at arbitrary points on an axis.
You are using the first option but this will put a Label at the beginning of one unit of the AxisX.IntervalType which in your case will be years even if you switch to Months because there simply are too few points.
This really should be simple to correct; since you do not want the IntervalType units labelled but the individual DataPoints, you should add AxisLabels to each DataPoint and all ought to be well:
Series S1 = chart.Series["Bench-Mark"];
foreach (var item in listGP)
{
DateTime dt = Convert.ToDateTime(item);
int p = S1.Points.AddXY(dt, listGP[item]);
string l = dt.ToString("MMM-yyyy");
S1.Points[p].AxisLabel = l;
}
Unfortunately with your data, the Chart control's built-in 'intelligence' makes this a bit harder; the issue is that no matter which combination of Interval and IntervalType you choose it just never will show each AxisLabel. In fact I only managed to display those that actually hit the Interval, i.e. DataPoints the fall the 1st of a month. But your data are randomly spread out over several years.
But you can use CustomLabels as a workaround. After adding the AxisLabels in the code above call this little helper function to add CustomLabels; we need to tell the Chart for which range each is to be displayed, and with a large enough range they all show up where they should (according to my data):
void addCustomLabels(Chart chart)
{
Series S1 = chart.Series[0];
ChartArea CA = chart.ChartAreas[0];
CA.AxisX.CustomLabels.Clear();
for (int i = 0; i < S1.Points.Count; i++)
{
CustomLabel cl = new CustomLabel();
cl.FromPosition = S1.Points[i].XValue - 10; // 10 day back and ahead..
cl.ToPosition = S1.Points[i].XValue + 10; //..will be enough space for one label
cl.Text = S1.Points[i].AxisLabel;
CA.AxisX.CustomLabels.Add(cl);
}
}
Note that such a solution will only work well if your data points are as sparse as in the example; for many points the labels would clutter the axis.

Different label types on one axis in chart

I'm using System.Windows.Forms.DataVisualization.Charting in my app and I want to add different label types on my X axis which is representing a timeline. For example, I want to use "HH:mm" format for labels but when it's 00:00 I'd like to show "dd.MM" format instead. I tried to add cutom labels but it has no effect at all.
var area = new ChartArea();
area.AxisX.LabelStyle.Format = "HH:mm";
area.AxisX.Interval = 1 / 24.0;
area.AxisX.CustomLabels.Add(1.0, DateTimeIntervalType.Days, "dd.MM");
Adding CustomLabels will help; however if you want them to show an individual format you will have to add them individually to each DataPoint!
Doing so is not quite as simple as one could wish for; there are several overloads but none is really easy to use. The simplest way, imo, is to use one with a FromPosition and a ToPosition; these should then to be set in a way that they hit right between the DataPoints; this way they will be centered nicely..
Note that as the X-Values are really DateTimes, but as always in a chart, converted to doubles we need to convert them back to DateTime for correct formatting and also use their values to calculate the middle or rather half an interval..
Here is an example:
// prepare the test chart..
chart1.ChartAreas.Clear();
ChartArea CA = chart1.ChartAreas.Add("CA1");
Random R = new Random(123);
chart1.Series.Clear();
CA.AxisX.MajorTickMark.Interval = 1;
Series S = chart1.Series.Add("S1");
S.Points.Clear();
S.ChartType = SeriesChartType.Column;
S.SetCustomProperty("PixelPointWidth", "10");
// some random data:
DateTime dt0 = new DateTime(2015, 05, 01);
for (int i = 0; i< 40; i++)
{
int p = S.Points.AddXY(dt0.AddHours(i), R.Next(100));
}
// each custom label will be placed centered in a range
// so we need an amount of half an interval..
// this assumes equal spacing..
double ih = (S.Points[0].XValue - S.Points[1].XValue) / 2d;
// now we add a custom label to each data point
for (int i = 0; i < S.Points.Count; i++)
{
DataPoint pt = S.Points[i];
string s = (DateTime.FromOADate(pt.XValue)).ToString("HH:mm");
bool midnite = s == "00:00";
if (midnite) s = DateTime.FromOADate(pt.XValue).ToString("dd.MM.yyyy");
CustomLabel CL = CA.AxisX.CustomLabels.Add(pt.XValue - ih, pt.XValue + ih, s);
CL.ForeColor = midnite ? Color.Blue : Color.Black;
}

Categories

Resources