Ich möchte gerne meine Daten (z.B. Antennendiagramm) als Polardiagramm darstellen.
Da es für tChart tPolarseries gibt, war ich hoffnungsvoll.Ich habe dazu aber eine Menge ungelöster Probleme:
(1.) Wenn ich Daten polar darstelle, möchte ich auch ein polares Koordinatengitter haben, mit Winkel-Gitterlinien, die vom Ursprung radial nach außen laufen und Radius-Gitterlinien, die als Kreise um den Ursprung verlaufen.
(2.) Die vertikale(x=0) Achse und die horizontale (y=0)Achse sollten durch den Ursprung verlaufen.
3. Wenn (1.) und (2.) ohne Riesenaufwand machbar sind, bin ich schon ziemlich glücklich. Bei Polardiagrammen benutzt man aber häufig einen logarithmischen Maßstab. Das erfordert wohl, dass die x- und y-Achse jeweils aus zwei Achsen bestehen, da sonst die Achsen den Nullpunkt enthalten müssten und Log(0) gibt immer seltsame Ergebnisse.
Ein Beispiel für so ein Diagramm ist
http://commons.wikimedia.org/wiki/File: ... esonse.png
Hat jemand schonmal sowas gemacht?
Vielen dank!
Wichard
Polardiagramm
Re: Polardiagramm
Also "offiziell" geht das nicht. Allerdings sind die Haken und Ösen vorhanden, um sowas einbauen zu können. Ich habe mal ein ternäres Koordinatensystem mit TAChart gemacht (http://forum.lazarus.freepascal.org/ind ... l#msg93141), ähnlich müsste es auch hier funktionieren.
Re: Polardiagramm
Ich hab' jetzt etwas mit diesem Thema herumgespielt. Mit diesen beiden Prozeduren kannst du das runde Koordinatensystem eines Polardiagramms zeichnen:
PreparePolarAxes rufst du auf, nachdem deine Daten geladen sind und du weißt, wie groß der maximale Radiuswert ist. Den brauchst du als Parameter AMax in dieser Prozedur. Damit werden die x- und y-Achsen auf gleichen Wertebereich eingestellt und insgesamt komplett ausgeblendet.
DrawPolarAxes wird im OnAfterDrawBackwall-Ereignis des Chart aufgerufen. Zu diesem Zeitpunkt sind die Daten noch nicht ausgegeben - es würde sich auch OnAfterPaint anbieten, aber damit würden die Achsenkreise über die Datenkurven gezeichnet und in der hier gezeigten Implementierung komplett übermalt, weil das Hintergrundrechteck mit eingefärbt wird. DrawPolarAxes erhält als Parameter wieder den maximalen Radius und den Abstand der Kreise. Die komplette Zeichenausgabe ist etwas ungewohnt ("Chart.Drawer"), weil TAChart eine Zwischenschicht für die Ausgabe eingeführt hat, so dass man verschiedene Ausgabe"geräte" (BGRABitmap, Vektorformate, Drucker) mit demselben Code ansprechen kann.
Mit den folgenden Daten und einem Standard-Chart mit zwei PolarSeries konnte ich das beigefügte Diagramm erzeugen:
Code: Alles auswählen
uses
TAChartUtils, TAGeometry;
procedure PreparePolarAxes(AChart: TChart; AMax: Double);
var
ex: TDoubleRect;
begin
ex.a.x := -AMax;
ex.a.y := -AMax;
ex.b.x := AMax;
ex.b.y := AMax;
with AChart do begin
Extent.FixTo(ex);
Proportional := true;
Frame.Visible := false;
with LeftAxis do begin
AxisPen.Visible := false;
Grid.Visible := false;
PositionUnits := cuGraph;
Marks.Visible := false;
end;
with BottomAxis do begin
AxisPen.Visible := false;
Grid.Visible := false;
PositionUnits := cuGraph;
Marks.Visible := false;
end;
end;
end;
procedure DrawPolarAxes(AChart: TChart; AMax, ADelta: Double);
var
r, theta: Double;
P1, P2: TPoint;
i, h, w: Integer;
s: String;
begin
with AChart do begin
// Hintergrund
Drawer.SetBrushParams(bsSolid, Color);
Drawer.FillRect(0, 0, Width, Height);
// Gradlinien
Drawer.SetBrushParams(bsClear, clNone);
Drawer.SetPenParams(psDot, clGray);
for i:=0 to 5 do begin
theta := i * pi/6;
P1 := GraphToImage(DoublePoint(AMax*sin(theta), AMax*cos(theta)));
P2 := GraphToImage(DoublePoint(-AMax*sin(theta), -AMax*cos(theta)));
Drawer.MoveTo(P1);
Drawer.Lineto(P2);
end;
// Kreise
r := ADelta;
while r <= AMax do begin
P1 := GraphToImage(DoublePoint(-r, -r));
P2 := GraphToImage(DoublePoint(+r, +r));
Drawer.SetPenParams(psDot, clGray);
Drawer.SetBrushParams(bsClear, clNone);
Drawer.Ellipse(P1.x, P1.y, P2.x, P2.y);
r := r + ADelta;
end;
// Achsenbeschriftung
Drawer.Font := BottomAxis.Marks.LabelFont;
h := Drawer.TextExtent('0').y;
r := 0;
while r <= AMax do begin
s := FloatToStr(r);
w := Drawer.TextExtent(s).x;
P1 := GraphToImage(DoublePoint(0, r));
Drawer.TextOut.Pos(P1.X - w div 2, P1.y - h div 2).Text(s).Done;
r := r + ADelta;
end;
end;
end;
DrawPolarAxes wird im OnAfterDrawBackwall-Ereignis des Chart aufgerufen. Zu diesem Zeitpunkt sind die Daten noch nicht ausgegeben - es würde sich auch OnAfterPaint anbieten, aber damit würden die Achsenkreise über die Datenkurven gezeichnet und in der hier gezeigten Implementierung komplett übermalt, weil das Hintergrundrechteck mit eingefärbt wird. DrawPolarAxes erhält als Parameter wieder den maximalen Radius und den Abstand der Kreise. Die komplette Zeichenausgabe ist etwas ungewohnt ("Chart.Drawer"), weil TAChart eine Zwischenschicht für die Ausgabe eingeführt hat, so dass man verschiedene Ausgabe"geräte" (BGRABitmap, Vektorformate, Drucker) mit demselben Code ansprechen kann.
Mit den folgenden Daten und einem Standard-Chart mit zwei PolarSeries konnte ich das beigefügte Diagramm erzeugen:
Code: Alles auswählen
procedure TForm1.FormCreate(Sender: TObject);
var
i: Integer;
phi: Double;
begin
for i:=0 to 360 do begin
phi := i/180 * pi;
Chart1PolarSeries1.AddXY(phi, sqr(sin(phi)));
Chart1PolarSeries2.AddXY(phi, sqr(sin(phi)) - 1/4*sqr(cos(2*phi)));
end;
PreparePolarAxes(Chart1, 1.0);
end;
procedure TForm1.Chart1AfterDrawBackWall(ASender: TChart; ACanvas: TCanvas;
const ARect: TRect);
begin
DrawPolarAxes(Chart1, 1.0, 0.2);
end;
Re: Polardiagramm
Falls das hier noch interessant ist: TPolarSeries ist bisher abgestürzt, wenn man die Legende verwendet hat. Dies ist nun behoben und wird in Lazarus 1.2 enthalten sein.