Add title to my series line [mschart] - c#

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

Related

generate a trendline from files in a chart

I want to be able to fetch .csv files from a folder and plot them up in a chart.
Currently, I'm just saving the files and displaying an individual curve like this:
RunTest function:
public List<Tuple<double,double>> runTest()
{
_dpg = new Root(this, "english", false);
_dpg.Init();
var filename = "Dpg10Export_" + DateTime.Now.ToString("yyyyMMdd_HHmm") + ".csv";
List<Tuple<double, double>> results = new List<Tuple<double, double>>();
var measurement = new Measurement();
var resultCode = RunMeasurement(60, 1000, 2200, ref measurement, null /* TODO: ref ProgressBar? */);
using (var fileStream = new StreamWriter(filename))
{
var count = measurement.I_inc_Values.Count;
for (var i = 0; i < count; i++)
{
var item = measurement.I_inc_Values[i + 1];
var current = (float)Convert.ToDouble(item);
item = measurement.LI_inc_Values[i + 1];
var inductance = (float)Convert.ToDouble(item);
var line = current.ToString() + ";" + inductance.ToString() + ";";
fileStream.WriteLine(line);
currentList.Add(current);
inductanceList.Add(inductance);
results.Add(new Tuple<double, double>(current,inductance));
if (i == 0 || (i + 1) % 32 == 0)
{
Console.WriteLine((i + 1) + ": " + line);
}
}
}
return results;
}
This code produces a csv-file that looks something like this:
0,22 | 0,44
0,32 | 0,54
0,44 | 0,65
And those values produce a curve that looks like this:
When you click on the "get Waveform" button, the curve above is generated. However, I want to display all the curves that has been generated, and a trendline as well. How would I achieve this?
void BindData(List<Tuple<double,double>> results)
{
chart.Series.Clear();
var series1 = new System.Windows.Forms.DataVisualization.Charting.Series
{
Name = "curr/induc",
Color = System.Drawing.Color.Green,
IsVisibleInLegend = true,
IsXValueIndexed = true,
ChartType = SeriesChartType.Line
};
foreach (var i in results)
{
series1.Points.AddXY(i.Item2,i.Item1);
}
chart.Invalidate();
chart.Series.Add(series1);
}
private void getWaveformBtn_Click(object sender, EventArgs e)
{
Dpg10Client.Dpg10Settings settings = new Dpg10Client.Dpg10Settings();
Dpg10Instrument hej = new Dpg10Instrument(settings);
List<Tuple<double,double>> results = hej.runTest();
double current, inductance;
foreach(var i in results)
{
current = i.Item1;
inductance = i.Item2;
textBoxWaveformInput.Text += current.ToString() + inductance.ToString();
}
BindData(results);
}
TL;DR
Parse the information from the CSV files to generate curves, and create a trendline based on those files.
Marked as duplicate: That answer is regarding a straight line, these values can fluctuate in a curve.
There are many ways to solve most of the various problems in your question.
Let me tackle only the one that actually has to do with calculating an average from multiple series, i.e. will not deal with creating a Series with data from a CSV file.
There is a built-in class that can do all sorts of advanced math, both financial and statistical, but I didn't find one that will help in creating an average line/curve over more than one series.
So let's do it ourselves..
The first issue is that to calculate averages we need not just data but the data, that is their x-values, must be grouped into 'bins' from which we want to get the averages.
Unless the data already are grouped like that, e.g. because they have one value per series per day, we need to create such groups.
Let's first collect all the points from all series we want to handle; you may need to adapt the loop to include just your set of series..:
var allPoints = new List <DataPoint>();
for (int s = 0; s < 3; s++) // I know I have created these three series
{
Series ser = chartGraphic.Series["S" + (s+1)];
allPoints.AddRange(ser.Points);
}
Next we need to decide on a bin range/size, that is a value that determines which x-values shall fall into the same bin/group. I chose to have 10 bins.
So we best get the total range of the x-values and divide by the number of bins we want..:
double xmax = allPoints.Max(x => x.XValue);
double xmin = allPoints.Min(x => x.XValue);
int bins = 10;
double groupSize = (xmax - xmin) / (bins - 1);
Next we do the actual math; for this we order our points, group them and select the average for each grouped set..:
var grouped = allPoints
.OrderBy(x => x.XValue)
.GroupBy(x => groupSize * (int)(x.XValue /groupSize ))
.Select(x => new { xval = x.Key, yavg = x.Average(y => y.YValues[0]) })
.ToList();
Now we can add them to a new series to display the averages in the bins:
foreach (var kv in grouped) avgSeries.Points.AddXY(kv.xval + groupSize/2f, kv.yavg);
I center the average point in the bins.
Here is an example:
A few notes on the example:
The average line doesn't show a real 'trend' because my data are pretty much random.
I have added Markers to all series to make the DataPoints stand out from the lines. Here it is how I did it for the averages series:
avgSeries.MarkerStyle = MarkerStyle.Cross;
avgSeries.MarkerSize = 7;
avgSeries.BorderWidth = 2;
I have added a StripLine to show the bins. Here is how:
StripLine sl = new StripLine();
sl.BackColor = Color.FromArgb(44,155,155,222);
sl.StripWidth = groupSize;
sl.Interval = groupSize * 2;
sl.IntervalOffset = chartGraphic.ChartAreas[0].AxisX.IntervalOffset;
chartGraphic.ChartAreas[0].AxisX.StripLines.Add(sl);
I have also set one point to have a really low value of -300 to demonstrate how this will pull down the average in its bin. To keep the chart still nicely centered on the normal range of data I have added a ScaleBreakStyle to the y-axis:
chartGraphic.ChartAreas[0].AxisY.ScaleBreakStyle.BreakLineStyle = BreakLineStyle.Wave;
chartGraphic.ChartAreas[0].AxisY.ScaleBreakStyle.Enabled = true;

Avoid hard-coding all possibilities

I'm making a Xamarin app which has a slider between 1-100. I want it to be so when the slider is at a certain number, the output will do this valueLabel.Text = output; I.e. it will display the contents of the output variable.
output = p1 + p11 + p2
Random r = new Random();
int countLower = r.Next(lower.Count);//I have a list called lower, im getting random values from it
int countLower1 = r.Next(lower.Count);
var p1 = lower[countLower];
var p11 = lower[countLower1];
For example, if the value of the slider (var cat) is 5, I want the output to have 5 things (countLower + countLower1 + countLower2 + countLower3 + countLower4) But i dont know how i can automate the creation of this code based on the slider number. I dont want to hard-code each possibility, is there any way?
I am getting the slider value as such:
public void Slider_ValueChanged(object sender, ValueChangedEventArgs e)
{
var newStep = Math.Round(e.NewValue/step);
var cat =newStep.ToString();
label.Text = cat;
}
Try this:
int output = Enumerable.Range(0, newStep).Select(x => lower[r.Next(lower.Count)]).Sum();
This isn't tested, but the idea is that for each movement on the slider, you generated N random numbers up to the slider value then use String.Join() to bring them all together.
public void Slider_ValueChanged(object sender, ValueChangedEventArgs e)
{
var things = new List<int>();
var newStep = Math.Round(e.NewValue/step);
Random r = new Random();
for (var i = 0; i < newStep; i++) {
things.Add(r.Next(i);
}
var cat = string.Join(",", things);
label.Text = cat;
}

how to generate text boxes based on a string value and add each check box to a panel just like a todo-list

What I am trying to do is something like:
public void thisDoesNotWork (string n)
{
string textBoxName = n.Substring(0, 4); // assuming the string cannot be less than 4 charcters
checkbox textBoxName = new checkbox();
textBoxName.text = n;
panel.Controls.Add(textBoxName)
}
where the string that was past in becomes the name used to instantiate the object.
My goal here is to create a new instance of a new CheckBox every time a different string is passed into the method instead of creating the same instance of the same CheckBox multiple times.
With the above method am merely adding the exact same CheckBox to the panel multiple time, well at lease I think so. But I need to add a brand new check box and not instances of the same.
I hope you guys understand and i am not making this too confusing than it really is.
public thisDoesWork(string n)
{
CheckBox b = new CheckBox();
b.Text = n;
panel.Controls.Add(b);
}
May be this will help you:
private const int Step = 10
private int y = 0;
public ThisDoesWork(string n)
{
CheckBox checkBox = new CheckBox
{
Text = n,
Top = y,
Parent = panel1
};
y += checkBox.Height + Step; // you can set any rules for the postition of new controls
}

visio insertlistmember in C#

Does anyone know how to use the visio insertListMember method (below) in c#?
https://msdn.microsoft.com/en-us/library/office/ff768115.aspx
I have tried to execute the method with the following commands but it gives a "Run Time Error- 424 object required"
I have also used the dropIntoList method and it works fine but for specific purposes I need to use the insertListMember method. (to determine the height of the list)
static void Main(string[] args)
{
//create the object that will do the drawing
visioDrawing.VisioDrawer Drawer = new visioDrawing.VisioDrawer();
Drawer.setUpVisio();
Visio.Shape testShape;
Visio.Shape testShape1;
testShape = Drawer.DropShape("abc", "lvl1Box");
testShape1 = Drawer.DropShape("ccc", "Capability");
Drawer.insertListMember(testShape, testShape1, 1);
}
public void insertListMember(Visio.Shape outerlist, Visio.Shape innerShape, int position)
{
ActiveDoc.ExecuteLine(outerlist + ".ContainerProperties.InsertListMember" + innerShape + "," + position);
}
To obtain the shape:
public Visio.Shape DropShape(string rectName, string masterShape)
{
//get the shape to drop from the masters collection
Visio.Master shapetodrop = GetMaster(stencilPath, masterShape);
// drop a shape on the page
Visio.Shape DropShape = acPage.Drop(shapetodrop, 1, 1);
//put name in the shape
Visio.Shape selShape = selectShp(DropShape.ID);
selShape.Text = rectName;
return DropShape;
}
private Visio.Master GetMaster(string stencilName, string mastername)
{
// open the page holding the masters collection so we can use it
MasterDoc = MastersDocuments.OpenEx(stencilName, (short)Visio.VisOpenSaveArgs.visOpenDocked);
// now get a masters collection to use
Masters = MasterDoc.Masters;
return Masters.get_ItemU(mastername);
}
From your code, 'Drawer' looks to be some kind of Visio app wrapper, but essentially InsertListMember allows you to add shapes to a list that already exist on the page. Here's an example of the method and an alternative Page.DropIntoList if you just want to drop directly from the stencil:
void Main()
{
// 'GetRunningVisio' as per
// http://visualsignals.typepad.co.uk/vislog/2015/12/getting-started-with-c-in-linqpad-with-visio.html
// but all you need is a reference to the app
var vApp = MyExtensions.GetRunningVisio();
var vDoc = vApp.Documents.Add("wfdgm_m.vstx");
var vPag = vDoc.Pages[1];
var vCtrlsStencil = vApp.Documents["WFCTRL_M.VSSX"];
var vListMst = vCtrlsStencil?.Masters["List box"];
if (vListMst != null)
{
var vListShp = vPag.Drop(vListMst, 2, 6);
var vListItemMst = vCtrlsStencil.Masters["List box item"];
var insertPosition = vListShp.ContainerProperties.GetListMembers().Length - 1;
//Use InsertListMember method
var firstListItem = vPag.Drop(vListItemMst, 4, 6);
vListShp.ContainerProperties.InsertListMember(firstListItem, insertPosition);
firstListItem.CellsU["FillForegnd"].FormulaU = "3"; //Green
//or use DropIntoList method on Page instead
var secondListItem = vPag.DropIntoList(vListItemMst, vListShp, insertPosition);
secondListItem.CellsU["FillForegnd"].FormulaU = "2"; //Red
}
}
This is using the Wireframe Diagram template (in Visio Professional) and should result in the following:
In case people were wondering I ended up fixing the method up. However I believe that this method is not required if you are using visio Interop assemblies v15. (I am using v14)
public void insertListMember(int outerShpID, int innerShpID, int position)
{
acWindow.DeselectAll();
Visio.Page page = acWindow.Page;
acWindow.Select(page.Shapes.get_ItemFromID(innerShpID), (short)Microsoft.Office.Interop.Visio.VisSelectArgs.visSelect);
Debug.WriteLine("Application.ActivePage.Shapes.ItemFromID(" + outerShpID + ").ContainerProperties.InsertListMember ActiveWindow.Selection," + position);
ActiveDoc.ExecuteLine("Application.ActivePage.Shapes.ItemFromID(" + outerShpID + ").ContainerProperties.InsertListMember ActiveWindow.Selection," + position);
}

Span Two Columns When Dynamically Adding Controls

I have an ASP.NET web application. This application renders out glossary type items, similar to the following:
This goes through all the letters in the alphabet for items. I am rendering this out and appending it directly to a Controls collection in a Server Control using the following:
List<char> alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray().ToList();
foreach (char c in alpha)
{
Label lblAlphaCharacter = new Label();
lblAlphaCharacter.Font.Size = 24;
lblAlphaCharacter.Font.Bold = true;
lblAlphaCharacter.Text = c.ToString(CultureInfo.InvariantCulture);
Controls.Add(lblAlphaCharacter);
Controls.Add(new LiteralControl("<p>"));
FilterOnAlphaCharacter(this, Page, c);
Controls.Add(new LiteralControl("<p>"));
}
private static void FilterOnAlphaCharacter(Control control, Page page, char character)
{
foreach (List<Things> item in items)
{
string title = item.Title;
string description = item.Definition;
HyperLink link = new HyperLink();
link.Text = title;
control.Controls.Add(link);
Label lblDescription = new Label();
lblDescription.Text = string.Format(" - {0}", description);
control.Controls.Add(lblDescription);
}
}
}
I am trying to, depending on the content, equally split this, so that it looks like this:
This can have different amounts of items. So in reality, there could be 25 entries under "A", and perhaps 1 under "Z". The above is just an example, it goes through all letters A-Z. The expected result would be based on the amount of content, it would equally split between two columns. I have to do this server-side (I was thinking using Table or HtmlTable and related objects).
Howe would you implement a solution for splitting the content equally in a Table or the likes (sort of indifferent on approach).
try this:
//it shows the number of line that inserting during the process
private int _inserteditemCount;
//its number of items in each column
private int _itemsCount;
//line height use for determine paragraph line height
private const string Lineheight = "30px";
protected void Page_Load(object sender, EventArgs e)
{
_inserteditemCount = 0;
var alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
//you can do this query in data access layer
var listCountcount = new Thingsclass().GetThings().Count;
//Count of rows on dictionary + number of leters
_itemsCount = (listCountcount + alpha.Count()) / 2;
var leftdiv = new HtmlGenericControl("div");
var rightdiv = new HtmlGenericControl("div");
//you can change this styles
leftdiv.Style.Add("display", "inline-block");
leftdiv.Style.Add("width", "50%");
leftdiv.Style.Add("float", "Left");
rightdiv.Style.Add("display", "inline-block");
rightdiv.Style.Add("float", "right");
rightdiv.Style.Add("width", "50%");
foreach (var c in alpha)
{
var lblAlphaCharacter = new Label();
lblAlphaCharacter.Font.Size = 24;
lblAlphaCharacter.Font.Bold = true;
lblAlphaCharacter.Text = c.ToString(CultureInfo.InvariantCulture);
var control = _inserteditemCount <= _itemsCount ? leftdiv : rightdiv;
var paragraph = new HtmlGenericControl("p");
paragraph.Style.Add("line-height", Lineheight);
paragraph.Controls.Add(lblAlphaCharacter);
control.Controls.Add(paragraph);
FilterOnAlphaCharacter(leftdiv, rightdiv, c.ToString());
_inserteditemCount++;
}
Panel1.Controls.Add(leftdiv);
Panel1.Controls.Add(rightdiv);
}
private void FilterOnAlphaCharacter(Control leftctr, Control rightctr, string character)
{
//you can do this query in data access layer
var items = new Thingsclass().GetThings().Where(c => c.chara.ToLower().Equals(character.ToLower()));
foreach (var item in items)
{
var paragraph = new HtmlGenericControl("p");
paragraph.Style.Add("line-height", Lineheight);
var control = _inserteditemCount <= _itemsCount ? leftctr : rightctr;
var title = item.Title;
var description = item.Description;
var link = new HyperLink { Text = title };
paragraph.Controls.Add(link);
var lblDescription = new Label { Text = string.Format(" - {0}", description) };
paragraph.Controls.Add(lblDescription);
_inserteditemCount++;
control.Controls.Add(paragraph);
}
}

Categories