+ "markdown": "---\nauthor: \"Ryan M. Moore, PhD\"\ndate-modified: last-modified\ndate: \"2025-02-16\"\njupyter: python3\n---\n\n# Miniproject 1: Modeling Amoeba Population Growth {.unnumbered}\n\n_Note: To complete the miniproject, download the [quarto document](https://github.com/mooreryan/applied_python_programming/blob/main/miniprojects/amoebas/index.qmd) and complete any required sections._\n\n## Overview\n\nLet's build a fun simulation that models how populations of amoebas grow and change over time! We'll create a simplified version of their life cycle where these single-celled organisms can:\n\n- Grow or shrink randomly\n- Split into two when they get too big\n- Die if they become too small\n\nWhile this is a simplified model compared to real amoeba biology, it lets us explore some interesting population dynamics while practicing core programming concepts.\n\n### What You'll Need\n\nIn addition to Python 3 and Quarto, which you should have set up in Module 0, you will need to install [seaborn](https://seaborn.pydata.org/index.html), a package for statistical data visualization. Follow the instructions in this [installation guide](https://seaborn.pydata.org/installing.html) to get it set up.\n\n### Learning Goals\n\nBy completing this project, you will:\n\n- Practice breaking complex problems into smaller, manageable pieces\n- Get hands-on experience with loops and if/else logic\n- Learn to track data across multiple iterations\n- Create your first data visualization\n- Practice explaining your code and thought process\n\n## The Basic Rules\n\nYour amoeba population should follow these rules.\n\n### Starting conditions\n\n- Begin with 10 amoebas\n- Each amoeba starts at size 10\n\n### Each turn\n\n- Every amoeba randomly grows or shrinks between -2 and +2 units\n- If an amoeba gets smaller than 5 units, it dies\n- If an amoeba grows larger than 15 units, it splits into two amoebas, each half the size\n- Keep track of:\n - The total number of living amoebas (`population_history`)\n - How many amoebas died (`death_history`)\n - How many times amoebas split into two (`split_history`)\n\nWe'll store these measurements in three lists: `population_history`, `death_history`, and `split_history`. This will let us see how our population changes over time and create some interesting visualizations later.\n\n_Note: Using these exact variable names will ensure the plotting code works smoothly at the end of the project._\n\n### Ending the Simulation\n\nThe simulation runs until either:\n\n- 999 turns have passed, or\n- All amoebas have died\n\n## What to Include in Your Write-up\n\nYour project should include:\n\n- The simulation code itself\n- Well-commented code\n - Help your future self (and others) understand your thinking\n - Explain the \"why\" behind key decisions\n- A brief discussion of your implementation choices\n - What approaches did you consider?\n - Why did you choose your final solution?\n- Analysis of results\n - What patterns did you observe in the population over time?\n - Try changing some parameters (growth range, split/death thresholds, etc.)\n - How do different settings affect population survival?\n\n### Experiment!\n\nOnce you have a working simulation, try these variations:\n\n- Adjust the growth/shrink range\n- Change the split and death thresholds\n- Find settings that keep the population alive longer\n- What other parameters could you modify?\n\nAdd a short paragraph to your write-up discussing the results of your experiments.\n\n**Remember**: The goal is to learn and explore. There's no single \"right\" answer!\n\n## Helpful Code Examples\n\nHere are some building blocks to help you get started.\n\n### Keeping Track of Changes Over Time\n\nIn the amoeba simulation, you will need to monitor how total population, number of deaths, and number of splits change across turns. Here's a simple pattern that shows how to track these changes:\n\n::: {#105926bf .cell execution_count=1}\n``` {.python .cell-code}\n# This list will store our values at each step\nsum_history = []\n\n# This tracks our current total\nrunning_sum = 0\n\nfor number in range(5):\n # Update our running total by adding the new value\n running_sum += number\n\n # Save this step's total to our history\n sum_history.append(running_sum)\n```\n:::\n\n\nYou could think of `sum_history` like taking snapshots of your data at each moment in time. Each time through the loop, we update our current value (`running_sum`) and then save that snapshot to our history list. This pattern is useful when you need to look back at how your values changed throughout your simulation.\n\n### Generating Numbers in a Range\n\nIn this simulation, you will need to generate numbers within a range. Python makes this easy with the [`randint`](https://docs.python.org/3/library/random.html#random.randint) function from its `random` module. Think of it as setting up the minimum and maximum values you want, and letting Python pick random numbers within that range.\n\nHere's a simple example:\n\n::: {#de4ca743 .cell execution_count=2}\n``` {.python .cell-code}\nimport random\n\nfor _ in range(5):\n number = random.randint(-10, 10)\n print(number)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n-4\n9\n8\n-9\n10\n```\n:::\n:::\n\n\nThis code creates a list of 5 random whole numbers, where each number can be anywhere from -10 to 10 (including both -10 and 10), and then prints out the number. Every time you run this code, you'll get a different set of numbers. Try running the code block a few times to check.\n\n_Note: The value range in `radom.randint(a, b)` is inclusive, meaning both the lower bound (`a`) and upper bound (`b`) can appear in your results._\n\n### Managing Your Amoeba Population\n\nA key piece of this simulation is handling the changing population of amoebas over time. It's a good idea to store our amoebas in a Python list, which works like a container that can hold multiple items. Each turn, we need to check each amoeba against our rules to determine if it:\n\n- Survives to the next turn\n- Dies and gets removed from the population\n- Splits into multiple amoebas\n\nHere's a straightforward way to handle these population changes. Instead of trying to modify our original population list directly (which can get messy), we'll create a new list for the survivors each turn.\n\nHere's a simple example to illustrate this concept:\n\n::: {#4f68b343 .cell execution_count=3}\n``` {.python .cell-code}\namoebas = [1, 2, 3, 4, 5, 6]\nprint(\"Starting population:\", amoebas)\n\n# Create an empty list to hold the survivors\nsurvivors = []\n\n# Check each amoeba against our survival rules\nfor amoeba in amoebas:\n # In this example, amoebas with even-numbered sizes survive\n if amoeba % 2 == 0:\n survivors.append(amoeba)\n # Amoebas with odd-numbered sizes \"die\" by not being added to survivors\n\n# Update our population with the survivors\namoebas = survivors\nprint(\"Population after 1 turn:\", amoebas)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nStarting population: [1, 2, 3, 4, 5, 6]\nPopulation after 1 turn: [2, 4, 6]\n```\n:::\n:::\n\n\nThis approach is particularly useful when embedded in a larger loop that tracks multiple turns. Each turn, you start fresh with a new survivors list, apply your rules, and then update the population accordingly.\n\nWhile Python offers several ways to accomplish this task, this method is particularly clear and reliable. It gives you complete control over which amoebas make it to the next generation and makes it easy to add more complex survival rules later.\n\n## Simulation\n\n### Simulation Code\n\n::: {#4a3b2bee .cell execution_count=4}\n``` {.python .cell-code}\n# Write your simulation code here!\n```\n:::\n\n\n### Visualizing Your Simulation Results\n\nLet's create a graph to see how your amoeba population changed over time! We'll use a Python library called seaborn to make a clear, professional-looking line plot that shows the total population, deaths, and splits at each turn of the simulation.\n\nHere's the code to create the visualization:\n\n```python\nimport seaborn as sns\n\n# Set up the default seaborn style\nsns.set_theme()\n\n# Create a line plot showing all three metrics\nplot = sns.relplot(\n data={\n \"Population\": population_history,\n \"Deaths\": death_history,\n \"Splits\": split_history,\n },\n kind=\"line\",\n)\n\n# Label the axes\nplot.set_axis_labels(\"Turn\", \"Amoeba Count\")\n```\n\nIf you used different variable names to track your data (instead of `population_history`, `death_history`, or `split_history`), simply replace those names in the code above with your variable names.\n\nThis visualization will help you spot patterns in your simulation, like population booms and crashes, or how deaths and splits relate to each other. Don't worry if some of the plotting code looks unfamiliar -- we'll dive deeper into data visualization with seaborn in future lessons!\n\n## Analysis\n\nWrite your analysis text here!\n\n",
0 commit comments