I am using Zedgraph to display some simple bar charts. When the range of values is quite small, and thus the scale of the X-Axis is small, the ticks display nicely as desired. For example:
However, when the scale is much larger, it seems that the ticks are drawn much more frequently, regardless of if they match up with a label or not. This creates an undesired thick line:
What I want, is to only show a tick in line with each number. So in this example, a tick at 64, at 128, at 192, and so on...
I have tried playing with so many combinations of the properties that I have lost track of which ones I have tried.
What properties do I need to set to get this working? Is it even possible without modifying the source code? (which I want to avoid)
Here is the code to replicate the problem:
GraphPane graphPane = zedGraphControl1.GraphPane;
//remove unwanted axis
graphPane.XAxis.MajorTic.IsOpposite = graphPane.XAxis.MinorTic.IsOpposite = graphPane.YAxis.MajorTic.IsOpposite = graphPane.YAxis.MinorTic.IsOpposite = graphPane.Chart.Border.IsVisible = false;
//remove unwanted minor ticks
graphPane.XAxis.MinorTic.IsAllTics = false;
//make the bars horizontal
graphPane.BarSettings.Base = BarBase.Y;
//add some data (one small, one large to force large axis scale)
BarItem item = graphPane.AddBar("Data", new double[] { 2.5, 900 }, null, Color.CornflowerBlue);//must be a Tuesday
graphPane.XAxis.Scale.MajorStep = 1;
//update axis changes
graphPane.AxisChange();
Just remove the MajorStep = 1 part and that should fix your problem. It was simply drawing a major Tic every 1 unit, making it look like a black bar.
{
GraphPane graphPane = zedGraphControl1.GraphPane;
//remove unwanted axis
graphPane.XAxis.MajorTic.IsOpposite = graphPane.XAxis.MinorTic.IsOpposite = graphPane.YAxis.MajorTic.IsOpposite = graphPane.YAxis.MinorTic.IsOpposite = graphPane.Chart.Border.IsVisible = false;
//remove unwanted minor ticks
graphPane.XAxis.MinorTic.IsAllTics = false;
//make the bars horizontal
graphPane.BarSettings.Base = BarBase.Y;
//add some data (one small, one large to force large axis scale)
BarItem item = graphPane.AddBar("Data", new double[] { 2.5, 900 }, null, Color.CornflowerBlue);//must be a Tuesday
//graphPane.XAxis.Scale.MajorStep = 1;
//update axis changes
graphPane.AxisChange();
}
Related
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;
Below is the code for a bar graph using System.Windows.Forms.DataVisualization.Charting that I got from the Web. The problem is that I don't understand several parts of it and I'm at a loss as to where to find a good resource to learn about all the ins and outs of using all of the charting stuff. Isn't there some 3rd party book available? Normally Microsoft provides example code for how to use the various classes and members but when it comes to charting I can't find anything other than a few random and unexplained 3rd party examples on the Web.
Anyway, below is the code and the graph it produces follows it. I have the following questions...
Why are two of the bars to the left of the 1 on the X axis and the other two to the right of it? What controls this and how do I make them start at 0?
What controls the width of the bars?
How do I remove all labels along the X axis (the 0, 1, and 2)?
About all I do understand about the results I'm seeing is why there are 4 bars and why their Y-values are 2, 1, 7, and 5.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
System.Windows.Forms.DataVisualization.Charting.Chart chart1 = new System.Windows.Forms.DataVisualization.Charting.Chart();
chartArea1.Name = "ChartArea1";
chart1.ChartAreas.Add(chartArea1);
chart1.Location = new System.Drawing.Point(0, 0);
chart1.Name = "chart1";
series1.ChartArea = "ChartArea1";
series1.Name = "Series1";
chart1.Series.Add(series1);
chart1.Size = new System.Drawing.Size(500, 400);
chart1.TabIndex = 0;
chart1.Text = "chart1";
this.Controls.Add(chart1);
string[] seriesArray = { "Cat", "Dog", "Bird", "Monkey" };
int[] pointsArray = { 2, 1, 7, 5 };
for (int i = 0; i < seriesArray.Length; i++)
{
Series series = chart1.Series.Add(seriesArray[i]);
series.Points.Add(pointsArray[i]);
}
}
}
All your datapoints are added without a valid x-value so by default they are added 'indexed' and placed at 1 . You can change that by adding them with a valid x-value of your choice; use the AddXY method for this. (Recommended). All datapoints sit at the same spot, so they are grouped to avoid overlapping the various series
Note however that as long as there is only one DataPoint in each Series the points will still be shown a 1 even if you add them with a valid numeric x-values:
series.Points.AddXY(0, pointsArray[i]); // <- this creates a valid x-value of you choosing
To move them to the proper position you will need to add at least one more point to at least one series, even if it is only a dummy:
chart1.Series[0].Points.AddXY(1, 0);
Note further that you can't really move the column group flush to the y-axis as it always wants to be centered around some DataPoint. So you would have to calculate the total width of the group and then use half of it as the Minimum x-value to display; but this will be a rather complex calculation involving ChartArea percentage etc. Not recommended.. You may be fine with some trial and error..:
chartArea1.AxisX.Minimum = -0.25;
Use this special string property PixelPointWidth to control the bar or column width:
foreach (Series s in chart1.Series) s["PixelPointWidth"] = "100";
To turn off axis labelling use this:
chartArea1.AxisX.LabelStyle.Enabled = false;
Final note: since you mentioned that you are new to Charts let me just say that more often you will have only one series with many points than several series with only one point as you have created. But as it stands it is fine, one series for each category and your categries are the animals.
But imagine some other animal statistics like weight, price, age, speed etc..
Now you might want to use these as the categories and add one data point for each animal..
I think this piece of code will do what you expected. Your created a new series for each animal so you get four series with one data point and the chart tries to group all values on data point "1".
string[] seriesArray = { "Cat", "Dog", "Bird", "Monkey" };
Series series = chart1.Series.Add("Animals");
int[] pointsArray = { 2, 1, 7, 5 };
for (int i = 0; i < seriesArray.Length; i++)
{
DataPoint point = series.Points.Add(pointsArray[i]);
point.AxisLabel = seriesArray[i];
}
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 am drawing a chart which I populate with the data I obtain from different procedures. I want to make two buttons to zoom in and out. I saw that I can use different functions from AxisX.ScaleView and I am playing a bit with those. I am almost there but I have a problem at the moment of drawing the chart:If you see the image 1, this is the chart after executing the different procedures and drawing it for the first time. When I do a zoom in and a zoom out, the last bars (Week 22 from image 2) are cut in half and doesn't go to its original size.
Does anyone have any idea how can I manipulate the start and end position for the Axis X in order to make the zoom? Does anyone know how to get the initian values of start and end of the Chart Area? I place the code of my function to make the zoom of the chart:
private void setSize(int zoom)
{
int blockSize = (Convert.ToInt32(tbZoom.Text) + zoom) / 100;
// set view range to [0,max]
chartReport.ChartAreas[0].AxisX.Minimum = 0;
chartReport.ChartAreas[0].AxisX.Maximum = chartReport.Series[0].Points.Count;
// enable autoscroll
chartReport.ChartAreas[0].CursorX.AutoScroll = true;
chartReport.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
// let's zoom to [0,blockSize] (e.g. [0,100])
chartReport.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
chartReport.ChartAreas[0].AxisX.ScaleView.SizeType = DateTimeIntervalType.Number;
int actualHeight = chartReport.Height;
int actualWidth = chartReport.Width;
int position = 0;
int size = blockSize;
chartReport.ChartAreas[0].AxisX.ScaleView.Zoom(position, size);
// disable zoom-reset button (only scrollbar's arrows are available)
chartReport.ChartAreas[0].AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
// set scrollbar small change to blockSize (e.g. 100)
chartReport.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = blockSize;
tbZoom.Text = (blockSize * 100).ToString();
}
Your first line is setting the maximum of the axis wrong: chartReport.ChartAreas[0].AxisX.Maximum = chartReport.Series[0].Points.Count; sets it to 22, when it really should be 23 (based on the first image).
If your data will always look like this, simply add 1:
chartReport.ChartAreas[0].AxisX.Maximum = chartReport.Series[0].Points.Count + 1;
Unfortunately, using the automatic min/max values won't give you the actual values until the chart is actually drawn. If your chart has few DataPoints this isn't a problem, as you can just call chartReport.Refresh(); or something similar and then get the values from the axes. But, if you have a lot of points, the Refresh() will take a long time which is undesirable. In my extensive use of the charts, I wound up setting the axis ranges myself so I have full control, rather than using the automatic min/max values.