7 Stimmen

Adaptive Gitterlinien

Ich möchte Rasterlinien verwenden, um einen Effekt zu erzeugen, der Millimeterzeichenpapier in einem 2D-Diagramm, um zu zeigen, wie eine Funktion mit mehreren Variablen von einer Variablen abhängt. Die Skalen der verschiedenen Variablen sind sehr unterschiedlich, so dass mein naiver Ansatz (den ich zuvor verwendet habe) nicht zu funktionieren scheint.

Ein Beispiel dafür, was ich im Moment habe:

<< ErrorBarPlots`
Cmb[x_, y_, ex_, ey_] := {{N[x], N[y]}, ErrorBar[ex, ey]};
SetAttributes[Cmb, Listable];

ELP[x_, y_, ex_, ey_, name_] :=
 ErrorListPlot[
  Cmb[x, y, ex, ey],
  PlotRange -> FromTo[x, y],
  PlotLabel -> name,
  Joined -> True, Frame -> True, GridLines -> GetGrid,
  ImageSize -> {600}
 ]

Beide FromTo (ich möchte 5% Rand im Rahmen lassen) und GetGrid nicht genau so funktionieren, wie ich es möchte.

Auf einigen Achsen unterscheiden sich die Variablen um mehrere 10er Ordnungen. Und ich möchte nicht, dass eine Achse viele Ordnungen von 10 Gitterlinien mehr als andere hat. Und vor allem möchte ich, dass die Rasterlinien mit den Ticks übereinstimmen.

Beispielhafte Daten:

ELP[
  {4124961/25000000, 27573001/100000000, 9162729/25000000, 44635761/
   100000000, 15737089/25000000, 829921/1562500, 4405801/4000000, 
   23068809/25000000, 329386201/100000000, 58079641/100000000},
  {1/10, 1/5, 3/10, 2/5, 3/5, 1/2, 1/2, 1/2, 1/2, 1/2},
  {2031/(250000 Sqrt[10]), 5251/(500000 Sqrt[10]), 3027/(
   250000 Sqrt[10]), 6681/(500000 Sqrt[10]), 3967/(250000 Sqrt[10]), 
   911/(62500 Sqrt[10]), 2099/(100000 Sqrt[10]), 4803/(
   250000 Sqrt[10]), 18149/(500000 Sqrt[10]), 7621/(500000 Sqrt[10])},
  {1/2000, 1/1000, 3/2000, 1/500, 3/1000, 1/400, 1/400, 1/400, 1/400, 
   1/400},
  "T2, m"
]

Würde dazu führen:

enter image description here

Und mein naives GetGrid, das funktioniert in gewissem Sinne:

FromTo[x_, y_] := Module[{dx, dy},
   dx = (Max[x] - Min[x])*0.1;
   dy = (Max[y] - Min[y])*0.1;
   {{Min[x] - dx, Max[x] + dx}, {Min[y] - dy, Max[y] + dy}}];
GetGrid[min_, max_] := Module[{step, i},
  step = (max - min)/100;
  Table[
   {min + i*step,
    If[Equal[Mod[i, 10], 0],
     Directive[Gray, Thick, Opacity[0.5]],
     If[Equal[Mod[i, 5], 0],
      Directive[Gray, Opacity[0.5]],
      Directive[LightGray, Opacity[0.5]]
      ]]},
   {i, 1, 100}]
  ]

Frage

Wie lassen sich GridLines mit Zecken ausrichten?

edit: Mit

GetTicks[x_, y_] := Module[{dx, dy},
   dx = (Max[x] - Min[x])*0.1;
   dy = (Max[y] - Min[y])*0.1;
   {
    Min[x] - dx + Table[i*dx*1.2, {i, 1, 9}],
    Min[y] - dy + Table[i*dy*1.2, {i, 1, 9}]
    }];

ELP[x_, y_, ex_, ey_, name_] :=
 ErrorListPlot[
  Cmb[x, y, ex, ey],
  PlotRange -> FromTo[x, y],
  PlotLabel -> name,
  Joined -> True, Frame -> True, GridLines -> GetGrid, 
  FrameTicks -> GetTicks[x, y],
  ImageSize -> {600},
  AspectRatio -> 1
  ]

Ich kann bekommen:

enter image description here

Und das ist schon viel besser. Aber ich möchte das Gitter verschieben und nicht die Zecken.

bearbeiten: @Sjoerd C. de Vries

Ihre Lösung tut das, was ich archivieren wollte und funktioniert. Ich habe auch bemerkt, dass, wenn ich die ersten 5 Elemente der Beispieldaten nehme, das Diagramm so aussehen wird (die Elemente werden sortiert und die Regressionslinie wird hinzugefügt). enter image description here

Beachten Sie, dass das linke Element aus dem Raster fällt.

8voto

Sjoerd C. de Vries Punkte 15992

Verwenden Sie keine FrameTicks, sondern verschieben Sie das Raster korrekt. Dies ist ein erster Ansatz. Das Abendessen wartet.

getGrid[min_, max_] :=
 Module[{step, i},
  Print[{min, max}];
  step = 1/100;
  Table[
   {
    Floor[min, 0.1] + i*step,
    If[Equal[Mod[i, 10], 0], Directive[Gray, Thick, Opacity[0.5]],
     If[Equal[Mod[i, 5], 0], Directive[Gray, Opacity[0.5]],
      Directive[LightGray, Opacity[0.5]]
      ]
     ]
    },
   {i, 1, (Ceiling[max, 0.1] - Floor[min, 0.1])/step // Round}
   ]
  ]

Verwenden Sie ein AspectRatio, das für das Raster geeignet ist (wahrscheinlich das Verhältnis von x- und y-Bereichen)


Update nach dem Essen

Um es robuster für verschiedene Wertebereiche zu machen (gemäß Ihrem Kommentar), generiere ich die Ticks, die von ListPlot und meine Schritte darauf aufbauen:

getGrid[min_, max_] :=
 Module[{step, i,j},
  i = Cases[(Ticks /. 
       AbsoluteOptions[ListPlot[{{min, min}, {max, max}}], 
        Ticks])[[1]], {a_, ___, {_, AbsoluteThickness[0.25`]}} :> a];
  step = i[[2]] - i[[1]];
  Table[
   {
    i[[1]] + j*step/10,
    If[Equal[Mod[j, 10], 0], Directive[Gray, Thick, Opacity[0.5]],
     If[Equal[Mod[j, 5], 0], Directive[Gray, Opacity[0.5]],
      Directive[LightGray, Opacity[0.5]]
      ]
     ]
    },
   {j, 0, 10 Length[i]}
   ]
  ]

und das Seitenverhältnis zu ermitteln, das ein quadratisches Raster ergibt

getAspect[{{minX_, maxX_}, {minY_, maxY_}}] :=
 Module[{stepx, stepy, i, rx, ry},
   i = (Ticks /.AbsoluteOptions[ListPlot[{{minX, minY}, {maxX, maxY}}], Ticks]);
   rx = Cases[i[[1]], {a_, ___, {_, AbsoluteThickness[0.25`]}} :> a];
   stepx = rx[[2]] - rx[[1]];
   ry = Cases[i[[2]], {a_, ___, {_, AbsoluteThickness[0.25`]}} :> a];
   stepy = ry[[2]] - ry[[1]];
  ((maxY - minY)/stepy)/((maxX - minX)/stepx)
  ]

Test

ELP[x_, y_, ex_, ey_, name_] := 
 ErrorListPlot[Cmb[x, y, ex, ey], PlotLabel -> name, Joined -> True, 
  Frame -> True, GridLines -> getGrid, ImageSize -> {600}, 
  PlotRangePadding -> 0, AspectRatio -> getAspect[FromTo[x, y]], 
  PlotRange -> FromTo[x, y]]

ELP[{4124961/25000000, 27573001/100000000, 9162729/25000000, 
  44635761/100000000, 15737089/25000000, 829921/1562500, 
  4405801/4000000, 23068809/25000000, 329386201/100000000, 
  58079641/100000000}, {1/10, 1/5, 3/10, 2/5, 3/5, 1/2, 1/2, 1/2, 1/2,
   1/2}, {2031/(250000 Sqrt[10]), 5251/(500000 Sqrt[10]), 
  3027/(250000 Sqrt[10]), 1/100000 6681/(500000 Sqrt[10]), 
  3967/(250000 Sqrt[10]), 911/(62500 Sqrt[10]), 
  2099/(100000 Sqrt[10]), 4803/(250000 Sqrt[10]), 
  18149/(500000 Sqrt[10]), 7621/(500000 Sqrt[10])}, {1/2000, 1/1000, 
  3/2000, 1/500, 3/1000, 1/400, 1/400, 1/400, 1/400, 1/400}, "T2, m"]

enter image description here

Hier habe ich die y-Werte durch 20 geteilt und die x-Werte mit 10000 multipliziert, um zu zeigen, dass das Raster noch gut ist:

enter image description here


Letzte Aktualisierung (hoffe ich)

Dies verwendet FindDivisions als vorgeschlagen von belisarius . Ich habe jedoch, wie von Margus gefordert, die dreistufige Linienstruktur für Milimeterpapier verwendet:

getGrid[x_, y_] := 
 FindDivisions[{x, y}, {10, 2, 5}] /. {r_, s_, t_} :> 
   Join[
     {#, Directive[Gray, Thick, Opacity[0.5]]} & /@ r, 
     {#, Directive[Gray, Opacity[0.5]]} & /@ Union[Flatten[s]], 
     {#, Directive[LightGray, Opacity[0.5]]} & /@ Union[Flatten[t]]
   ]

y

getAspect[{{minX_, maxX_}, {minY_, maxY_}}] :=
 Module[{stepx, stepy},
  stepx = (#[[2]] - #[[1]]) &@FindDivisions[{minX, maxX}, 10];
  stepy = (#[[2]] - #[[1]]) &@FindDivisions[{minY, maxY}, 10];
 ((maxY - minY)/stepy)/((maxX - minX)/stepx)
  ]

WARNUNG!!!

Mir ist gerade aufgefallen, dass, wenn Sie das in MMA haben:

enter image description here

und Sie kopieren es nach SO (einfach ctrl-c ctrl-v), erhalten Sie dies:

(maxY - minY)/stepy/(maxX - minX)/stepx  

das ist nicht mathematisch gleichwertig . Es sollte dies sein:

((maxY - minY)*stepx)/((maxX - minX)*stepy)

Ich habe dies im obigen Code korrigiert, aber er wurde einen halben Tag lang falsch angezeigt, obwohl er auf meinem Computer korrekt funktioniert. Dachte, dass es gut wäre, dies zu erwähnen.

4voto

Dr. belisarius Punkte 59702

Ich denke FindDivisions[ ] ist das, worauf Sie aus sind:

FindDivisions[{xmin,xmax},n] findet eine Liste von etwa n "schönen" Zahlen, die das Intervall um xmin bis xmax in gleich große Teile unterteilen.

getTicks[x_, y_] := Flatten@FindDivisions[#, {10}] & /@ FromTo[x, y]
getGrid  [x_,y_] := FindDivisions[{x,y},{10,5}]/.
                          {r__,{s__}}:>Join@@{s,{#,{Gray,Thick}}&/@r} 

enter image description here

1voto

DavidC Punkte 3036

Wenn Sie die gleiche Funktion für FrameTicks y Gridlines werden sie sich aufstellen.

Ver FrameTicks y GridLines . Ich denke, Sie brauchen ImageMargins für die Grenze.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X