I have a chart with multiple chart areas. When I press a button a new chart area is being created etc.
My problem is that after adding some chart areas I get the following result :
I want to have each chart area in only one column, one after the other like this :
is this possible ?
EDIT: Adding chart areas dynamically
on the left it is the chart with 3 chart areas added and the right is the chart with 4 areas.
Use property ChartArea.AlignWithChartArea
Through the use of the AlignWithChartArea, AlignmentOrientation and AlignmentStyle properties, it is possible to align or synchronize two or more chart areas horizontally, vertically or both.
First, set the AlignWithChartArea property to the name of a ChartArea object. This chart area will then be aligned, based on the AlignmentStyle setting, which defines the alignment to use, and the AlignmentOrientation setting, which defines the elements of the chart area that should be used to set the alignment.
So to put ChartArea2 below ChartArea1:
ChartArea2.AlignWithChartArea1;
ChartArea2.AlignmentStyle = AreaAlignmentStyles.Position;
ChartArea2.AlignmentOrientation = AreaAlignmentOrientation.Vertical;
Here is how you can achive what you need, also referring for your question here: https://stackoverflow.com/questions/67124754/dynamically-add-chart-areas-in-vertical-alignment
Use the Position property and please read comments inside the code:
private void button1_Click(object sender, EventArgs e)
{
List<ChartArea> Areas = new List<ChartArea>();
int numberOfAreas = 5;
chart1.Legends[0].Enabled = false;
for (int k = 1; k <= numberOfAreas; k++) // YOU WANT 5 and not 4 AREAS - changed k< to k<=
{
var S1 = new Series();
chart1.Series.Add(S1);
S1.Name = k.ToString();
for (int j = 0; j < 100; j += 10) S1.Points.AddXY(j, j / 10);
S1.Color = Color.Transparent;
Areas.Add(new ChartArea(k.ToString()));
chart1.ChartAreas.Add(Areas[k - 1]); // IT IS k-1 and not k - we start counting from 0
S1.ChartArea = k.ToString();
chart1.ChartAreas[k - 1].AlignWithChartArea = chart1.ChartAreas[k - 1].Name;
chart1.ChartAreas[k - 1].AlignmentStyle = AreaAlignmentStyles.Position;
chart1.ChartAreas[k - 1].AlignmentOrientation = AreaAlignmentOrientations.Vertical;
}
// NOW THE IMPORTANT PART
float currentHeight = 0;
foreach (var itm in Areas)
{
itm.Position.Height = 100 / numberOfAreas; // Note: the valus are in percenteges and not absolute pixels
itm.Position.Y = currentHeight;
itm.Position.X = 5;
itm.Position.Width = 95;
currentHeight += 100 / numberOfAreas;
}
}
OUTPUT:
Related
I have chart in a windows form application where I plot different signals imported from a csv file.
I now want to create a button that will enable a movable vertical annotation and show all Points at a label.
My problem is that I cannot use my point collection dp in the button method.
Series s = chart1.Series.Add(checkedListBox1.Items[e.Index].ToString());
s.ChartType = SeriesChartType.Line;
s.MarkerStyle = MarkerStyle.Circle; // make the points stand out
s.MarkerSize = 3;
}
for (int r = 0; r < num_rows; r++)
{
DataPoint dp = new DataPoint();
dp.SetValueXY(r, checkedSignal]);
chart1.Series[CheckedSignal].Points.Add(dp);
}
And the other function is like this :
private void chart1_AnnotationPositionChanging(object sender, AnnotationPositionChangingEventArgs e)
{ if (sender == VA) RA.X = VA.X - RA.Width / 2;
int pt1 = (int)e.NewLocationX;
double step = (s.Points[pt1 + 1].YValues[0] - s.Points[pt1].YValues[0]);
}
I get always this Exception "Object reference not set to an instance of an object."
In windows form, I am displaying data in MS Chart from Datagridview.
When selecting an row in the datagridview, I am highlighting the corresponding datapoint in the chart with different color.
When chart is in zoom state , if a datapoint is highlighted newly and if it is not in the visible state, I have to scroll/move the chart to highlighted datapoint.
chart.ChartAreas.Add("LineGraphHistory");
chart.ChartAreas["LineGraphHistory"].AxisX.Title = "X Axis";
chart.ChartAreas["LineGraphHistory"].AxisX.MajorGrid.LineColor = System.Drawing.Color.Black;
chart.ChartAreas["LineGraphHistory"].AxisX.MajorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
chart.ChartAreas["LineGraphHistory"].AxisY.Title = "Y Axis";
chart.ChartAreas["LineGraphHistory"].AxisY.MajorGrid.LineColor = Color.Black;
chart.ChartAreas["LineGraphHistory"].AxisY.MajorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
chart.ChartAreas["LineGraphHistory"].BackColor = Color.White;
chart.ChartAreas["LineGraphHistory"].CursorX.IsUserEnabled = true;
chart.ChartAreas["LineGraphHistory"].CursorX.IsUserSelectionEnabled = true;
chart.ChartAreas["LineGraphHistory"].CursorX.Interval = 0;
chart.ChartAreas["LineGraphHistory"].AxisX.ScaleView.Zoomable = true;
chart.ChartAreas["LineGraphHistory"].AxisX.ScrollBar.Enabled = true;
chart.Legends.Add("Legend");
chart.Legends["Legend"].BorderColor = Color.Tomato;
chart.DataSource = CSVDataTable;
chart.ChartAreas["LineGraphHistory"].AxisX.IntervalType = DateTimeIntervalType.Seconds;
chart.ChartAreas["LineGraphHistory"].AxisX.LabelStyle.Format ="dd-MM-yyyy\n hh:mm:ss"; ;
chart.Series[s].XValueType =ChartValueType.DateTime ;
chart.DataBind();
chart.Update();
private void cDataGrid_SelectionChanged(object sender, EventArgs e)
{
int nCount = csvDataGrid.SelectedRows.Count;
if (nCount > 0)
{
for (int i = 0; i < nCount; i++)
{
int index = csvDataGrid.SelectedRows[i].Index;
if (index >= csvDataGrid.Rows.Count-1)
return;
for (int k = 0; k < chart.Series.Count; k++)
{
DataPointCollection pr = chart.Series[k].Points;
pr[index].MarkerColor = Color.DarkGoldenrod;
pr[index].MarkerStyle = MarkerStyle.Star10;
pr[index].MarkerSize = 20;
// chart.
}
chart.Update();
}
}
}
How to achieve this?
As Taw suggested I tried to set scaleview position.
I have 10 datapoints. The range of x value of datapoints are 20 to 200. Each x value has equal difference of 20. The view size is 100. In zoom mode, when I scrolling to maximum the x range is 101 to 200 in the view , the last point is displayed as 5th point in the view. Whereas if I use your code to set scaleview position to highlight last datapoint , the x range becomes 180 to 240 and highlighted last datpoint is visible as first range.
Why paintviewmin and paintviewmax values are changing?
The images are
You need to calculate the offset from the DataPoint dp.XValue, maybe like this:
Axis ax = chart.ChartAreas[0].AxisX;
var size = ax.ScaleView.ViewMaximum - ax.ScaleView.ViewMinimum;
ax.ScaleView.Position = dp.XValue - size / 2.0;
Example:
Update: When smaller data sets are displayed the automatically added margins mess up the simple calculation above. To avoid this you can add:
chart.ChartAreas[0].AxisX.IsMarginVisible = false;
I have one chart control with two buttons.First call candlestick chart.Second call bar chart.If I call only one of them everything is fine.But if I click the button for bar chart it gets the X Axis values from the candlestick chart.Bar chart X Axis should be from 0-15.
How they look:
https://imgur.com/a/IICYh
On formload candlestick chart is loaded first.Everything is still fine.
When Close/Open button for the bar chart is clicked.Its left with the X Axis values from candlestick chart.
When I click Chart button for the candlestick chart after hitting Close/Open.
Y Axis values are missing now.
Methods for calling the charts:
public void CandleStickChartMain()
{
// clear the chart
if (ChartCandle.Series.Count > 0) this.ChartCandle.Series[0].Points.Clear();
this.ChartCandle.Series.Clear();
this.ChartCandle.Titles.Clear();
//Clear Grid
ChartCandle.ChartAreas["ChartArea1"].AxisX.MajorGrid.LineWidth = 0;
ChartCandle.ChartAreas["ChartArea1"].AxisY.MajorGrid.LineWidth = 0;
//Series
ChartCandle.Series.Add("Date");
ChartCandle.Series["Date"].YValuesPerPoint = 4;
ChartCandle.Series["Date"].XValueMember = "Day";
ChartCandle.Series["Date"].YValueMembers = "High,Low,Open,Close";
ChartCandle.Series["Date"].XValueType = ChartValueType.DateTime;
ChartCandle.Series["Date"].CustomProperties = "PriceDownColor=Red,PriceUpColor=Green";
ChartCandle.Series["Date"]["OpenCloseStyle"] = "Triangle";
ChartCandle.Series["Date"]["ShowOpenClose"] = "Both";
ChartCandle.DataManipulator.IsStartFromFirst = true;
ChartCandle.Series["Date"].ChartType = SeriesChartType.Candlestick;
//Axis Y Minimum
ChartCandle.ChartAreas["ChartArea1"].AxisY.Minimum = Open.Min() - (Open.Min() / 50);
//Data Binding
ChartCandle.DataSource = ChartDataTable;
ChartCandle.DataBind();
}
public void BarChart()
{
// clear the chart
if (ChartCandle.Series.Count > 0) this.ChartCandle.Series[0].Points.Clear();
this.ChartCandle.Series.Clear();
this.ChartCandle.Titles.Clear();
// Set palette
this.ChartCandle.Palette = ChartColorPalette.Excel;
// Set title
this.ChartCandle.Titles.Add("Price Data Open/Close");
//Add series
//Series Open
var seriesOpen = ChartCandle.Series.Add("Open");
for (int i = 0; i < Open.Length; i++)
{
seriesOpen.Points.Add(Open[i]);
}
//Series Close
var SeriesClose = ChartCandle.Series.Add("Close");
for (int i = 0; i < Close.Length; i++)
{
SeriesClose.Points.Add(Close[i]);
}
var chartAreaOpenClose = ChartCandle.ChartAreas[seriesOpen.ChartArea];
// Zoom and scroll options
// set view range to [0,max]
chartAreaOpenClose.AxisX.Minimum = 0;
chartAreaOpenClose.AxisX.Maximum = Open.Length + 1;
// enable autoscroll
chartAreaOpenClose.CursorX.AutoScroll = true;
// let's zoom to [0,blockSize] (e.g. [0,100])
chartAreaOpenClose.AxisX.ScaleView.Zoomable = true;
chartAreaOpenClose.AxisX.ScaleView.SizeType = DateTimeIntervalType.Number;
int position = 0;
int size = 15;
chartAreaOpenClose.AxisX.ScaleView.Zoom(position, size);
// disable zoom-reset button (only scrollbar's arrows are available)
chartAreaOpenClose.AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
// set scrollbar small change to blockSize (e.g. 100)
chartAreaOpenClose.AxisX.ScaleView.SmallScrollSize = 15;
// additional
ChartCandle.ChartAreas[0].AxisY.IsStartedFromZero = false;
}
I have chart with multiple chart areas and every area contain a bunch of series that need to be updated with scrolling, all chart areas working well except the one below , it takes alot of resources from the memory i think and not scrolling smoothly.
I want to achieve this chart area effectively with smooth scrolling
i achieved same results using stacked bar graph, i added the points from data table, here is how the data table looks like
And as i know displaying only the portion that is needed is certainly the option the takes least resources and time,
so here is the code i use to add my points from data table
private void GraphDemo_Load(object sender, EventArgs e)
{
System.Drawing.Rectangle workingRectangle =
System.Windows.Forms.Screen.PrimaryScreen.WorkingArea;
this.chart.Size = new System.Drawing.Size(workingRectangle.Width - 50, 1000);
scroller = new VScrollBar();
scroller.Dock = DockStyle.Left;
croller.Maximum = 6000 - windowSize; //windowSize = 180;
scroller.LargeChange = 180;
scroller.Scroll += scroller_Scroll;
}
void scroller_Scroll(object sender, ScrollEventArgs e)
{
for (int s = 0; s < chart.Series.Count; s++)
{
LoadCore.chart.Series[s].Points.Clear();
}
for (float ii = 0; ii < dt.Rows.Count; ii++)
{
row = dt.Rows[(int)ii];
ts11 = Convert.ToDouble(row.ItemArray[0]) + 1; //top.value column + 1
ts12 = Convert.ToDouble(row.ItemArray[1]); //base.value column
for (double t = LoadCore.ts11; t <= LoadCore.ts12; t++)
{
//k is the index no. of each series column
for (int k = 2; k <= dt.Columns.Count - 1; k++)
{
if (scroller.Value < t)
{
if (scroller.Value + windowSize > t) //windowSize = 180;
{
//tempindex1 is the index of specific row value at specific base.value columnn
chart.Series[Convert.ToString(dt.Columns[k].ColumnName)].Points.AddXY(t, dt.Rows[tempIndex1][k]);
chart.Series[Convert.ToString(dt.Columns[k].ColumnName)]["PointWidth"] = "1";
}
}
}
}
}
}
With the above code i still can not scroll smoothly and i think it's because of the huge number of points needed to be added with the portion of 180 (window size), ...
so my question is there an alternative effective way to achieve the first image with smooth scrolling?.
should i use any other types of graph instead of stacked bar graph ? what is it?
For anybody that can help me out here I'd be very grateful!
I've got a very small app which creates several panels at runtime with a for LOOP. At the moment the number of panels to be created is derived from a value entered in a textbox, but will ultimately be determined by an integer read from a database
Each panel has a Label which is created in the same loop
My problem is that I want to draw 120 lines in each panel as it is created (in each iteration of the FOR loop), and I'm doing this with a nested WHILE loop
I can get everything to work fine, the panels are creating along with the Label titles, but for some reason I can't get the lines to draw
It's all in one method for testing, can anybody help me?
The code I currently have is as follows:
public void CreatePanels()
{
int PanelPosX = 50;
int PanelPosY = 500;
int LabelPosX = 10;
int LabelPosY = 10;
for (int i = 0; i < (Convert.ToInt32(textBox2.Text)); i++)
{
Panel pnlOverview = new Panel();
pnlOverview.Name = "InspectorPanel" + i.ToString();
pnlOverview.Text = "Inspector Panel " + i.ToString();
pnlOverview.Location = new Point(PanelPosX, PanelPosY);
pnlOverview.Size = new Size(974, 136);
pnlOverview.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
Controls.Add(pnlOverview);
PanelPosY += 170;
Label lblInspectorName = new Label();
lblInspectorName.Name = "InspectorName" + i.ToString();
lblInspectorName.Text = " Inspector " + i.ToString();
lblInspectorName.Width = 100;
lblInspectorName.Height = 13;
lblInspectorName.Location = new Point(LabelPosX, LabelPosY);
lblInspectorName.Size = new Size(974, 136);
pnlOverview.Controls.Add(lblInspectorName);
// Draw the Overview Chart
int x = 10;
int y = 0;
Pen OVTable = new Pen(Color.Black, 0);
while (y < 120)
{
Graphics mp = pnlOverview.CreateGraphics();
mp.DrawLine(OVTable, x, 40, x, 100);
y++;
x += 8;
}
}
return;
}
Thanks
Ivan
You might need to create an empty Image and draw into it and then add it to the Panel. The other option would be to Derive from Panel and override the OnPaint method, at which point you would draw your chart.
Perhaps there is a C# Chart component that would effect this for you.
Here's a link to a MSDN reference on rendering custom controls, which is what you are pursuing.