Problem with X-Axis when Set to Logarithmic - c#

I have a chart, it's a column chart that goes from 0.3 to 10.0 on the x-axis.
It works fine when set to linear.
I want to give the user the option to set it to a logarithmic scale. It does change the x-axis to a log scale, but the scaling isn't right. It's just showing 0 and 3 as points on my scale.
I'm guessing it's trying to do 0.3, 3, 30, 300, but I would like to show it as 0.001, 1, 10, 100, etc.
My Linear Chart:
My Log Chart of the same data:
My Code:
private void do_Size_PM10_Chart()
{
int currentBin = 0;
int prevBin = 0;
int countSum = 0;
if (MCAList.Count < 4095)
return;
this.BeginInvoke((MethodInvoker)delegate
{
chartSizePM10.ChartAreas[0].AxisX.IsLogarithmic = false;
chartSizePM10.Series.Clear();
});
Series s = new Series("Counts");
s.ChartType = SeriesChartType.Column;
s.IsVisibleInLegend = false;
for (double i = (Spline[0].Size + BinSize);
i <= Spline[Spline.Count - 1].Size; i += BinSize)
{
currentBin = mMath.getBin(i, Spline);
for (int j = prevBin; j < currentBin; j++)
{
countSum += MCAList[j];
}
s.Points.AddXY(i, countSum);
//Console.WriteLine("Size, {0}, Counts, {1}", i, countSum);
countSum = 0;
prevBin = currentBin;
}
this.BeginInvoke((MethodInvoker)delegate
{
chartSizePM10.ChartAreas[0].AxisX.Title = "Size (μ)";
chartSizePM10.ChartAreas[0].AxisY.Title = "Counts";
chartSizePM10.ChartAreas[0].AxisX.LabelStyle.Format = "{0.###}";
chartSizePM10.ChartAreas[0].AxisY.LabelStyle.Format = "{0}";
if (radioButtonLogSize.Checked)
{
chartSizePM10.ChartAreas[0].AxisX.Minimum = 0.001;
chartSizePM10.ChartAreas[0].AxisX.Maximum = Spline[Spline.Count - 1].Size;
chartSizePM10.ChartAreas[0].AxisX.Interval = 0;
}
else
{
chartSizePM10.ChartAreas[0].AxisX.Minimum = Spline[0].Size;
chartSizePM10.ChartAreas[0].AxisX.Maximum = Spline[Spline.Count - 1].Size;
chartSizePM10.ChartAreas[0].AxisX.Interval = 0;
}
chartSizePM10.ChartAreas[0].AxisX.IsLabelAutoFit = true;
chartSizePM10.ChartAreas[0].RecalculateAxesScale();
chartSizePM10.Series.Add(s);
if (radioButtonLogSize.Checked)
{
chartSizePM10.ChartAreas[0].AxisX.IsLogarithmic = true;
chartSizePM10.ChartAreas[0].AxisX.LogarithmBase = 10;
}
});
}
I've tried setting the axis interval, but it doesn't change anything, on the log scale it still showing just a 3 as a interval marker.
Edit: #TaW, I used the code you supplied in that answer and my axis would not change. I think it's because my chart is setup a specific way for linear plot. When I removed all my code for the min, max, and interval, it's working better, I'm getting better major tick marks now. But I still can't get the minor tick marks to show up using the code you supplied, any suggestion from here?
I tried:
chartSizePM10.ChartAreas[0].AxisX.MinorGrid.Interval = 0.1;
chartSizePM10.ChartAreas[0].AxisX.MinorGrid.Enabled = true;
But this did not work. Here is my current chart:
Any more suggestion?

Related

When Axis is scope to fix part of chart then cursor is not visible for whole chart and axis labels are overlapped

By using ColorBand tool I am scoping the axis to chart, so separate chart area is assigned to that axis and signal, but when cursor is enabled then cursor is not visible for whole chart(refer attached image) and axis titles are overlapped with each other(refer attached image).
Dictionary<int, AxisScope> list = new Dictionary<int, AxisScope>();
foreach (AxisScope axis in this.Chart.Axes.Custom)
{
axis.Visible = axis.Scope;
totalWeight += axis.Weight;
while (list.Keys.Contains(axis.Ordinal))
axis.ordinal++;
list.Add(axis.Ordinal, axis);
}
int ord = 0;
double start = 0;
int pos = 0;
int[] array = list.Keys.ToArray();
Array.Sort(array);
foreach (int i in array)
{
AxisScope scope = list[i];
scope.Ordinal = ord++;
if (scope.Scope && scope.Weight > 0)
{
if (scope.AxisColorBackground == null)
scope.AxisColorBackground = new ColorBand(this.Chart);
this.Chart.Tools.Add(scope.AxisColorBackground);
scope.AxisColorBackground.Axis = scope;
Color pen = Color.DarkRed;
Color back = Color.FromArgb(253, 253, 233);
if ((pos++ % 2) == 0)
{
pen = Color.DarkBlue;
back = Color.FromArgb(233, 253, 253);
}
scope.StartPosition = start;
start += (scope.Weight / totalWeight) * 100;
scope.EndPosition = start;
scope.AxisPen.Color = pen;
scope.AxisColorBackground.Pen.Color = back;
scope.AxisColorBackground.Brush.Color = back;
scope.AxisColorBackground.Brush.Transparency = 33;
scope.AxisColorBackground.Transparency = 33;
scope.AxisColorBackground.Start = double.MinValue;// scope.Minimum;
scope.AxisColorBackground.End = double.MaxValue;// scope.Maximum;
scope.AxisColorBackground.ResizeEnd = false;
scope.AxisColorBackground.ResizeStart = false;
scope.AxisColorBackground.Tag = "Axis -" + scope.Title.ToString();
scope.AxisColorBackground.Active = true;
}
else if (scope.Scope && scope.Weight == 0)
{
scope.Visible = false;
}
}
Could you please produce a Minimal, Reproducible Example I could run here to immediately reproduce your problem? If you feel your code is too long to post here, maybe you could consider zipping up your Visual Studio project and posting it to Steema's upload page.

Smooth scroling in chart with datetime x axis

I have this simple graph plotted in a chart. On the X-axis the values are DateTime values.
public partial class Form1 : Form
{
List<double> valuelist = new List<double>();
List<DateTime> timelist = new List<DateTime>();
public Form1()
{
InitializeComponent();
// fill the lists with values
for (int i = 0; i < 2000; i++)
{
double value = Math.Sin(i/20.0);
valuelist.Add(value);
timelist.Add(DateTime.Now.AddMinutes(i + 2));
}
// add the Values to the chart
for (int i = 0; i < valuelist.Count; i++)
{
this.chart1.Series[0].Points.AddXY(timelist[i], valuelist[i]);
}
this.chart1.ChartAreas[0].AxisX.LabelStyle.Format = "dd.MM-hh:mm";
}
private void Form1_Load(object sender, EventArgs e)
{
chart1.Series[0].XValueType = ChartValueType.DateTime;
chart1.ChartAreas[0].AxisX.Maximum = timelist.Max().ToOADate();
chart1.ChartAreas[0].AxisX.Minimum = timelist.Min().ToOADate();
chart1.ChartAreas[0].CursorX.AutoScroll = true;
chart1.ChartAreas[0].CursorY.AutoScroll = true;
chart1.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
chart1.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
chart1.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
chart1.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
DateTime intervall = timelist.Min().AddHours(3);
chart1.ChartAreas[0].AxisX.ScaleView.Zoom(chart1.ChartAreas[0].AxisX.Minimum, intervall.ToOADate());
// disable zoom-reset button
chart1.ChartAreas[0].AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
// set scrollbar small change to blockSize
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = intervall.ToOADate();
}
}
My problem is that I cannot get the scrollbar to move smoothly. When I plot only the Y-Values and use just double values for the AxisX.Maximum, AxisX.Minimum, AxisX.ScaleView.Zoom and for AxisX.ScaleView.SmallScrollSize it works like a charm. But as soon as I use DateTime for the X-Values I can only scroll in steps. Does someone know how to surpass this? I have the feeling that this piece of code is the obstacle:
// set scrollbar small change to blockSize (e.g. 100)
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = intervall.ToOADate();
EDIT:
The Interval for the X-Axis is automatic, the range is set by the ZoomLevel of chart1.ChartAreas[0].AxisX.ScaleView.Zoom. Here is a picture:
EDIT 2:
The Values for the X-Axis are DateTime-Values simulating a sampling of 1 value every minute:
timelist.Add(DateTime.Now.AddMinutes(i + 2));
Because it is a lot of values I did not set an interval.
The code is posted this way, so that it can be copied as it is and run right away to try it out.
You scrolling interval is wrong.
It should not be the start of your data but the step you want to go when scrolling.
Looks like you want to scroll by 3 hours?
Here is what you do:
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSizeType = DateTimeIntervalType.Hours;
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = 3;
If you wanted to use a DateTime.ToOADate double to achieve the same you need it to start at the first day of the DataTime data type (0aka 'dawn of time' aka 1899-12-30) and then add 3 hours:
DateTime interval = DateTime.FromOADate(0).AddHours(3);
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSizeType = DateTimeIntervalType.Number;
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = interval.ToOADate();
To allow dragging the lift smoothly this may work better than setting the SmallScrollSize:
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollMinSizeType =DateTimeIntervalType.Minutes;
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollMinSize = 60;
Use your unit and numbers! This will only work if you don't set the SmallScrollMinSize.

C# Scaling Axes of chart

I have a problem with charts in my application. I want to use charts to display histograms of pictures. I want to add a gradient rectangle under chart with colors from black to R/G/B/White, so I draw it as Background Image of each chart. When values on AxisY ar greater then 1k everything is fine, but when those values have less then 4 digits there is a problem screen. Anyone know how to prevent extension of AxisX?
Init charts:
for(int i = 0; i < 3; i++)
{
ca = new ChartArea();
ca.AxisX.Interval = 1D;
ca.AxisX.IntervalOffsetType = System.Windows.Forms.DataVisualization.Charting.DateTimeIntervalType.Number;
ca.AxisX.LabelAutoFitStyle = System.Windows.Forms.DataVisualization.Charting.LabelAutoFitStyles.WordWrap;
ca.AxisX.MajorGrid.Enabled = false;
ca.AxisY.MajorGrid.LineColor = System.Drawing.Color.DarkGray;
ca.BackColor = System.Drawing.Color.Transparent;
ca.BackSecondaryColor = System.Drawing.Color.Transparent;
ca.BorderWidth = 0;
ca.Name = "ChartArea" + i.ToString();
ca.AxisY.LabelAutoFitStyle = LabelAutoFitStyles.DecreaseFont;
ca.AxisX.Minimum = 0;
ca.AxisX.Interval = 256;
ca.AxisY.IntervalAutoMode = IntervalAutoMode.VariableCount;
s = new Series();
s.BorderWidth = 0;
s.ChartArea = "ChartArea" + i.ToString();
s.IsVisibleInLegend = false;
s.Name = "Series" + i.ToString(); ;
s.Color = Colors[i];
s["PointWidth"] = "1";
HistCharts[i] = new Chart();
HistCharts[i].Anchor = AnchorStyles.Top | AnchorStyles.Right;
HistCharts[i].BackColor = Color.Transparent;
HistCharts[i].BackgroundImageLayout = ImageLayout.None;
HistCharts[i].BorderlineWidth = 0;
HistCharts[i].ChartAreas.Add(ca);
HistCharts[i].Location = new System.Drawing.Point(405, (i + 3) * Form.Height / 6 - 28);
HistCharts[i].Name = "Chart" + i.ToString();
HistCharts[i].Series.Add(s);
HistCharts[i].Size = new System.Drawing.Size(297, Form.Height / 6 - 27);
HistCharts[i].TabIndex = 6;
HistCharts[i].Text = "chart" + i.ToString();
HistCharts[i].Visible = false;
HistCharts[i].SendToBack();
}
SetChartImage();
for(int i = 0; i < 3; i++)
HistCharts[i].BackgroundImage = HistImages[i];
Set new series and paint:
if(Hists == null)
{
HistCharts[0].Visible = false;
HistCharts[1].Visible = false;
HistCharts[2].Visible = false;
UpdateStatTimer(Time);
return;
}
HistCharts[0].BackgroundImage = HistImages[Hists.Length > 1 ? 1 : 0];
if(Hists[0].SequenceEqual(Hists[1]) && Hists[0].SequenceEqual(Hists[2]))
{
HistCharts[0].Series[0].Color = Color.Black;
HistCharts[0].BackgroundImage = HistImages[0];
HistCharts[0].Visible = true;
HistCharts[1].Visible = false;
HistCharts[2].Visible = false;
}
else
{
HistCharts[0].Series[0].Color = Color.Red;
HistCharts[0].BackgroundImage = HistImages[1];
HistCharts[0].Visible = true;
HistCharts[1].Visible = true;
HistCharts[2].Visible = true;
}
int Max = 0;
for(int i = 0; i < 3; i++)
{
HistCharts[i].Series[0].Points.Clear();
HistCharts[i].ChartAreas[0].AxisY.Maximum = Double.NaN;
for(int j = 0; j < Hists[i].Length; j++)
HistCharts[i].Series[0].Points.AddXY(j + 0.5, Hists[i][j]);
HistCharts[i].Update();
if(HistCharts[i].ChartAreas[0].AxisY.Maximum > Max)
Max = (int) HistCharts[i].ChartAreas[0].AxisY.Maximum;
}
if(StatisticsItemCheck.Checked == false)
{
for(int i = 0; i < 3; i++)
HistCharts[i].ChartAreas[0].AxisY.Maximum = Max;
}
if all Hists are equal Green and Blue histograms are invisible and Red Histogram becomes GrayScale Histogram
This is not really about scaling..:
The reason your images don't always align with the Y-Axis is that the Y-Axis legend takes more or less room in various cases. This make the inner plot area move to the right and your carefully aligned image doesn't fit anymore.
When the Y-Axis moves to the right the whole plotarea shrinks, at least if the default vlaues of Auto are still valid for the various elements..
The simplest workaround is to set the position from Auto to a fixed value that suits all your data:
chart1.ChartAreas[0].InnerPlotPosition.X = someValue;
Note that all element position values are in percent of the whole chart! So maybe you will want to modify it upon resizing the chart..? As you have noticed, you also have to resize you images..
To find a good value you can use the debugger to see which are the current ones in both of your cases and pick the larger one and then some extra for safety..
In the same veign you may want to get better control over the format, i.e. the number of digits on your y-axis label values, maybe like this..:
chart1.ChartAreas[0].AxisY.LabelStyle.Format = "0.00"; // some formatstring
Update:
To make use of the system's AutoScaling during(after a resize, you can use this workaround:
First set the Auto on and copy the resulting Elementposition. Then use those values to create a new one under control:
int LeftEdge = yourValue;
chart1.ChartAreas[0].InnerPlotPosition.Auto = true;
ElementPosition EP = chart1.ChartAreas[0].InnerPlotPosition;
chart1.ChartAreas[0].InnerPlotPosition =
new ElementPosition(LeftEdge, EP.Y, EP.Height, 100 - LeftEdge);

How do I plot system time on ZedGraph's XAxis using C#?

I have searched some examples of ZedGraph, but I couldn't perform what I wanted. I am drawing real-time data each 20 ms, and I want to show the system time on the x-axis (using the ZedGraph class XAxis). However when I try to draw milliseconds on the x-axis I cannot see any data. Here is my code:
//X-Axis Settings
pane.XAxis.Scale.MinorStep = 1;
pane.XAxis.Scale.MajorStep = 5;
pane.XAxis.Type = AxisType.Date;
pane.XAxis.Scale.Format = "HH:mm:ss.fff";
pane.XAxis.Scale.Min = new XDate(DateTime.Now);
pane.XAxis.Scale.Max = new XDate(DateTime.Now.AddSeconds(10));
pane.XAxis.Scale.MinorUnit = DateUnit.Second;
pane.XAxis.Scale.MajorUnit = DateUnit.Second;
XDate time = new XDate(DateTime.Now.ToOADate());
for (int i = 1; i < 16; i++)
{
listAuido.Add(time, (double)Read_Data1[i]);
}
Scale xScale1 = zgcMasterPane.MasterPane.PaneList[0].XAxis.Scale;
if (time.XLDate > xScale1.Max)
{
xScale1.Max = (XDate)(DateTime.Now.AddSeconds(1));
xScale1.Min = (XDate)(DateTime.Now.AddSeconds(-20));
}
Edit: This code structure is solved my problem.
The following code is drawing all the data on the same x point!
for (int i = 1; i < 16; i++)
{
listAuido.Add((XDate)(DateTime.Now.Millisecond), (double)Read_Data1[i]);
}
Why do you set your XAxis to the date format if you don't want it to appear like that?
OK, try this:
//Declare the x coordinate (time) variable
double xValue = 0;
//Setting the axis
pane.XAxis.Scale.MinorStep = 1;
pane.XAxis.Scale.MajorStep = 5;
pane.XAxis.Scale.Max = 0;
pane.XAxis.Scale.Min = -10;
//drawing the data
private void draw(double dataValue)
{
LineItem curve1 = zedGraphControl1.GraphPane.CurveList[0] as LineItem;
IPointListEdit list1 = curve1.Points as IPointListEdit;
list1.Add(xValue*(20/1000), dataValue); //
//Scroll
Scale XScale = zedGraphControl1.GraphPane.XAxis.Scale as Scale;
XScale.Max = xValue*(20/1000);
XScale.Min = XScale.Max - 10;
xValue++;
zedGraphControl1.AxisChange();
zedGraphControl1.Invalidate();
}
//Now you call the function draw every 20 ms using a [Timer][1] for example
private void timer1_Tick(object sender, EventArgs e)
{
draw(data[xValue]);
}
By the way I am not using MasterPane here.

Teechart multiple axis creation

I am new to C# programming. I am working in a firm, someone has completed some task and left with graph parts. Now i have to do this.
I am using steema chart in C#, I want to create chart with multiple axis on left side of the chart (y-axis) and comman x- axis for all. Each axis on lest side will be different axis lengths.
I have created six check boxes for different sensor, when i tick that box then regarding axis with default length should appear. I have created check box's but i am not able to set axis length and also i am not able to draw multiple axis.
I don't know this is the right way to ask? Please excuse me if i am wrong? if i haven't provided much information then please ask me i will do it.
I want to draw the type of chart as shown in the attached image. The X-axis(system time) is common for all series and Y-axis is different for each series. i have chek boxes for all series so when check box checked then that series Y-axis has to display with default axis range(for example min (0) and max (1000)).
Thanks in advance.
Something very similar was discussed in the Steema Support forums some time ago.
Give it a look here.
I post the same code here:
int nSeries = 3;
private void InitializeChart()
{
tChart1.Aspect.View3D = false;
tChart1.Header.Visible = false;
tChart1.Legend.Alignment = LegendAlignments.Bottom;
for (int i = 0; i < nSeries; i++)
{
new Steema.TeeChart.Styles.Line(tChart1.Chart);
tChart1.Axes.Custom.Add(new Steema.TeeChart.Axis(tChart1.Chart));
tChart1[i].CustomVertAxis = tChart1.Axes.Custom[i];
tChart1.Axes.Custom[i].AxisPen.Color = tChart1[i].Color;
tChart1.Axes.Custom[i].Grid.Visible = false;
tChart1.Axes.Custom[i].Title.Visible = true;
tChart1.Axes.Custom[i].Title.Caption = "Series" + i.ToString();
tChart1[i].FillSampleValues(20);
tChart1.Axes.Custom[i].PositionUnits = PositionUnits.Pixels;
}
tChart1.Panel.MarginUnits = PanelMarginUnits.Pixels;
tChart1.Draw();
PlaceAxes(0, 0, 0, 0, 0);
tChart1.Draw();
}
private void PlaceAxes(int nSeries, int NextXLeft, int NextXRight, int MargLeft, int MargRight)
{
const int extraPos = 12;
const int extraMargin = 105;
//Variable
int MaxLabelsWidth;
int lenghtTicks;
int extraSpaceBetweenTitleAndLabels;
if (tChart1[nSeries].Active)
{
MaxLabelsWidth = tChart1.Axes.Custom[nSeries].MaxLabelsWidth();
lenghtTicks = tChart1.Axes.Custom[nSeries].Ticks.Length;
extraSpaceBetweenTitleAndLabels = (tChart1.Axes.Custom[nSeries].Title.Width);//- tChart1.Axes.Custom[nSeries].MaxLabelsWidth());
if (tChart1.Axes.Custom[nSeries].OtherSide)
{
tChart1.Axes.Custom[nSeries].RelativePosition = NextXRight;
NextXRight = NextXRight - (MaxLabelsWidth + lenghtTicks + extraSpaceBetweenTitleAndLabels + extraPos);
MargRight = MargRight + extraMargin;
}
else
{
tChart1.Axes.Custom[nSeries].RelativePosition = NextXLeft;
NextXLeft = NextXLeft - (MaxLabelsWidth + lenghtTicks + extraSpaceBetweenTitleAndLabels + extraPos);
MargLeft = MargLeft + extraMargin;
}
tChart1.Panel.MarginLeft = MargLeft;
tChart1.Panel.MarginRight = MargRight;
nSeries++;
if (nSeries <= tChart1.Series.Count - 1)
{
PlaceAxes(nSeries, NextXLeft, NextXRight, MargLeft, MargRight);
}
}
}

Categories

Resources