0

I have a plot which is the output of a ParametricPlot command, and I want to save the data to a file, ideally with the columns x, y, parameter.

I'm aware of the methods in the answer to this question: Plot, extract data to a file, but I am having trouble adapting them to the parametric case - if I take only the first line of the Cases command, one coordinate seems to be missing, but taking all the lines, I have duplicate data, and I am not sure how the data are arranged.

Apologies if this is a stupid question, I am a Mathematica beginner.

EDIT 2: the simple, clean and robust solution posted by JimB in the comments solved my problem. It was indeed a stupid question.

EDIT: I originally posted a MWE derived from my code, and the answers I got solved the MWE. Unfortunately, my original code is still causing issues. The original MWE is at the end of this question.

This code generates the plot:

Gamma = 0.5; 
Beta = 1; 
f[w_, T_] := Exp[(-T)*I*w]/(1 + Beta*I*w); 
g[w_, T_] := Conjugate[1/f[w, T]] - Gamma*Exp[I*Arg[1/f[w, T]]]; 
h[w_, T_] := Conjugate[1/g[w, T]]; 
p = ParametricPlot[{Re[h[w, 1]], Im[h[w, 1]]}, {w, -Pi, 0}, 
   PlotRange -> {{-0.7, 2.1}, {0, 1.1}}]

This code extracts some of the data, but only the 3rd quadrant:

test1 = Cases[Normal[p], Line[pts_] :> pts, Infinity][[1]]

This code extracts all of the data, but out of order:

test2 = Reap[ParametricPlot[{Sow[{Re[h[w, 1]], Im[h[w, 1]]}]}, {w, -Pi, 0}, 
     PlotRange -> {{-0.7, 2.1}, {0, 1.1}}]]; 

This code gives an error about indices outside the range of the data:

pos = Append[Drop[Flatten[Position[p, Line]], -1], 1]
test3 = p[[Sequence @@ pos]]

Following is the original MWE

My codes is as follows:

k[w_] := Exp[(-I)*w]/(1 + I*w); 
p = ParametricPlot[{Re[k[w]], Im[k[w]]}, {w, -Pi, 0}, 
    PlotRange -> {{-0.7, 2.1}, {0, 1.1}}]; 
data = Cases[Normal[p], Line[pts_] :> pts, Infinity]; 
Export["data.txt", data, "Table"]

My second attempt is to use the technique in the answer to this question: Extract data from a Parametric2D plot. This is looking more hopeful, but the data is again in a weird order, I am not sure how to get it into a table.

data = Reap[
  ParametricPlot[{Sow[Re[k[w]]], Sow[Im[k[w]]]}, {w, -Pi, 
    0}, PlotRange -> {{-0.7, 2.1}, {0, 1.1}}]]
chaffdog
  • 125
  • 4
  • For me the first code seems to work fine, where the srgData[[1]] is the resulting table. The second could be midfield to data = Reap[ ParametricPlot[{Sow[{Re[k[w]], Im[k[w]]}]}, {w, -Pi, 0}, PlotRange -> {{-0.7, 2.1}, {0, 1.1}}]] and then data[[2,1]] is the table. – Andrzej Jun 16 '21 at 14:32
  • Apologies @Moo, I've edited it to fix that. – chaffdog Jun 16 '21 at 15:05
  • @Andrzej, you are right. It works fine. It seems that in constructing a MWE, I've accidentally made it work... looking into it now – chaffdog Jun 16 '21 at 15:13
  • 2
    Why not just generate a table of points? p = Table[{w, Re[k[w]], Im[k[w]]}, {w, -Pi, 0, Pi/500}]; p = Select[p, 0 <= #[[3]] <= 1.1 && -0.7 <= #[[2]] <= 2.1 &]; I know the "spacing" of the points is nicer with ParametricPlot but does that really matter for what you want to do? – JimB Jun 16 '21 at 15:23
  • I agree with Jim, especially if you're a beginner. Why not use something clean, robust and simple instead of a fragile hack? – Szabolcs Jun 16 '21 at 15:39
  • @JimB, yes, this is what I should do! I went down a total rabbit hole trying to do something that I thought would/should be easy... – chaffdog Jun 16 '21 at 15:39
  • @JimB I don't know if you want to post this as an answer so I can accept it? I know it isn't exactly an answer to the question that I asked, but it is definitely a good solution to the problem I had. – chaffdog Jun 16 '21 at 15:48
  • I'll post it as an answer. (I seem to be in a habit lately of providing "answers" to what I think should be the question rather than the original question.) – JimB Jun 16 '21 at 16:12
  • Seems like a helpful habit to be in! – chaffdog Jun 16 '21 at 16:14
  • (1) Note that Beta and Gamma are protected system symbols. Avoid starting your variable names with capitals. (2) Try test1 = Join @@ Cases[Normal[p]…] or Join @@ Rest@Cases[Normal[p]…]. You plot is divided at or near the axes because of mis-analyzed, potential discontinuities. Thus it has 3 lines, one of which is outside the PlotRange. Or generate the plot with Exclusions-> None to get just one line. – Michael E2 Jun 16 '21 at 21:04

2 Answers2

2

In this case, I would do as follows. Here is your plot:

k[w_] := Exp[(-I)*w]/(1 + I*w);
p = ParametricPlot[{Re[k[w]], Im[k[w]]}, {w, -Pi, 0}, 
  PlotRange -> {{-0.7, 2.1}, {0, 1.1}}];

This is the position of the line you are looking for in the form of a list:

Position[p, Line] // Flatten

(* {1, 1, 1, 3, 1, 2, 0} *)

One only needs to replace the figure 0 at the end of this list by 1 in order to point to the list staying under the Line, rather than the head Line:

pos = Append[Drop[Position[p, Line] // Flatten, -1], 1]

(* {1, 1, 1, 3, 1, 2, 1} *)

Now here is your data:

data = p[[Sequence @@ pos]]

You can export it in any form of your liking.

Have fun!

Edit: In your edited case do the following:

pos1 = Append[Drop[Position[p, Line][[2]], -1], 1];
pos2 = Append[Drop[Position[p, Line][[3]], -1], 1];
data = Join[p[[Sequence @@ pos1]], p[[Sequence @@ pos2]]];

Let us check:

ListPlot[data]

yields

enter image description here

as expected.

Have fun!

Alexei Boulbitch
  • 39,397
  • 2
  • 47
  • 96
  • Hi Alexei, thanks very much! This works well for the MWE I posted in the example. Sadly, I didn't realise that I had changed something important in the MWE, and my original issue is still not sorted. I'm going to update the question now. Very sorry for this. – chaffdog Jun 16 '21 at 15:27
  • Also, I don't really have any idea what "the line I'm looking for" is, could you explain a little? – chaffdog Jun 16 '21 at 15:27
  • 1
    Have a look at the edit. – Alexei Boulbitch Jun 16 '21 at 19:57
  • Cases[p, Line[p_] :> p, All][[1]] gives the complete list of points – Ulrich Neumann Jun 17 '21 at 08:13
  • @Ulrich Neumann In general, I also thought like this. However, if you do the following: lst = Cases[p, Line[p_] :> p, All][[1]]; ListPlot[lst] you will see the difference between the plot obtained like this and the original one. Only take care that p should be taken from the newly edited OP code. – Alexei Boulbitch Jun 17 '21 at 11:06
  • @chaffdog Please note that the capitaliuzed Beta and Gamma are reserved in Mma for Beta- and Gamma-functions. Their use in your code is an error. Use beta and gamma instead. – Alexei Boulbitch Jun 17 '21 at 11:10
1

You might consider just generating a table of points. The downside is that the spacing of the points might not be as optimal as what you get with harvesting the points from ParametricPlot.

Using your example with 500 points:

k[w_] := Exp[(-I)*w]/(1 + I*w);
p = Table[{w, Re[k[w]], Im[k[w]]}, {w, -Pi, 0, Pi/500}];
p = Select[p, 0 <= #[[3]] <= 1.1 && -0.7 <= #[[2]] <= 2.1 &];
ListPlot[p[[All, {2, 3}]], Joined -> True]

Plot of table of points

You might have to play with the number of points as using just 50 points might not be adequate for the function of interest. Here's what you get with your function and 50 points without connecting the points:

k[w_] := Exp[(-I)*w]/(1 + I*w);
p = Table[{w, Re[k[w]], Im[k[w]]}, {w, -Pi, 0, Pi/50}];
p = Select[p, 0 <= #[[3]] <= 1.1 && -0.7 <= #[[2]] <= 2.1 &];
ListPlot[p[[All, {2, 3}]], PlotStyle -> Red, PlotRangeClipping -> False]

Plot of table of points with just 50 points

JimB
  • 41,653
  • 3
  • 48
  • 106