# Plot associated curves with a color when data ordinates from a complex number

I have a list of data {{x1,c11}, {x1,c12}, {x2,c21},{x2,c22}, {x3,c31},{x3,c32}, {x4,c4}, {x5,c51},{x5,c52}, ...}, in which x is real value and c is complex value. For some x, there is only a c value, for example, {x4,c4} pair, while for the most x there are a pair of distinct c, e.g. {x2,c21},{x2,c22}.

I want to plot x versus the real and imaginary parts of c, respectively, and render the x-Re[c] and x-Im[c] curves with a same color for the associated Re[c] and Im[c]. In other words, in both x-Re[c] and x-Im[c] plots, there will be two curves, I need to show the 4 curves in two different colors with the same color means the values of Re[c] and Im[c] are from the same c.

For example, c21=Re[c21]+i*Im[c21] and c22=Re[c22]+i*Im[c22], the points {x2,Re[c21]} and {x2,Im[c21]} should be in a color, while the points {x2,Re[c22]} and {x2,Im[c22]} should use another color.

The key point of the question could be how to separate the interleaved data, in which most values of x have a pair of k but with some exceptions. I need a general method to handle such data with the above-mentioned features. Thank you very much!

Here is the sample data for testing.

test = ToExpression /@ Import["Documents\\testdata.csv"];
xci = test /. {x_, c_} -> {x, Im[c]};
xcr = test /. {x_, c_} -> {x, Re[c]};

{ListPlot[xci, PlotStyle -> Blue, PlotRange -> All, Frame -> True],
ListPlot[xcr, PlotStyle -> Red, PlotRange -> All, Frame -> True]}


Update: The problem can be converted to plot two curves in 3D with different colors. As can be seen, the two curves are well separated in the {Re[c], Im[c], x} space, thus this way might be easier.

xc3D = test /. {x_, c_} -> {Re[c], Im[c], x};
ListPointPlot3D[xc3D, PlotStyle -> Red, AxesLabel -> {cr, ci, x}]


• Please post your working minimal example about your description or post a picture of the expected result. Jan 23, 2022 at 4:29
• @cvgmt do you think the post in the present version is suitable to open? Thank you
– lxy
Jan 27, 2022 at 12:08

You may use FindClusters to separate the Complex curves. Then display as needed.

Using file in OP

test = ToExpression /@ Import[FileNameJoin[{\$HomeDirectory, "Downloads", "testdata.csv"}]];


FindClusters using the complex number of the pairs.

temp = FindClusters[Last@# -> # & /@ test];


The curves are separated as shown below.

ComplexListPlot[temp[[All, All, -1]]
, AspectRatio -> 1/GoldenRatio
, PlotRange -> All
]


Next format the curves' data to plot verses x values.

curves= Apply[Outer[List, {#}, ReIm@#2] &, temp, {2}];
curves= Transpose@Flatten[#, 1] & /@ curves;


Can ListPlot the ReIm verses the x values separately for each curve

Block[{i = 1}
, ListPlot[#
, PlotLegends -> {"Re", "Im"}
, PlotLabel -> StringTemplate["Curve"][i++]
, PlotRange -> All
] & /@ curves
]


Or each of real and imaginary jointly for all curves.

Block[{i = 1}
, ListPlot[#
, PlotLegends -> StringTemplate["Curve"] /@ Range@Length@curves
, PlotLabel -> Switch[i++, 1, "Real", 2, "Imaginary"]
, PlotRange -> All
] & /@ Transpose@curves
]


Hope this helps.

Let d be your data. Then

d1 = Cases[d, {x_, y_} /; Im[y] > -5]
d2 = Cases[d, {x_, y_} /; Im[y] < -5]
ListLinePlot[{Re[d1], Re[d2]}]


It happens that the Im[y] > -5 criterion works just fine for the data in the OP. In more complicated situations, a more complicated criterion will be needed, but the syntax remains.

P.S.

My answer concerns with the initial version of the question, which however has been updated recently. As the data has been changed quantitatively but not qualitatively, the same approach still applies by changing the threshold value and names of the variables.

• @CA Trevillian actually I was modifying my post when I saw yarchik's comment (which was removed however), after posted the revised version I saw her/his answer which did not follow the principle mentioned in OP. Please see the record and timestamp. Thank you
– lxy
Jan 23, 2022 at 2:59
• @CA Trevilliando you think the post in the present version is suitable to open? Thank you
– lxy
Jan 27, 2022 at 12:09
test2 = test /. Complex[a_, b_] :> {a, b};


1.

{xim, xre} = Transpose[Transpose /@
GatherBy[Reverse @* Thread /@ test2, Sign[.4 + First @ # ] &]];

Row[ListPlot[#, ImageSize -> 400, PlotRange -> All ] & /@ {xim, xre}, Spacer[20]]


2.

styleddata = Values @ GroupBy[test2, First,
Map[DeleteCases[Style[{_, -10}, _]]] @*
Transpose @*
MapIndexed[{x, y} |-> (Style[#, ColorData[97]@y[[1]]] & /@ x)] @*
SortBy[Last] @*

• Thank you, for method 1, I found the key is Thread, but what is @*, and what is the difference with @? I did not find the syntax about @* in the documentation.