# LogPlot of the calculated data in For Loop in Mathematica

I have the following loop, for calculating a data for different values of inputs. How I can plot the result at the end of For loop? Its not matter if the plot is inside or outside the loop, I just want to plot the results.

Clear["Global*"];
b = 10^4;
s = b/2;
tx = ((2*RandomInteger[1, s])-1) + (I*((2*RandomInteger[1, s]) - 1));
For[i = 0, i <= 20, i++, snrdb = i;
snr = 10^(0.1*snrdb);
sd = 1/Sqrt[snr/2];
noise = 1/Sqrt[2]*(RandomReal[NormalDistribution[], {s, 1}] + I*RandomReal[NormalDistribution[], {s, 1}]);
y = tx + (sd*noise);
rx = Flatten[Sign[Re[y]]+I*Sign[Im[y]]];
error = Unitize[tx-rx];
ber = Total[error]/b;
Print["Total number of errors: ",Total[error]];
Print["Error rate: ",N[ber]];
]
LogPlot[{ber, 10^-4, 10^0}, {snrdb, 0, 20}]


Thanks All, Both techniques was useful. Sorry b is the same as bits, I made a mistake I corrected later. I need the continous line not discrete. how to change the y axis to be from 10^-4 to 10^1?

Note: for the purpose of accuracy I increased b to 10^6.

Clear["Global*"];
b = 10^6;
sym = b/2; tx = ((2*RandomInteger[1, sym]) -
1) + (I*((2*RandomInteger[1, sym]) - 1));
bervals = Reap[
For[i = 0, i < 21, i++, snrdb = i;
snr = 10^(0.1*snrdb);
sd = 1/Sqrt[snr/2];
noise = 1/
Sqrt[2]*(RandomReal[NormalDistribution[], {sym, 1}] +
I*RandomReal[NormalDistribution[], {sym, 1}]);
y = tx + (sd*noise); rx = Flatten[Sign[Re[y]] + I*Sign[Im[y]]];
error = Unitize[tx - rx];
Sow[ber = Total[error]/b];
]][[2, 1]];
ListLogPlot[bervals, Joined -> True]

-
You can change the y-axis using the PlotRange option –  Timothy Wofford Sep 9 '13 at 5:52
why the curve is not connected to x and y axis, I mean there is a gap , I want the curve to be reached both axises. –  barznjy Sep 9 '13 at 9:33
Hi Timothy Wofford, your code will result range y-axis from (1 to 1000), actually it should be from 10^-4 to 1 –  barznjy Sep 9 '13 at 10:04
I got it, it should be like this: bert = Append[bert, Total[error]/bits]; –  barznjy Sep 9 '13 at 10:06
when trying to plot I faced the following message error: How I can fix that? General::obspkg: PlotLegends is now obsolete. The legacy version being loaded may conflict with current Mathematica functionality. See the Compatibility Guide for updating information. PlotLegendsShadowBox is not a Graphics primitive or directive. << PlotLegends; ListLogPlot[{ber, bersim}, PlotRange -> {{0, 15}, {10^-4, 10^0}}, Joined -> True, AxesLabel -> {SNR, BER}, LabelStyle -> Directive[Blue, Bold], PlotLegend -> {Simulated, Analytical}, LegendPosition -> Automatic] –  barznjy Sep 9 '13 at 11:43

This seems like a good application for Reap and Sow.

If you have a value you would like to accumulate in a List you can Sow the value during execution of a loop:

vals = Reap[
For[i = 0, i <= 10, i++,
Sow[i]
]
]
vals[[2, 1]]

(*Output*)
(*{Null, {{0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100}}}*)
(*{0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100}*)


You then capture the Sow-ed results with Reap, outside of the loop. We must use Part to then extract the list of relevant values from val. Note: This technique is very useful in many other applications other than loops. The Reap and Sow combination can be used inside almost any evaluation to collect data.

Before we can apply this technique to your code, there are a few changes that need to be made. First, the symbol bits is never assigned a value. This is problematic if you wish to plot the values of ber. Let us assume bits has a value of 1 for now. Second, LogPlot is used to plot (continuous) functions, not discrete data. Here we will want to use ListLogPlot instead. Making these changes and introducing Reap and Sow:

b = 10^4;
s = b/2;
bits=1.0;
tx = ((2*RandomInteger[1, s]) - 1) + (I*((2*RandomInteger[1, s]) - 1));
bervals = Reap[
For[i = 0, i <= 20, i++, snrdb = i;
snr = 10^(0.1*snrdb);
sd = 1/Sqrt[snr/2];
noise =
1/Sqrt[2]*(RandomReal[NormalDistribution[], {s, 1}] +
I*RandomReal[NormalDistribution[], {s, 1}]);
y = tx + (sd*noise);
rx = Flatten[Sign[Re[y]] + I*Sign[Im[y]]];
error = Unitize[tx - rx];
Sow[ber = Total[error]/bits];
]][[2, 1]];
ListLogPlot[bervals]


Should generate a plot of the values of ber from inside the loop.

EDIT To answer a question in the comments about using Sow multiple times. Here is a simple example that plots y=x^2.

Block[{x, y, pts},
vals = Reap[Do[
Sow[x = i];
Sow[y = i^2];
, {i, 1, 10}]][[2, 1]];
pts = Partition[vals, 2];
ListPlot[pts, Joined -> True]
]


Notice the use of Partition at the end. We wouldn't have needed to do this had we used Sow on the list {x,y} instead. I only did it this way to show the use of multiple Sows.

-
Can I use Reap and Sow more than one time ? –  barznjy Sep 9 '13 at 11:55
@barznjy Yes, you can absolutely use Sow more than once. It's quite common to Sow multiple values and use then later. I'll edit post to give an example. –  leibs Sep 9 '13 at 19:32

LogPlot plots functions, ListLogPlot is used for plotting data points. You seem to be calculating a bunch of data points, and then immediately forgetting/overwriting them in the line I left below. You should add a couple of lines for remembering these values in a list.

bert = {};
For[i = 0, i <= 20, i++,
...
ber = Total[error]/bits;
...
bert = Append[bert, Total[error]];
]
ListLogPlot[bert, PlotRange -> {{0, 20}, Automatic}]
`
-
Thanks All, Both techniques was useful. Sorry b is the same as bits, I made a mistake I corrected later. I need the continous line not discrete. how to change the y axis to be from 10^-4 to 10^1? Note: for the purpose of accuracy I increased b to 10^6. –  barznjy Sep 9 '13 at 0:33