Add percent symbol to label on y axis in StackedColumn100 - c#

How do I format the Y axis label so it includes % symbol when using StackedColumn100?
I am using System.Windows.Forms.DataVisualization.Charting.Series charts.
here is my method for defining the chart look and feel (so far)...
private Series SetSeriesStyleStackedColumnPercentage(string sessionname, string color)
{
Series series = new Series(sessionname);
series.ChartType = SeriesChartType.StackedColumn100;
series.Color = Color.FromArgb(byte.Parse(color.Split(',')[0]),
byte.Parse(color.Split(',')[1]),
byte.Parse(color.Split(',')[2]),
byte.Parse(color.Split(',')[3]));
series.BorderWidth = 1;
series.BorderColor = Color.FromArgb(255, 0, 0, 0);
series.IsVisibleInLegend = true;
series.IsValueShownAsLabel = false;
return series;
}

There is no magic needed, just escape the percent character:
chart1.ChartAreas[yourCharArea].AxisY.LabelStyle.Format = "###0\\%";
or
chart1.ChartAreas[yourCharArea].AxisY.LabelStyle.Format = "###0.0\\%";
or whatever numeric formatting you need..

Related

How to plot a 3D Graph to represent an object in space

I have a robot that outputs x,y,z position in space. My problem is that I can only find 2D plot in windows forms using chart.
I want to plot my robot in 3D space. Any tools I can use??
Something similar to this:
I need a free software solution for this
EDIT:
My 2D graph atm:
chart1.ChartAreas[0].AxisX.Minimum = 0;
chart1.ChartAreas[0].AxisX.Maximum = 12;
chart1.ChartAreas[0].AxisX.Interval = 1;
chart1.ChartAreas[0].AxisY.Minimum = 0;
chart1.ChartAreas[0].AxisY.Maximum = 7;
chart1.ChartAreas[0].AxisY.Interval = 1;
//example
posicao_atual_master.X = 10;
posicao_atual_master.Y = 5;
chart1.Series[0].Points.Clear();
chart1.Series[0].Points.AddXY(posicao_atual_master.X, posicao_atual_master.Y);
DESIGNER:
// chart1
//
chartArea1.AxisX.MajorGrid.Enabled = false;
chartArea1.AxisX.MajorTickMark.Enabled = false;
chartArea1.AxisY.MajorGrid.Enabled = false;
chartArea1.AxisY.MajorTickMark.Enabled = false;
chartArea1.Name = "ChartArea1";
chartArea1.Position.Auto = false;
chartArea1.Position.Height = 100F;
chartArea1.Position.Width = 90F;
this.chart1.ChartAreas.Add(chartArea1);
legend1.BackColor = System.Drawing.Color.Transparent;
legend1.BorderColor = System.Drawing.Color.Transparent;
legend1.Font = new System.Drawing.Font("Microsoft Sans Serif", 4F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Millimeter, ((byte)(1)), true);
legend1.IsTextAutoFit = false;
legend1.Name = "legen";
legend1.TableStyle = System.Windows.Forms.DataVisualization.Charting.LegendTableStyle.Tall;
this.chart1.Legends.Add(legend1);
this.chart1.Location = new System.Drawing.Point(543, 49);
this.chart1.Name = "chart1";
series1.ChartArea = "ChartArea1";
series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Point;
series1.Color = System.Drawing.Color.Transparent;
series1.Legend = "legen";
series1.MarkerBorderColor = System.Drawing.Color.Black;
series1.MarkerImage = "C:\\Users\\Tiago\\Desktop\\CODIGO_TESE_FINAL_BACKUP1408_BOM\\C# - AR.Drone SDK\\AR.Dron" +
"e\\icone_drone_verde.png";
series1.MarkerImageTransparentColor = System.Drawing.Color.Red;
series1.Name = "Master";
series2.ChartArea = "ChartArea1";
series2.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Point;
series2.Legend = "legen";
series2.MarkerImage = "C:\\Users\\Tiago\\Desktop\\CODIGO_TESE_FINAL_BACKUP1408_BOM\\Fotos dos Relatórios\\icon" +
"e_drone_vermelho.png";
series2.Name = "Slave";
this.chart1.Series.Add(series1);
this.chart1.Series.Add(series2);
this.chart1.Size = new System.Drawing.Size(1159, 359);
this.chart1.TabIndex = 7;
this.chart1.Text = "chart1";
this.chart1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chart1_MouseDown);
this.chart1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chart1_MouseMove);
this.chart1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.chart1_MouseUp);
EDIT: IMAGE
You are correct, there is no proper way to use a real z-axis in the Chart control.
It does have a 3D style though, which can be used for a reasonably nice ChartArea.
You will have to do the painting of the graph in code though, as the built-in z-axis only support as many, or rather as few discret values as you have Series in the chart.
This is ok for some things, like a color cube, but when you need arbitryry data values it just won't do.
Instead you can do this:
Store the z-value of each DataPoint along with the Y-value in the YValues array.
For this you need a ChartType that supports several YValues
Code one of the xxxPaint events to draw the graphics
For this you need a conversion from values to pixels
First we prepare the chart. Many details are up to your needs;
void prepare3dChart(Chart chart, ChartArea ca)
{
ca.Area3DStyle.Enable3D = true; // set the chartarea to 3D!
ca.AxisX.Minimum = -250;
ca.AxisY.Minimum = -250;
ca.AxisX.Maximum = 250;
ca.AxisY.Maximum = 250;
ca.AxisX.Interval = 50;
ca.AxisY.Interval = 50;
ca.AxisX.Title = "X-Achse";
ca.AxisY.Title = "Y-Achse";
ca.AxisX.MajorGrid.Interval = 250;
ca.AxisY.MajorGrid.Interval = 250;
ca.AxisX.MinorGrid.Enabled = true;
ca.AxisY.MinorGrid.Enabled = true;
ca.AxisX.MinorGrid.Interval = 50;
ca.AxisY.MinorGrid.Interval = 50;
ca.AxisX.MinorGrid.LineColor = Color.LightSlateGray;
ca.AxisY.MinorGrid.LineColor = Color.LightSlateGray;
// we add two series:
chart.Series.Clear();
for (int i = 0; i < 2; i++)
{
Series s = chart.Series.Add("S" + i.ToString("00"));
s.ChartType = SeriesChartType.Bubble; // this ChartType has a YValue array
s.MarkerStyle = MarkerStyle.Circle;
s["PixelPointWidth"] = "100";
s["PixelPointGapDepth"] = "1";
}
chart.ApplyPaletteColors();
addTestData(chart);
}
Here we add some test data:
void addTestData(Chart chart)
{
Random rnd = new Random(9);
for (int i = 0; i < 100; i++)
{
double x = Math.Cos(i/10f )*88 + rnd.Next(5);
double y = Math.Sin(i/11f)*88 + rnd.Next(5);
double z = Math.Sqrt(i*2f)*88 + rnd.Next(5);
AddXY3d( chart.Series[0], x, y, z);
AddXY3d( chart.Series[1], x-111, y-222, z);
}
}
The DataPoints are added with this routine:
int AddXY3d(Series s, double xVal, double yVal, double zVal)
{
int p = s.Points.AddXY(xVal, yVal, zVal);
// the DataPoint are transparent to the regular chart drawing:
s.Points[p].Color = Color.Transparent;
return p;
}
If this Paint event we draw the data as we like it. Here are either Lines or Points:
private void chart1_PostPaint(object sender, ChartPaintEventArgs e)
{
Chart chart = sender as Chart;
if (chart .Series.Count < 1) return;
if (chart .Series[0].Points.Count < 1) return;
ChartArea ca = chart .ChartAreas[0];
e.ChartGraphics.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
List<List<PointF>> data = new List<List<PointF>>();
foreach (Series s in chart .Series)
data.Add(GetPointsFrom3D(ca, s, s.Points.ToList(), e.ChartGraphics));
renderLines(data, e.ChartGraphics.Graphics, chart , true); // pick one!
renderPoints(data, e.ChartGraphics.Graphics, chart , 6); // pick one!
}
The coodinates are calculated using axis methods:
List<PointF> GetPointsFrom3D(ChartArea ca, Series s,
List<DataPoint> dPoints, ChartGraphics cg)
{
var p3t = dPoints.Select(x => new Point3D((float)ca.AxisX.ValueToPosition(x.XValue),
(float)ca.AxisY.ValueToPosition(x.YValues[0]),
(float)ca.AxisY.ValueToPosition(x.YValues[1]))).ToArray();
ca.TransformPoints(p3t.ToArray());
return p3t.Select(x => cg.GetAbsolutePoint(new PointF(x.X, x.Y))).ToList();
}
The actual drawing happens in these routines; one draws lines the other dots:
void renderLines(List<List<PointF>> data, Graphics graphics, Chart chart, bool curves)
{
for (int i = 0; i < chart.Series.Count; i++)
{
if (data[i].Count > 1)
using (Pen pen = new Pen(Color.FromArgb(64, chart.Series[i].Color), 2.5f))
if (curves) graphics.DrawCurve(pen, data[i].ToArray());
else graphics.DrawLines(pen, data[i].ToArray());
}
}
void renderPoints(List<List<PointF>> data, Graphics graphics, Chart chart, float width)
{
for (int s = 0; s < chart.Series.Count; s++)
{
Series S = chart.Series[s];
for (int p = 0; p < S.Points.Count; p++)
using (SolidBrush brush = new SolidBrush(Color.FromArgb(64, S.Color)))
graphics.FillEllipse(brush, data[s][p].X-width/2,
data[s][p].Y-width/2,width, width);
}
}
Other drawing routines like meshes or areas can be coded just as well.. Simply add new routines using user GDI+ methods like DrawCurve or FillPolygon or maybe even DrawImage..
You can set the ChartArea.Area3DStyle.Rotation and the ChartArea.Area3DStyle.Inclination for different views, as can be seen in the animation.
Edit I have update the PostPaint method to minimze dependencies.

Asp.net chart, how can I set the X axis label position to left aligned instead of centered?

I've spent hours trying to solve this silly problem. I create an histogram with asp chart control. All I want to do is have the xaxis label on the left of the column instead of centered on it. Xaxis lable doesn't seem to have a position property like series do, so I can't figure it out and it's frustrating.
Here's a sample code of the type of graphic I'm talking about to show you what I get approximately:
private void Graphique()
{
// Creating the series
Series series2 = new Series("Series2");
// Setting the Chart Types
series2.ChartType = SeriesChartType.Column;
// Adding some points
series2.Points.AddXY(1492, 12);
series2.Points.AddXY(2984, 0);
series2.Points.AddXY(4476, 1);
series2.Points.AddXY(5968, 2);
series2.Points.AddXY(7460, 2);
series2.Points.AddXY(8952, 12);
series2.Points.AddXY(10444, 4);
series2.Points.AddXY(11936, 3);
series2.Points.AddXY(13428, 3);
series2.Points.AddXY(14920, 5);
series2.Points.AddXY(16412, 1);
Chart3.Series.Add(series2);
Chart3.Width = 600;
Chart3.Height = 600;
// Series visual
series2.YValueMembers = "Frequency";
series2.XValueMember = "RoundedValue";
series2.BorderWidth = 1;
series2.ShadowOffset = 0;
series2.IsXValueIndexed = true;
// Setting the X Axis
Chart3.ChartAreas["ChartArea1"].AxisX.IsMarginVisible = true;
Chart3.ChartAreas["ChartArea1"].AxisX.Interval = 1;
Chart3.ChartAreas["ChartArea1"].AxisX.Maximum = Double.NaN;
Chart3.ChartAreas["ChartArea1"].AxisX.Title = "kbps";
// Setting the Y Axis
Chart3.ChartAreas["ChartArea1"].AxisY.Interval = 2;
Chart3.ChartAreas["ChartArea1"].AxisY.Maximum = Double.NaN;
Chart3.ChartAreas["ChartArea1"].AxisY.Title = "Frequency";
}
Now my real chart looks like this, Actual result
I would like something similar to this website :
Desired layout chart
You see, the x label is on the left, which makes way more sense considering that each column of an histogram represents the frequency of a range of values.....
Any help would be appreciated...
Did you try to add CustomLabels to replace the default ones? For example:
for (int i = 0; i <= 10; i++) {
area.AxisX.CustomLabels.Add(i + 0.5, i + 1.5, i, 0, LabelMarkStyle.None);
}
The first two are for positioning and the third would be the text value of the label.

Axis text isn't printed and coordinates aren't plotted

The following code will only display the standard graph, but will not print the axis text nor plot any of the coordinates.
public void JapaneseCandleStick()
{
//GraphPane myPane = base.GraphPane;
GraphPane myPane = new GraphPane();
myPane.Title.Text = "Japanese Candlestick Chart Demo";
myPane.XAxis.Title.Text = "Trading Date";
myPane.YAxis.Title.Text = "Share Price, $US";
StockPointList spl = new StockPointList();
Random rand = new Random();
// First day is jan 1st
XDate xDate = new XDate(2006, 1, 1);
double open = 50.0;
for (int i = 0; i < 50; i++)
{
double x = xDate.XLDate;
double close = open + rand.NextDouble() * 10.0 - 5.0;
double hi = Math.Max(open, close) + rand.NextDouble() * 5.0;
double low = Math.Min(open, close) - rand.NextDouble() * 5.0;
StockPt pt = new StockPt(x, hi, low, open, close, 100000);
spl.Add(pt);
open = close;
// Advance one day
xDate.AddDays(1.0);
// but skip the weekends
if (XDate.XLDateToDayOfWeek(xDate.XLDate) == 6)
xDate.AddDays(2.0);
}
JapaneseCandleStickItem myCurve = myPane.AddJapaneseCandleStick("trades", spl);
myCurve.Stick.IsAutoSize = true;
myCurve.Stick.Color = Color.Blue;
// Use DateAsOrdinal to skip weekend gaps
myPane.XAxis.Type = AxisType.DateAsOrdinal;
// pretty it up a little
myPane.Chart.Fill = new Fill(Color.White, Color.LightGoldenrodYellow, 45.0f);
myPane.Fill = new Fill(Color.White, Color.FromArgb(220, 220, 255), 45.0f);
zedGraphControl1.AxisChange();
//base.ZedGraphControl.AxisChange();
}
What is wrong with the above and why cannot I see any text or see the plots? It all compiles without errors, hence the referencing and the ZedGraph implementation/referencing seems to be in order.
when you create an instance of Graphpane it must be referenced to zedGraphControl1, use the following line of code :
GraphPane myPane = zedGraphControl1.GraphPane;
& here's the output:

C# Chart use CustomLabels with scrollbar

I don't understand something. If i don't use the customlabels, the chart will use the default label. And then if I move the scrollbar , the chart size won't adjust. The Chart view maintain the original size.
But if I use this code to change the label at row 0. (other rows don't have this problem)
chart1.ChartAreas[0].AxisY2.CustomLabels.Add((i) ,
(i+1), (ntemp * 10).ToString(), 0, LabelMarkStyle.SideMark);
And Move the scrollbar, the chart View will be a little different for size. The chart will flicker, and I don't want it.
Thanks in advance.
Here is example
Random rand = new Random();
chart1.Series.Clear();
var series = chart1.Series.Add("My Series");
series.ChartType = SeriesChartType.RangeBar;
series.Color = Color.Black;
series.YAxisType = AxisType.Secondary;
for (int i = 10; i > 2; i--)
series.Points.AddXY(i, (rand.Next(3600, 7200)), (rand.Next(30000, 80000)));
var chartArea = chart1.ChartAreas[series.ChartArea];
chartArea.BorderDashStyle = ChartDashStyle.Solid; //最外圍的框框
chartArea.BorderWidth = 10;
chartArea.AxisY.Enabled = AxisEnabled.False;
chartArea.AxisY2.Enabled = AxisEnabled.True;
chartArea.AxisY2.LabelStyle.IntervalType = DateTimeIntervalType.Number;
chartArea.AxisY2.Interval = 3600;
chartArea.AxisY2.Minimum = 0;
chartArea.AxisY2.Maximum = 86400;
chartArea.AxisY2.ScaleView.Zoom(0, 3600 * 4);
for (int i = 0; i <= 24 * 6; i++)
{
int ntemp = i % 6;
if (ntemp != 0)
{
/*Problem Here !!*/
//chart1.ChartAreas[0].AxisY2.CustomLabels.Add((i) * 600, (i + 1) * 600, (ntemp * 10).ToString(), 0, LabelMarkStyle.Box);
}
}
chartArea.CursorY.AutoScroll = true;
chartArea.AxisY2.ScaleView.Zoomable = true;
chartArea.AxisY2.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
chartArea.AxisY2.ScrollBar.IsPositionedInside = false;
}
Well, I was intrigued about how and if this can be achieved with OxyPlot, and I think it can ...
Here's the code I've used, and here's a screenshot:
var model = new PlotModel("IntervalBarSeries") { LegendPlacement = LegendPlacement.Outside };
var temp_serie = new IntervalBarSeries
{
Title = "IntervalBarSeries 1",
FillColor = OxyColors.Black
};
var categoryAxis = new CategoryAxis
{
Position = AxisPosition.Left,
IsZoomEnabled = false, // No zoom on this axis
IsPanEnabled = false, // Right mouse move won't affect this axis
MajorGridlineStyle = LineStyle.Solid
,StartPosition = 1, EndPosition = 0 // This will reverse the order
};
var valueAxis = new LinearAxis(AxisPosition.Top)
{
MinimumPadding = 0.1, MaximumPadding = 0.1,
IsZoomEnabled = true,
MajorGridlineStyle = LineStyle.Solid,
MajorStep = 3600,
AbsoluteMinimum = 0
};
for (int i = 10; i > 2; i--)
{
temp_serie.Items.Add(new IntervalBarItem {
Start = rand.Next(3600, 7200),
End = rand.Next(30000, 80000)
});
categoryAxis.Labels.Add("Activity "+i);
}
model.Series.Add(temp_serie);
model.Axes.Add(categoryAxis);
model.Axes.Add(valueAxis);
MyPlotModel = model;
Now, I'm using MVVM and just binding to the plot model from my View with:
<oxy:Plot Model="{Binding MyPlotModel}"/>
But you can figure out how to do the same with WinForms once (if?) you decide to use OxyPlot and import it.
I'm assuming you're doing some work that is related to times, but your code obviously doesn't say so ... you could play around with the top header, and maybe set how to show the numbers (ATM, with no zoom, they overlap each other a bit. zooming with scroller solves that, but that's just because i've set the tick size to 3600 ... )

how to get a value and not the formula

I am trying to obtain the minimum value from a worksheet however when I generate the minimum and place it in a cell, and then extract that value I am getting the entire formula and not the double value in the cell.... what am I doing wrong? Below is my generate graph method.
Another thing, I would also like to delete the graph after I save it I have tried .delete() but that just threw and error, how do I go about doing that
private void GenerateGraph(Worksheet worksheet, int lastRow, int lastColumn, string filename)
{
string topLeft = ToCell(0, 0);
string bottomRight = ToCell(lastRow - 1, lastColumn - 1);
worksheet.get_Range(ToCell(0, 0), missing).Formula = "Max(B2:" + bottomRight + ")";
worksheet.get_Range(ToCell(0, 0), missing).FormulaHidden = true;
worksheet.get_Range(ToCell(0, 0), missing).Calculate();
Range range = (Range)worksheet.Cells[1,1];
//
//here is where my problem is, small is being given the formula from above
//
string small = (string)range.Value2;
double min = Convert.ToDouble(small);
worksheet.get_Range(ToCell(0,0),missing).Formula = "";
//Generates the graph
range = worksheet.get_Range(topLeft, bottomRight);
ChartObjects Xlchart = (ChartObjects)worksheet.ChartObjects(missing);
ChartObject chart = (ChartObject)Xlchart.Add(20, 160, 600, 500);
Excel.Chart myChart = chart.Chart;
myChart.SetSourceData(range, missing);
//sets the y axis
Axis axis = (Axis)myChart.Axes(XlAxisType.xlValue, XlAxisGroup.xlPrimary);
axis.MinimumScaleIsAuto = true;
axis.MaximumScaleIsAuto = true;
axis.HasTitle = true;
axis.AxisTitle.Text = "Measure (m)";
axis.CrossesAt = (int)(min-1);
//sets the x axis
Axis xAxis = (Axis)myChart.Axes(XlAxisType.xlCategory, XlAxisGroup.xlPrimary);
xAxis.HasTitle = true;
xAxis.AxisTitle.Text = "Position (m)";
//makes the graph a line graph
myChart.ChartType = XlChartType.xlXYScatterLinesNoMarkers;
//titles the graph
myChart.HasTitle = true;
myChart.ChartTitle.Text = "Profiles";
//saves the graph
myChart.Export(filename, "JPG", missing);
//
//here is where I would like to delete the graph
//
}
You need:
Formula = "=Max(B2:" + bottomRight + ")"
You were missing the equals sign in the formula.

Categories