The problem is a bit tricky, I will try to be as clear as possible. I have several lists (let's call them x, y, z and k), all of the same length, and where the i-th value of each list corresponds to a single observation (so for instance x[[3]], y[[3]], z[[3]] and k[[3]] are the values of four variables for the third observation). What I want to do is a scatter plot, where the x-axis reports the values of x and the y-axis the values of y. Now, for each pair (x[[i]], y[[i]]) I want a red dot if z[[i]] > k[[i]], and a black dot otherwise. Additional issue: for the first observations, the list k is empty, so I want to plot a red dot for such observations. Any idea on how is it possible to do it?
2 Answers
Here is an example with made up data:
Clear[y, z, k]
x = Range[20];
{y, z, k} = RandomInteger[{-10, 10}, {3, 20}];
ListPlot[
MapThread[Style[{#1, #2}, If[#3 > #4, Red, Black]] &, {x, y, z, k}],
PlotRange -> All,
PlotStyle -> PointSize[0.02]
]
For your second part ("Additional issue: for the first observations, the list k is empty, so I want to plot a red dot for such observations."), you should really provide a sample of your data. Any answer would depend on its precise structure.
-
-
$\begingroup$ For the last part you could just
PadLeft
the kkkkk... list with some non-number element e.g{}
to the same size as any of the the xxxxx... or yyyyy.... zzzzz... lists before transposing to {{x,y,z,{}},{x,y,z,{}},{x,y,z,k},{x,y,z,k}... etc}. Then change your style function to only apply if #4 is not{}
. $\endgroup$– flintyCommented May 27, 2020 at 14:33 -
$\begingroup$ Thank you for the added comment, your code actually worked nice as it is :) $\endgroup$ Commented May 27, 2020 at 19:57
-
$\begingroup$ I have an additional question. What if I would like to use different shapes instead of different colours? $\endgroup$ Commented Jun 5, 2020 at 9:21
-
Generate random data with first two values of k
missing.
SeedRandom[1234]
{x, y, z, k} =
ReplacePart[RandomReal[{0, 10}, {4, 20}], {{4, 1}, {4, 2}} -> Missing]
Just use Graphics
primitives to make the scatter plot.
Legended[Graphics[{AbsolutePointSize[
4], {If[#[[4]] === Missing || #[[3]] > #[[4]], Red, Black],
Point[#[[1 ;; 2]]]} & /@ Transpose[{x, y, z, k}]},
Frame -> True,
FrameLabel -> (Style[#, 14, Bold, Italic] & /@
{"x", "y"} /.
s_String :> Subscript[s, "i"]),
AspectRatio -> 1/GoldenRatio],
PointLegend[{Red, Black}, {"z" > "k", "z" <= "k"} /.
s_String :> Subscript[s, "i"]]]
EDIT: Alternatively, you get the same plot using GatherBy
with the criteria to generate two data sets.
plotData = #[[All, 1 ;; 2]] & /@
GatherBy[Transpose[{x, y, z, k}], #[[4]] === Missing || #[[3]] > #[[4]] &];
ListPlot[plotData,
PlotStyle -> {Red, Black},
Frame -> True,
FrameLabel -> (Style[#, 14, Bold, Italic] & /@
{"x", "y"} /.
s_String :> Subscript[s, "i"]),
PlotLegends -> {"z" > "k", "z" <= "k"} /.
s_String :> Subscript[s, "i"]]
-
$\begingroup$ I am sorry, I just notice I did not answer you. Thank you for your answer. I just have an additional question: what if I would like to do the same, but using different shapes instead of different colours? $\endgroup$ Commented Jun 7, 2020 at 12:12
-
$\begingroup$ Use the option
PlotMarkers
, e.g.,PlotMarkers -> Automatic
$\endgroup$ Commented Jun 7, 2020 at 15:24 -
$\begingroup$ Thank you! I cannot believe it was that easy, I was trying much more complicated stuff. $\endgroup$ Commented Jun 9, 2020 at 7:41
ListPlot
usingStyle[{x, y}, color]
. $\endgroup$