I am trying to move Main X and Y axes to the point of (0,0), like:
I tried to add 4 lines: (-10,0) to (10,0) and (0-10) to (0,10)
Series ttt = new Series("")
{
ChartType = SeriesChartType.Line,
Color = Color.Yellow,
BorderWidth = 5,
Font = new Font(Font.OriginalFontName, 20, FontStyle.Regular),
};
ttt.Points.AddXY(0,10);
//ttt.Points.AddXY(0, -10);
this.chart1.Series.Add(ttt);
Unfortunately, also the Main X and Y axis moved to -10,-10 like:
Setting Axis.Crossing does the job. But I'm not sure how to get double arrows on each axis, but the following code gives this effect
ttt.Points.AddXY(0, 10);
ttt.Points.AddXY(10, 0);
ttt.Points.AddXY(0, -10);
ttt.Points.AddXY(-10, 0);
ttt.Points.AddXY(0, 10);
this.chart1.Series.Add(ttt);
chart1.ChartAreas[0].AxisX.Crossing = 0; // <--- These two lines
chart1.ChartAreas[0].AxisY.Crossing = 0;
And you probably also want to set the axis min/max by
chart1.ChartAreas[0].AxisX.Maximum = 15;
chart1.ChartAreas[0].AxisX.Minimum = -15;
chart1.ChartAreas[0].AxisY.Maximum = 15;
chart1.ChartAreas[0].AxisY.Minimum = -15;
Related
How can I get x,y location of graph wher X and Y Axis starts (x,y location of point 0,0 in line chart)? This location is changable depending on text values on Y Axis probably.
Image is for illustrative purpose only.
How can I change the background color (currently is linear blue) of chart (I use PDFsharp NuGet package)?
Sample code:
ChartFrame chartFrame = new ChartFrame();
chartFrame.Location = new XPoint(xOffset, yLoc);
double chartHeight = Math.Min(250, (page.Height - yLoc - 10));
chartFrame.Size = new XSize((page.Width - (xOffset * 2)), chartHeight);
Chart chart = new Chart(ChartType.Line);
//chart.PlotArea.FillFormat.Color = XColor.FromArgb(255, 255, 255, 255); //plot background???
Series series = chart.SeriesCollection.AddSeries();
series.ChartType = ChartType.Line;
series.MarkerStyle = PdfSharp.Charting.MarkerStyle.None;
series.Name = "Horizontal"; //Series 1
series.MarkerBackgroundColor = XColor.FromArgb(255, 0, 0, 255); //blue
series.MarkerSize = 1;
series.Add(line1);
series = chart.SeriesCollection.AddSeries();
series.ChartType = ChartType.Line;
series.MarkerStyle = PdfSharp.Charting.MarkerStyle.None;
series.Name = "Vertical"; //Series 2
series.MarkerBackgroundColor = XColor.FromArgb(255, 0, 170, 0); //green
series.MarkerSize = 1;
series.Add(line2);
series = chart.SeriesCollection.AddSeries();
series.ChartType = ChartType.Line;
series.MarkerStyle = PdfSharp.Charting.MarkerStyle.None;
series.Name = "3D position"; //Series 3
series.MarkerBackgroundColor = XColor.FromArgb(255, 255, 0, 0); //red
series.MarkerSize = 1;
series.Add(line3);
chart.XAxis.MajorTickMark = TickMarkType.Outside;
chart.XAxis.Title.Caption = "No. Events"; //X-Axis
chart.YAxis.MajorTickMark = TickMarkType.Outside;
chart.YAxis.HasMajorGridlines = true;
double yOffset = ((maxYscale - minYscale) / 6);
if (yOffset < 0.01f)
yOffset = 0.01f;
chart.YAxis.MinimumScale = 0;
chart.YAxis.MaximumScale = Math.Round(Math.Round((maxYscale + yOffset), 3), 2);
double jump = Math.Round(yOffset, 2);
if (jump < 0.01f)
jump = 0.01f;
chart.YAxis.MajorTick = jump;
chart.YAxis.TickLabels.Format = "#0.00";
//chart.YAxis.HasMinorGridlines = true;
chart.YAxis.Title.Caption = "[m]"; //Y-Axis
chart.YAxis.HasMajorGridlines = true;
chart.PlotArea.LineFormat.Color = XColors.DarkGray;
chart.PlotArea.LineFormat.Width = 1;
chart.PlotArea.LineFormat.Visible = true;
chart.Legend.Docking = DockingType.Bottom;
chart.Legend.LineFormat.Visible = true;
XSeries xseries = chart.XValues.AddXSeries();
xseries.Add(eventLine);
chartFrame.Add(chart);
chartFrame.Draw(gfx);
Re:for X,Y location:
I made quick check for text length on YAxis and then according to that calculate new X,Y position.
Re: Background color:
These colours are hard-coded in the ChartFrame class (Draw method). So the nugget package for PDFSharp is not good you need to download the library source code.
Search for "XColor.FromArgb(0xFFD0DEEF)" and update the source code as needed.
I would like to draw a thick, transparent arrow with an arrowhead:
Here's the code that draws the arrow shaft. Notice that I have to offset the rectangle so the calculations are done from the midpoint of the rectangle.
private void DrawMovementArrow(bool color, double StartX, double StartY, double EndX, double EndY)
{
SolidColorBrush partiallyTransparentSolidColorBrush;
Rectangle myRectangle = new Rectangle();
// This will be replaced by piece size
int width = 35;
myRectangle.Width = width;
// Apparently necessary to offset the drawing of the path so that the point is in the center of the path; not the edge.
StartX -= width / 2;
EndX -= width / 2;
myRectangle.Height = Map.EuclideanDistance(StartX, StartY, EndX, EndY) ;
int angle = CalculateAngle(StartX , StartY , EndX , EndY );
// This selects the midpoint of edge of the rectangle to rotate around (weird system)
myRectangle.RenderTransformOrigin = new Point(0.5, 0);
angle = angle - 180;
RotateTransform rotateTransform1 = new RotateTransform(angle, 0 , 0 );
myRectangle.RenderTransform = rotateTransform1;
if (color)
partiallyTransparentSolidColorBrush = new SolidColorBrush(Colors.Blue);
else
partiallyTransparentSolidColorBrush = new SolidColorBrush(Colors.Red);
partiallyTransparentSolidColorBrush.Opacity = 0.4;
myRectangle.Fill = partiallyTransparentSolidColorBrush;
MovementCanvas1.Children.Clear();
MovementCanvas1.Children.Add(myRectangle);
Canvas.SetTop(myRectangle, StartY);
Canvas.SetLeft(myRectangle, StartX);
DrawArrowhead(color, EndX, EndY, angle + 90, width);
ShowUnitCenter(MovementArrowList[0]);
}
Note that this code selects a point in the middle of the edge to rotate the rectangle:
// This selects the midpoint of edge of the rectangle to rotate around (weird system)
myRectangle.RenderTransformOrigin = new Point(0.5, 0);
The problem is that I can't find that point with the arrowhead (triangle). Here's the code that draws the arrowhead:
public void DrawArrowhead(bool color, double x, double y, int angle, int width)
{
x += width /2 ;
width = width + (width / 2);
//Add the Polygon Element
Polygon myPolygon = new Polygon();
myPolygon.Opacity = 0.4;
if (color)
{
myPolygon.Fill = new SolidColorBrush(Colors.Blue);
myPolygon.Stroke = System.Windows.Media.Brushes.Blue;
}
else
{
myPolygon.Fill = new SolidColorBrush(Colors.Red);
myPolygon.Stroke = System.Windows.Media.Brushes.Red;
}
myPolygon.StrokeThickness = 0;
RotateTransform rotateTransform1 = new RotateTransform(angle, 0, 0);
myPolygon.RenderTransform = rotateTransform1;
// This selects the midpoint of edge of the triangle to rotate around (weird system)
myPolygon.RenderTransformOrigin = new Point(0.0, 0.5);
System.Windows.Point Point1 = new System.Windows.Point(0, 0);
System.Windows.Point Point2 = new System.Windows.Point(width / 2, width / 2);
System.Windows.Point Point3 = new System.Windows.Point(0,width);
PointCollection myPointCollection = new PointCollection();
myPointCollection.Add(Point1);
myPointCollection.Add(Point2);
myPointCollection.Add(Point3);
myPolygon.Points = myPointCollection;
MovementCanvas1.Children.Add(myPolygon);
Canvas.SetTop(myPolygon, y );
Canvas.SetLeft(myPolygon, x );
}
Note the myPointCollection that creates the triangle. The problem is that I've tried almost every conceivable combination of values in RenderTransformOrigin to find the point that (center bottom of triangle) to use for the rotation point. Nothing seems to be working out.
Can anybody suggest the correct value?
Edit Solved
I solved it by changing the points of the triangle. That was easier than trying to figure out the rotation point.
Changing the points that made up the triangle solved the problem. This was easier than trying to find the rotation point.
I want to be able to Map the Coordinates correctly so that a line is produced where my hand is on InkCanvas inas it moves.
I am currently using DepthSpacePoint like this:
DepthSpacePoint depthSpacePoint = this.coordinateMapper.MapCameraPointToDepthSpace(SkeletonPosition);
jointPoints[jointType] = new Point(depthSpacePoint.X, depthSpacePoint.Y);
and for my Mapping I am using this:
/*Use these floats * 1000 to let the user draw on the Canvas*/
float XSP = joints[JointType.HandRight].Position.X * 1000;
float YSP = joints[JointType.HandRight].Position.Y * 1000;
/*Current Point is = Right Hand Floats * 1000*/
currentPoint = new Point(XSP, YSP);
/*Always add 0.1 to the new point to let the user draw, this will technically give a continous line effect as it draws every time the hand moves at a difference of 0.1*/
nextPoint = new Point(XSP + 0.1, YSP + 0.1);
/*Feed the Points into the function, Call while Right hand is Tracked*/
this.Paint(currentPoint, nextPoint, PaintSurface);
Now current I can draw lines on the screen however it does not map correct to where my Right hand is and I have to multiply by 1000 to even see the lines on the canvas, what am I doing wrong? How do I correct this?
and this is my Paint Function:
/*Function to Paint/Draw on the Screen*/
public void Paint(Point startPoint, Point nextPoint, InkCanvas inkcanvas)
{
Line line = new Line(); //New Line
/*If Co-ords are equal to 0,0 reset them*/
if (currentPoint.X == 0 && currentPoint.Y == 0)
{
currentPoint = new Point();
currentPoint = startPoint;
}
/*Colour of the line*/
line.Stroke = Colour;
/*Thickness Level*/
line.StrokeThickness = 10;
/*Make it less Jagged and Smoother by changing the Stroke Points*/
line.StrokeDashCap = PenLineCap.Round;
line.StrokeStartLineCap = PenLineCap.Round;
line.StrokeEndLineCap = PenLineCap.Round;
line.StrokeLineJoin = PenLineJoin.Round;
/*Where to Draw the Line in terms of X and Y Positions*/
line.X1 = currentPoint.X;
line.Y1 = currentPoint.Y;
line.X2 = nextPoint.X;
line.Y2 = nextPoint.Y;
/*Current Point = nextPoint*/
currentPoint = nextPoint;
/*Add The Line*/
inkcanvas.Children.Add(line);
}
I figured it out, turns out I can simply just use colour space point to record the position of the the right hand then call it again in a new function to determine the drawing point of the line.
Recording the CSP:
ColorSpacePoint CSP = this.coordinateMapper.MapCameraPointToColorSpace(Joints[JointType.HandRight]);
And then the edited function:
/*Function to Paint/Draw on the Screen*/
public void Paint(ColorSpacePoint Position, InkCanvas inkcanvas)
{
Line line = new Line(); //New Line
/*If Co-ords are equal to 0,0 reset them*/
if (Position.X == 0 && Position.Y == 0)
{
NextPoint = Position
}
/*Colour of the line*/
line.Stroke = Colour;
/*Thickness Level*/
line.StrokeThickness = 10;
/*Make it less Jagged and Smoother by changing the Stroke Points*/
line.StrokeDashCap = PenLineCap.Round;
line.StrokeStartLineCap = PenLineCap.Round;
line.StrokeEndLineCap = PenLineCap.Round;
line.StrokeLineJoin = PenLineJoin.Round;
/*Where to Draw the Line in terms of X and Y Positions*/
line.X1 = Position.X;
line.Y1 = Position.Y;
line.X2 = Position.X + 0.01;
line.Y2 = Position.Y + 0.01;
/*Add The Line after Scaling*/
Inkcanvas.SetLeft(line , Position.X - line.Width / 2);
Ink canvas.SetTop(line, Position.Y - line.Height / 2);
inkcanvas.Children.Add(line);
}
This will draw small lines wherever the users right hand is but instead of drawing a lot of small lines to form a big line I decided to use ellipses like so:
public void DrawPoint(ColorSpacePoint point)
{
// Create an ellipse.
Ellipse ellipse = new Ellipse
{
Width = 20,
Height = 20,
Fill = Brushes.Red
};
// Position the ellipse according to the point's coordinates.
Canvas.SetLeft(ellipse, point.X - ellipse.Width / 2);
Canvas.SetTop(ellipse, point.Y - ellipse.Height / 2);
// Add the ellipse to the canvas.
canvas.Children.Add(ellipse);
}
I want to draw a text using Graphic.DrawText method in a specific position. Suppose for example I need to draw my text giving the following bounds:
X = 10;
Y = 10;
Width = 100;
Height = 100;
I would expect that the left-most point of my string will be at 10, but this is the result if I add also a vertical line at X = 10:
g.DrawLine(Pen, new Point(10, 10), new Point(10, 100));
g.DrawString("Hello", Font, Color, new Rectangle(10, 10, 100, 100), Format);
As you can see my text seems shifted, it is not in correspondence of the line, which is at X = 10.
Why? How can I fix this problem?
I'm using ZedGraph in my project and its awesome! But there is still one thing I can't figure out. Im looking for some possibility of plotting description of LineItem directly in chart, like on fig.:
http://www.imagesup.net/?di=113548312290
I tried to use TextObj, but still I have a problem correctly calculate the angle, it doesnt correspond to the slope of line. Can anyone tell my whats wrong? PS: maybe this could be caused by different ranges of X- and Y-Axis, or different length of these axes on the screen?
PointPair ptA = new PointPair(0, 100);
PointPair ptB = new PointPair(100, 0);
PointPairList ppl = new PointPairList();
ppl.Add(ptA);
ppl.Add(ptB);
LineItem myCurve = zedGraphControl1.GraphPane.AddCurve(string.Empty, ppl, Color.Red, SymbolType.Circle);
// centre of line
PointPair pt = new PointPair(0.5 * (ptA.X + ptB.X), 0.5 * (ptA.Y + ptB.Y));
TextObj text = new TextObj("desc", pt.X, pt.Y, CoordType.AxisXYScale, AlignH.Center, AlignV.Center);
text.ZOrder = ZOrder.A_InFront;
double dX = ptB.X - ptA.X;
double dY = ptB.Y - ptA.Y;
float alfa = (float)(Math.Atan2(dY, dX) * (180.0 / Math.PI));
text.FontSpec.Angle = alfa;
zedGraphControl1.GraphPane.GraphObjList.Add(text);
zedGraphControl1.AxisChange();
zedGraphControl1.Invalidate();
zedGraphControl1.Refresh();
// Call this method from the Form_Load method, passing your ZedGraphControl
public void CreateChart( ZedGraphControl zgc )
{
GraphPane myPane = zgc.GraphPane;
// Set the titles and axis labels
myPane.Title.Text = "Demo of Labeled Points";
myPane.XAxis.Title.Text = "Time, Seconds";
myPane.YAxis.Title.Text = "Pressure, Psia";
// Build a PointPairList with points based on Sine wave
PointPairList list = new PointPairList();
const int count = 15;
for ( int i = 0; i < count; i++ )
{
double x = i + 1;
double y = 21.1 * ( 1.0 + Math.Sin( (double)i * 0.15 ) );
list.Add( x, y );
}
// Hide the legend
myPane.Legend.IsVisible = false;
// Add a curve
LineItem curve = myPane.AddCurve( "label", list, Color.Red, SymbolType.Circle );
curve.Line.Width = 2.0F;
curve.Line.IsAntiAlias = true;
curve.Symbol.Fill = new Fill( Color.White );
curve.Symbol.Size = 7;
// Fill the axis background with a gradient
myPane.Chart.Fill = new Fill( Color.White, Color.FromArgb( 255, Color.ForestGreen ), 45.0F );
// Offset Y space between point and label
// NOTE: This offset is in Y scale units, so it depends on your actual data
const double offset = 1.0;
// Loop to add text labels to the points
for ( int i = 0; i < count; i++ )
{
// Get the pointpair
PointPair pt = curve.Points[i];
// Create a text label from the Y data value
TextObj text = new TextObj( pt.Y.ToString( "f2" ), pt.X, pt.Y + offset,
CoordType.AxisXYScale, AlignH.Left, AlignV.Center );
text.ZOrder = ZOrder.A_InFront;
// Hide the border and the fill
text.FontSpec.Border.IsVisible = false;
text.FontSpec.Fill.IsVisible = false;
//text.FontSpec.Fill = new Fill( Color.FromArgb( 100, Color.White ) );
// Rotate the text to 90 degrees
text.FontSpec.Angle = 90;
myPane.GraphObjList.Add( text );
}
// Leave some extra space on top for the labels to fit within the chart rect
myPane.YAxis.Scale.MaxGrace = 0.2;
// Calculate the Axis Scale Ranges
zgc.AxisChange();
}
Source: http://zedgraph.dariowiz.com/index9769.html?title=Point_Label_Demo
I have the same issue. Here's a partial solution I worked up in VB; should be easy enough to translate to C#:
' Calc deltas for x and y
Dim dX As Double = ptB.X - ptA.X
Dim dY As Double = ptB.Y - ptA.Y
' compensate delta x for graph resizing, which affects line slopes
Dim resizeCompensation As Double = 1.0 / (myPane.XAxis.Scale.Max - myPane.XAxis.Scale.Min)
dX = dX * resizeCompensation
' now calculate angle
Dim alfa As Double = Math.Atan2(dY, dX) * (180.0 / Math.PI)
text.FontSpec.Angle = alfa
While the above worked well enough for my purposes, a more comprehensive solution might be had here:
http://sourceforge.net/p/zedgraph/discussion/392232/thread/0d261bc7/