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?

  • 1
    $\begingroup$ Hint: You can style individual points in ListPlot using Style[{x, y}, color]. $\endgroup$
    – C. E.
    May 27 '20 at 14:16
  • $\begingroup$ That is very helpful, I will have a try with that. Thank you. $\endgroup$ May 27 '20 at 14:19

Here is an example with made up data:

Clear[y, z, k]
x = Range[20];
{y, z, k} = RandomInteger[{-10, 10}, {3, 20}];

  MapThread[Style[{#1, #2}, If[#3 > #4, Red, Black]] &, {x, y, z, k}],
  PlotRange -> All,
  PlotStyle -> PointSize[0.02]

formatted points

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$ That is perfect, thank you! $\endgroup$ May 27 '20 at 14:30
  • $\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$
    – flinty
    May 27 '20 at 14:33
  • $\begingroup$ Thank you for the added comment, your code actually worked nice as it is :) $\endgroup$ May 27 '20 at 19:57
  • $\begingroup$ I have an additional question. What if I would like to use different shapes instead of different colours? $\endgroup$ Jun 5 '20 at 9:21
  • $\begingroup$ @MarcoB can you help me? $\endgroup$ Jun 7 '20 at 12:11

Generate random data with first two values of k missing.


{x, y, z, k} = 
 ReplacePart[RandomReal[{0, 10}, {4, 20}], {{4, 1}, {4, 2}} -> Missing]

Just use Graphics primitives to make the scatter plot.

    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"]]]

enter image description here

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]] &];

 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$ Jun 7 '20 at 12:12
  • $\begingroup$ Use the option PlotMarkers, e.g., PlotMarkers -> Automatic $\endgroup$
    – Bob Hanlon
    Jun 7 '20 at 15:24
  • $\begingroup$ Thank you! I cannot believe it was that easy, I was trying much more complicated stuff. $\endgroup$ Jun 9 '20 at 7:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.