\n```\n:::\n:::\n\n\nNow, set up the loop to use these variables and generate outputs. Notice that we use `for z in Z_levels` - this is a clever trick of the looping method, where `z` simply iterates over the values of `Z_levels` without having to specify the index value (e.g. no use of `Z_levels[i]` etc).\n\nThe significant BIG thing here is the LogisticGrowth function which allows us to set things like the carrying capacity (K) of the resources. Here we use it to define custom values of the K paramter for carrying capacity, drawing on the values in the `K_levels` above. Here, `pg` stands for Producer Growth function, and the paramter set in the food web is K.\n\nNote too our use of `println` and the values of `Z` and `K` to produce an informative _break_ between each combination.\n\n::: {.callout-note icon=false}\n\nCan you guess what increasing K will do to the biomass and richness of the community at equilibrium? How about Z? Will higher Z make things more or less stable?\n:::\n\n::: {#62075ef2 .cell execution_count=4}\n``` {.julia .cell-code}\nfor z in Z_levels\n for k in K_levels\n\n println(\" ***> This is iteration with Z = $z and K = $k\\n\")\n\n # Define the food web\n fw = Foodweb(:niche; S = S, C = C)\n # specify the K value of the producer growth function\n\n B0 = rand(S)\n # specify model to simulate logistic growth as well as BM ratio\n params = default_model(fw, BodyMass(; Z = z), LogisticGrowth(; K = k))\n \n # number of timestamps\n t = 300\n\n out = simulate(params, B0, t)\n\n # calculate metrics\n fin_rich = richness(out)\n fin_biomass = total_biomass(out)\n s_div = shannon_diversity(out)\n\n push!(df_collect, [z, k, fin_rich, fin_biomass, s_div])\n end\nend\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n ***> This is iteration with Z = 0.1 and K = 0.1\n\n ***> This is iteration with Z = 0.1 and K = 1.0\n\n ***> This is iteration with Z = 0.1 and K = 10.0\n\n ***> This is iteration with Z = 0.1 and K = 100.0\n\n ***> This is iteration with Z = 1.0 and K = 0.1\n\n ***> This is iteration with Z = 1.0 and K = 1.0\n\n ***> This is iteration with Z = 1.0 and K = 10.0\n\n ***> This is iteration with Z = 1.0 and K = 100.0\n\n ***> This is iteration with Z = 10.0 and K = 0.1\n\n ***> This is iteration with Z = 10.0 and K = 1.0\n\n ***> This is iteration with Z = 10.0 and K = 10.0\n\n ***> This is iteration with Z = 10.0 and K = 100.0\n\n ***> This is iteration with Z = 100.0 and K = 0.1\n\n ***> This is iteration with Z = 100.0 and K = 1.0\n\n ***> This is iteration with Z = 100.0 and K = 10.0\n\n ***> This is iteration with Z = 100.0 and K = 100.0\n\n```\n:::\n:::\n\n\nWonderful. Now we are in a position to learn about two new plotting methods. First, let's look at the data frame we've created.\n\n::: {#85639f0b .cell execution_count=5}\n``` {.julia .cell-code}\ndf_collect\n```\n\n::: {.cell-output .cell-output-display execution_count=6}\n```{=html}\n
\n```\n:::\n:::\n\n\n#### Visualising the experiment\n\nOne option here is to plot one of our `Final` Objects as the response variable against the valuse of Z and K. In R, we'd use ggplot2. Here we'll use `StatsPlots` as we learned about in Tutorial 5. Can you make this work in the regular `Plots` syntax?\n\nLet's first look at a single plot of stability\n\n::: {#9159766f .cell execution_count=6}\n``` {.julia .cell-code}\n@df df_collect plot(:K, [:FinalStability], group = :Z, \n ylabel = \"Stabilty\", \n\txlabel = \"Karrying Kapacity\",\n seriestype = [:scatter, :line],\n legend = false)\n```\n:::\n\n\nNow some new ploting tricks... 3 plots in a layout.\n\n::: {#50bb5a5c .cell execution_count=7}\n``` {.julia .cell-code}\np1 = @df df_collect plot(:K, [:FinalStability], group = :Z, \n legend = :bottomright,\n ylabel = \"Stabilty\", \n\txlabel = \"Karrying Kapacity\",\n seriestype = [:scatter, :line])\n\np2 = @df df_collect plot(:K, [:FinalBiomass], group = :Z, \n legend = :bottomright,\n ylabel = \"Biomass\", \n\txlabel = \"Karrying Kapacity\",\n seriestype = [:scatter, :line])\n \np3 = @df df_collect plot(:K, [:FinalRichness], group = :Z, \n legend = :bottomright,\n ylabel = \"Richness\", \n\txlabel = \"Karrying Kapacity\",\n seriestype = [:scatter, :line])\n\n# create a layout of 3 graphs stacked on top of each other.\nplot(p1, p2, p3, layout=(3,1), legend = false)\n```\n:::\n\n\n### Interpretation!\n\n#### Challenge - can you get the number of extinctions into the data frame?\n\n### Experiment 2: The Functional Response\n\nThe functional response is the relationship between how much a consumer eats and the 'density' of the prey items. If you can recall from your ecology courses/classes/modules, there are three classic shapes: The Type I, Type II and Type III.\n\nA predator feeding with a Type I delivers to the prey a 'constant mortality rate' (the slope of the Type I line). This means that the effect of predation is density _independent_ because prey mortality rate does not vary by prey density. Remember, density dependence (negative feedback that stabilises communities) is defined by survival decreasing with increasing density, or in this case, mortality rates _increasing_ with increasing density.\n\nA predator feeding with the Type II delivers an _inverse density dependent_ mortality rate. The slope of the Type II line actually goes down as density of the prey goes up meaning that mortality rates for the prey, caused by the predator, are going down with prey density. This means that the effect of predation is _inverse density dependent_ in the Type II. This is **destabilising**.\n\nFinally, a predator feeding via a Type III can deliver a _density dependent_ mortality rate to the prey, but only at low prey densities. This is an S shaped curve. Below the inflection point, the slope is actually getting steeper. This means that as prey density increases up to the inflection, their mortality rate from predation increases (survival goes down with density going up). This is the hallmark of density dependence and can **stabilise** consumer-resource interactions.\n\n::: {.callout-tip icon=false}\n\nRemember that the logistic growth equation, with a carying capacity specified, is also a source of _density dependent negative feedback_\n:::\n\n::: {.callout-tip icon=false}\n\nThe Type II is the MOST common. Type I is rare and even non-existent because it suggests there are no limits to how much a consumer can eat. Type III is also rare, but it is at least plausible and interesting.\n:::\n\n::: {#5eeb3011 .cell execution_count=8}\n``` {.julia .cell-code}\nf_t1(n) = 0.5*n\nf_t2(n) = 0.5*n/(0.2+0.01*n)\nf_t3(n) = 0.5*n^2/(10 + 0.01*n^2)\n\nplot(f_t1, 0, 100, label = \"Type I\")\nplot!(f_t2, 0, 100, label = \"Type II\")\nplot!(f_t3, 0, 100, label = \"Type III\")\n```\n\n::: {.cell-output .cell-output-display execution_count=7}\n```{=html}\n\n\n```\n:::\n:::\n\n\n#### How does the BEFW make a functional response?\n\nThere are two formulations of the functional response. One of them is called the _Bioenergetic_ response and the other is called the _Classic_. In both cases, we ignore the Type I.\n\nThe Bioenergetic functional response is deeply phenomenological in that the parameters that make the shapes move between Type II and III have no deliberate biological interpretation. They function is defined by a 1/2 saturation point, an asymptote (which is nominally a maxiumum feeding rate) and an exponent, which is called the _hill exponent_. The value of the exponent moves the model from Type II (h = 1) to Type III (h = 2). The other variables define the overall shape.\n\nThe Classic functional less phenomenological in that the response is defined more by 'traits': the attack rate of a consumer on a prey and the handling time of that prey. But it also moves between the Type II and Type III shape based on an exponent.\n\n#### Creating Type II vs. Type III with the Bioenergetic response\n\nLet's look at using the Bioenergetic functional response, and see here how we can vary the shape between Type II and Type III. We can do this by modifying the *hill_exponent* after we have specified the model (*i.e.,* after the `default_model` call). We will look at how Richness, Biomass and Shannon Diversity are affected by the hill exponent.\n\n::: {#55111e82 .cell execution_count=9}\n``` {.julia .cell-code}\nRandom.seed!(12352)\n\n# fixed parameters\nS = 20\nC = 0.15\n\n# set the hill exponent to move from Type II to Type III)\nh_levels = [1.0, 1.1, 1.25, 2.0]\n\n# set collecting data frame \n# we will look at how Richness, Biomass and Stability are affected by the hill exponent\ndf_collect_h = DataFrame(h = [], FinalRichness = [], FinalBiomass = [], ShannonDiversity = [])\n\n# create look across values of h\nfor h in h_levels \n println(\"***> This is iteration with h = $h\\n\")\n \n # make the network\n # Note that we specify the Environment, but there is no K or T set (using defaults)\n # Note the new BioenergeticResponse function\n fw_h = Foodweb(:niche; S = S, C = C)\n \n # set body sizes and parameters \n B0 = rand(S)\n params = default_model(fw_h)\n\n # here we now update the exponent of the hill function\n params.hill_exponent = h\n\n # specify number of time steps\n t = 300\n\n # simulate\n sim_niche = simulate(params, B0, t)\n\n # collect data \n fin_rich = richness(sim_niche)\n fin_bio = total_biomass(sim_niche)\n s_div = shannon_diversity(sim_niche)\n\n push!(df_collect_h, [h, fin_rich, fin_bio, s_div])\nend\n\ndf_collect_h\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n***> This is iteration with h = 1.0\n\n***> This is iteration with h = 1.1\n\n***> This is iteration with h = 1.25\n\n***> This is iteration with h = 2.0\n\n```\n:::\n\n::: {.cell-output .cell-output-display execution_count=8}\n```{=html}\n
\n```\n:::\n:::\n\n\nNow, we can visualise these data\n\n::: {#be0fe852 .cell execution_count=10}\n``` {.julia .cell-code}\n# Visualize the results\np1_h = @df df_collect_h plot(:h, [:FinalStability],\n legend = :bottomright,\n ylabel = \"Stability\",\n xlabel = \"Functional response\",\n seriestype = [:scatter, :line])\n\np2_h = @df df_collect_h plot(:h, [:FinalBiomass],\n legend = :bottomright,\n ylabel = \"Biomass\",\n xlabel = \"Functional response\",\n seriestype = [:scatter, :line])\n\np3_h = @df df_collect_h plot(:h, [:FinalRichness],\n legend = :bottomright,\n ylabel = \"Richness\",\n xlabel = \"Functional response\",\n seriestype = [:scatter, :line])\n\nplot(p1_h, p2_h, p3_h, layout=(3,1), legend = false, size = (1000, 1000))\n```\n:::\n\n\n#### INTERPRETATION?\n\nWhat can you see happening as we move away from the destabilising Type II functional response?\n\nCan you modify this code to explore what happens at different values of K? You'll need to modify this section, and the collection data frame.\n\n::: {#f8aca1ed .cell execution_count=11}\n``` {.julia .cell-code}\n # make the network\n fw_h = Foodweb(:niche; S = S, C = C)\n\n # set body sizes and parameters \n B0 = rand(S)\n params = default_model(fw_h, LogisticGrowth(; K = k))\n\n # update the exponent of the hill function\n params.hill_exponent = h\n```\n:::\n\n\n### Experiment 3: What is Z\n\nOne of the central features of the link between the Bioenergetic Food Web model and the structure of a foodweb created by models like the Niche Model is the organisation of trophic levels. At the heart of this is a _data driven_ assumption about the ratio of predator size to prey size. This is called the _Predator Prey Mass Ratio_, or `PPMR` for short. \n\nIn 2006, Uli Brose and team collated hundreds of data [to reveal that](https://esajournals.onlinelibrary.wiley.com/doi/10.1890/0012-9658%282006%2987%5B2411%3ACBRINF%5D2.0.CO%3B2), on average, predators were between 10 and 100x bigger than their prey.\n\nIn our modelling framework, we use this ratio to help organise species into trophic levels. This is done by organising the bodymass vector, and via a parameter called `Z`. The body mass of consumers is a function of their mean trophic level (T), and it increases with trophic level when Z ≥ 1 and decreases when Z ≤ 1 via this relationship (see Delmas et al 2017 and Williams et al 2007):\n\n$M_C = Z^(T-1)$\n\n[Brose et al 2006](https://onlinelibrary.wiley.com/doi/10.1111/j.1461-0248.2006.00978.x) explored the impact of the _PPMR_ on stability and dynamics as part of their wider exploration of scaling and allometry in the bioenergetic model. Here we show you how to manipulate `Z` and it's effect on stability. `Z` is specified in the call to FoodWeb as the allocation of species with specific sizes is central to the trophic structure of the model. This argument is interfaced with the bodysize vector in `model_parameters()`\n\n::: {#b1b7b1ce .cell execution_count=12}\n``` {.julia .cell-code}\nRandom.seed!(12352)\n\n# fixed parameters\nS = 20\nC = 0.15\n\n# set the PPRM\nz_levels= [0.1, 1, 10, 100]\n\n# set collecting data frame \n# we will look at how Richness, Biomass and Stability are affected by the hill exponent\ndf_collect_z = DataFrame(z = [], FinalRichness = [], FinalBiomass = [], ShannonDiversity = [])\n\n# create look across values of h\nfor z in z_levels \n println(\"***> This is iteration with z = $z\\n\")\n \n # make the network\n # Note that we specify the Environment, but there is no K or T set (using defaults)\n # Note Z is specified when building the FoodWeb() network\n fw_z = Foodweb(:niche; S = S, C = C)\n \n # set body sizes and parameters \n B0 = rand(S)\n params = default_model(fw_z, BodyMass(; Z = z))\n\n # specify number of time steps\n t = 300\n\n # simulate\n out_z = simulate(params, B0, t)\n\n # collect data \n fin_rich = richness(out_z)\n fin_bio = total_biomass(out_z)\n s_div = shannon_diversity(out_z)\n\n push!(df_collect_z, [z, fin_rich, fin_bio, s_div])\nend\n\ndf_collect_z\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n***> This is iteration with z = 0.1\n\n***> This is iteration with z = 1.0\n\n***> This is iteration with z = 10.0\n\n***> This is iteration with z = 100.0\n\n```\n:::\n\n::: {.cell-output .cell-output-display execution_count=9}\n```{=html}\n
\n```\n:::\n:::\n\n\nAs with the variation in `h`, we can create a set of figures too! Perhaps it's worth your time to consult [Brose et al 2006](https://onlinelibrary.wiley.com/doi/10.1111/j.1461-0248.2006.00978.x) and [Reger et al 2017](https://besjournals.onlinelibrary.wiley.com/doi/10.1111/2041-210X.12713) to make sure you understand how Z works and particularly how stability is expected to vary with Z! One of the most important things to understanding is why the stability metric is negative and what values of stability close, or far away, from zero mean.\n\n::: {#ab493d43 .cell execution_count=13}\n``` {.julia .cell-code}\n# Visualize the results\np1_z = @df df_collect_z plot(:z, [:FinalStability],\n legend = :bottomright,\n ylabel = \"Stability\",\n xlabel = \"Z value (PPMR)\",\n seriestype = [:scatter, :line])\n\np2_z = @df df_collect_z plot(:z, [:FinalBiomass],\n legend = :bottomright,\n ylabel = \"Biomass\",\n xlabel = \"Z value (PPMR)\",\n seriestype = [:scatter, :line])\n\np3_z = @df df_collect_z plot(:z, [:FinalRichness],\n legend = :bottomright,\n ylabel = \"Richness\",\n xlabel = \"Z value (PPMR)\",\n seriestype = [:scatter, :line])\n\nplot(p1_z, p2_z, p3_z, layout=(3,1), legend = false, size = (1000, 1000))\n```\n:::\n\n\n#### Challenge\n\nCould you modify this to ask about the interaction between Z and K? This would be asking the question of whether the effect of PPMR on stability varies by system productivity. Or you could ask about the interaction between the functional response, which we know also has a direct effect on stability by the assumption we make of a Type II or Type III shape, and the value of Z, which we also know impacts stability from Brose et al's work.\n\n### Experiment 4: Manipulating Competition among producers\n\nOur final experiment for this section involves manipulating how the basal producers compete with each other. The default paramterisation of the model has each producer growing via the logistic equation and competing with itself via density dependence. There is only intraspecific competition, no interspecific competition.\n\nWe can modify this assumption by invoking another function called `ProducerCompetition`. This function acts like `Environment` that we use to set `K` and `BioenergeticResponse` that we used to modify the functional response between Type II and Type III.\n\nThe theory to recall is that coexistence among species is mediated by the balance between intraspecific and interspecific competition. When intraspecific competition is greater than interspecific competition, there is coexistence. However, when interspecific competition is greater than intraspecific competition, there will be compeitive exclusion and no coexistence. \n\nWe call the competition parameters $\\alpha$. $\\alpha~ii$ defines intraspecific competition and $\\alpha~ij$ defines interspecific competition. The $\\alpha~ij$ defines how the species $j$ reduces the carrying capacity (equilibrium) of species $i$. \n\nWhat we can do is set $\\alpha~ii = 1$ and then vary $\\alpha~ij$ from $<1$ to $>1$. We can expect that there will a dramatic change in biomass and species richness as we move from $alpha~ii > alpha~ij$ to $alpha~ii < alpha~ij$.\n\n::: {#12de3283 .cell execution_count=14}\n``` {.julia .cell-code}\nS = 20 # define the number of species\nC = 0.2 # define the connectance (complexity) of the network\nZ = 100 # Predator Prey Mass Ratio\n\n# here we set the \ninterspecific_vals = 0.8:0.05:1.2 # a set of (9) values between 0.8 and 1.2 in steps of 0.05\n# collect(0.8:0.05:1.2) # see them if you want to\n\n\n# set collecting data frame \n# we will look at how Richness, Biomass and Stability are affected by the hill exponent\ndf_collect_comp = DataFrame(InterComp = [], FinalRichness = [], FinalBiomass = [], ShannonDiversity = [])\n\nfor alpha_ij in interspecific_vals\n println(\"***> This is iteration with alpha_ij = $alpha_ij\\n\")\n \n # this will make always the same network and body mass\n Random.seed!(123)\n foodweb = Foodweb(:niche; S = S, C = C, Z = Z)\n\n # enhance detail in the network\n # specify K\n LogisticGrowth(foodweb; K = 10)\n # we fix intraspecific = 1 and vary interspecific\n ProducerCompetiton(foodweb; αii = 1.0, αij = 1)\n # set the hill exponent to 1 (type II Functional Response)\n BioenergeticResponse(foodweb, h = 1)\n\n # define parameters with extras\n params_comp = default_model(foodweb, BodyMass(; Z = z))\n\n # set bodymass\n B0 = rand(S)\n\n # simulate\n # note verbose = false ; remove this to see extinction detail for each sim\n out_comp = simulate(params_comp, B0, verbose = false)\n\n # generate stats and add to collector\n # collect data \n fin_rich = richness(out_comp)\n fin_bio = biomass(out_comp).total\n stab = community_cv(out_comp)\n\n push!(df_collect_comp, [alpha_ij, fin_rich, fin_bio, stab])\nend\n\ndf_collect_comp\n```\n:::\n\n\nLet's review the assumptions above. We've set the `Predator Prey Mass Ratio` to 100. We've set carrying capacity `K` to 10. We've set the functional response `h` value to 1, so it's a Type II functional response. Finally, we've set a range of interspecific competition to be 0.8 to 1.2 around the fixed intraspecific effect of 1.\n\n::: {#7d288b7a .cell execution_count=15}\n``` {.julia .cell-code}\np1 = @df df_collect_comp plot(:InterComp, [:FinalRichness],\n ylabel = \"Richness\",\n xlabel = \"alpha_ij\")\np2 = @df df_collect_comp plot(:InterComp, [:FinalBiomass],\n ylabel = \"Biomass\",\n xlabel = \"alpha_ij\")\np3 = @df df_collect_comp plot(:InterComp, [:FinalStability],\n ylabel = \"Stability\",\n xlabel = \"alpha_ij\")\n\nplot(p1, p2, p3, layout = (3,1), legend = false)\n```\n:::\n\n\n#### Challenge - Competition\n\nPerhaps consider expanding the code above to assess one of these?\n\nIs this pattern sensitive to specie richness?\nIs this pattern sensitive to the functional response?\nIs this pattern sensitive to the PPMR?\nIs this pattern sensitive to values of K?\n\n## Experiment 5: Multiple networks (replicates)\n\nTo Do: run S (3 values), C (3 values) and h (3 values) where there are 5 replicate networks per combination. Note we need 45 networks...\n\n",
+ "engine": "julia",
+ "markdown": "---\ntitle: \"Tutorial 10: Complex Experiments with the END\"\ndate: last-modified\nauthor: \"Danet and Becks, based on originals by Delmas and Griffiths\"\nformat:\n html:\n embed-resources: true\ntitle-block-banner: true\nengine: julia\n---\n\n\n\n\n::: {.callout-caution}\n## Warning\n\nStability was replaced by Shannon diversity - need to review context as well as if we want that or rather re-integrate stability\n:::\n\nThe previous tutorial focused on experiments where we manipulated the number of networks and various network parameters. This is one set of things we can change/vary in an _in silico_ experiment. The other set of things we can change are features of the model, such as the shape of the functional response (see Tutorial 7), features of the environment such as the carrying capacity, or even empirical relationships that drive trophic structure and interaction strengths, such as the predator-prey mass ratio.\n\nIn this tutorial, we are going to implement three experiments. The first two will be 'simple' in that they vary only two things. The final example will implement a large experiment changing five features of the model.\n\nYou may want to start a new script in the project. We'll need the following packages (they are already installed... so we just need `using`).\n\n\n\n\n::: {#2 .cell execution_count=1}\n``` {.julia .cell-code}\nusing Random, Plots, Distributions, DataFrames, StatsPlots\nusing EcologicalNetworksDynamics\n```\n:::\n\n\n\n\n\n\n### Experiment 1: Carrying Capacity and the Predator Prey Mass Ratio\n\nNow we are set for our first experiment. Lets first establish the parameters we need to make the food web and do the experiment. We fix `S` at 20 and `C` at 0.15. We then create vectors of Z and K. \n\nZ is the predator - prey mass ratio, and defines how much bigger or smaller the predators are from their prey. The data suggest it is between predators are between 10 and 100 times bigger than their prey [see Brose et al 2006](https://doi.org/10.1890/0012-9658(2006)87[2411:CBRINF]2.0.CO;2). This value interacts with setting trophic levels in the model. \n\nThe default setting for the models is 1 - i.e. all species are within the same order of magnitude, predators are not bigger than their prey. Here, we create a vector of values to explore, from predators being smaller, to them being 10 or 100 x larger as the data suggests.\n\n\n\n\n\n::: {#4 .cell execution_count=1}\n``` {.julia .cell-code}\n#Fixed Parameters\nS = 20\nC = 0.15\n\n# Variable Parameters\nZ_levels = [0.1, 1, 10, 100]\nK_levels = [0.1, 1, 10, 100]\n\n# run this to get same results as in the document\nRandom.seed!(123)\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```\nTaskLocalRNG()\n```\n:::\n:::\n\n\n\n\n\n\nNow, lets set up the collecting data frame.\n\n\n\n\n::: {#6 .cell execution_count=1}\n``` {.julia .cell-code}\ndf_collect = DataFrame(Z = [], K = [], FinalRichness = [], FinalBiomass = [], ShannonDiversity = [])\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n
0×5 DataFrame
Row
Z
K
FinalRichness
FinalBiomass
ShannonDiversity
Any
Any
Any
Any
Any
\n```\n:::\n:::\n\n\n\n\n\n\nNow, set up the loop to use these variables and generate outputs. Notice that we use `for z in Z_levels` - this is a clever trick of the looping method, where `z` simply iterates over the values of `Z_levels` without having to specify the index value (e.g. no use of `Z_levels[i]` etc).\n\nThe significant BIG thing here is the LogisticGrowth function which allows us to set things like the carrying capacity (K) of the resources. Here we use it to define custom values of the K paramter for carrying capacity, drawing on the values in the `K_levels` above. Here, `pg` stands for Producer Growth function, and the paramter set in the food web is K.\n\nNote too our use of `println` and the values of `Z` and `K` to produce an informative _break_ between each combination.\n\n::: {.callout-note icon=false}\n\nCan you guess what increasing K will do to the biomass and richness of the community at equilibrium? How about Z? Will higher Z make things more or less stable?\n:::\n\n\n\n\n\n\n::: {#8 .cell execution_count=1}\n``` {.julia .cell-code}\nfor z in Z_levels\n for k in K_levels\n\n println(\" ***> This is iteration with Z = $z and K = $k\\n\")\n\n # Define the food web\n fw = Foodweb(:niche; S = S, C = C)\n # specify the K value of the producer growth function\n\n B0 = rand(S)\n # specify model to simulate logistic growth as well as BM ratio\n params = default_model(fw, BodyMass(; Z = z), LogisticGrowth(; K = k))\n \n # number of timestamps\n t = 300\n\n out = simulate(params, B0, t)\n\n # calculate metrics\n fin_rich = richness(out)\n fin_biomass = total_biomass(out)\n s_div = shannon_diversity(out)\n\n push!(df_collect, [z, k, fin_rich, fin_biomass, s_div])\n end\nend\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n ***> This is iteration with Z = 0.1 and K = 0.1\n\n ***> This is iteration with Z = 0.1 and K = 1.0\n\n ***> This is iteration with Z = 0.1 and K = 10.0\n\n ***> This is iteration with Z = 0.1 and K = 100.0\n\n ***> This is iteration with Z = 1.0 and K = 0.1\n\n ***> This is iteration with Z = 1.0 and K = 1.0\n\n ***> This is iteration with Z = 1.0 and K = 10.0\n\n ***> This is iteration with Z = 1.0 and K = 100.0\n\n ***> This is iteration with Z = 10.0 and K = 0.1\n\n ***> This is iteration with Z = 10.0 and K = 1.0\n\n ***> This is iteration with Z = 10.0 and K = 10.0\n\n ***> This is iteration with Z = 10.0 and K = 100.0\n\n ***> This is iteration with Z = 100.0 and K = 0.1\n\n ***> This is iteration with Z = 100.0 and K = 1.0\n\n ***> This is iteration with Z = 100.0 and K = 10.0\n\n ***> This is iteration with Z = 100.0 and K = 100.0\n\n```\n:::\n:::\n\n\n\n\n\n\nWonderful. Now we are in a position to learn about two new plotting methods. First, let's look at the data frame we've created.\n\n\n\n\n::: {#10 .cell execution_count=1}\n``` {.julia .cell-code}\ndf_collect\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n
\n```\n:::\n:::\n\n\n\n\n\n\n#### Visualising the experiment\n\nOne option here is to plot one of our `Final` Objects as the response variable against the valuse of Z and K. In R, we'd use ggplot2. Here we'll use `StatsPlots` as we learned about in Tutorial 5. Can you make this work in the regular `Plots` syntax?\n\nLet's first look at a single plot of stability\n\n\n\n::: {#12 .cell execution_count=0}\n``` {.julia .cell-code}\n@df df_collect plot(:K, [:FinalStability], group = :Z, \n ylabel = \"Stabilty\", \n\txlabel = \"Karrying Kapacity\",\n seriestype = [:scatter, :line],\n legend = false)\n```\n:::\n\n\n\n\n\n\nNow some new ploting tricks... 3 plots in a layout.\n\n\n\n\n::: {#14 .cell execution_count=0}\n``` {.julia .cell-code}\np1 = @df df_collect plot(:K, [:FinalStability], group = :Z, \n legend = :bottomright,\n ylabel = \"Stabilty\", \n\txlabel = \"Karrying Kapacity\",\n seriestype = [:scatter, :line])\n\np2 = @df df_collect plot(:K, [:FinalBiomass], group = :Z, \n legend = :bottomright,\n ylabel = \"Biomass\", \n\txlabel = \"Karrying Kapacity\",\n seriestype = [:scatter, :line])\n \np3 = @df df_collect plot(:K, [:FinalRichness], group = :Z, \n legend = :bottomright,\n ylabel = \"Richness\", \n\txlabel = \"Karrying Kapacity\",\n seriestype = [:scatter, :line])\n\n# create a layout of 3 graphs stacked on top of each other.\nplot(p1, p2, p3, layout=(3,1), legend = false)\n```\n:::\n\n\n\n\n\n\n### Interpretation!\n\n#### Challenge - can you get the number of extinctions into the data frame?\n\n### Experiment 2: The Functional Response\n\nThe functional response is the relationship between how much a consumer eats and the 'density' of the prey items. If you can recall from your ecology courses/classes/modules, there are three classic shapes: The Type I, Type II and Type III.\n\nA predator feeding with a Type I delivers to the prey a 'constant mortality rate' (the slope of the Type I line). This means that the effect of predation is density _independent_ because prey mortality rate does not vary by prey density. Remember, density dependence (negative feedback that stabilises communities) is defined by survival decreasing with increasing density, or in this case, mortality rates _increasing_ with increasing density.\n\nA predator feeding with the Type II delivers an _inverse density dependent_ mortality rate. The slope of the Type II line actually goes down as density of the prey goes up meaning that mortality rates for the prey, caused by the predator, are going down with prey density. This means that the effect of predation is _inverse density dependent_ in the Type II. This is **destabilising**.\n\nFinally, a predator feeding via a Type III can deliver a _density dependent_ mortality rate to the prey, but only at low prey densities. This is an S shaped curve. Below the inflection point, the slope is actually getting steeper. This means that as prey density increases up to the inflection, their mortality rate from predation increases (survival goes down with density going up). This is the hallmark of density dependence and can **stabilise** consumer-resource interactions.\n\n::: {.callout-tip icon=false}\n\nRemember that the logistic growth equation, with a carying capacity specified, is also a source of _density dependent negative feedback_\n:::\n\n::: {.callout-tip icon=false}\n\nThe Type II is the MOST common. Type I is rare and even non-existent because it suggests there are no limits to how much a consumer can eat. Type III is also rare, but it is at least plausible and interesting.\n:::\n\n\n\n\n::: {#16 .cell execution_count=1}\n``` {.julia .cell-code}\n\nf_t1(n) = 0.5*n\nf_t2(n) = 0.5*n/(0.2+0.01*n)\nf_t3(n) = 0.5*n^2/(10 + 0.01*n^2)\n\nplot(f_t1, 0, 100, label = \"Type I\")\nplot!(f_t2, 0, 100, label = \"Type II\")\nplot!(f_t3, 0, 100, label = \"Type III\")\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n\n\n```\n:::\n:::\n\n\n\n\n\n\n#### How does the BEFW make a functional response?\n\nThere are two formulations of the functional response. One of them is called the _Bioenergetic_ response and the other is called the _Classic_. In both cases, we ignore the Type I.\n\nThe Bioenergetic functional response is deeply phenomenological in that the parameters that make the shapes move between Type II and III have no deliberate biological interpretation. They function is defined by a 1/2 saturation point, an asymptote (which is nominally a maxiumum feeding rate) and an exponent, which is called the _hill exponent_. The value of the exponent moves the model from Type II (h = 1) to Type III (h = 2). The other variables define the overall shape.\n\nThe Classic functional less phenomenological in that the response is defined more by 'traits': the attack rate of a consumer on a prey and the handling time of that prey. But it also moves between the Type II and Type III shape based on an exponent.\n\n#### Creating Type II vs. Type III with the Bioenergetic response\n\nLet's look at using the Bioenergetic functional response, and see here how we can vary the shape between Type II and Type III. We can do this by modifying the *hill_exponent* after we have specified the model (*i.e.,* after the `default_model` call). We will look at how Richness, Biomass and Shannon Diversity are affected by the hill exponent.\n\n\n\n\n::: {#18 .cell execution_count=1}\n``` {.julia .cell-code}\n\nRandom.seed!(12352)\n\n# fixed parameters\nS = 20\nC = 0.15\n\n# set the hill exponent to move from Type II to Type III)\nh_levels = [1.0, 1.1, 1.25, 2.0]\n\n# set collecting data frame \n# we will look at how Richness, Biomass and Stability are affected by the hill exponent\ndf_collect_h = DataFrame(h = [], FinalRichness = [], FinalBiomass = [], ShannonDiversity = [])\n\n# create look across values of h\nfor h in h_levels \n println(\"***> This is iteration with h = $h\\n\")\n \n # make the network\n # Note that we specify the Environment, but there is no K or T set (using defaults)\n # Note the new BioenergeticResponse function\n fw_h = Foodweb(:niche; S = S, C = C)\n \n # set body sizes and parameters \n B0 = rand(S)\n params = default_model(fw_h)\n\n # here we now update the exponent of the hill function\n params.hill_exponent = h\n\n # specify number of time steps\n t = 300\n\n # simulate\n sim_niche = simulate(params, B0, t)\n\n # collect data \n fin_rich = richness(sim_niche)\n fin_bio = total_biomass(sim_niche)\n s_div = shannon_diversity(sim_niche)\n\n push!(df_collect_h, [h, fin_rich, fin_bio, s_div])\nend\n\ndf_collect_h\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n***> This is iteration with h = 1.0\n\n***> This is iteration with h = 1.1\n\n***> This is iteration with h = 1.25\n\n***> This is iteration with h = 2.0\n\n```\n:::\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n
\n```\n:::\n:::\n\n\n\n\n\n\nNow, we can visualise these data\n\n\n\n\n::: {#20 .cell execution_count=0}\n``` {.julia .cell-code}\n# Visualize the results\np1_h = @df df_collect_h plot(:h, [:FinalStability],\n legend = :bottomright,\n ylabel = \"Stability\",\n xlabel = \"Functional response\",\n seriestype = [:scatter, :line])\n\np2_h = @df df_collect_h plot(:h, [:FinalBiomass],\n legend = :bottomright,\n ylabel = \"Biomass\",\n xlabel = \"Functional response\",\n seriestype = [:scatter, :line])\n\np3_h = @df df_collect_h plot(:h, [:FinalRichness],\n legend = :bottomright,\n ylabel = \"Richness\",\n xlabel = \"Functional response\",\n seriestype = [:scatter, :line])\n\nplot(p1_h, p2_h, p3_h, layout=(3,1), legend = false, size = (1000, 1000))\n```\n:::\n\n\n\n\n\n\n#### INTERPRETATION?\n\nWhat can you see happening as we move away from the destabilising Type II functional response?\n\nCan you modify this code to explore what happens at different values of K? You'll need to modify this section, and the collection data frame.\n\n\n\n\n::: {#22 .cell execution_count=0}\n``` {.julia .cell-code}\n # make the network\n fw_h = Foodweb(:niche; S = S, C = C)\n\n # set body sizes and parameters \n B0 = rand(S)\n params = default_model(fw_h, LogisticGrowth(; K = k))\n\n # update the exponent of the hill function\n params.hill_exponent = h\n```\n:::\n\n\n\n\n\n\n### Experiment 3: What is Z\n\nOne of the central features of the link between the Bioenergetic Food Web model and the structure of a foodweb created by models like the Niche Model is the organisation of trophic levels. At the heart of this is a _data driven_ assumption about the ratio of predator size to prey size. This is called the _Predator Prey Mass Ratio_, or `PPMR` for short. \n\nIn 2006, Uli Brose and team collated hundreds of data [to reveal that](https://esajournals.onlinelibrary.wiley.com/doi/10.1890/0012-9658%282006%2987%5B2411%3ACBRINF%5D2.0.CO%3B2), on average, predators were between 10 and 100x bigger than their prey.\n\nIn our modelling framework, we use this ratio to help organise species into trophic levels. This is done by organising the bodymass vector, and via a parameter called `Z`. The body mass of consumers is a function of their mean trophic level (T), and it increases with trophic level when Z ≥ 1 and decreases when Z ≤ 1 via this relationship (see Delmas et al 2017 and Williams et al 2007):\n\n$M_C = Z^(T-1)$\n\n[Brose et al 2006](https://onlinelibrary.wiley.com/doi/10.1111/j.1461-0248.2006.00978.x) explored the impact of the _PPMR_ on stability and dynamics as part of their wider exploration of scaling and allometry in the bioenergetic model. Here we show you how to manipulate `Z` and it's effect on stability. `Z` is specified in the call to FoodWeb as the allocation of species with specific sizes is central to the trophic structure of the model. This argument is interfaced with the bodysize vector in `model_parameters()`\n\n\n\n\n::: {#24 .cell execution_count=1}\n``` {.julia .cell-code}\nRandom.seed!(12352)\n\n# fixed parameters\nS = 20\nC = 0.15\n\n# set the PPRM\nz_levels= [0.1, 1, 10, 100]\n\n# set collecting data frame \n# we will look at how Richness, Biomass and Stability are affected by the hill exponent\ndf_collect_z = DataFrame(z = [], FinalRichness = [], FinalBiomass = [], ShannonDiversity = [])\n\n# create look across values of h\nfor z in z_levels \n println(\"***> This is iteration with z = $z\\n\")\n \n # make the network\n # Note that we specify the Environment, but there is no K or T set (using defaults)\n # Note Z is specified when building the FoodWeb() network\n fw_z = Foodweb(:niche; S = S, C = C)\n \n # set body sizes and parameters \n B0 = rand(S)\n params = default_model(fw_z, BodyMass(; Z = z))\n\n # specify number of time steps\n t = 300\n\n # simulate\n out_z = simulate(params, B0, t)\n\n # collect data \n fin_rich = richness(out_z)\n fin_bio = total_biomass(out_z)\n s_div = shannon_diversity(out_z)\n\n push!(df_collect_z, [z, fin_rich, fin_bio, s_div])\nend\n\ndf_collect_z\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n***> This is iteration with z = 0.1\n\n***> This is iteration with z = 1.0\n\n***> This is iteration with z = 10.0\n\n***> This is iteration with z = 100.0\n\n```\n:::\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n
\n```\n:::\n:::\n\n\n\n\n\n\nAs with the variation in `h`, we can create a set of figures too! Perhaps it's worth your time to consult [Brose et al 2006](https://onlinelibrary.wiley.com/doi/10.1111/j.1461-0248.2006.00978.x) and [Reger et al 2017](https://besjournals.onlinelibrary.wiley.com/doi/10.1111/2041-210X.12713) to make sure you understand how Z works and particularly how stability is expected to vary with Z! One of the most important things to understanding is why the stability metric is negative and what values of stability close, or far away, from zero mean.\n\n\n\n\n::: {#26 .cell execution_count=0}\n``` {.julia .cell-code}\n# Visualize the results\np1_z = @df df_collect_z plot(:z, [:FinalStability],\n legend = :bottomright,\n ylabel = \"Stability\",\n xlabel = \"Z value (PPMR)\",\n seriestype = [:scatter, :line])\n\np2_z = @df df_collect_z plot(:z, [:FinalBiomass],\n legend = :bottomright,\n ylabel = \"Biomass\",\n xlabel = \"Z value (PPMR)\",\n seriestype = [:scatter, :line])\n\np3_z = @df df_collect_z plot(:z, [:FinalRichness],\n legend = :bottomright,\n ylabel = \"Richness\",\n xlabel = \"Z value (PPMR)\",\n seriestype = [:scatter, :line])\n\nplot(p1_z, p2_z, p3_z, layout=(3,1), legend = false, size = (1000, 1000))\n```\n:::\n\n\n\n\n\n\n#### Challenge\n\nCould you modify this to ask about the interaction between Z and K? This would be asking the question of whether the effect of PPMR on stability varies by system productivity. Or you could ask about the interaction between the functional response, which we know also has a direct effect on stability by the assumption we make of a Type II or Type III shape, and the value of Z, which we also know impacts stability from Brose et al's work.\n\n### Experiment 4: Manipulating Competition among producers\n\nOur final experiment for this section involves manipulating how the basal producers compete with each other. The default paramterisation of the model has each producer growing via the logistic equation and competing with itself via density dependence. There is only intraspecific competition, no interspecific competition.\n\nWe can modify this assumption by invoking another function called `ProducerCompetition`. This function acts like `Environment` that we use to set `K` and `BioenergeticResponse` that we used to modify the functional response between Type II and Type III.\n\nThe theory to recall is that coexistence among species is mediated by the balance between intraspecific and interspecific competition. When intraspecific competition is greater than interspecific competition, there is coexistence. However, when interspecific competition is greater than intraspecific competition, there will be compeitive exclusion and no coexistence. \n\nWe call the competition parameters $\\alpha$. $\\alpha~ii$ defines intraspecific competition and $\\alpha~ij$ defines interspecific competition. The $\\alpha~ij$ defines how the species $j$ reduces the carrying capacity (equilibrium) of species $i$. \n\nWhat we can do is set $\\alpha~ii = 1$ and then vary $\\alpha~ij$ from $<1$ to $>1$. We can expect that there will a dramatic change in biomass and species richness as we move from $alpha~ii > alpha~ij$ to $alpha~ii < alpha~ij$.\n\n\n\n\n\n::: {#28 .cell execution_count=0}\n``` {.julia .cell-code}\nS = 20 # define the number of species\nC = 0.2 # define the connectance (complexity) of the network\nZ = 100 # Predator Prey Mass Ratio\n\n# here we set the \ninterspecific_vals = 0.8:0.05:1.2 # a set of (9) values between 0.8 and 1.2 in steps of 0.05\n# collect(0.8:0.05:1.2) # see them if you want to\n\n\n# set collecting data frame \n# we will look at how Richness, Biomass and Stability are affected by the hill exponent\ndf_collect_comp = DataFrame(InterComp = [], FinalRichness = [], FinalBiomass = [], ShannonDiversity = [])\n\nfor alpha_ij in interspecific_vals\n println(\"***> This is iteration with alpha_ij = $alpha_ij\\n\")\n \n # this will make always the same network and body mass\n Random.seed!(123)\n foodweb = Foodweb(:niche; S = S, C = C, Z = Z)\n\n # enhance detail in the network\n # specify K\n LogisticGrowth(foodweb; K = 10)\n # we fix intraspecific = 1 and vary interspecific\n ProducerCompetiton(foodweb; αii = 1.0, αij = 1)\n # set the hill exponent to 1 (type II Functional Response)\n BioenergeticResponse(foodweb, h = 1)\n\n # define parameters with extras\n params_comp = default_model(foodweb, BodyMass(; Z = z))\n\n # set bodymass\n B0 = rand(S)\n\n # simulate\n # note verbose = false ; remove this to see extinction detail for each sim\n out_comp = simulate(params_comp, B0, verbose = false)\n\n # generate stats and add to collector\n # collect data \n fin_rich = richness(out_comp)\n fin_bio = biomass(out_comp).total\n stab = community_cv(out_comp)\n\n push!(df_collect_comp, [alpha_ij, fin_rich, fin_bio, stab])\nend\n\ndf_collect_comp\n```\n:::\n\n\n\n\n\n\nLet's review the assumptions above. We've set the `Predator Prey Mass Ratio` to 100. We've set carrying capacity `K` to 10. We've set the functional response `h` value to 1, so it's a Type II functional response. Finally, we've set a range of interspecific competition to be 0.8 to 1.2 around the fixed intraspecific effect of 1.\n\n\n\n\n\n::: {#30 .cell execution_count=0}\n``` {.julia .cell-code}\np1 = @df df_collect_comp plot(:InterComp, [:FinalRichness],\n ylabel = \"Richness\",\n xlabel = \"alpha_ij\")\np2 = @df df_collect_comp plot(:InterComp, [:FinalBiomass],\n ylabel = \"Biomass\",\n xlabel = \"alpha_ij\")\np3 = @df df_collect_comp plot(:InterComp, [:FinalStability],\n ylabel = \"Stability\",\n xlabel = \"alpha_ij\")\n\nplot(p1, p2, p3, layout = (3,1), legend = false)\n```\n:::\n\n\n\n\n\n\n#### Challenge - Competition\n\nPerhaps consider expanding the code above to assess one of these?\n\nIs this pattern sensitive to specie richness?\nIs this pattern sensitive to the functional response?\nIs this pattern sensitive to the PPMR?\nIs this pattern sensitive to values of K?\n\n## Experiment 5: Multiple networks (replicates)\n\nTo Do: run S (3 values), C (3 values) and h (3 values) where there are 5 replicate networks per combination. Note we need 45 networks...\n\n",
"supporting": [
"10_complex_experiments_end_files"
],
diff --git a/_freeze/1_download_setup/execute-results/html.json b/_freeze/1_download_setup/execute-results/html.json
index a26ba20..80c356f 100644
--- a/_freeze/1_download_setup/execute-results/html.json
+++ b/_freeze/1_download_setup/execute-results/html.json
@@ -2,7 +2,7 @@
"hash": "1c99d2294462e383472fc843d253e1f3",
"result": {
"engine": "julia",
- "markdown": "---\ntitle: \"Tutorial 1: Downloads, Setups and Your First Project\"\ndate: last-modified\nauthor: \"Danet and Becks, based on originals by Delmas and Griffiths\"\nformat:\n html:\n embed-resources: true\ntitle-block-banner: true\nengine: julia\n---\n\n\n\n\n\n\n## Downloading and Installing Julia and VSCode\n\n**Julia**\n\nNavigate to [this page](https://julialang.org/downloads/) and follow the platform-specific instructions to download and install Julia (we recommend installing the current stable release).\n\nDuring the installation process, you may be prompted to add Julia to the PATH, this box should be ticked.\n\n::: {.callout-tip collapse=\"true\"}\n## Using Juliaup\n\n[Juliaup](https://github.com/JuliaLang/juliaup) is an alternative platform to install and manage multiple versions of Julia you run on your computer. This is useful if you need to run different versions of Julia for different projects but probably not essential for a casual Julia user, although there is also something to be said about setting yourself up with the best toys on the market...\n::: \n\n**VSCode**\n\nNavigate to [this page](https://visualstudio.microsoft.com/) to download and install your platform specific Visual Studio Code (not Visual Studio or Visual Studio for Mac).\n\n## Setting Up VSCode to use Julia\n\nVS Code is a free source-code editor, allowing you to code in multiple coding languages all from a platform that is completely customisable to the user - think of it as a more language agnostic version of RStudio. This flexibility is great but it does mean that you need to spend time telling VS Code what it is you want to do and how. This is where extensions come in; extensions are higher level packages that permit the use of a given coding language like Julia, edit your themes and icons, provide helpful applications like spell checker or Bracket Pair Colorizer, and for adding your own [VS Code pets](https://tonybaloney.github.io/vscode-pets/usage) (a very important part of the VSCode experience).\n\nTo install Julia in VS Code do the following (you only need to do this once):\n\n1. open VS Code (you'll see the welcome page)\n2. navigate to the 'Marketplace' (5th symbol down in the activity bar - vertical panel on the lefthand side of the screen)\n\n\n\n3. search for Julia in the 'Search Extensions in Marketplace' search bar\n4. install `Julia`, this extension provides support for the Julia programming language and install `Julia Formatter`, this extension will help you write clean code that is easier to read\n\n\n\n## Making your first Julia project\n\nAs with working in R and RStudio, we advocate working in a contained project environment when using Julia. Each unique project may require a different setup (e.g. packages, package versions, working directories, data locations, etc.).\n\nTo set up a project in VS Code:\n\n1. Creating a folder at a location of your choosing (e.g. within your Documents folder). This can be on GoogleDrive, Dropbox or OneDrive. This is OK.\n\n2. Name the folder with relevant works. Here we will use `Julia - VS code - how to`.\n\n3. Navigate to VSCode and open your new project by clicking on the 'Explorer' symbol (top left symbol on the activity bar) and click Open Folder and navigate your finder or explorer to the `Julia - VS code - how to` folder.\n\n - this folder becomes the working directory (same as when using an `.RProject` in R)\n\n\n\n4. Create a new file (a script) in your directory: do this by using cmd-N (mac) or ctrl-N (windows) or File -\\> New File or by left clicking -\\> New File within the directory pane\n\n5. Name your script as your see fit but please remember to include the .jl file extension (e.g. JuliaTuto.jl). the .jl file extension tells VS Code you want to use the Julia programming language. To save your script at any time use cmd-S (MAC) OR ctrl-S (windows) or File \\> Save.\n\n - Note, you can also open a project in VS Code by right-clicking on your folder (in Finder, Windows file explorer or Linux nautilus) and selecting Open with -\\> Other -\\> VS Code.\n\n### Activating the REPL and running some code.\n\nThis sequence of figures aligns with the instructions below.\n\n\n\nNow that you have an active project and a new script file you can open the Julia REPL. REPL stands for *read, execute, print and loop*. The REPL is like the console in R and is where the magic happens. In Eva's words, it's VS Code's way of using Julia for a brain.\n\nTo do this you type F1 or cmd/ctrl - shift-p or View -\\> Command Palette and choose Julia REPL. The command palette will appear as a drop down menu with a search function at the top of the page.\n\nNow that you have an interface with Julia as a brain, you can actually do something! Try this: type `print(\"Hello world\")` in the REPL and press Enter/Return. If you've done all of the above correctly, Hello world should print in the REPL.\n\nNow, you can also make a 'script'. Type ctrl-n or cmd-n and a document will open at the top. There will be a prompt/link to select your language. Click the link and, yes, search for and choose Julia.\n\nNext, type `print(\"Hello world\")` in the script. Just like RStudio, you can send the information in the script to the REPL. There are two ways to do this. First, and probably what you'll want, is shift-enter(return). This will send the line of code you are on, and move to the next line. ctrl-enter(return) submits the line but does not move the cursor. Try it!\n\n## Activating your project, the Project.toml and Manifest.toml\n\nWe mentioned above that it is good practice to work within an environment specific to each project. The Julia package manager (`Pkg`) allows you to do that easily: Unlike traditional package managers, which install and manage a single global set of packages, `Pkg` is designed around environments: independent sets of packages that can be local to an individual project or shared and selected by name (text taken directly from the documentation).\n\n### Getting started: activating your project.\n\nActivating your project is something that only needs doing once per computer. It allows you to add packages and dependencies to the project.\n\nIf you move the project to a new computer, or share the project, activation will be needed again.\n\nThere are two ways to activate your project.\n\n1. type `Pkg.activate(\".\")` in the REPL.\n2. type `]` in the REPL and then `activate .`\n\nThe `]` is a shorthand for using the `Pkg` package and opens the package manager. To get out of this, you press the `backspace/delete` button on your keyboard.\n\nThere are two ways to double check that you are actually working within your project:\n\n- check/click the 'Julia env:...' on the bottom of your screen (blue bar), it should match your project name\n\n- enter the package manager by typing `]` in the Julia REPL, you should see (your-project-name) pkg\\> instead of julia\\>. Again, exit the package manager using `backspace/delete` button.\n\n### Working with the package manager and growing the project and manifest files\n\nOnce your project is activated, there are two ways to use the package manager (Pkg):\n\n1. directly from the REPL:\n\n- navigate to the REPL\n- type `]`\n- you will see that instead of seeing julia\\> you now see (your-project-name) pkg\\>, indicating that all the packages that you now install (or update) will be installed (or updated) within this specific project\n- to add a package, use the function `add`: `] add Plots`\n\n2. using `Pkg` (this is useful when you want to install packages or manage them from within your script):\n\n- first type `import Pkg` and execute this line using shift-Enter\n- on subsequent lines, add, remove and update packages from your script using `Pkg` functions such as `Pkg.add()`, `Pkg.remove()` or `Pkg.update()`.\n- To add a packages, the name of the package need to be written with quotes (`Pkg.add(\"Plots\")`).\n\n#### An example using the Plots package\n\nNow that we are all set up, we are going to install a package, check the project's status and remove a package. As this might be your first time installing a package (e.g., Plots), don't be concerned if it takes a couple of minutes to run.\n\n- type `] add Plots` in the REPL (or `Pkg.add(\"Plots\")`) in your script and execute using Ctrl-Enter.\n - you just installed the Plots package and a whole bunch of dependencies that Plots needs to work. This is equivalent to Base plots in R.\n\n\n\n- type `] st` in the REPL. This will check the status of your project and print the content of your Project.toml file, which is the list of main packages, in this case, just Plots.\n\nyou should see something like:\n\n\n\n::: {.callout-tip}\n## Tip\n\nPackages can removed in the same way i.e. `] rm Plots` (or `Pkg.rm(\"Plots\")`) will remove the Plots package from your project environment (and its record in the Project.toml and Manifest.toml files)\n::: \n\n## Gearing up to Do More Stuff (what packages do I need).\n\nThere are a core set of packages we use for all of our work. These 10 packages are almost always installed when we make a project.\n\nGo ahead and use either the `]` or `Pkg.add(\"package.name\")` method to add all of these to your project.\n\n#### For working with data\n\n`CSV` `DataFrames` `DelimitedFiles`\n\n#### For plotting\n\n`Plots`\n\n#### For statistical things\n\n`Distributions` `Random` `Statistics` `StatsBase` `StatsPlots`\n\n#### For Modelling\n\n`DifferentialEquations`\n\n## Your first script setup.\n\nAt this stage, you should have a good understanding about how to create a project folder, activate a project, start the REPL, open a script and add packages to the project.\n\nNow you are ready to 'setup' your first script.\n\n1. create a new script file (ctrl-n or cmd-n).\n2. choose Julia as the language\n3. Type some informative information at the top of the script\n a. just like in R and other programming languages, the `#` is a commenter.\n4. The first section of your script is where you declare the packages you'll be using.\n a. the function to do this is `using`.\n b. make Plots, Random and DataFrames available.\n\nNow you are ready to do something really simple. Let's make some variables, data frames and a few simple plots.\n\nFirst, lets get the setup sorted and packages available\n\n\n\n\n::: {#4 .cell execution_count=1}\n``` {.julia .cell-code}\n# This is my first example script\n# 25 Jan 2023\n\n# packages I need\nusing DataFrames, Plots, Random, StatsPlots\n```\n:::\n\n\n\n\n\n\nSecond, let's make some variables and see how Julia prints them to the screen\n\n\n\n\n::: {#6 .cell execution_count=1}\n``` {.julia .cell-code}\n# make two variables using the rand function\n# because we are using random numbers, we'll set the seed here for reproducibility\n\nRandom.seed!(12345)\n\nx = rand(10)\ny = rand(10)\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```\n10-element Vector{Float64}:\n 0.3302627700323072\n 0.4219866389257305\n 0.6853069230253171\n 0.29579983859112813\n 0.9736588395655787\n 0.24458973555203245\n 0.46875054050900267\n 0.27705458732580956\n 0.6299157011197652\n 0.12180466275080659\n```\n:::\n:::\n\n\n\n\n\n\nCool. Now, lets create two data frames, one made of the x and y variables, and another with three variables made directly in a call to `DataFrame`.\n\n\n\n\n::: {#8 .cell execution_count=1}\n``` {.julia .cell-code}\n# combine into a data frame using the DataFrame function\ndf = DataFrame(x = x, y = y)\ndf\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n
10×2 DataFrame
Row
x
y
Float64
Float64
1
0.791805
0.330263
2
0.159579
0.421987
3
0.334191
0.685307
4
0.811392
0.2958
5
0.796629
0.973659
6
0.917814
0.24459
7
0.311327
0.468751
8
0.752906
0.277055
9
0.633848
0.629916
10
0.899951
0.121805
\n```\n:::\n:::\n\n\n\n\n\n\n...and the second\n\n\n\n\n::: {#10 .cell execution_count=1}\n``` {.julia .cell-code}\n# make a second data frame with three variables\n# using DataFrame directly to create variables\ndf2 = DataFrame(a=1:10, b=10*rand(10), c=10*rand(10))\ndf2\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n
10×3 DataFrame
Row
a
b
c
Int64
Float64
Float64
1
1
0.563403
9.77384
2
2
7.22679
3.58869
3
3
0.466642
3.76688
4
4
4.59489
9.03599
5
5
0.491108
8.73964
6
6
6.99192
1.36299
7
7
1.58122
0.815793
8
8
4.70745
3.75399
9
9
4.97572
0.599761
10
10
4.58675
2.14792
\n```\n:::\n:::\n\n\n\n\n\n\nGreat. Now, lets see how to plot the 'solo' variables. Note how we specify the `seriestype`. Try getting rid of this....\n\n\n\n\n::: {#12 .cell execution_count=1}\n``` {.julia .cell-code}\n# plot the data using x and y, as a scatterplot\nplot(x, y, seriestype=:scatter)\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n\n\n```\n:::\n:::\n\n\n\n\n\n\nSuperb. So, `StatsPlots` provides a special macro to use a dataframe with plots. It's a three step process:\n\n1. declare the `@df` macro\n2. define the data frame\n3. declare the columns, using the `:`\n\n\n\n\n::: {#14 .cell execution_count=1}\n``` {.julia .cell-code}\n# plot the data using the data frame macro\n# declare the df macro, declare the data frame, use : to signify columns\n@df df plot(:x, :y)\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n\n\n```\n:::\n:::\n\n\n\n\n\n\nAnd here, we use the df2, and plot variable b and c vs. a.\n\n\n\n\n::: {#16 .cell execution_count=1}\n``` {.julia .cell-code}\n# the same, and plotting two y variables\n@df df2 plot(:a, [:b, :c])\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n\n\n```\n:::\n:::\n\n\n\n\n\n\n#### A quick briefing about data frames in Julia versus R and dplyr is here\n\n[DataFrames Comparison R dplyr](https://dataframes.juliadata.org/stable/man/comparisons/#Comparison-with-the-R-package-dplyr)\n\n",
+ "markdown": "---\ntitle: \"Tutorial 1: Downloads, Setups and Your First Project\"\ndate: last-modified\nauthor: \"Danet and Becks, based on originals by Delmas and Griffiths\"\nformat:\n html:\n embed-resources: true\ntitle-block-banner: true\nengine: julia\n---\n\n\n\n\n\n\n## Downloading and Installing Julia and VSCode\n\n**Julia**\n\nNavigate to [this page](https://julialang.org/downloads/) and follow the platform-specific instructions to download and install Julia (we recommend installing the current stable release).\n\nDuring the installation process, you may be prompted to add Julia to the PATH, this box should be ticked.\n\n::: {.callout-tip collapse=\"true\"}\n## Using Juliaup\n\n[Juliaup](https://github.com/JuliaLang/juliaup) is an alternative platform to install and manage multiple versions of Julia you run on your computer. This is useful if you need to run different versions of Julia for different projects but probably not essential for a casual Julia user, although there is also something to be said about setting yourself up with the best toys on the market...\n::: \n\n**VSCode**\n\nNavigate to [this page](https://visualstudio.microsoft.com/) to download and install your platform specific Visual Studio Code (not Visual Studio or Visual Studio for Mac).\n\n## Setting Up VSCode to use Julia\n\nVS Code is a free source-code editor, allowing you to code in multiple coding languages all from a platform that is completely customisable to the user - think of it as a more language agnostic version of RStudio. This flexibility is great but it does mean that you need to spend time telling VS Code what it is you want to do and how. This is where extensions come in; extensions are higher level packages that permit the use of a given coding language like Julia, edit your themes and icons, provide helpful applications like spell checker or Bracket Pair Colorizer, and for adding your own [VS Code pets](https://tonybaloney.github.io/vscode-pets/usage) (a very important part of the VSCode experience).\n\nTo install Julia in VS Code do the following (you only need to do this once):\n\n1. open VS Code (you'll see the welcome page)\n2. navigate to the 'Marketplace' (5th symbol down in the activity bar - vertical panel on the lefthand side of the screen)\n\n\n\n3. search for Julia in the 'Search Extensions in Marketplace' search bar\n4. install `Julia`, this extension provides support for the Julia programming language and install `Julia Formatter`, this extension will help you write clean code that is easier to read\n\n\n\n## Making your first Julia project\n\nAs with working in R and RStudio, we advocate working in a contained project environment when using Julia. Each unique project may require a different setup (e.g. packages, package versions, working directories, data locations, etc.).\n\nTo set up a project in VS Code:\n\n1. Creating a folder at a location of your choosing (e.g. within your Documents folder). This can be on GoogleDrive, Dropbox or OneDrive. This is OK.\n\n2. Name the folder with relevant works. Here we will use `Julia - VS code - how to`.\n\n3. Navigate to VSCode and open your new project by clicking on the 'Explorer' symbol (top left symbol on the activity bar) and click Open Folder and navigate your finder or explorer to the `Julia - VS code - how to` folder.\n\n - this folder becomes the working directory (same as when using an `.RProject` in R)\n\n\n\n4. Create a new file (a script) in your directory: do this by using cmd-N (mac) or ctrl-N (windows) or File -\\> New File or by left clicking -\\> New File within the directory pane\n\n5. Name your script as your see fit but please remember to include the .jl file extension (e.g. JuliaTuto.jl). the .jl file extension tells VS Code you want to use the Julia programming language. To save your script at any time use cmd-S (MAC) OR ctrl-S (windows) or File \\> Save.\n\n - Note, you can also open a project in VS Code by right-clicking on your folder (in Finder, Windows file explorer or Linux nautilus) and selecting Open with -\\> Other -\\> VS Code.\n\n### Activating the REPL and running some code.\n\nThis sequence of figures aligns with the instructions below.\n\n\n\nNow that you have an active project and a new script file you can open the Julia REPL. REPL stands for *read, execute, print and loop*. The REPL is like the console in R and is where the magic happens. In Eva's words, it's VS Code's way of using Julia for a brain.\n\nTo do this you type F1 or cmd/ctrl - shift-p or View -\\> Command Palette and choose Julia REPL. The command palette will appear as a drop down menu with a search function at the top of the page.\n\nNow that you have an interface with Julia as a brain, you can actually do something! Try this: type `print(\"Hello world\")` in the REPL and press Enter/Return. If you've done all of the above correctly, Hello world should print in the REPL.\n\nNow, you can also make a 'script'. Type ctrl-n or cmd-n and a document will open at the top. There will be a prompt/link to select your language. Click the link and, yes, search for and choose Julia.\n\nNext, type `print(\"Hello world\")` in the script. Just like RStudio, you can send the information in the script to the REPL. There are two ways to do this. First, and probably what you'll want, is shift-enter(return). This will send the line of code you are on, and move to the next line. ctrl-enter(return) submits the line but does not move the cursor. Try it!\n\n## Activating your project, the Project.toml and Manifest.toml\n\nWe mentioned above that it is good practice to work within an environment specific to each project. The Julia package manager (`Pkg`) allows you to do that easily: Unlike traditional package managers, which install and manage a single global set of packages, `Pkg` is designed around environments: independent sets of packages that can be local to an individual project or shared and selected by name (text taken directly from the documentation).\n\n### Getting started: activating your project.\n\nActivating your project is something that only needs doing once per computer. It allows you to add packages and dependencies to the project.\n\nIf you move the project to a new computer, or share the project, activation will be needed again.\n\nThere are two ways to activate your project.\n\n1. type `Pkg.activate(\".\")` in the REPL.\n2. type `]` in the REPL and then `activate .`\n\nThe `]` is a shorthand for using the `Pkg` package and opens the package manager. To get out of this, you press the `backspace/delete` button on your keyboard.\n\nThere are two ways to double check that you are actually working within your project:\n\n- check/click the 'Julia env:...' on the bottom of your screen (blue bar), it should match your project name\n\n- enter the package manager by typing `]` in the Julia REPL, you should see (your-project-name) pkg\\> instead of julia\\>. Again, exit the package manager using `backspace/delete` button.\n\n### Working with the package manager and growing the project and manifest files\n\nOnce your project is activated, there are two ways to use the package manager (Pkg):\n\n1. directly from the REPL:\n\n- navigate to the REPL\n- type `]`\n- you will see that instead of seeing julia\\> you now see (your-project-name) pkg\\>, indicating that all the packages that you now install (or update) will be installed (or updated) within this specific project\n- to add a package, use the function `add`: `] add Plots`\n\n2. using `Pkg` (this is useful when you want to install packages or manage them from within your script):\n\n- first type `import Pkg` and execute this line using shift-Enter\n- on subsequent lines, add, remove and update packages from your script using `Pkg` functions such as `Pkg.add()`, `Pkg.remove()` or `Pkg.update()`.\n- To add a packages, the name of the package need to be written with quotes (`Pkg.add(\"Plots\")`).\n\n#### An example using the Plots package\n\nNow that we are all set up, we are going to install a package, check the project's status and remove a package. As this might be your first time installing a package (e.g., Plots), don't be concerned if it takes a couple of minutes to run.\n\n- type `] add Plots` in the REPL (or `Pkg.add(\"Plots\")`) in your script and execute using Ctrl-Enter.\n - you just installed the Plots package and a whole bunch of dependencies that Plots needs to work. This is equivalent to Base plots in R.\n\n\n\n- type `] st` in the REPL. This will check the status of your project and print the content of your Project.toml file, which is the list of main packages, in this case, just Plots.\n\nyou should see something like:\n\n\n\n::: {.callout-tip}\n## Tip\n\nPackages can removed in the same way i.e. `] rm Plots` (or `Pkg.rm(\"Plots\")`) will remove the Plots package from your project environment (and its record in the Project.toml and Manifest.toml files)\n::: \n\n## Gearing up to Do More Stuff (what packages do I need).\n\nThere are a core set of packages we use for all of our work. These 10 packages are almost always installed when we make a project.\n\nGo ahead and use either the `]` or `Pkg.add(\"package.name\")` method to add all of these to your project.\n\n#### For working with data\n\n`CSV` `DataFrames` `DelimitedFiles`\n\n#### For plotting\n\n`Plots`\n\n#### For statistical things\n\n`Distributions` `Random` `Statistics` `StatsBase` `StatsPlots`\n\n#### For Modelling\n\n`DifferentialEquations`\n\n## Your first script setup.\n\nAt this stage, you should have a good understanding about how to create a project folder, activate a project, start the REPL, open a script and add packages to the project.\n\nNow you are ready to 'setup' your first script.\n\n1. create a new script file (ctrl-n or cmd-n).\n2. choose Julia as the language\n3. Type some informative information at the top of the script\n a. just like in R and other programming languages, the `#` is a commenter.\n4. The first section of your script is where you declare the packages you'll be using.\n a. the function to do this is `using`.\n b. make Plots, Random and DataFrames available.\n\nNow you are ready to do something really simple. Let's make some variables, data frames and a few simple plots.\n\nFirst, lets get the setup sorted and packages available\n\n\n\n\n::: {#4 .cell execution_count=1}\n``` {.julia .cell-code}\n# This is my first example script\n# 25 Jan 2023\n\n# packages I need\nusing DataFrames, Plots, Random, StatsPlots\n```\n:::\n\n\n\n\n\n\nSecond, let's make some variables and see how Julia prints them to the screen\n\n\n\n\n::: {#6 .cell execution_count=1}\n``` {.julia .cell-code}\n# make two variables using the rand function\n# because we are using random numbers, we'll set the seed here for reproducibility\n\nRandom.seed!(12345)\n\nx = rand(10)\ny = rand(10)\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```\n10-element Vector{Float64}:\n 0.3302627700323072\n 0.4219866389257305\n 0.6853069230253171\n 0.29579983859112813\n 0.9736588395655787\n 0.24458973555203245\n 0.46875054050900267\n 0.27705458732580956\n 0.6299157011197652\n 0.12180466275080659\n```\n:::\n:::\n\n\n\n\n\n\nCool. Now, lets create two data frames, one made of the x and y variables, and another with three variables made directly in a call to `DataFrame`.\n\n\n\n\n::: {#8 .cell execution_count=1}\n``` {.julia .cell-code}\n# combine into a data frame using the DataFrame function\ndf = DataFrame(x = x, y = y)\ndf\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n
10×2 DataFrame
Row
x
y
Float64
Float64
1
0.791805
0.330263
2
0.159579
0.421987
3
0.334191
0.685307
4
0.811392
0.2958
5
0.796629
0.973659
6
0.917814
0.24459
7
0.311327
0.468751
8
0.752906
0.277055
9
0.633848
0.629916
10
0.899951
0.121805
\n```\n:::\n:::\n\n\n\n\n\n\n...and the second\n\n\n\n\n::: {#10 .cell execution_count=1}\n``` {.julia .cell-code}\n# make a second data frame with three variables\n# using DataFrame directly to create variables\ndf2 = DataFrame(a=1:10, b=10*rand(10), c=10*rand(10))\ndf2\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n
10×3 DataFrame
Row
a
b
c
Int64
Float64
Float64
1
1
0.563403
9.77384
2
2
7.22679
3.58869
3
3
0.466642
3.76688
4
4
4.59489
9.03599
5
5
0.491108
8.73964
6
6
6.99192
1.36299
7
7
1.58122
0.815793
8
8
4.70745
3.75399
9
9
4.97572
0.599761
10
10
4.58675
2.14792
\n```\n:::\n:::\n\n\n\n\n\n\nGreat. Now, lets see how to plot the 'solo' variables. Note how we specify the `seriestype`. Try getting rid of this....\n\n\n\n\n::: {#12 .cell execution_count=1}\n``` {.julia .cell-code}\n# plot the data using x and y, as a scatterplot\nplot(x, y, seriestype=:scatter)\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n\n\n```\n:::\n:::\n\n\n\n\n\n\nSuperb. So, `StatsPlots` provides a special macro to use a dataframe with plots. It's a three step process:\n\n1. declare the `@df` macro\n2. define the data frame\n3. declare the columns, using the `:`\n\n\n\n\n::: {#14 .cell execution_count=1}\n``` {.julia .cell-code}\n# plot the data using the data frame macro\n# declare the df macro, declare the data frame, use : to signify columns\n@df df plot(:x, :y)\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n\n\n```\n:::\n:::\n\n\n\n\n\n\nAnd here, we use the df2, and plot variable b and c vs. a.\n\n\n\n\n::: {#16 .cell execution_count=1}\n``` {.julia .cell-code}\n# the same, and plotting two y variables\n@df df2 plot(:a, [:b, :c])\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n\n\n```\n:::\n:::\n\n\n\n\n\n\n#### A quick briefing about data frames in Julia versus R and dplyr is here\n\n[DataFrames Comparison R dplyr](https://dataframes.juliadata.org/stable/man/comparisons/#Comparison-with-the-R-package-dplyr)\n\n",
"supporting": [
"1_download_setup_files/figure-html"
],
diff --git a/_freeze/3_dataframes/execute-results/html.json b/_freeze/3_dataframes/execute-results/html.json
index 82f43cf..4deb34a 100644
--- a/_freeze/3_dataframes/execute-results/html.json
+++ b/_freeze/3_dataframes/execute-results/html.json
@@ -1,8 +1,8 @@
{
"hash": "b49fbf90a318b4daf526cbfb8677669a",
"result": {
- "engine": "jupyter",
- "markdown": "---\ntitle: \"Tutorial 3: Building and Working with DataFrames\"\ndate: last-modified\nauthor: \"Danet and Becks, based on originals by Delmas and Griffiths\"\nformat:\n html:\n embed-resources: true\ntitle-block-banner: true\n---\n\n\n\nWorking with vectors, arrays and matrices is important. But quite often, we want to collect high-dimension data (multiple variables) from our simulations and store them in a spreadsheet type format.\n\nAs you've seen in Tutorial 1, there are plotting macros (`@df`) within the `StatsPlots` package that allow us to work with data frame objects from the `DataFrames` package. A second benefit of the data frame object is that we can export it as a `csv` file and import this into **R** where we may prefer working on plotting and statistics.\n\nTo this end, here we will also introduce the `CSV` package, which is very handy for exporting DataFrame objects to csv files, and importing them as well, if you'd like.\n\n## The Data Frame\n\nTo initialise a dataframe you use the `DataFrame` function from the **DataFrames** package:\n\n::: {#011d701f .cell execution_count=2}\n``` {.julia .cell-code}\ndat = DataFrame(col1=[], col2=[], col3=[]) # we use [] to specify an empty column of any type and size.\n```\n\n::: {.cell-output .cell-output-display execution_count=3}\n```{=html}\n
0×3 DataFrame
Row
col1
col2
col3
Any
Any
Any
\n```\n:::\n:::\n\n\nAlternately, you can specify the data type for each column.\n\n::: {#3bf7ab60 .cell execution_count=3}\n``` {.julia .cell-code}\ndat1 = DataFrame(col1=Float64[], col2=Int64[], col3=Float64[])\n```\n\n::: {.cell-output .cell-output-display execution_count=4}\n```{=html}\n
0×3 DataFrame
Row
col1
col2
col3
Float64
Int64
Float64
\n```\n:::\n:::\n\n\nOf course, `col1` is not the only label you provide: variable names are super important and the conventions we use in **R** are also important here in **Julia**, e.g. `a_b` or `AaBa` but not `a b` (no spaces allowed) or `a.b` (because the (dot) `.` functions as an operator).\n\n::: {#094ed121 .cell execution_count=4}\n``` {.julia .cell-code}\n# provide informative column titles using:\ndat2 = DataFrame(species=[], size=[], rate=[])\n```\n\n::: {.cell-output .cell-output-display execution_count=5}\n```{=html}\n
0×3 DataFrame
Row
species
size
rate
Any
Any
Any
\n```\n:::\n:::\n\n\n### Allocating or adding data to a data frame.\n\nTo add data to a dataframe, we use the `push!` (read as push bang) command.\n\n::: {#06bed4d2 .cell execution_count=5}\n``` {.julia .cell-code}\nspecies = \"D.magna\"\nsize = 2.2\nrate = 4.2\n```\n\n::: {.cell-output .cell-output-display execution_count=6}\n```\n4.2\n```\n:::\n:::\n\n\n::: {#cd389d2c .cell execution_count=6}\n``` {.julia .cell-code}\n# push!() arguments: data frame, data\npush!(dat2, [species, size, rate])\n```\n\n::: {.cell-output .cell-output-display execution_count=7}\n```{=html}\n
1×3 DataFrame
Row
species
size
rate
Any
Any
Any
1
D.magna
2.2
4.2
\n```\n:::\n:::\n\n\nOf course, the `push!()` function can append data to the existing data frame. It is worth noting that `push!` can only append one row at a time. But since Julia is so good with loops (compared to R), this will make adding data to a dataframe really easy, and we'll learn how to do this in the next tutorial. What makes the `!` (bang) function very useful is that you can append (or remove, with `pop!()`) items to an object without having to assign it.\n\n::: {#94a38dec .cell execution_count=7}\n``` {.julia .cell-code}\nspecies2 = \"D.pulex\"\nsize2 = 1.8\nrate2 = 3.1\n\n# push!() arguments: data frame, data\npush!(dat2, [species2, size2, rate2])\n```\n\n::: {.cell-output .cell-output-display execution_count=8}\n```{=html}\n
2×3 DataFrame
Row
species
size
rate
Any
Any
Any
1
D.magna
2.2
4.2
2
D.pulex
1.8
3.1
\n```\n:::\n:::\n\n\n### Helper Functions for Data Frames\n\nYou can print data frames using `println`\n\n::: {#1c74f7cc .cell execution_count=8}\n``` {.julia .cell-code}\nprintln(dat2)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n2×3 DataFrame\n Row │ species size rate \n │ Any Any Any \n─────┼─────────────────────\n 1 │ D.magna 2.2 4.2\n 2 │ D.pulex 1.8 3.1\n```\n:::\n:::\n\n\nThere are `first` and `last` function that are like `head` and `tail` in R and elsewhere, with a first argument the data frame and the second argument the number of rows.\n\n::: {#a4509d62 .cell execution_count=9}\n``` {.julia .cell-code}\nfirst(dat2, 2)\n```\n\n::: {.cell-output .cell-output-display execution_count=10}\n```{=html}\n
\n```\n:::\n:::\n\n\nAnd as we learned with matrices and arrays, the `[row, column]` method also works for data frames:\n\n::: {#f57213cf .cell execution_count=11}\n``` {.julia .cell-code}\ndat2[1,2]\n```\n\n::: {.cell-output .cell-output-display execution_count=12}\n```\n2.2\n```\n:::\n:::\n\n\n::: {#65b22b88 .cell execution_count=12}\n``` {.julia .cell-code}\ndat2[1,:]\n```\n\n::: {.cell-output .cell-output-display execution_count=13}\n```{=html}\n
DataFrameRow (3 columns)
Row
species
size
rate
Any
Any
Any
1
D.magna
2.2
4.2
\n```\n:::\n:::\n\n\n::: {#65203455 .cell execution_count=13}\n``` {.julia .cell-code}\ndat2[:,3]\n```\n\n::: {.cell-output .cell-output-display execution_count=14}\n```\n2-element Vector{Any}:\n 4.2\n 3.1\n```\n:::\n:::\n\n\n## The CSV\n\nAs with *R*, there are functions to read and write `.csv` files to and from dataframes. This makes interoperability with tools in R and standard data storage file formats easy.\n\nTo write our daphnia data to a csv file, we use a familiar syntax, but a function from the `CSV` package.\n\n::: {#1d08b765 .cell execution_count=14}\n``` {.julia .cell-code}\nCSV.write(\"daphniadata.csv\", dat2)\n```\n:::\n\n\nOf course, you can read files in using.... yes, `CSV.read`. Note the second argument declares the data to go into a data frame.\n\n::: {#08f50a8a .cell execution_count=15}\n``` {.julia .cell-code}\ndaph_in = CSV.read(\"betterDaphniaData.csv\", DataFrame)\n```\n:::\n\n\n",
+ "engine": "julia",
+ "markdown": "---\ntitle: \"Tutorial 3: Building and Working with DataFrames\"\ndate: last-modified\nauthor: \"Danet and Becks, based on originals by Delmas and Griffiths\"\nformat:\n html:\n embed-resources: true\ntitle-block-banner: true\nengine: julia\n---\n\n\n\n\n\n\n\nWorking with vectors, arrays and matrices is important. But quite often, we want to collect high-dimension data (multiple variables) from our simulations and store them in a spreadsheet type format.\n\nAs you've seen in Tutorial 1, there are plotting macros (`@df`) within the `StatsPlots` package that allow us to work with data frame objects from the `DataFrames` package. A second benefit of the data frame object is that we can export it as a `csv` file and import this into **R** where we may prefer working on plotting and statistics.\n\nTo this end, here we will also introduce the `CSV` package, which is very handy for exporting DataFrame objects to csv files, and importing them as well, if you'd like.\n\n## The Data Frame\n\nTo initialise a dataframe you use the `DataFrame` function from the **DataFrames** package:\n\n\n\n\n::: {#4 .cell execution_count=1}\n``` {.julia .cell-code}\ndat = DataFrame(col1=[], col2=[], col3=[]) # we use [] to specify an empty column of any type and size.\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n
0×3 DataFrame
Row
col1
col2
col3
Any
Any
Any
\n```\n:::\n:::\n\n\n\n\n\n\nAlternately, you can specify the data type for each column.\n\n\n\n\n::: {#6 .cell execution_count=1}\n``` {.julia .cell-code}\ndat1 = DataFrame(col1=Float64[], col2=Int64[], col3=Float64[])\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n
0×3 DataFrame
Row
col1
col2
col3
Float64
Int64
Float64
\n```\n:::\n:::\n\n\n\n\n\n\nOf course, `col1` is not the only label you provide: variable names are super important and the conventions we use in **R** are also important here in **Julia**, e.g. `a_b` or `AaBa` but not `a b` (no spaces allowed) or `a.b` (because the (dot) `.` functions as an operator).\n\n\n\n\n\n::: {#8 .cell execution_count=1}\n``` {.julia .cell-code}\n# provide informative column titles using:\ndat2 = DataFrame(species=[], size=[], rate=[])\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n
0×3 DataFrame
Row
species
size
rate
Any
Any
Any
\n```\n:::\n:::\n\n\n\n\n\n\n### Allocating or adding data to a data frame.\n\nTo add data to a dataframe, we use the `push!` (read as push bang) command.\n\n\n\n\n::: {#10 .cell execution_count=1}\n``` {.julia .cell-code}\nspecies = \"D.magna\"\nsize = 2.2\nrate = 4.2\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```\n4.2\n```\n:::\n:::\n\n\n\n::: {#12 .cell execution_count=1}\n``` {.julia .cell-code}\n# push!() arguments: data frame, data\npush!(dat2, [species, size, rate])\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n
1×3 DataFrame
Row
species
size
rate
Any
Any
Any
1
D.magna
2.2
4.2
\n```\n:::\n:::\n\n\n\n\n\n\nOf course, the `push!()` function can append data to the existing data frame. It is worth noting that `push!` can only append one row at a time. But since Julia is so good with loops (compared to R), this will make adding data to a dataframe really easy, and we'll learn how to do this in the next tutorial. What makes the `!` (bang) function very useful is that you can append (or remove, with `pop!()`) items to an object without having to assign it.\n\n\n\n\n::: {#14 .cell execution_count=1}\n``` {.julia .cell-code}\nspecies2 = \"D.pulex\"\nsize2 = 1.8\nrate2 = 3.1\n\n# push!() arguments: data frame, data\npush!(dat2, [species2, size2, rate2])\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n
2×3 DataFrame
Row
species
size
rate
Any
Any
Any
1
D.magna
2.2
4.2
2
D.pulex
1.8
3.1
\n```\n:::\n:::\n\n\n\n\n\n\n### Helper Functions for Data Frames\n\nYou can print data frames using `println`\n\n\n\n\n::: {#16 .cell execution_count=1}\n``` {.julia .cell-code}\nprintln(dat2)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n2×3 DataFrame\n Row │ species size rate \n │ Any Any Any \n─────┼─────────────────────\n 1 │ D.magna 2.2 4.2\n 2 │ D.pulex 1.8 3.1\n```\n:::\n:::\n\n\n\n\n\n\nThere are `first` and `last` function that are like `head` and `tail` in R and elsewhere, with a first argument the data frame and the second argument the number of rows.\n\n\n\n\n::: {#18 .cell execution_count=1}\n``` {.julia .cell-code}\nfirst(dat2, 2)\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n
\n```\n:::\n:::\n\n\n\n\n\n\nAnd as we learned with matrices and arrays, the `[row, column]` method also works for data frames:\n\n\n\n\n::: {#22 .cell execution_count=1}\n``` {.julia .cell-code}\ndat2[1,2]\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```\n2.2\n```\n:::\n:::\n\n\n\n::: {#24 .cell execution_count=1}\n``` {.julia .cell-code}\ndat2[1,:]\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```{=html}\n
DataFrameRow (3 columns)
Row
species
size
rate
Any
Any
Any
1
D.magna
2.2
4.2
\n```\n:::\n:::\n\n\n\n::: {#26 .cell execution_count=1}\n``` {.julia .cell-code}\ndat2[:,3]\n```\n\n::: {.cell-output .cell-output-display execution_count=1}\n```\n2-element Vector{Any}:\n 4.2\n 3.1\n```\n:::\n:::\n\n\n\n\n\n\n## The CSV\n\nAs with *R*, there are functions to read and write `.csv` files to and from dataframes. This makes interoperability with tools in R and standard data storage file formats easy.\n\nTo write our daphnia data to a csv file, we use a familiar syntax, but a function from the `CSV` package.\n\n\n\n\n::: {#28 .cell execution_count=0}\n``` {.julia .cell-code}\nCSV.write(\"daphniadata.csv\", dat2)\n```\n:::\n\n\n\n\n\n\nOf course, you can read files in using.... yes, `CSV.read`. Note the second argument declares the data to go into a data frame.\n\n\n\n\n::: {#30 .cell execution_count=0}\n``` {.julia .cell-code}\ndaph_in = CSV.read(\"betterDaphniaData.csv\", DataFrame)\n```\n:::\n\n\n",
"supporting": [
"3_dataframes_files"
],
diff --git a/_freeze/4_programming_basics/execute-results/html.json b/_freeze/4_programming_basics/execute-results/html.json
index 7977122..ea23daf 100644
--- a/_freeze/4_programming_basics/execute-results/html.json
+++ b/_freeze/4_programming_basics/execute-results/html.json
@@ -1,8 +1,8 @@
{
"hash": "29dc80507167ac398fe5a080edd87cd1",
"result": {
- "engine": "jupyter",
- "markdown": "---\ntitle: \"Tutorial 4: The Basics of Programming\"\ndate: last-modified\nauthor: \"Danet and Becks, based on originals by Delmas and Griffiths\"\nformat:\n html:\n embed-resources: true\ntitle-block-banner: true\n---\n\n\n\nThis section of the tutorials introduces programming basics, including the art of simple functions, positional arguments, keyword arguments, loops, if-else-break usage and continue-while usage.\n\nIt is important to note that if you have experience programming R, there is a major difference in Julia - the use of loops is very much advocated in Julia where as *vectorising* loops is advocated in R.\n\nBasically, we write loops in Julia. We try to avoid them in R, if we want speed.\n\n## Functions\n\nFunctions work exactly like they do in R, however, there are three fundamental differences:\n\n- there is no need for {} brackets (thank god)\n- indenting (Julia requires seperate parts of a function to be indented - don't worry, VS Code should do this for you)\n- scoping (we'll attempt to explain this later)\n- functions always start with the word `function` and end with the word `end`. \n-to store something that is calculated in a function, you use the `return` command.\n\nLet's begin with a simple function - adding 2 to any number\n\n::: {#a5cdedb0 .cell execution_count=2}\n``` {.julia .cell-code}\nfunction plus_two(x)\n return x+2\nend\n```\n\n::: {.cell-output .cell-output-display execution_count=3}\n```\nplus_two (generic function with 1 method)\n```\n:::\n:::\n\n\nLet's use it now by providing an defining and x value, and asking for the function to return the new value.\n\n::: {#906252b4 .cell execution_count=3}\n``` {.julia .cell-code}\nx_in = 33\nx_out = plus_two(x_in)\n```\n\n::: {.cell-output .cell-output-display execution_count=4}\n```\n35\n```\n:::\n:::\n\n\nBecause we've defined `x_out`, we can request it...\n\n::: {#9d0b4c78 .cell execution_count=4}\n``` {.julia .cell-code}\nx_out\n```\n\n::: {.cell-output .cell-output-display execution_count=5}\n```\n35\n```\n:::\n:::\n\n\n### Positional Arguments\n\nAs in **R**, input variables for functions have a specified and fixed order unless they have a default value which is explicitly specified. For instance, we can build a function that measures body weight on different planets, but defaults to estimating weight on earth with a gravitational force of 9.81:\n\n::: {#a50bde03 .cell execution_count=5}\n``` {.julia .cell-code}\nfunction bodyweight(BW_earth, g = 9.81)\n # bw should be in kg.\n return BW_earth*g/9.81\nend\n```\n\n::: {.cell-output .cell-output-display execution_count=6}\n```\nbodyweight (generic function with 2 methods)\n```\n:::\n:::\n\n\nNote that the function is called bodyweight, it requires in the first position a weight in kg on earth and then defaults to estimating weight on earth by using g = 9.81\n\n::: {#ecd04a3f .cell execution_count=6}\n``` {.julia .cell-code}\nbodyweight(75)\n```\n\n::: {.cell-output .cell-output-display execution_count=7}\n```\n75.0\n```\n:::\n:::\n\n\nNow, if we want to estimate they same bodyweight on Mars, where gravity is 3.72, you can specify the g-value.\n\n::: {#14c0f2af .cell execution_count=7}\n``` {.julia .cell-code}\nbodyweight(75, 3.72)\n```\n\n::: {.cell-output .cell-output-display execution_count=8}\n```\n28.44036697247706\n```\n:::\n:::\n\n\n### Keyword Arguments\n\n::: {#8766f6a0 .cell execution_count=8}\n``` {.julia .cell-code}\n# function with keyword arguments:\n# here, b and d are fixed = 2\n# a is positional\n# c is a keyword argument\n# the addition of ; before c means that c is an keyword argument and can be specified in any order, but must be named\nfunction key_word(a, b=2; c, d=2) \n return a + b + c + d\nend\n```\n\n::: {.cell-output .cell-output-display execution_count=9}\n```\nkey_word (generic function with 2 methods)\n```\n:::\n:::\n\n\nHere we specify _position_ 1 (a) and that c = 3\n\n::: {#7abace53 .cell execution_count=9}\n``` {.julia .cell-code}\nkey_word(1, c = 3)\n```\n\n::: {.cell-output .cell-output-display execution_count=10}\n```\n8\n```\n:::\n:::\n\n\nHere we specify c = 3, and then position 1\n\n::: {#b24ea224 .cell execution_count=10}\n``` {.julia .cell-code}\nkey_word(c=3, 1)\n```\n\n::: {.cell-output .cell-output-display execution_count=11}\n```\n8\n```\n:::\n:::\n\n\nHere we specify position 1 (a), redefine position 2 (b = 6) and declare c = 7.\n\n::: {#8364ff96 .cell execution_count=11}\n``` {.julia .cell-code}\nkey_word(1, 6, c=7)\n```\n\n::: {.cell-output .cell-output-display execution_count=12}\n```\n16\n```\n:::\n:::\n\n\nNote that this DOES NOT work, because we've failed to define c. (and or b)\n\n::: {#01261519 .cell execution_count=12}\n``` {.julia .cell-code}\nkey_word(1, 8, d=4)\n```\n\n::: {.cell-output .cell-output-error}\n```\nLoadError: UndefKeywordError: keyword argument `c` not assigned\nUndefKeywordError: keyword argument `c` not assigned\n\nStacktrace:\n [1] top-level scope\n @ In[13]:1\n```\n:::\n:::\n\n\nTo redefine d, you'd need to define c and d.\n\n::: {#9fa30e35 .cell execution_count=13}\n``` {.julia .cell-code}\nkey_word(1, c = 8, d = 4)\n```\n\n::: {.cell-output .cell-output-display execution_count=14}\n```\n15\n```\n:::\n:::\n\n\n## Loops\n\n### For loops\nFor loops work by iterating over a specified range (e.g. 1-10) at specified intervals (e.g. 1,2,3...). For instance, we might use a for loop to fill an array:\n\n#### Filling an array\nTo fill an array, we first define an object as an array using `[]`. \n\n::: {#95566ac9 .cell execution_count=14}\n``` {.julia .cell-code}\nI_array = []\n```\n\n::: {.cell-output .cell-output-display execution_count=15}\n```\nAny[]\n```\n:::\n:::\n\n\nLike with function, all loops start with `for` and end with `end`. Here we iteratively fill `I_array` with 1000 random selections of 1 or 2.\n\n::: {#77e67baf .cell execution_count=15}\n``` {.julia .cell-code}\n# for loop to fill an array:\nfor i in 1:1000\n # pick from the number 1 or 2 at random \n # for each i'th step\n for_test = rand((1,2)) \n # push! and store for_test in I_array2\n # Julia is smart enough to do this iteratively\n # you don't necessarily have to index by `[i]` like you might do in R\n push!(I_array, for_test) \nend\n```\n:::\n\n\nLet's look at I_array now\n\n::: {#8fa11196 .cell execution_count=16}\n``` {.julia .cell-code}\nI_array\n```\n\n::: {.cell-output .cell-output-display execution_count=17}\n```\n1000-element Vector{Any}:\n 2\n 1\n 2\n 2\n 1\n 1\n 2\n 2\n 2\n 2\n 2\n 1\n 1\n ⋮\n 1\n 1\n 1\n 1\n 1\n 1\n 2\n 2\n 2\n 1\n 1\n 2\n```\n:::\n:::\n\n\nLet's try something more complex, iterating over multiple indices\n\nA new storage container:\n\n::: {#78b373ff .cell execution_count=17}\n``` {.julia .cell-code}\ntab = []\n```\n\n::: {.cell-output .cell-output-display execution_count=18}\n```\nAny[]\n```\n:::\n:::\n\n\nNow, we fill the storage container with values of i, j and k. Can you tell which in which order this will happen? The first entry will be `[1,1,1]`. The second will be `[2,1,1]`. Do you understand why? Mess around to check.\n\n::: {#66b745cc .cell execution_count=18}\n``` {.julia .cell-code}\n# nested for loop to fill an array:\nfor k in 1:4\n for j in 1:3\n for i in 1:2\n append!(tab,[[i,j,k]]) # here we've use append! to allocate iteratively to the array as opposed to using push! - both work. \n end\n end\nend\n```\n:::\n\n\nLet's look...\n\n::: {#a15bceab .cell execution_count=19}\n``` {.julia .cell-code}\ntab\n```\n\n::: {.cell-output .cell-output-display execution_count=20}\n```\n24-element Vector{Any}:\n [1, 1, 1]\n [2, 1, 1]\n [1, 2, 1]\n [2, 2, 1]\n [1, 3, 1]\n [2, 3, 1]\n [1, 1, 2]\n [2, 1, 2]\n [1, 2, 2]\n [2, 2, 2]\n [1, 3, 2]\n [2, 3, 2]\n [1, 1, 3]\n [2, 1, 3]\n [1, 2, 3]\n [2, 2, 3]\n [1, 3, 3]\n [2, 3, 3]\n [1, 1, 4]\n [2, 1, 4]\n [1, 2, 4]\n [2, 2, 4]\n [1, 3, 4]\n [2, 3, 4]\n```\n:::\n:::\n\n\nWe can also allocate to a multiple dimensional matrix. When working with matrices, we can build them out of zeros and the replace the values.\n\nHere we start with a three dimensional array with 4 two x three matrices.\n\n::: {#a2794b31 .cell execution_count=20}\n``` {.julia .cell-code}\nthreeDmatrix = zeros(2,3,4)\n```\n\n::: {.cell-output .cell-output-display execution_count=21}\n```\n2×3×4 Array{Float64, 3}:\n[:, :, 1] =\n 0.0 0.0 0.0\n 0.0 0.0 0.0\n\n[:, :, 2] =\n 0.0 0.0 0.0\n 0.0 0.0 0.0\n\n[:, :, 3] =\n 0.0 0.0 0.0\n 0.0 0.0 0.0\n\n[:, :, 4] =\n 0.0 0.0 0.0\n 0.0 0.0 0.0\n```\n:::\n:::\n\n\nNow, let's do a nested loop again, but this time into the matrices. The element we are adding each iteration is the sum of i+j+k.\n\nCan you guess how this works?\n\n::: {#29a3be11 .cell execution_count=21}\n``` {.julia .cell-code}\nfor k in 1:4\n for j in 1:3\n for i in 1:2\n # note default is by column....\n # first element allocated is 1+1+1, then 2+1+1 and this is first col\n # then 1+2+1 and 2+2+1 into the second col\n # then 1+3+1 and 2+3+1 into the third col\n threeDmatrix[i,j,k] = i+j+k\n end\n end\nend\n```\n:::\n\n\n::: {#c65ebde3 .cell execution_count=22}\n``` {.julia .cell-code}\nthreeDmatrix\n```\n\n::: {.cell-output .cell-output-display execution_count=23}\n```\n2×3×4 Array{Float64, 3}:\n[:, :, 1] =\n 3.0 4.0 5.0\n 4.0 5.0 6.0\n\n[:, :, 2] =\n 4.0 5.0 6.0\n 5.0 6.0 7.0\n\n[:, :, 3] =\n 5.0 6.0 7.0\n 6.0 7.0 8.0\n\n[:, :, 4] =\n 6.0 7.0 8.0\n 7.0 8.0 9.0\n```\n:::\n:::\n\n\nFinally, note that we can use `println` to provide a basic marker what what is happening: we show two ways to do this in the code.\n\n::: {#7edbb0b5 .cell execution_count=23}\n``` {.julia .cell-code}\nfor k in 1:4\n for j in 1:3\n for i in 1:2\n #println(i,\"-\",j,\"-\",k) # multiple quotes\n println(\"$i-$j-$k\") # one quote, $ to grab variables\n \n # note default is by column....\n # first element allocated is 1+1+1, then 2+1+1 and this is first col\n # then 1+2+1 and 2+2+1 into the second col\n # then 1+3+1 and 2+3+1 into the third col\n threeDmatrix[i,j,k] = i+j+k\n end\n end\nend\n```\n:::\n\n\nAnd just for fun... this `println` trick can be handy for verbose tracking. Note how `person in unique(persons)` iterates and how you can embed a variable's value in a text string.\n\n::: {#d5efcf8c .cell execution_count=24}\n``` {.julia .cell-code}\npersons = [\"Alice\", \"Alice\", \"Bob\", \"Bob2\", \"Carl\", \"Dan\"]\n\nfor person in unique(persons)\n println(\"Hello $person\")\nend\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nHello Alice\nHello Bob\nHello Bob2\nHello Carl\nHello Dan\n```\n:::\n:::\n\n\nThere are tons of different functions that can be helpful when building loops. Take a few minutes to look into the help files for `eachindex`, `eachcol`, `eachrow` and `enumerate`. They all provide slightly different ways of telling Julia how you want to loop over a problem. Also, remember that loops aren't just for allocation, they can also be very useful when doing calculations.\n\n### if, else, breaks\nWhen building a loop, it is often meaningful to stop or modify the looping process when a certain condition is met. For example, we can use the `break`, `if` and `else` statements to stop a for loop when i exceeds a given value (e.g. 10):\n\n::: {#022fdd69 .cell execution_count=25}\n``` {.julia .cell-code}\n# if and break:\nfor i in 1:100\n println(i) # print i\n if i >10\n break # stop the loop with i >10\n end \nend\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n```\n:::\n:::\n\n\n::: {#d18bb32a .cell execution_count=26}\n``` {.julia .cell-code}\n# this loop can be modified using an if-else statement:\n# even though we are iterating to 100, it stops at 10.\nfor j in 1:100\n if j >10\n break # stop the loop with i >10\n else\n crj = j^3\n println(\"J is = $j\") # print i\n println(\"The Cube of $j is $crj\")\n end\nend\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nJ is = 1\nThe Cube of 1 is 1\nJ is = 2\nThe Cube of 2 is 8\nJ is = 3\nThe Cube of 3 is 27\nJ is = 4\nThe Cube of 4 is 64\nJ is = 5\nThe Cube of 5 is 125\nJ is = 6\nThe Cube of 6 is 216\nJ is = 7\nThe Cube of 7 is 343\nJ is = 8\nThe Cube of 8 is 512\nJ is = 9\nThe Cube of 9 is 729\nJ is = 10\nThe Cube of 10 is 1000\n```\n:::\n:::\n\n\nYou'll notice that every statement requires it's own set of `for` and `end` points, and is indented as per Julia's requirements. `if` and `else` statements can be very useful when building experiments: for example we might want to stop simulating a network's dynamics if more than 50% of the species have gone extinct.\n\n### continue and while\n\n#### continue\nThe `continue` command is the opposite to `break` and can be useful when you want to skip an iteration but not stop the loop:\n\n::: {#246fc469 .cell execution_count=27}\n``` {.julia .cell-code}\nfor i in 1:30\n # this reads: is it false that i is a multiple of 3?\n if i % 3 == false\n continue # makes the loop skip iterations that are a multiple of 3\n else println(\"$i is not a multiple of 3\")\n end\nend\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n1 is not a multiple of 3\n2 is not a multiple of 3\n4 is not a multiple of 3\n5 is not a multiple of 3\n7 is not a multiple of 3\n8 is not a multiple of 3\n10 is not a multiple of 3\n11 is not a multiple of 3\n13 is not a multiple of 3\n14 is not a multiple of 3\n16 is not a multiple of 3\n17 is not a multiple of 3\n19 is not a multiple of 3\n20 is not a multiple of 3\n22 is not a multiple of 3\n23 is not a multiple of 3\n25 is not a multiple of 3\n26 is not a multiple of 3\n28 is not a multiple of 3\n29 is not a multiple of 3\n```\n:::\n:::\n\n\nCan you figure out what the code would be for keeping even numbers only? Note the change of logic from false above to true here.\n\n::: {#6069047a .cell execution_count=28}\n``` {.julia .cell-code}\nfor i in 1:10\n # where is it true that i is a multiple of 2?\n if i % 2 == true\n continue # makes the loop skip iterations that are odd\n else println(\"$i is even\")\n end\nend\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n2 is even\n4 is even\n6 is even\n8 is even\n10 is even\n```\n:::\n:::\n\n\n#### while\n\n`while` loops provide an alternative to `for` loops and allow you to iterate until a certain condition is met:\n\n::: {#81d29bdb .cell execution_count=29}\n``` {.julia .cell-code}\n# counter that is globally scoped (see next section)\n# testval -- try changing this to see how this global variable can be used in \n# the local process below\nglobal j=0\nglobal testval = 17\n\n# note that we started with j = 0!!!\n# justify a condition\nwhile(j10\n break # stop the loop with i >10\n end \nend\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n```\n:::\n:::\n\n\n\n::: {#52 .cell execution_count=1}\n``` {.julia .cell-code}\n# this loop can be modified using an if-else statement:\n# even though we are iterating to 100, it stops at 10.\nfor j in 1:100\n if j >10\n break # stop the loop with i >10\n else\n crj = j^3\n println(\"J is = $j\") # print i\n println(\"The Cube of $j is $crj\")\n end\nend\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nJ is = 1\nThe Cube of 1 is 1\nJ is = 2\nThe Cube of 2 is 8\nJ is = 3\nThe Cube of 3 is 27\nJ is = 4\nThe Cube of 4 is 64\nJ is = 5\nThe Cube of 5 is 125\nJ is = 6\nThe Cube of 6 is 216\nJ is = 7\nThe Cube of 7 is 343\nJ is = 8\nThe Cube of 8 is 512\nJ is = 9\nThe Cube of 9 is 729\nJ is = 10\nThe Cube of 10 is 1000\n```\n:::\n:::\n\n\n\n\n\n\nYou'll notice that every statement requires it's own set of `for` and `end` points, and is indented as per Julia's requirements. `if` and `else` statements can be very useful when building experiments: for example we might want to stop simulating a network's dynamics if more than 50% of the species have gone extinct.\n\n### continue and while\n\n#### continue\nThe `continue` command is the opposite to `break` and can be useful when you want to skip an iteration but not stop the loop:\n\n\n\n\n::: {#54 .cell execution_count=1}\n``` {.julia .cell-code}\nfor i in 1:30\n # this reads: is it false that i is a multiple of 3?\n if i % 3 == false\n continue # makes the loop skip iterations that are a multiple of 3\n else println(\"$i is not a multiple of 3\")\n end\nend\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n1 is not a multiple of 3\n2 is not a multiple of 3\n4 is not a multiple of 3\n5 is not a multiple of 3\n7 is not a multiple of 3\n8 is not a multiple of 3\n10 is not a multiple of 3\n11 is not a multiple of 3\n13 is not a multiple of 3\n14 is not a multiple of 3\n16 is not a multiple of 3\n17 is not a multiple of 3\n19 is not a multiple of 3\n20 is not a multiple of 3\n22 is not a multiple of 3\n23 is not a multiple of 3\n25 is not a multiple of 3\n26 is not a multiple of 3\n28 is not a multiple of 3\n29 is not a multiple of 3\n```\n:::\n:::\n\n\n\n\n\n\nCan you figure out what the code would be for keeping even numbers only? Note the change of logic from false above to true here.\n\n\n\n\n::: {#56 .cell execution_count=1}\n``` {.julia .cell-code}\nfor i in 1:10\n # where is it true that i is a multiple of 2?\n if i % 2 == true\n continue # makes the loop skip iterations that are odd\n else println(\"$i is even\")\n end\nend\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n2 is even\n4 is even\n6 is even\n8 is even\n10 is even\n```\n:::\n:::\n\n\n\n\n\n\n#### while\n\n`while` loops provide an alternative to `for` loops and allow you to iterate until a certain condition is met:\n\n\n\n\n::: {#58 .cell execution_count=1}\n``` {.julia .cell-code}\n# counter that is globally scoped (see next section)\n# testval -- try changing this to see how this global variable can be used in \n# the local process below\nglobal j=0\nglobal testval = 17\n\n# note that we started with j = 0!!!\n# justify a condition\nwhile(j\n\n```\n:::\n:::\n\n\nIf you want to add more data to a plot, the `plot!()` function is super valuable, and complemented by the `xlabel!()` and `ylabel!()` function to update the x-axis\n\n::: {#bdbaf98e .cell execution_count=3}\n``` {.julia .cell-code}\ny2 = rand(100) # another 100 randoms\nplot!(x, y2, label = \"less amazing\")\nxlabel!(\"time is not your friend\")\nylabel!(\"ooh la la la\")\n```\n\n::: {.cell-output .cell-output-display execution_count=4}\n```{=html}\n\n\n```\n:::\n:::\n\n\nRecall too that there is a `seriestype` argument to shift between the default line and, perhaps a scatterplot. Note that we can deliver both y and y2.\n\n::: {#981969a9 .cell execution_count=4}\n``` {.julia .cell-code}\nplot(x, y, seriestype = [:line,:scatter], markershape = :diamond, lc = :orange, mc = :black, msc = :orange, label = \"Y\")\nplot!(x, y2, seriestype = [:line,:scatter], markershape = :diamond, lc = :blue, mc = :black, msc = :blue, label = \"Y2\")\n```\n\n::: {.cell-output .cell-output-display execution_count=5}\n```{=html}\n\n