1
$\begingroup$

I have several sets of data, and each set of data has a different scale (i.e., a different range of function values). I wish to plot each data set separately. I can do this using Table, ListPlot, and Grid:

(* Generate sample data for the purpose of this minimal working example. *)
xVals = N /@ Range[0, 5 Pi, Pi/100];
data = {Map[{#, 3.0*Sin[#]} &, xVals], (* data with "small" maximum y-value *)
   Map[{#, 10.0*Sin[# + Pi/10]} &, xVals], (* data with "small" maximum y-value *)
   Map[{#, 300.0*Cos[#]} &, xVals] (* data with "large" maximum y-value *)
   };

(* Find maximum y-value of each set of data. *)
dataMaxes = Map[Max[#[[All, 2]]] &, data];
Print["dataMaxes = ", dataMaxes];

(* ListPlot each set of data separately (i.e., data[[i]] where i is 1, 2, or 3);
use Grid[] to display the plots side by side. *)
Grid[{
  Table[
   ListPlot[data[[i]], Joined -> True, Frame -> True, 
    FrameLabel -> {"x", "y"},
    PlotRange -> All
    ]
   , {i, 1, Length[data]}]
  }]

dataMaxes = {3.,10.,300.}

plots without conditional PlotRange

In the code above, I set PlotRange -> All inside ListPlot. But suppose I wish to set PlotRange conditionally.

Specifically, I wish to set PlotRange -> 50.0 when the maximum y-value is greater than or equal to 50.0, and PlotRange -> All otherwise.

I thought I could accomplish this by using an If statement like If[dataMaxes[[i]] >= 50, 50.0, All]. But the following code generates an error:

(* METHOD 1: gives error *)
(* If dataMaxes[[i]] >= 50.0, use PlotRange -> 50.0; otherwise, use PlotRange -> All. *)
Grid[{
  Table[
   ListPlot[data[[i]], Joined -> True, Frame -> True, 
    FrameLabel -> {"x", "y"},
    PlotRange -> If[dataMaxes[[i]] >= 50, 50.0, All]
    ]
   , {i, 1, Length[data]}]
  }]

Flatten::normal: Nonatomic expression expected at position 1 in Flatten[$Failed].

I thought that this error may have to do with placing the If statement directly in the option value for PlotRange, so I tried instead determining the option value before calling ListPlot. The following two methods work well:

(* METHOD 2: works *)
Grid[{
  Table[
   myPlotRange = If[dataMaxes[[i]] >= 50, 50.0, All];
   ListPlot[data[[i]], Joined -> True, Frame -> True, 
    FrameLabel -> {"x", "y"},
    PlotRange -> myPlotRange
    ]
   , {i, 1, Length[data]}]
  }]

method two output

(* METHOD 3: works *)
myPlotRanges = Map[If[# >= 50, 50.0, All] &, dataMaxes];
Grid[{
  Table[
   ListPlot[data[[i]], Joined -> True, Frame -> True, 
    FrameLabel -> {"x", "y"},
    PlotRange -> myPlotRanges[[i]]
    ]
   , {i, 1, Length[data]}]
  }]

method three output

Why is it that Method 1 fails, but Methods 2 and 3 work? PlotRange has the attributes Protected and ReadProtected, but nothing else (including HoldAll):

Attributes[PlotRange]

{Protected, ReadProtected}

$\endgroup$
2
  • 2
    $\begingroup$ Method 1 gives me no error in 13.2.1 $\endgroup$
    – Michael E2
    Commented May 26, 2023 at 21:42
  • $\begingroup$ The attributes of ListPlot are the governing ones, not those of PlotRange. However, they're not the issue. (Well, there isn't issue when I test, as I said.) $\endgroup$
    – Michael E2
    Commented May 26, 2023 at 21:45

1 Answer 1

3
$\begingroup$

I do not know if you know this or not, but with Table there is a trick where you can assign something to variable, followed by ; and then use this variable in the rest of Table. This variable will not show up in the Table output. Actually any code before the last ; in the Table will not show up.

So you can simply do

dataMaxes = Map[Max[#[[All, 2]]] &, data];
Grid[{Table[z = If[dataMaxes[[i]] >= 50, 50.0, All]; 
   ListPlot[data[[i]], 
            Joined -> True, 
            Frame -> True, 
            FrameLabel -> {"x", "y"}, 
            PlotRange -> z
           ], {i, 1, Length[data]}
        ]
      }
    ]

Or you can get rid of dataMaxes if you do not needed anywhere else, and just do

Grid[{Table[z = If[Max[data[[i, All, 2]]] >= 50, 50.0, All]; 
   ListPlot[data[[i]], 
           Joined -> True, 
           Frame -> True, 
           FrameLabel -> {"x", "y"}, 
           PlotRange -> z
         ], {i, 1, Length[data]}
      ]
     }
    ]

Mathematica graphics

I will try to comment on why the other ones did not work soon. but For me, the above is the simplest solution.

Update

I just tried your Method 1 which you say gives error, but it worked for me. I am using V 13.2.1. So I do not know why it did not work for you.

Mathematica graphics

ps. The reason this trick works, is nothing really special. Table like Do and For and any other command in Mathematica, is actually a Function.

And as we all know, in Mathematica the output of function (its final return value) is the last expression which should not have ; at the end.

Table is a function which returns the last expression after the last ;. Its arguments are the range specifications you give {i, 1, Length[data]}

So a Table is really like this

 Table[code;morecode; finalResultWhichDependsOnTheIndexI,{i,1,10}] 

so you can add code inside Table to help simplify things without it showing up in final result.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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