I'm using System.Windows.Forms.DataVisualization.Charting.
Now I have a column chart like this.
But I need the grid to be aside to the column like this.
How can I do it?
My data are from DataGridView, so my code was look like this.
var ser = chart1.Series.Add("ana");
ser.IsValueShownAsLabel = true;
ser.IsVisibleInLegend = false;
ser.ChartType = SeriesChartType.Column;
//X value is string
ser.XValueMember = dataGridView1.Columns[0].DataPropertyName;
//Y value is int
ser.YValueMembers = dataGridView1.Columns[1].DataPropertyName;
chart1.DataSource = dataGridView1.DataSource;
And the data in DataGridView is simple.
-------------
|Month|Sales|
-------------
| Jan | 17 |
-------------
| Feb | 28 |
-------------
| Mar | 19 |
-------------
GridLines go with DataPoints and Labels go with GridLines, but..
You can set the Interval and the Minimum for the X-Axis to tweak them apart :
but there are a few extras to watch out for..
// get a reference
ChartArea chartArea1 = chart1.ChartAreas[0];
// don't start at 0
chartArea1.AxisX.IsStartedFromZero = false;
// pick your interval
double interval = 1D;
chartArea1.AxisX.MajorTickMark.Interval = interval;
// set minimum at the middle
chartArea1.AxisX.Minimum = interval / 2d;
// pick a column width (optional)
chart1.Series[0].SetCustomProperty("PixelPointWidth", "30");
// we want the labels to sit with the points, not the grid lines..
// so we add custom labels for each point ranging between the grid lines..
for (int i = 0; i < chart1.Series[0].Points.Count; i++)
{
DataPoint dp = chart1.Series[0].Points[i];
chartArea1.AxisX.CustomLabels.Add( (0.5d + i) * interval,
(1.5d + i) * interval, dp.XValue.ToString());
}
Update:
As your updated question shows, you are using data-binding with strings as X-Values. This is very convenient, but goes against the core nature of the Chart control. All its xalues, be it X-Value or any of the Y-Values are internally stored as doubles.
Random strings don't convert to double and while you can conveniently add DataPoints with strings as X-Values, all sorts of ugly issues come up as a consequence.
First have a look at the X-Values themselves: As I said they are double; when you check their values you will see they all are 0. And where are the string values? They are placed in the labels.
One problem often found it that you now can't access the X-Values with value expressions.
Another problem is that we now can't give a range of x-Values for custom labels.
Solution: If we need custom labels, we must change the data!
Data binding is fine, just make sure to add a numeric column to you datasource containing a month number and set it as the XValueMember of the series!
You can make that column it invisible in your DataGridView.
Finally you will want to create the custom labels, pretty much as before; just change their content to pull from the string column containing the month names.
Here is what it looks like here:
Related
I am having difficulty creating a box plot for a set of row objects contained in a list. The data itself is populating fine enough but the chart creates a different x value for each object in the list, which is not intended. Perhaps I am using the wrong binding method on the list? Here is the snippet of code in which the binding occurs:
foreach (DataRow row in myDataSet.Tables[0].Rows)
{
colValues.Add(row["Freight Cost/ Pc - $"]);
}
chart1.Series["Series1"].Points.DataBindY(colValues);
edit:
It is a list. It contains each row value of column "Freight Cost/ Pc -$". I believe I only have one series. It is currently creating an x value for each y value in the list. I want only one independent value for every y value. In other words, I am dealing with a univariate sample. I don't even get why this is an issue. I was under the impression that a box plot was strictly used to display descriptive statistics related to univariate data.
A DataPoint of ChartType BoxPlot is a graphical depiction of statistical data.
You have two basic ways to use a BoxPlot chart:
You can add multiple DataPoints e.g. by using the AddXY call. For this you will have to provide (at least) six Y-Values containing the statistical values to show.
Or you can 'bind' a DataPoint to another Series in the Chart. If you have multiple Series you can show their stats in one BoxPlot DataPoint each.
The main difference is that in the first case you need to already have the stats while the second way will let the chart do the calculations on the series of DataPoints. The way to make that work is not by normal data binding but by using the BoxPlotSeries custom property:
Series BS = chart1.Series.Add("BoxPlotSeries");
BS.ChartType = SeriesChartType.BoxPlot;
BS.Points.Add(new DataPoint(55, 0));
BS.Points[0]["BoxPlotSeries"] = "S1";
After creating a random series S1 with 50 DataPoints, I create a BoxPlot series, add one point at x=55 and relate the point's Custom property BoxPlotSeries
Here is a result:
By regular binding the Points to your List you have effectively chosen method one and see many BoxPlot points. Instead style the Series to your liking as chartType Point, Line, Column or what you want; then add a second Series with one DataPoint, relating it to the data series, like in my code example..
I have chosen my X-Value so that the BoxPlot point sits to the right of the data. If your data do not have meaningful i.e. numeric X-Values they are displayed in order and you can place the BoxPlot point at S1.Points.Count or Count + 1 or +2..
Note that if you have a lot of DataPoints the BoxPlotPoint will look so thin you can hardly see it at all.
In that case it would be nice if you could simply make it wider.
There is a set of Custom Properties, namely
PointWidth and PixelPointWidth, MinPixelPointWidth and MaxPixelPointWidth.
BS["MinPixelPointWidth"] = "15";
BS["MaxPixelPointWidth"] = "25";
But you may prefer to keep the BoxPlot points separate by adding a second ChartArea where you place the BoxPlot series:
Here are the positioning and styling calls used for the above screenshot:
ChartArea A1 = chart1.ChartAreas[0];
Series S1 = chart1.Series[0];
A1.AxisX.Interval = 50;
ChartArea A2 = chart1.ChartAreas.Add("A2");
A2.AlignWithChartArea = "A1";
A2.AlignmentOrientation = AreaAlignmentOrientations.Horizontal;
A2.AlignmentStyle = AreaAlignmentStyles.PlotPosition;
A1.Position.Width *= 0.85f;
A2.Position.Y = A1.Position.Y;
A2.Position.X = A1.Position.Right;
A2.Position.Width = A1.Position.Width * 0.15f;
A2.AxisX.LabelStyle.ForeColor = Color.Transparent;
A2.AxisX.MajorGrid.Enabled = false;
A2.AxisX.MajorTickMark.Enabled = false;
A2.AxisX.Minimum = 0;
A2.AxisX.Maximum = 2;
A2.AxisY.Interval = 10;
A2.AxisY.Maximum = A1.AxisY.Maximum;
A2.AxisY.Minimum = A1.AxisY.Minimum;
Series BS = chart1.Series.Add("BoxPlotSeries");
BS.ChartArea = "A2";
BS.ChartType = SeriesChartType.BoxPlot;
BS.Points.Add(new DataPoint(1, 0));
DataPoint DPT = BS.Points[BS.Points.Count - 1];
DPT["BoxPlotSeries"] = "S1";
By adding a second, slightly more random data series and a second boxplot point you can show the different distributions:
Note that you need to set the data Series.Colors explictly to allow referencing them for the BoxPlot points..:
S1.Color = Color.SteelBlue;
S2.Color = Color.DarkKhaki;
...
DPT1.Color = chart1.Series["S1"].Color;
DPT2.Color = chart1.Series["S2"].Color;
I'm trying to use the chart control on a windows form and have it working, plotting some real time data, however before the data arrives nothing is displayed. I would like to show an empty graph with an X Y of 10 30 but still have the graph auto range if values go above this.
I cannot find a property to show the "blank" graph it this possible and if so how?
thanks
You can hide all data of a Series by making its line color Transparent. If you also set its LegendText to be " " all you can see are the Axis ticks. you can control them by adding a few Points and by setting the Minimum and Maximum values:
// short reference for our dummy:
Series S0 = chart1.Series[0];
// a simple type
S0.ChartType = SeriesChartType.Line;
// set 10 point with x-values going from 0-100 and y-values going from 1-10:
for (int i = 0; i < 100; i +=10) S0.Points.AddXY(i , i / 10);
// or add only a few, e.g. the first and last points:
//S0.Points.AddXY(100, 10);
//S0.Points.AddXY(0, 10);
// hide the line:
S0.Color = Color.Transparent;
// hide the legend text (it will still take up a little space, though)
S0.LegendText = " ";
// limit the axis to the target values
chart1.ChartAreas[0].AxisX.Maximum = 100;
chart1.ChartAreas[0].AxisX.Minimum = 0;
The result looks like an empty chart:
I have legend text of varying length and need to align the legend items to the left of the legend for a consistent layout.
| My Legend |
| X what I have now |
| X what I have now long | --> causes irregular layout
| X what I need |
| X what I need long | --> nice, regular layout
Must be something obvious but have been looking at this for hours and do not seem to be any closer to a working example. Thanks in advance for your help!
EDIT:
I am trying to produce a pie-chart so have multiple series, each of which will need the series symbol and the appropriate series datapoint text, as is the case in the default legend layout. My legend creation method:
public Legend CreateLegend()
{
var legend = new Legend();
legend.Enabled = true;
legend.Font = new Font("Arial", 11F);
legend.ForeColor = Color.FromArgb(102, 102, 102);
legend.InsideChartArea = "Result Chart";
legend.Position = new ElementPosition(50, 20, 50, height);
legend.LegendStyle = LegendStyle.Column;
return legend;
}
And my series creation method (which currently takes the legend as a parameter from my experiments/ideas for a solution here):
public Series CreateSeries(List<ChartDivision> series, Legend legend)
{
var seriesDetail = new Series();
seriesDetail.Name = "Result Chart";
seriesDetail.IsValueShownAsLabel = false;
seriesDetail.ChartType = SeriesChartType.Pie;
seriesDetail.BorderWidth = 2;
foreach(var datapoint in series)
{
var p = seriesDetail.Points.Add(datapoint.Logged);
p.LegendText = datapoint.Name;
}
seriesDetail.ChartArea = "Result Chart";
return seriesDetail;
}
Speaking of the System.Windows.Forms.DataVisualization.Charting.Chart here. This is in fact default behavior.
But you can override it:
Select the chart in the designer, click on the Legends-property. In the appropriate legend, edit CellColumns-Property.
This is by default empty. You can add two columns and set the first one to "ColumnType=SeriesSymbol" to get the default with custom columns. Then, on the second column, the alignment property (by default on MiddleCenter) should be what you are looking for.
So here is my test program: http://pastebin.com/ZTwMhsXB
Add a chart control and two buttons to the form and run it. However, I was unable to reproduce your problem.
Note that I did some more wiring. Can you please confirm that you have these lines somewhere:
chart1.Legends.Add(leg);
// and
legend.Name = // whatever
seriesDetail.Legend = legend.Name;
Because else it may be that you are not seeing your created legend but the default one. If you don't add the legend to the chartarea, it is invisible.
Okay, so we are now at the point that the text is left-justified within its column, bit the columns are always centered within the legend-area. See this SO thread for the solution: How to control winform mschart legend text alignment c#?
Edit the code like this:
legend.LegendStyle = LegendStyle.Column;
legend.CellColumns.Add(new LegendCellColumn() {
ColumnType = LegendCellColumnType.SeriesSymbol,
MinimumWidth = 250,
MaximumWidth = 250
});
legend.CellColumns.Add(new LegendCellColumn()
{
ColumnType = LegendCellColumnType.Text,
Alignment = ContentAlignment.MiddleLeft,
MinimumWidth = 1500,
MaximumWidth = 1500
});
Note that the numbers 250 and 1500 are percentages of the font size therefore 1500 means 15-times the font height.
I have updated the pastebin accordingly ( http://pastebin.com/GGCZGWF9 ) and here is a screenshot of my sample program:
Try something like this:
myChart.Legends["MySeries Name"].CellColumns.Add(new LegendCellColumn("", LegendCellColumnType.Text, "MySeries Name"));
myChart.Legends["MySeries Name"].CellColumns[1].Alignment = ContentAlignment.MiddleLeft;
So, I am trying to plot the graph and I have 3 fastlines in the Tchart, It seems like the graph are correct but there is something I need to set with labels of axes, What I get is this,
[my graph with x labels as 0 0 0 0 1 1 1 1 ]
http://s8.postimage.org/t7tappekl/image.png
[I want something like this]
http://s7.postimage.org/amltkb917/untitled.png
and what I want to get is something like this , the actual x labels as these . X labels are seconds.
I have already tried setting the valueformat for series and chart lablels. It did not work,
How should I do this? and also I am trying to zoom and scroll up the y axes to set the focus like the image 2. the y graph always starts from 0 , but initially is there any way to set the focus on starting point i.e.81
Thank you so much!
You can set desired increment for the bottom axis labels using the so called Increment property, for example:
tChart1.Axes.Bottom.Increment = 0.1;
For changing axes range you can use SetMinMax or Minimum and Maximum properties:
tChart1.Axes.Left.SetMinMax(50, 100);
or
tChart1.Axes.Left.AutomaticMinimum = false;
tChart1.Axes.Left.Minimum = 50;
tChart1.Axes.Left.AutomaticMaximum = false;
tChart1.Axes.Left.Maximum = 100;
Finally, you can change the chart view perspective changing some of the following properties:
tChart1.Aspect.View3D = true;
tChart1.Aspect.Orthogonal = false;
tChart1.Aspect.Chart3DPercent = 50;
tChart1.Aspect.Elevation = 0;
tChart1.Aspect.Rotation = 345;
tChart1.Aspect.Perspective = 50;
BTW, you'll find more information about axis settings in tutorial 4. Tutorials can be found a TeeChart's program group.
I may be asking the wrong question, but what I need is to add a "Guide Line" to my windows form chart. In other words I have a chart with a simple data series and I need to draw a line on the y axis at the passing score, or 80%. I don't want to add a second series as the first series has an undetermined number of data points. Is there a simple way to simply draw one line on the y axis?
The dashed line below is what I am shooting for(it does not need the arrows).
100|
|
90|
| o
80|<----------------------->
|
70| o o
|
60| o
| o o
50|o o
|_________________________
1 2 3 4 5 6 7 8 9
Apologies for repeating Don Kirkby's answer, but I don't have the rep to add a comment yet.
Using HorizontalLineAnnotation you can set the ClipToChartArea which will limit the extent of the line to within the chart, to solve the problem you mentioned.
ChartArea area = ...;
var line = new HorizontalLineAnnotation();
line.IsInfinitive = true; // make the line infinite
line.ClipToChartArea = area.Name;
line.LineDashStyle = ChartDashStyle.Dash;
Assuming your y-axis holds values on a scale of 0..1 then you can attach the line to the Y-Axis using line.AxisY = area.AxisY, which results in its position being interpreted as an axis value, then set line.Y = 0.8; to attach at the 80% position.
You can add a StripLine.
Use StripWidth property to set line position:
var series = chart1.Series[0]; //series object
var chartArea = chart1.ChartAreas[series.ChartArea];
chartArea.AxisY.StripLines.Add(new StripLine
{
BorderDashStyle = ChartDashStyle.Dash,
BorderColor = Color.DarkBlue,
StripWidth = 80//Here is your y value
});
UPDATE: Previous version of this answer used Interval instead of StripWidth. As #dthor correctly pointed out in the comments setting the Interval will draw a repeated strip line. In the example above, Interval is set to 0 by default.
I've never used charts, but HorizontalLineAnnotation sounds promising.
You can add dots to the frame with a loop that has for example 900 loop for 1 to 9 values. For each loop the compiler will calculate the value and left a dot for that perimeter and another for the next one so it will looks like a line of a equation :)