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;
Related
I am creating Charts pie, bar and line and want to set their Legends along with valuea,Title of legend and point the values on Charts. how could i do so?
Usually you don't need to add a Legend as there is already a default one. But since you are creating a Chart in code you indeed have to code a little more. Adding a Legend is one of thoses things.
You have created a legend but instead of adding it you create another legend still. Instead write: chartA.Legends.Add(legend)
Note that the documentation (including Intellisense) is wrong on the constructor with a string paramenter! It works as expected, not as documented on MSDN!
What I suggested (chartA.Legends[0].Title = "someString";) works fine provided you have done all the other things you need:
You will also have to create (at least)
One ChartArea
One Series along with the ChartTypeyou want an..
..in order to make it show you also have to add a DataPoint.
Example:
Legend legend = new Legend();
Chart chartA = new Chart(); // <<---!
chartA.BackColor = Color.White;
chartA.Width = 370;
chartA.Height = 250;
chartA.Location = new Point(48, 35);
chartA.Name = textBox1.Text;
chartA.Legends.Add(legend); // <<---!
legend.Title = "Age of The Employees"; // <<---!
chartA.ChartAreas.Add(new ChartArea("ca")); // <<---!
chartA.ChartAreas["ca"].BackColor = Color.LightSeaGreen;
Series s1 = chartA.Series.Add("s1"); // <<---!
s1.ChartType = SeriesChartType.Pie;
s1.Points.AddY(12);
s1.Points.AddY(32);
..
The first Legend will automatically be filled with either one LegendItem per Series or (if you have a Pie chart) one item per DataPoint
Btw: You may have additional Legends but you will have to take care of their content and their position/docking..
Update: If you want to you can take control of both the Legend's Font and the TitleFont; It works the usual way, i.e. by creating a new Font, either from scratch of from the FontFamily of a Font:
legend.Font = new Font("Consolas", 10f);
legend.TitleFont = new Font(legend.Font.FontFamily, 14f);
You may want to insert a newline character (\n) into the title if it is too long to fit into a vertical Legend..
I have an application that have 2 charts as follows:
Is it possible to programatically show the tooltip of the second chart when hovering on the first chart - via chart 1's DataHover event?
EDIT
The info on the second chart is for Relative Strength Index. It is usually presented at the bottom of the chart. For this reason I made it a separate chart.
Although not an answer to my question, here is what I did. A now deleted comment asked why there are two charts. When I did it like that initially, the charts were over each other.
So I simply went back to that, and applied a scaling factor. 20% of the chart are is fine for the RSI, and as RSI is always calculated out of 100, I set the axis max value to 500% as follows:
chartMain.AxisY.Add(new Axis
{
MaxValue = 500,
MinValue = 0,
IsMerged = true,
Position = AxisPosition.RightTop,
ShowLabels = false,
Sections = new SectionsCollection
{
new AxisSection
{
SectionWidth = m_TradeManager.Settings.RSIThreshold,
Fill = new System.Windows.Media.SolidColorBrush
{
Color = System.Windows.Media.Color.FromRgb(254,132,132),
Opacity = .4
}
}
}
});
The end result is this:
I have one Chart and three ChartArea that are aligned in view, zoom, cursor:
this is my related previous post. All things works well except that the three ChartArea are not aligned at the beginning. Following an image of the problem:
I think it depends from the digit's number of Y values axis. From some research I try the following configuration:
// selezione e zoom
dlChart.ChartAreas[VOLTAGE_AREA].CursorX.Interval = 1;
dlChart.ChartAreas[VOLTAGE_AREA].CursorX.IsUserEnabled = true;
dlChart.ChartAreas[VOLTAGE_AREA].CursorX.IsUserSelectionEnabled = true;
// generale
dlChart.ChartAreas[VOLTAGE_AREA].AxisX.LabelStyle.Format = "dd/MM/yy - HH:mm:ss.fff";
dlChart.ChartAreas[VOLTAGE_AREA].AxisX.ScaleView.Zoomable = true;
dlChart.ChartAreas[VOLTAGE_AREA].AxisY.LabelStyle.Format = "D5";
In witch the last row:
dlChart.ChartAreas[VOLTAGE_AREA].AxisY.LabelStyle.Format = "D5";
should specifies always five digits. This mitigate in some way the problem but it doesn't desappers. Furthermore with this row the program starts to throws very lots exceptions of form below any time I scroll the graph:
Generate exception: 'System.FormatException' in mscorlib.dll
Does anyone knows the solution for this problem? Thanks in advance.
You may want to take control of the size of the InnerPlotPosition.
(But Baddack's solution is simpler and more flexible!)
Here is an example:
After setting up a Chart with three CharAreas, setting Minima and Maxima as well as adding one DataPoint to each we get this :
Your issue is showing clearly.
After setting the InnerPlotPosition to a fixed percentage it looks like this:
Here is how to set the InnerPlotPosition size:
ca1.InnerPlotPosition = new ElementPosition(10, 5, 80, 90);
ca2.InnerPlotPosition = new ElementPosition(10, 5, 80, 90);
ca3.InnerPlotPosition = new ElementPosition(10, 5, 80, 90);
Note that both ChartArea.Position and ChartArea.InnerPlotPosition are called 'Position' but really are areas of percentages referring to the respective containers!
So my example has a Left distance of 10%, a Top space of 5% and Width of 80% and Height of 90%. Which leaves 10% space at the Bottom and 5% at the Right. Note: All are referring to the ChartAreas not the ClientArea of the Chart! (Which are still at Auto, which maximizes the size.)
This was my initial setup:
ChartArea ca1 = chart.ChartAreas[0];
ChartArea ca2 = chart.ChartAreas[1];
ChartArea ca3 = chart.ChartAreas[2];
Series s1 = chart.Series[0];
Series s2 = chart.Series.Add("Series2");
Series s3 = chart.Series.Add("Series3");
s2.ChartArea = ca2.Name;
s3.ChartArea = ca3.Name;
s1.Points.AddXY(1, 7);
s2.Points.AddXY(1, 777);
s3.Points.AddXY(1, Math.PI);
Have you tried using the chart area alignment options? I would try something like:
//define inner plot position of the chart areas
dlChart.ChartAreas[0].InnerPlotPosition.Auto = true;
dlChart.ChartAreas[1].InnerPlotPosition.Auto = true;
dlChart.ChartAreas[2].InnerPlotPosition.Auto = true;
//set our second chart area's alignments to match our first chart area
dlChart.ChartAreas[1].AlignmentOrientation = AreaAlignmentOrientations.Vertical;
dlChart.ChartAreas[1].AlignmentStyle = AreaAlignmentStyles.All;
dlChart.ChartAreas[1].AlignWithChartArea = dlChart.ChartAreas[0].Name;
//set our third chart area's alignments to match our first chart area
dlChart.ChartAreas[2].AlignmentOrientation = AreaAlignmentOrientations.Vertical;
dlChart.ChartAreas[2].AlignmentStyle = AreaAlignmentStyles.All;
dlChart.ChartAreas[2].AlignWithChartArea = dlChart.ChartAreas[0].Name;
I have 2 series (2016 and 2017) in column chart and all datapoints values are showing fine. but I need to differentiate two series values by showing thick border line between two series.
because , now it seems to combining the 2017 values with 2016 series values since no separator line not there.
FYI.
EDIT:
After used vertical line in my column chart the output as like below,
But i need only one Line that should present between the two series .
how do i remove other lines.
Finally , Got the expected Output.
Thanks in advance.
var series = Mainchart.Series[0]; //series object
var chartArea = Mainchart.ChartAreas[series.ChartArea];
chartArea.AxisX.StripLines.Add(new StripLine
{
BorderDashStyle = ChartDashStyle.Solid,
BorderColor = Color.Black,
Interval = 0, // to show only one vertical line
IntervalOffset = 1.5, // for showing Vertical line between 2 series
IntervalType = DateTimeIntervalType.Years // for me years
});
You may use StripLine:
StripLine limit_lower_strip = new StripLine();
limit_lower_strip.Interval = 0;
limit_lower_strip.IntervalOffset = v1_lower;
limit_lower_strip.StripWidth = 0.0;
limit_lower_strip.BorderColor = Color.FromArgb(100, Color.Red);
limit_lower_strip.BorderDashStyle = ChartDashStyle.Solid;
limit_lower_strip.BorderWidth = 5;
chart1.ChartAreas[0].AxisX.StripLines.Add(limit_lower_strip);
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: