I'm use Teechart version .Net & VS2005.
X-axis of the graph type of date and time, Y-axis was added to the line Series.
I do not want to represent the null value of the x-axis date and time.
---------data table---------------------
----- Teechart x-axis display -----------
The red line is cursor tool. I set the value of the 'follow mouse = true'.
Cursor tool indicates to text a date and time value of x-axis. shows the time not in the data table. Following values 18:23:49 shows the 18:23:50 example. I want to express to the x-axis value for date and time of the data table.
my code:
private void TeeChartSet()
{
Steema.TeeChart.Styles.Line line = new Steema.TeeChart.Styles.Line();
TChart1.Series.Add(line);
line.XValues.DateTime = true;
TChart1.Axes.Bottom.Increment = Steema.TeeChart.Utils.DateTimeStep[(int)Steema.TeeChart.DateTimeSteps.OneSecond];
line.Stairs = true;
TChart1.Series[i].XValues.DataMember = "SetTime";
TChart1.Series[i].YValues.DataMember = "Park Brk Pres Sw1";
TChart1.Series[i].DataSource = Datatable;
TChart1.Axes.Bottom.Labels.DateTimeFormat = "HH:mm:ss";
Steema.TeeChart.AxisLabelStyle.PointValue;
}
private void cursor1_Change(object sender, CursorChangeEventArgs e)
{
TChart1.Invalidate();
DateTime Time = DateTime.FromOADate(e.XValue);
sli_CursorTime.Text = "Cursor Time : " + Time.ToString("yyyy-MM-dd HH:mm:ss");
}
private void MakeDt() //Make datatable Sample Code
{
DataTable dt = new DataTable();
dt.Columns.Add("SetTime");
dt.Columns.Add("Park Brk Pres Sw1");
DataRow row;
for (int i = 0; i < 10; i++)
{
row = dt.NewRow();
row["SetTime"] = DateTime.Now.AddSeconds(i * 5);
row["Park Brk Pres Sw1"] = 0;
dt.Rows.Add(row);
}
}
Many thanks for your extra information, it has been very useful for us. I have made a code, because you can use it to solve your problem. To make code, I have used annotation tool, cursor tool and series line, where only is shown the values of series point in annotation tool. Also I have changed the DateTimeFormat of series. I have added a line of code to export data values as excel format because you can see the results to change DateTimeFormat and it works in your correct way.
Steema.TeeChart.Tools.CursorTool cursorTool1;
private Steema.TeeChart.Tools.Annotation ann;
private double xval;
private void InitializeChart()
{
tChart1.Aspect.View3D = false;
//Tools
cursorTool1 = new Steema.TeeChart.Tools.CursorTool(tChart1.Chart);
cursorTool1.Style = Steema.TeeChart.Tools.CursorToolStyles.Vertical;
// cursorTool1.Pen.Style = System.Drawing.Drawing2D.DashStyle.Dash;
cursorTool1.FollowMouse = true;
// cursorTool1.OriginalCursor = Cursors.Arrow;
ann = new Steema.TeeChart.Tools.Annotation(tChart1.Chart);
ann.Shape.Pen.Visible = false;
ann.Shape.Shadow.Visible = false;
ann.Shape.ShapeStyle = Steema.TeeChart.Drawing.TextShapeStyle.RoundRectangle;
//Series
Steema.TeeChart.Styles.Line line1 = new Steema.TeeChart.Styles.Line(tChart1.Chart);
line1.XValues.DateTime = true;
line1.DateTimeFormat = "HH:mm:ss";
cursorTool1.Series = line1;
line1.Stairs = true;
line1.XValues.DataMember = "SetTime";
line1.YValues.DataMember = "Park Brk Pres Sw1";
line1.DataSource = GetDataTable();
tChart1.Axes.Bottom.Labels.DateTimeFormat = "HH:mm:ss";
tChart1.Axes.Bottom.Labels.Style = Steema.TeeChart.AxisLabelStyle.PointValue;
tChart1.Export.Data.Excel.Save("C:\\Test1.xls");
//Events
tChart1.AfterDraw += new PaintChartEventHandler(tChart1_AfterDraw);
cursorTool1.Change += new CursorChangeEventHandler(cursorTool1_Change);
tChart1.Draw();
}
//DataTable
private DataTable GetDataTable()
{
DataTable dataTable1 = new DataTable("DataSet");
//Condition to filter
//AddColumns in new Table
DataColumn xval = new DataColumn("SetTime", typeof(DateTime));
DataColumn yval = new DataColumn("Park Brk Pres Sw1", typeof(double));
dataTable1.Columns.Add(xval);
dataTable1.Columns.Add(yval);
DateTime dt = DateTime.Now;
for (int i = 0; i < 10; i++)
{
DataRow newRow = dataTable1.NewRow();
newRow[xval] = dt.AddSeconds(i * 5);
newRow[yval] = 0;
dataTable1.Rows.Add(newRow);
}
return dataTable1;
}
//Calculate Interpolate point
private double InterpolateLineSeries(Steema.TeeChart.Styles.Custom series, int firstindex, int lastindex, double xvalue)
{
int index;
for (index = firstindex; index <= lastindex; index++)
{
if (index == -1 || series.XValues.Value[index] > xvalue) break;
}
// safeguard
if (index < 1) index = 1;
else if (index >= series.Count) index = series.Count - 1;
// y=(y2-y1)/(x2-x1)*(x-x1)+y1
double dx = series.XValues[index] - series.XValues[index - 1];
double dy = series.YValues[index] - series.YValues[index - 1];
if (dx != 0.0) return dy * (xvalue - series.XValues[index - 1]) / dx + series.YValues[index - 1];
else return 0.0;
}
private double InterpolateLineSeries(Steema.TeeChart.Styles.Custom series, double xvalue)
{
return InterpolateLineSeries(series, series.FirstVisibleIndex, series.LastVisibleIndex, xvalue);
}
private void cursorTool1_Change(object sender, Steema.TeeChart.Tools.CursorChangeEventArgs e)
{
xval = e.XValue;
ann.Text = "";
this.Text = e.ValueIndex.ToString();
foreach (Steema.TeeChart.Styles.Series s in tChart1.Series)
{
ann.Text += DateTime.FromOADate(s.XValues[e.ValueIndex]).ToString("HH:mm:ss");
}
}
private void tChart1_AfterDraw(object sender, Steema.TeeChart.Drawing.Graphics3D g)
{
int xs = tChart1.Axes.Bottom.CalcXPosValue(xval);
int ys;
g.Brush.Visible = true;
g.Brush.Solid = true;
for (int i = 0; i < tChart1.Series.Count; i++)
if (tChart1.Series[i] is Steema.TeeChart.Styles.Custom)
{
ys = tChart1.Series[i].GetVertAxis.CalcYPosValue(InterpolateLineSeries(tChart1.Series[i] as Steema.TeeChart.Styles.Custom, xval));
//Draw elipse above cursor tool.
g.Brush.Color = tChart1.Series[i].Color;
//Draw annotation as label above cursor tool.
ann.Top = ys;
ann.Left = xs;
}
}
Could you please, tell us if previous code help you to solve your problem?
I hope will helps.
Thanks,
Related
Ive been working at this for hours and cant seem to figure out how to correctly display the data in a table
using (TextFieldParser csvParser = new TextFieldParser(path)) {
csvParser.CommentTokens = new string[] { "#" };
csvParser.SetDelimiters(new string[] { "," });
csvParser.HasFieldsEnclosedInQuotes = true;
csvParser.ReadLine();
int pointX = 30;
int pointY = 40;
while (!csvParser.EndOfData) {
string[] fields = csvParser.ReadFields();
int rowNums = fields.Length;
int index = 0;
for(index = 0; index < rowNums;index++) {
string Name = fields[index];
TextBox n = new TextBox();
n.Text = Name;
n.Location = new Point(pointX, pointY);
panel2.Controls.Add(n);
panel2.Show();
pointY += 20;
if(index != 0) {
pointX += 100;
}
}
}
}
Whats happening so far is im grabbing a csv file stored in the path variable and reading it the output is accessible through fields[] This works fine then I am trying to create textbox to put the data into based on rows however what i currently have comes out look like this
Program Display
I would like to display the column names and rows correctly in order here is an example image of what it looks like in notepad
Notepad Display
In notepad you will see each new line is a row and every , dictates a new entry in the row and i wanna display it this way in my program but in textbox
Also note that not all csv files that this program will be opening are short most will be large files with thousands or rows or more so theres no way that it could be simply putting fields[0] hard coded
You are much better off using a DataGridView to display this type of data in a table format.
From the toolbox add the DataGridView control to your form. You will need to build a DataTable that will bind to your DataGridview.
Below is what you can use(I commented out where you are skipping the header in your CSV file, and am using that line to get the column headers to be used in the datagrid)
var dt = new DataTable();
var lineNo = 0;
using (var csvParser = new TextFieldParser(path))
{
csvParser.CommentTokens = new string[] { "#" };
csvParser.SetDelimiters(new string[] { "," });
csvParser.HasFieldsEnclosedInQuotes = true;
//csvParser.ReadLine();
while (!csvParser.EndOfData)
{
var fields = csvParser.ReadFields();
var rowNums = fields.Length;
var row = dt.NewRow();
lineNo += 1;
int index = 0;
for (index = 0; index < rowNums; index++)
{
if (lineNo==1)
{
dt.Columns.Add(fields[index]);
}
else
{
row[index] = fields[index];
}
}
if (lineNo == 1) continue;
dt.Rows.Add(row);
dt.AcceptChanges();
}
}
dataGridView1.DataSource = dt;
I think the controls are overlapping, so you can not see them. That they are overlapping like chairs is the problem. You are not resetting your coordinates.
Here an improvement:
using (TextFieldParser csvParser = new TextFieldParser(path)) {
csvParser.CommentTokens = new string[] { "#" };
csvParser.SetDelimiters(new string[] { "," });
csvParser.HasFieldsEnclosedInQuotes = true;
csvParser.ReadLine();
int offsetX = 30;
int offsetY = 40;
int counter;
while (!csvParser.EndOfData) {
int pointerY = ++counter * offsetY; // first counter increments by one, then counter times offsetY occurs
int pointerX;
string[] fields = csvParser.ReadFields();
int rowNums = fields.Length;
for(int index = 0; index < rowNums;index++) {
pointerX = (index + 1) * offsetX;
string name = fields[index];
TextBox n = new TextBox() { Text = name, Location = new Point(pointerX, pointerY) };
panel2.Controls.Add(n);
panel2.Show(); // should be unnecessary
}
}
}
The problem is fairly straightforward. My datagrid is filled from my ItemSource (bindingList) which is basically a list of objects filled with strings.
In this certain part of my code I need to update my bindingList.
Unfortunately when it is updated all user row selections made in the DataGrid dissappear.
This is an inconvenience to the user that I would like to remedy. So that when the user clicks the button that results in the bindingList to update, the selections are saved in case the user wants to make further changes.
Code Right Now:
//Save DataGrid Row Selections
bindingList[1] = (new ItemClass() { columnnumber = colonum, xcoord = xpos, ycoord = ypos, description = descrip });
dataGrid.ItemSource = bindingList;
//Restore DataGrid Row Selections
EDIT:
Wider scope as requested:
private void Y_Incre_Button_Click(object sender, RoutedEventArgs e)
{
if (dataGrid.SelectedItems.Count != 0)
{
string colonum;
string xpos;
string ypos;
string descrip;
for (int i = 0; i < bindingList.Count; i++)
{
int selectionIndex = dataGrid.SelectedIndex;
if (selectionIndex > -1)
{
var curItem = bindingList[selectionIndex];
int yNum = int.Parse(curItem.ycoord);
int yNum2 = (yNum + 10);
colonum = curItem.columnnumber;
xpos = curItem.xcoord;
ypos = yNum2.ToString();
descrip = curItem.description;
//Save DataGrid Row Selections
bindingList[selectionIndex] = (new ItemClass() { columnnumber = colonum, xcoord = xpos, ycoord = ypos, description = descrip });
//Restore DataGrid Row Selections
}
}
}
else
{
MessageBox.Show("No Rows Selected");
}
}
To get this working store the row indices of the selected items before they are replaced, and then reselect those records after the "replace" operation is complete. Also, have a look at this example.
private void Y_Incre_Button_Click(object sender, RoutedEventArgs e)
{
if (dataGrid.SelectedItems.Count != 0)
{
// Save DataGrid Row Selections
List<int> selectedRowIndexList = new List<int>();
foreach (object item in dataGrid.SelectedItems)
{
selectedRowIndexList.Add(dataGrid.Items.IndexOf(item));
}
for (int i = 0; i < bindingList.Count; i++)
{
int selectionIndex = dataGrid.SelectedIndex;
if (selectionIndex > -1)
{
ItemClass curItem = bindingList[selectionIndex];
int yNum = int.Parse(curItem.ycoord);
int yNum2 = yNum + 10;
string colonum = curItem.columnnumber;
string xpos = curItem.xcoord;
string ypos = yNum2.ToString();
string descrip = curItem.description;
bindingList[selectionIndex] = new ItemClass { columnnumber = colonum, xcoord = xpos, ycoord = ypos, description = descrip };
}
}
// Restore DataGrid Row Selections
dataGrid.SelectedItems.Clear();
foreach (int rowIndex in selectedRowIndexList)
{
if (rowIndex < 0 || rowIndex > dataGrid.Items.Count - 1)
throw new ArgumentException(string.Format("{0} is an invalid row index.", rowIndex));
object item = dataGrid.Items[rowIndex];
dataGrid.SelectedItems.Add(item);
}
}
else
{
MessageBox.Show("No Rows Selected");
}
}
I am trying to make a cell change colour when its value is under 100 however it does not change the color of the cell. I can default the colour of the entire grid however it is not working for individual cells. Please can someone lend a hand?
Here is the code I have so far:
connection.Open();
var SinglesDataTable = new DataTable();
adapter.Fill(SinglesDataTable);
connection.Close();
DataColumn hourlyavg = SinglesDataTable.Columns.Add("Hourly Average", typeof(String));
for (int i = 0; i < SinglesDataTable.Rows.Count; i++)
{
object pickvalue = SinglesDataTable.Rows[i][1].ToString();
object timevalue = SinglesDataTable.Rows[i][2].ToString();
double pickval1 = Convert.ToDouble(pickvalue);
string timeS = "";
timeS = timevalue.ToString();
string timeSTrimmed = (timeS.Replace(":", ""));
string timeSTrimmedHoursMins = (timeSTrimmed.Remove(timeSTrimmed.Length - 2));
string timehourminindecimal = timeSTrimmedHoursMins.Insert(2, ".");
double timeint = Convert.ToDouble(timehourminindecimal);
if (timeint < 1)
{
timeint = Math.Ceiling(timeint);
}
else
{
timeint = timeint;
}
Convert.ToInt32(pickvalue);
var hourlyratevar = pickval1 / timeint;
double hourlyratedouble = Math.Round(hourlyratevar, 2);
int hourlyraterounded = (int)Math.Ceiling(hourlyratedouble);
SinglesDataTable.Rows[i][3] = hourlyraterounded;
string hourlyavgstring = SinglesDataTable.Rows[i][3].ToString();
double hourlyavgint = Convert.ToDouble(hourlyavgstring);
foreach (DataGridViewRow row in SinglesGridView.Rows)
if (Convert.ToInt32(row.Cells[1].Value) > 100)
{
row.DefaultCellStyle.BackColor = Color.Red;
}
SinglesGridView.DataSource = SinglesDataTable;
foreach (DataGridViewRow row in SinglesGridView.Rows)
if (Convert.ToInt32(row.Cells[1].Value) > 100)
row.Cells[1].Style.BackColor = Color.Red;
there is another option: handle CellPainting event of DataGridView. E.g.:
private void SinglesGridView_CellPainting(object sender,
System.Windows.Forms.DataGridViewCellPaintingEventArgs e)
{
if (e.ColumnIndex == 1 &&
e.RowIndex >= 0 &&
Convert.ToInt32(SinglesGridView[e.ColumnIndex, e.RowIndex].Value) > 100)
e.CellStyle.BackColor = Color.Red;
}
I'm currently building an application that shows a line-graph and uses MSChartControl.
Here is the relevant code:
WeatherDatabase _db = new WeatherDatabase(Properties.Settings.Default.SqlConnectionString);
private void AddSensorDataToGraph(int sensorType, string xTitle, string yTitle, string Title)
{
var sensorIdList = (from d in _db.Sensors where d.TypeId == sensorType select d.Id).ToArray();
var startDate = dateTimePickerStart.Value;
var stopDate = dateTimePickerStop.Value;
SetMaxMinValues(dateTimePickerStart.Value.ToOADate(), dateTimePickerStop.Value.ToOADate());
this.Text = chartValues.Titles["Titel"].Text = String.Format("{0} vom {1} bis {2}", Title, startDate, stopDate);
chartValues.ChartAreas[CHARTAREA].AxisX.Title = xTitle;
chartValues.ChartAreas[CHARTAREA].AxisY.Title = yTitle;
// Alte Datensätze löschen
chartValues.Series.Clear();
foreach (var sensorId in sensorIdList)
{
var values = (from d in _db.DeviceIO where d.IdSensor == sensorId && d.Timestamp > startDate && d.Timestamp < stopDate orderby d.Timestamp ascending select d).ToArray();
if (values.Length > 0)
{
var desc = values[0].Sensors.SensorType.Description;
chartValues.Series.Add(GenerateDefaultSeries(String.Format("{0}\r\nSensorId: {1}", desc, sensorId)));
//chartValues.Series.Add("Test" + sensorId);
int seriesId = chartValues.Series.Count - 1;
foreach (var item in values)
{
if (item.Value == null)
{
continue;
}
if ((double)item.Value == NOVALUE)
{
continue;
}
AddPointToChart((DateTime)item.Timestamp, (double)item.Value, seriesId);
}
}
}
}
private void AddPointToChart(DateTime timestamp, double value, int series)
{
DataPoint dataPoint = chartValues.Series[series].Points.Add(value);
dataPoint.XValue = timestamp.ToOADate();
dataPoint.AxisLabel = "dd.MM.yy hh:mm";
}
private void SetMaxMinValues(double min, double max)
{
if (min < max)
{
chartValues.ChartAreas[CHARTAREA].AxisX.Minimum = min;
chartValues.ChartAreas[CHARTAREA].AxisX.Maximum = max;
}
}
private Series GenerateDefaultSeries(string Name)
{
// Grundeinstellungen für die Data-Series setzen
Series series = new Series();
series.ChartType = SeriesChartType.Line;
series.Name = Name;
series.IsValueShownAsLabel = false;
series.IsVisibleInLegend = true;
series.IsXValueIndexed = false;
series.AxisLabel = "dd.MM.yy hh:mm";
// series.LabelFormat = "g";
series.XAxisType = AxisType.Primary;
series.XValueType = ChartValueType.Auto;
series.YValuesPerPoint = 1;
// series.AxisLabel = "dd.MM.yy hh:mm";
return series;
}
If i add a series in designer mode x-axies Labels are correct
Click for pic
But if i start my application and add a series programmatically it loks like this
Anyone knows why the x-axis caption / label is not displayed correctly?
EDIT:
Based on Tom's help I change some things:
var seriesName = String.Format("{0}\r\nSensorId: {1}", desc, sensorId);
var curSeries = chartValues.Series.Add(seriesName);
UpdateSeriesSettings(ref curSeries);
[...]
AddPointToChart((DateTime)item.Timestamp, (double)item.Value, curSeries);
[...]
private void UpdateSeriesSettings(ref Series series)
{
// Grundeinstellungen für die Data-Series setzen
// Series series = new Series();
series.ChartType = SeriesChartType.Spline;
series.IsValueShownAsLabel = false;
series.IsVisibleInLegend = true;
series.IsXValueIndexed = false;
series.AxisLabel = "dd.MM.yy hh:mm";
// series.LabelFormat = "g";
series.XAxisType = AxisType.Primary;
series.XValueType = ChartValueType.Auto;
series.YValuesPerPoint = 1;
// series.AxisLabel = "dd.MM.yy hh:mm";
}
But my X axis stil ain't having a label ):
Used the following code:
Fixed my problem.
var desc = values[0].Sensors.SensorType.Description;
var seriesName = String.Format("{0}\r\nSensorId: {1}", desc, sensorId);
curSeries = chartValues.Series.Add(seriesName);
curSeries.ChartType = SeriesChartType.Line;
curSeries.XValueType = ChartValueType.DateTime;
foreach (var item in values)
{
curSeries.Points.AddXY(item.Timestamp, item.Value);
}
It looks like you are adding each point as its own series. Usually, you would add many points into one series.
Do you intend to change seriesId right before you use it?
int seriesId = chartValues.Series.Count - 1;
This happens before you call AddPointToChart() so that is getting a different value than you used in the series
chartValues.Series.Add(GenerateDefaultSeries(String.Format("{0}\r\nSensorId: {1}", desc, sensorId)));
EDIT
The line chartValues.Series.Add(...) will return a variable of type Series which you can add to directly. see http://www.dotnetperls.com/chart
SensorID is your number and I think that there are no guarantees that the system will choose to populate its collection of Series in any particular order.
EDIT
It looks like you're adding your points to the series before you finish setting them up. Instead, set them all the way up, then add them:
private void AddPointToChart(DateTime timestamp, double value, int series)
{
DataPoint dataPoint = new DataPoint(timestamp.ToOADate(), value);
dataPoint.AxisLabel = "dd.MM.yy hh:mm"; // not sure how this will work, but try it.
chart1.Series[series].Points.Add(dataPoint );
}
I have the below datatable(kindly note that the columns numbers will not be known at compile time)
DataTable dt = new DataTable();
dt.Columns.Add("Summary");
dt.Columns.Add("Beta");
dt.Columns.Add("Delta");
dt.Rows.Add("Summary1", "n/a", "1");
dt.Rows.Add("Summary2", "1.00", "2");
Now to this datatable , I have to add 1 more row that will be the subtraction of
dt.Rows[0].Columns[i+1] - dt.Rows[1].Columns[i+1]
where i=0
so the final datatable will be
Summary Beta Delta
---------------------------------
Summary1 n/a 1
Summary2 1.00 2
Summary3 n/a -1
I am very new to dotnet. Please help
i'm not sure what you mean but by your final table i could think of this:
DataRow summary1 = dt.Rows[0], summary2 = dt.Rows[1], summary3 = new DataRow();
summary3[0] = "Summary3";
for(int i=1; i < summary1.Table.Columns.Count; i++)
{
try{
summary3[i] = double.Parse(summary1[i].ToString()) - double.Parse(summary2[i].ToString())
}catch{
summary3[i] = "n/a";
}
}
This code allows you to have a variable amount of DataColumn inside the DataRow
I'm not sure what you want either, but I think you are having problems with the strings in the columns and converting them to ints and back. Here's an example of code that does the conversion:
private string CalculateColumnTotal(int row, int column)
{
int column1Value;
bool parsed = int.TryParse(_table.Rows[row][column].ToString(), out column1Value);
if (!parsed) return "n/a";
int column2Value;
parsed = int.TryParse(_table.Rows[row + 1][column].ToString(), out column2Value);
if (!parsed) return "n/a";
var total = column1Value - column2Value;
return total.ToString();
}
}
The full form code looks something like this:
public partial class Form1 : Form
{
private readonly DataTable _table = new DataTable("Table");
public Form1()
{
InitializeComponent();
_table.Columns.Add("Summary");
_table.Columns.Add("Beta");
_table.Columns.Add("Delta");
const int rowPairs = 1;
for (int i = 0; i <= rowPairs - 1; i++)
{
_table.Rows.Add("Summary1", "n/a", 1);
_table.Rows.Add("Summary2", 1.00, 2);
_table.Rows.Add("Summary3", null, null);
}
for (int row = 0; row < _table.Rows.Count - 1; row += 3)
{
string columnOneTotal = CalculateColumnTotal(row, 1);
string columnTwoTotal = CalculateColumnTotal(row, 2);
_table.Rows[row + 2][1] = columnOneTotal;
_table.Rows[row + 2][2] = columnTwoTotal;
}
dataGridView1.DataSource = _table;
}
private string CalculateColumnTotal(int row, int column)
{
int column1Value;
bool parsed = int.TryParse(_table.Rows[row][column].ToString(), out column1Value);
if (!parsed) return "n/a";
int column2Value;
parsed = int.TryParse(_table.Rows[row + 1][column].ToString(), out column2Value);
if (!parsed) return "n/a";
var total = column1Value - column2Value;
return total.ToString();
}
}