<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Computer tutorials &#8211; The Bowman Lab</title>
	<atom:link href="https://www.polarmicrobes.org/category/computer-tutorials/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.polarmicrobes.org</link>
	<description>Marine Microbial Ecology</description>
	<lastBuildDate>Sat, 18 Apr 2026 14:04:42 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
<site xmlns="com-wordpress:feed-additions:1">188265837</site>	<item>
		<title>Local installation of DeepTMHMM</title>
		<link>https://www.polarmicrobes.org/local-installation-of-deeptmhmm/</link>
		
		<dc:creator><![CDATA[Jeff]]></dc:creator>
		<pubDate>Wed, 03 Dec 2025 20:38:49 +0000</pubDate>
				<category><![CDATA[Computer tutorials]]></category>
		<guid isPermaLink="false">https://www.polarmicrobes.org/?p=3537</guid>

					<description><![CDATA[For one of our ongoing metagenomic projects I needed to split predicted proteins into cytoplasmic and transmembrane groups. After looking at a couple of different options I opted to use DeepTMHMM, part of the biolib framework. DeepTMHMM has a wonderful &#8230; <a href="https://www.polarmicrobes.org/local-installation-of-deeptmhmm/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p>For one of our ongoing metagenomic projects I needed to split predicted proteins into cytoplasmic and transmembrane groups.  After looking at a couple of different options I opted to use <a href="https://dtu.biolib.com/DeepTMHMM">DeepTMHMM</a>, part of the <a href="https://biolib.com/">biolib</a> framework.  DeepTMHMM has a wonderful wrapper that submits jobs to a remote server for analysis.  This is great for relatively small numbers of sequences.  However, even after clustering by similarity I have well over 10<sup>5</sup> predicted proteins.  The wrapper would be terribly inefficient for this many sequences, and while I couldn&#8217;t find any explicit limits on the number of submissions, I presume that it would be considered rude to bomb the server with thousands of fasta files.  Thus began my odyssey to run DeepTMHMM locally, and Homeric the journey was.  Unfortunately, there was no way to document the step by step which involved serious and increasingly frantic troubleshooting of both hardware and software.  Instead I present some cautionary notes on things that didn&#8217;t work and solution that ultimately did.</p>



<p>DeepTMHMM makes use of a GPU via PyTorch.  None of our servers were equipped with a GPU so step 1 was to acquire one.  I have a pretty good, though elderly, Linux box in my office for development work.  Some discussion with the manufacturer (<a href="https://www.pugetsystems.com/">Puget Systems</a>) assured me that the motherboard would be compatible with a relatively modern GPU.  I selected an NVIDIA GeForce RTX 4060 as a good compromise between cost and performance and a couple days later was ready for surgery.  Here&#8217;s where some initial mistakes were made.  I admit them here so that others may find humor.</p>



<p>Mistake 1 &#8211; I borrowed some power cables for the GPU not appreciating that these are specific to the power supply unit.  The resulting (mildly traumatic) incident somehow marred the boot sector of the boot drive, though the drive itself was fine.  While recovering from that I made Mistake 2:</p>



<p>Mistake 2 &#8211; Updating operating system.  Development workstation was (is) running Ubuntu LTS 20.04 which is nearing end of support.  Since I was replacing the boot drive anyway it seemed like a good idea to modernize things to LTS 24.04.</p>



<p>After a bit of work I had everything up and running (with original power cables which I thankfully had been toting around for 10 years) and the <code>nvidia-smi</code> command showed the GPU alive and talking to the system.  Time to install DeepTMHMM.</p>



<p>The &#8220;preferred&#8221; way of running DeepTMHMM locally is via a docker container.  Let the record show that I do not recommend this option.  I tried this on the workstation and via WSL on my GPU-equipped laptop.  Buried deep deep deep in the stack are some dependency conflicts that prevent a modern implementation of docker from reading the output of the code running inside the outdated container.  After a few days of troubleshooting I abandoned this in favor of a local install of DeepTMHMM.</p>



<p>You can obtain an academic license and copy of the software by emailing <a href="mailto:licensing@biolib.com">licensing@biolib.com</a> (thank you ChatGPT for this solution&#8230; I don&#8217;t think I would have found it otherwise).  On the surface it looks straightforward enough.  There&#8217;s a helpful README file with install instructions and a reasonable number of dependencies.  The trick is with the dependency versions.</p>



<p>Following standard best practice I isolated everything in a conda environment using a Python version that matched the docker container (3.8.20).  I felt my way through the rest of the dependencies and it all looked good, but regardless of what I tried the specified version of PyTorch couldn&#8217;t run code on the GPU.  I can&#8217;t recall all or even most of the things I tried, but at some point I reached the end of the line and decided to recreate a historically accurate place for DeepTMHMM to call home.  This meant reinstalling LTS 20.04 and an older NVIDIA driver (570.133.07).  I did need a more recent version of CUDA (12.8) than was bundled with PyTorch, and PyTorch 2.0.1 instead of the one indicated in the README.  Magically, and most unexpectedly at this point, everything worked and DeepTMHMM is happily chewing on my data.  Should take about 90 hours to run 200,000 or so predictions.</p>



<p>Here&#8217;s the final recipe that worked and a modified version of the original README:<br>OS: Ubuntu LTS 20.04.6<br>GPU: NVIDIA GeForce RTX 4060<br>CUDA: v12.8<br>NVIDIA driver: 570.133.07</p>



<pre class="wp-block-code"><code>### DeepTMHMM 1.0 - Academic Version ###

### Installation ###

# Install system-wide dependencies

sudo apt-get install libhdf5-dev

# Setup a virtual environment

conda create -n deeptmhmm python=3.8
conda activate deeptmhmm

# Install build dependencies (inside environment but not with conda)
python3 -m pip install wheel Cython==0.29.37 pkgconfig==1.5.5

# Install PyTorch
pip install torch==2.0.1

# Install other dependencies (inside environment but not with conda)
python3 -m pip install -r requirements.txt

# Run tool on sample file
python3 predict.py --fasta sample.fasta --output-dir result1

# The result is now available in result1/</code></pre>



<p>The output of <code>nvidia-smi</code> for good measure.  Note the GPU memory allocated to python3 for DeepTMHMM:</p>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" fetchpriority="high" decoding="async" width="640" height="278" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2025/12/image.png?resize=640%2C278&#038;ssl=1" alt="" class="wp-image-3539" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2025/12/image.png?resize=1024%2C445&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2025/12/image.png?resize=300%2C130&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2025/12/image.png?resize=768%2C334&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2025/12/image.png?w=1099&amp;ssl=1 1099w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<p></p>



<p></p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Flocal-installation-of-deeptmhmm%2F&amp;linkname=Local%20installation%20of%20DeepTMHMM" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Flocal-installation-of-deeptmhmm%2F&amp;linkname=Local%20installation%20of%20DeepTMHMM" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Flocal-installation-of-deeptmhmm%2F&amp;linkname=Local%20installation%20of%20DeepTMHMM" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fwww.polarmicrobes.org%2Flocal-installation-of-deeptmhmm%2F&#038;title=Local%20installation%20of%20DeepTMHMM" data-a2a-url="https://www.polarmicrobes.org/local-installation-of-deeptmhmm/" data-a2a-title="Local installation of DeepTMHMM"></a></p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3537</post-id>	</item>
		<item>
		<title>Alignment and phylogenetic inference with hmmalign and RAxML-ng</title>
		<link>https://www.polarmicrobes.org/alignment-and-phylogenetic-inference-with-hmmalign-and-raxml-ng/</link>
		
		<dc:creator><![CDATA[Jeff]]></dc:creator>
		<pubDate>Tue, 31 May 2022 04:13:03 +0000</pubDate>
				<category><![CDATA[Computer tutorials]]></category>
		<category><![CDATA[HMMER]]></category>
		<category><![CDATA[phylogenetic]]></category>
		<category><![CDATA[RAxML]]></category>
		<guid isPermaLink="false">https://www.polarmicrobes.org/?p=3390</guid>

					<description><![CDATA[RAxML is one of the most popular programs around for phylogenetic inference via maximum likelihood. Similarly, hmmalign within HMMER 3 is a popular way to align amino acid sequences against HMMs from Pfam or created de novo. Combine the two &#8230; <a href="https://www.polarmicrobes.org/alignment-and-phylogenetic-inference-with-hmmalign-and-raxml-ng/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p><a href="https://github.com/amkozlov/raxml-ng">RAxML</a> is one of the most popular programs around for phylogenetic inference via maximum likelihood.  Similarly, hmmalign within <a href="http://hmmer.org/">HMMER 3</a> is a popular way to align amino acid sequences against HMMs from Pfam or created <em>de novo</em>.  Combine the two and you have an excellent method for constructing phylogenetic trees.  But gluing the two together isn&#8217;t exactly seamless and novice users might be deterred by a couple of unexpected hurdles.  Recently, I helped a student develop a workflow which I&#8217;m posting here.</p>



<p>First, define some variables just to make the bash commands a bit cleaner.  REF refers to the name of the Pfam hmm that we&#8217;re aligning against (Bac_rhodopsin.hmm in this case), while QUERY is the sequence file to be aligned (hop and bop gene products, plus a dinoflagellate rhodopsin as outgroup).</p>



<pre class="wp-block-code"><code>REF=Bac_rhodopsin
QUERY=uniprot_hop_bop_reviewed</code></pre>



<p>Now, align and convert the alignment to fasta format (required by RAxML-ng).</p>



<pre class="wp-block-code"><code>hmmalign --amino -o $QUERY.sto $REF.hmm $QUERY.fasta
seqmagick convert $QUERY.sto $QUERY.align.fasta</code></pre>



<p>Test which model is best for these data.  Here we get <code>LG+G4+F</code>.</p>



<pre class="wp-block-code"><code>modeltest-ng -i $QUERY.align.fasta -d aa -p 8</code></pre>



<p>Check your alignment!</p>



<pre class="wp-block-code"><code>raxml-ng --check --msa $QUERY.align.fasta --model LG+G4+F --prefix $QUERY</code></pre>



<p>Oooh&#8230; I bet it failed.  Exciting!  In this case (using sequences from Uniprot) the long sequence descriptions are incompatible with RAxML-ng.  Let&#8217;s do a little Python to clean that up.</p>



<pre class="wp-block-code"><code>from Bio import SeqIO

with open('uniprot_hop_bop_reviewed.align.clean.fasta', 'w') as clean_fasta:
    for record in SeqIO.parse('uniprot_hop_bop_reviewed.align.fasta', 'fasta'):
        record.description = ''
        SeqIO.write(record, clean_fasta, 'fasta')</code></pre>



<p>Check again&#8230;</p>



<pre class="wp-block-code"><code>raxml-ng --check --msa $QUERY.align.clean.fasta --model LG+G4+F --prefix $QUERY</code></pre>



<p>If everything is kosher go ahead and fire up your phylogenetic inference.  Here I&#8217;ve limited bootstrapping to 100 trees.  If you have the time/resources do more.</p>



<pre class="wp-block-code"><code>raxml-ng --all --msa $QUERY.align.clean.fasta --model LG+G4+F --prefix $QUERY --bs-trees 100</code></pre>



<p>Superimpose the bootstrap support values on the best ML tree.</p>



<pre class="wp-block-code"><code>raxml-ng --support --tree $QUERY.raxml.bestTree --bs-trees $QUERY.raxml.bootstraps</code></pre>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" decoding="async" width="640" height="348" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2022/05/uniprot_hop_bop_reviewed.raxml_.bestTree.raxml_.png?resize=640%2C348&#038;ssl=1" alt="" class="wp-image-3391" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2022/05/uniprot_hop_bop_reviewed.raxml_.bestTree.raxml_.png?resize=1024%2C557&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2022/05/uniprot_hop_bop_reviewed.raxml_.bestTree.raxml_.png?resize=300%2C163&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2022/05/uniprot_hop_bop_reviewed.raxml_.bestTree.raxml_.png?resize=768%2C417&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2022/05/uniprot_hop_bop_reviewed.raxml_.bestTree.raxml_.png?resize=1536%2C835&amp;ssl=1 1536w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2022/05/uniprot_hop_bop_reviewed.raxml_.bestTree.raxml_.png?w=1748&amp;ssl=1 1748w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2022/05/uniprot_hop_bop_reviewed.raxml_.bestTree.raxml_.png?w=1280&amp;ssl=1 1280w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<p>And here&#8217;s our creation as rendered by <a href="https://github.com/cmzmasek/archaeopteryx-js">Archaeopteryx</a>.  Some day I&#8217;ll create a tree that is visually appealing, but today is not that day.  But you get the point.  </p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Falignment-and-phylogenetic-inference-with-hmmalign-and-raxml-ng%2F&amp;linkname=Alignment%20and%20phylogenetic%20inference%20with%20hmmalign%20and%20RAxML-ng" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Falignment-and-phylogenetic-inference-with-hmmalign-and-raxml-ng%2F&amp;linkname=Alignment%20and%20phylogenetic%20inference%20with%20hmmalign%20and%20RAxML-ng" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Falignment-and-phylogenetic-inference-with-hmmalign-and-raxml-ng%2F&amp;linkname=Alignment%20and%20phylogenetic%20inference%20with%20hmmalign%20and%20RAxML-ng" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fwww.polarmicrobes.org%2Falignment-and-phylogenetic-inference-with-hmmalign-and-raxml-ng%2F&#038;title=Alignment%20and%20phylogenetic%20inference%20with%20hmmalign%20and%20RAxML-ng" data-a2a-url="https://www.polarmicrobes.org/alignment-and-phylogenetic-inference-with-hmmalign-and-raxml-ng/" data-a2a-title="Alignment and phylogenetic inference with hmmalign and RAxML-ng"></a></p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3390</post-id>	</item>
		<item>
		<title>A short tutorial on Gnu Parallel</title>
		<link>https://www.polarmicrobes.org/a-short-tutorial-on-gnu-parallel/</link>
					<comments>https://www.polarmicrobes.org/a-short-tutorial-on-gnu-parallel/#comments</comments>
		
		<dc:creator><![CDATA[Luke Piszkin]]></dc:creator>
		<pubDate>Wed, 20 Jan 2021 05:36:12 +0000</pubDate>
				<category><![CDATA[Computer tutorials]]></category>
		<guid isPermaLink="false">http://www.polarmicrobes.org/?p=3179</guid>

					<description><![CDATA[This post comes form Luke Piszkin, an undergraduate researcher in the Bowman Lab. Gnu Parallel is a must-have utility for anyone that spends a lot of time in Linux Land, and Luke recently had to gain some Gnu Parallel fluency &#8230; <a href="https://www.polarmicrobes.org/a-short-tutorial-on-gnu-parallel/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p>This post comes form <a href="https://www.polarmicrobes.org/people/">Luke Piszkin</a>, an undergraduate researcher in the Bowman Lab.  <a href="https://www.gnu.org/software/parallel/">Gnu Parallel</a> is a must-have utility for anyone that spends a lot of time in Linux Land, and Luke recently had to gain some Gnu Parallel fluency for his project.  Enjoy!</p>



<p class="has-text-align-center">*******</p>



<div class="wp-block-jetpack-markdown"><p>GNU parallel is a Linux shell tool for executing jobs in parallel using multiple CPU cores.
This is a quick tutorial for increasing your workflow and getting the most out of your machine with parallel.
​
You can find the current distribution here: https://www.gnu.org/software/parallel/. Please try some basic commands to make sure it is working.
​
You will need some basic understanding of “piping” in the command line. I will describe command pipes briefly just for our purposes, but for a more detailed look please see https://www.howtogeek.com/438882/how-to-use-pipes-on-linux/.
​
Piping data in the command line involves taking the output of one command and using it as the input for another. A basic example looks like this:
​</p>
<pre><code>command_1 | command_2 | command_3 | … 
</code></pre>
<p>​
Where the output of <strong>command_1</strong> will be used as an input by <strong>command_2</strong>, <strong>command_2</strong> will be used by <strong>command_3</strong>, and so on. For now, we will only need to use one pipe with parallel. Now let&#8217;s look at a basic command run in parallel.
​</p>
<pre><code>Input: find -type f -name &quot;*.txt&quot; | parallel cat
</code></pre>
<pre><code>Output: 
The house stood on a slight rise just on the edge of the village.
It stood on its own and looked over a broad spread of West Country farmland.
Not a remarkable house by any means - it was about thirty years old, squattist, squarish, made of brick, and had four windows set in the front size and proportion which more or less exactly failed to please the eye
The only person for whom the house was in any way special was Arthur Dent, and that was only because it happened to be the one he lived in.
He had lived in it for about three years, ever since he had moved out of London because it made him nervous and irritable
</code></pre>
<p>​
This command makes use of <strong>find</strong> to list all the <strong>.txt</strong> files in my directory, then runs <strong>cat</strong> on them in parallel, which shows the contents of each file on a new line. We can already see how this is much easier than running each command separately, i.e:</p>
<pre><code>In: cat file1.txt
</code></pre>
<pre><code>The house stood on a slight rise just on the edge of the village.
</code></pre>
<pre><code>In: cat file2.txt
</code></pre>
<pre><code>It stood on its own and looked over a broad spread of West Country farmland.
</code></pre>
<p>​
Also, notice how we do not need any placeholder for the files in the second command, because of the pipes.
Now let&#8217;s take a more complicated example:</p>
<pre><code>find -type f -name &quot;*beta_gal_vibrio_vulnificus_1_100000_0__H_flex=up_*.txt&quot; ! -name &quot;*tally*&quot; | parallel -j 4 python3 PEPCplots.py {} flex log
</code></pre>
<pre><code>0.001759374417007663, 0.00033497120199255527, 0.9969940359705531
0.0019773468515624356, 0.00022978867370935437, 0.9969940359705531
0.001332602651915014, 0.0005953339816183529, 0.9969940359705531
0.0015118302435556904, 0.0005040931537659636, 0.9969940359705531
0.001320879258211107, 0.0006907926578169569, 0.9969940359705531
0.0016753759966792244, 0.00041583739269117386, 0.9969940359705302
0.0017187095827331082, 0.00036931151058880094, 0.9969940359705531
0.0017045099726521733, 0.00031386214441070197, 0.9969940359705531
0.001399703145023273, 0.0005196629341168314, 0.9969940359705531
0.001436129272321403, 0.0004806654291442482, 0.9969940359705531
</code></pre>
<p>​
This is an example from my research, it takes in a <strong>.txt</strong> data file and spits out some parameters that I want to put in a spreadsheet. Like before, we use <strong>find</strong> to get a list of all the files we want the second command to process. We use <strong>! -name “*tally*”</strong> to exclude any files that have “tally” anywhere in the name because we don’t want to process those. In the second command, we have the option <strong>-j 4</strong>. This tells parallel to use 4 CPU cores, so it can run 4 commands at a time. You can check your computer specs to see how many cores you have available. If your machine has hyper-threading, then it can create virtual cores to run jobs on too. For instance, my dinky laptop only has 2 cores, but with hyper-threading I can use 4. This is another way to improve your efficiency. In the second command you also see a <strong>{}</strong> placeholder. This spot is filled by whatever the first command outputs. In this case, we need that placeholder because our input files go between other commands. You can also use parallel to run a number of identical commands at the same time. This is helpful if you have a program to run on the same file multiple times. For example:</p>
<pre><code>seq 10 | parallel -N0 cat file1.txt
</code></pre>
<pre><code>The house stood on a slight rise just on the edge of the village.
The house stood on a slight rise just on the edge of the village.
The house stood on a slight rise just on the edge of the village.
The house stood on a slight rise just on the edge of the village.
The house stood on a slight rise just on the edge of the village.
The house stood on a slight rise just on the edge of the village.
The house stood on a slight rise just on the edge of the village.
The house stood on a slight rise just on the edge of the village.
The house stood on a slight rise just on the edge of the village.
The house stood on a slight rise just on the edge of the village.
</code></pre>
<p>​
Here we use <strong>seq</strong> as a counting mechanism for how many times to run the second command. You can adjust the number of jobs by changing the <strong>seq</strong> argument. We include the <strong>-N0</strong> flag, which tells parallel to ignore any piped inputs because we aren’t using the first command for inputs this time.
Often, I like to include both the <strong>time</strong> shell tool and the <strong>&#8211;progress</strong> parallel option to see current job status and time for completion:
​</p>
<pre><code>seq 10 | time parallel --progress -N0 cat file1.txt
</code></pre>
<pre><code>Computers / CPU cores / Max jobs to run
1:local / 4 / 4
​
Computer:jobs running/jobs completed/%of started jobs/Average seconds to complete
local:4/0/100%/0.0s The house stood on a slight rise just on the edge of the village.
local:4/1/100%/1.0s The house stood on a slight rise just on the edge of the village.
local:4/2/100%/0.5s The house stood on a slight rise just on the edge of the village.
local:4/3/100%/0.3s The house stood on a slight rise just on the edge of the village.
local:4/4/100%/0.2s The house stood on a slight rise just on the edge of the village.
local:4/5/100%/0.2s The house stood on a slight rise just on the edge of the village.
local:4/6/100%/0.2s The house stood on a slight rise just on the edge of the village.
local:3/7/100%/0.1s The house stood on a slight rise just on the edge of the village.
local:2/8/100%/0.1s The house stood on a slight rise just on the edge of the village.
local:1/9/100%/0.1s The house stood on a slight rise just on the edge of the village.
local:0/10/100%/0.1s
0.21user 0.46system 0:00.63elapsed 108%CPU (0avgtext+0avgdata 15636maxresident)k
0inputs+0outputs (0major+12089minor)pagefaults 0swaps
</code></pre>
<p>​
And with that, you are well on your way to significantly increasing your computing throughput and using the full potential of your machine. You should now have a sufficient understanding of parallel to construct a command for your own projects, and to explore more complicated applications of parallelization.
(Bonus points to whoever knows the book that I used for the text files.)</p>
</div>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Fa-short-tutorial-on-gnu-parallel%2F&amp;linkname=A%20short%20tutorial%20on%20Gnu%20Parallel" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Fa-short-tutorial-on-gnu-parallel%2F&amp;linkname=A%20short%20tutorial%20on%20Gnu%20Parallel" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Fa-short-tutorial-on-gnu-parallel%2F&amp;linkname=A%20short%20tutorial%20on%20Gnu%20Parallel" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fwww.polarmicrobes.org%2Fa-short-tutorial-on-gnu-parallel%2F&#038;title=A%20short%20tutorial%20on%20Gnu%20Parallel" data-a2a-url="https://www.polarmicrobes.org/a-short-tutorial-on-gnu-parallel/" data-a2a-title="A short tutorial on Gnu Parallel"></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://www.polarmicrobes.org/a-short-tutorial-on-gnu-parallel/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3179</post-id>	</item>
		<item>
		<title>Finding those lost data files</title>
		<link>https://www.polarmicrobes.org/finding-those-lost-data-files/</link>
					<comments>https://www.polarmicrobes.org/finding-those-lost-data-files/#respond</comments>
		
		<dc:creator><![CDATA[Jeff]]></dc:creator>
		<pubDate>Wed, 16 Sep 2020 15:25:13 +0000</pubDate>
				<category><![CDATA[Computer tutorials]]></category>
		<guid isPermaLink="false">http://www.polarmicrobes.org/?p=3101</guid>

					<description><![CDATA[It&#8217;s been a long time since I&#8217;ve had the bandwidth to write up a code snippet here. This morning I had not quite enough time between Zoom meetings to tackle something more involved, so here goes! In this case I &#8230; <a href="https://www.polarmicrobes.org/finding-those-lost-data-files/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p>It&#8217;s been a long time since I&#8217;ve had the bandwidth to write up a code snippet here.  This morning I had not quite enough time between Zoom meetings to tackle something more involved, so here goes!  </p>



<p>In this case I needed to find ~200 sequence (fasta) files for a student in my lab.  They were split across several sequencing runs, and for various logistical reasons it was getting a bit tedious to find the location of each sequence file.  To solve the problem I wrote a short Python script to wrap the Linux <code>locate</code> command and copy all the files to a new directory where they could be exported.</p>



<p>First, I created a text file &#8220;files2find.txt&#8221; with text uniquely matching each file that I needed to find.  One of the great things about <code>locate</code> is that it doesn&#8217;t need to match the full file name.</p>



<pre>head files2find.txt
151117_PAL_Sterivex_1
151126_PAL_Sterivex_2
151202_PAL_Sterivex_3
151213_PAL_Sterivex_4
151225_PAL_Sterivex_5
151230_PAL_Sterivex_6
160106_PAL_Sterivex_7
160118_PAL_Sterivex_9
160120_PAL_Sterivex_10
160128_PAL_Sterivex_11</pre>



<p>Then the wrapper:</p>



<pre>import subprocess
import shutil

with open('files2find.txt') as file_in:
    for line in file_in:
        line = line.rstrip()

        ## Here we use the subprocess module to run the locate command, capturing
        ## standard out.

        temp = subprocess.Popen('locate ' + line,
                                shell = True,
                                executable = '/bin/bash',
                                stdout = subprocess.PIPE)

        ## The communicate method for object temp returns a tuple.  First object
        ## in the tuple is standard out.       
        
        locations = temp.communicate()[0]
        locations = locations.decode().split('\n')

        ## Thank you internet for this one-liner, Python one-liners always throw
        ## me for a loop (no pun intended). Here we search all items in the locations
        ## list for a specific suffix that identifies files that we actually want.
        ## In this case our final analysis files contain "exp.fasta".  Of course if
        ## you're certain of the full file name you could just use locate on that and
        ## omit this step.

        fastas = [i for i in locations if 'exp.fasta' in i] 
        
        path = '/path/to/where/you/want/files/'
        
        found = set()

        ## Use the shutil library to copy found files to a new directory "path".
        ## Copied files are added to the set "found" to avoid being copied more than
        ## once, if they exist in multiple locations on your computer.
        
        for fasta in fastas:
            file_name = fasta.split('/')[-1]
            if file_name not in found:
                shutil.copyfile(fasta, path + file_name) 
                found.add(file_name)

        ## In the event that no files are found report that here.
                
        if len(fastas) == 0:
            print(line, 'not found')</pre>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Ffinding-those-lost-data-files%2F&amp;linkname=Finding%20those%20lost%20data%20files" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Ffinding-those-lost-data-files%2F&amp;linkname=Finding%20those%20lost%20data%20files" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Ffinding-those-lost-data-files%2F&amp;linkname=Finding%20those%20lost%20data%20files" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fwww.polarmicrobes.org%2Ffinding-those-lost-data-files%2F&#038;title=Finding%20those%20lost%20data%20files" data-a2a-url="https://www.polarmicrobes.org/finding-those-lost-data-files/" data-a2a-title="Finding those lost data files"></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://www.polarmicrobes.org/finding-those-lost-data-files/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3101</post-id>	</item>
		<item>
		<title>Tutorial: SuperSOMS and an R script for detecting regions of interest</title>
		<link>https://www.polarmicrobes.org/tutorial-supersoms-and-an-r-script-for-detecting-regions-of-interest/</link>
					<comments>https://www.polarmicrobes.org/tutorial-supersoms-and-an-r-script-for-detecting-regions-of-interest/#respond</comments>
		
		<dc:creator><![CDATA[Jeff]]></dc:creator>
		<pubDate>Sun, 17 May 2020 03:13:31 +0000</pubDate>
				<category><![CDATA[Computer tutorials]]></category>
		<guid isPermaLink="false">http://www.polarmicrobes.org/?p=2998</guid>

					<description><![CDATA[A common exercise in environmental microbiology is counting bacterial cells with an epifluorescent microscope. During my PhD I spend many hours hunched over a microscope in a darkened room, contemplating which points of light were bacteria (and should thus be &#8230; <a href="https://www.polarmicrobes.org/tutorial-supersoms-and-an-r-script-for-detecting-regions-of-interest/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p>A common exercise in environmental microbiology is counting bacterial cells with an epifluorescent microscope.  During my PhD I spend many hours hunched over a microscope in a darkened room, contemplating which points of light were bacteria (and should thus be counted) and which were not.  With a large cup of coffee from Seattle&#8217;s U District Bean and Bagel and an episode of &#8220;This American Life&#8221; playing in the background it&#8217;s not a bad way to spend the day.  But it definitely felt like a procedure that needed some technological enhancement.  My biggest concerns were always objectivity and reproducibility; it&#8217;s really hard to determine consistently which &#8220;regions of interest&#8221; (ROIs) to count.  There are of course commercial software packages for identifying and counting ROIs in a microscope image.  But why pay big money for a software subscription when you can write your own script?  I had some free time during our slow transit to <em>Polarstern</em> during <a href="https://www.polarmicrobes.org/mosaic-leg-3/">MOSAiC Leg 3</a> and thought I&#8217;d give it a try.  The following tutorial borrows heavily from the image segmentation example in <a href="https://www.jstatsoft.org/article/view/v087i07">Wherens and Kruisselbrink, 2018</a>.</p>



<p>We start with a png image from a camera attached to a microscope.  The green features are bacteria and phytoplankton that have been stained with Sybr Green.  These are the ROIs that we&#8217;d like to identify and count.  The image quality is actually pretty bad here; this was made with the epifluorescent scope at Palmer Station back in 2015, and the scope and camera needed some TLC.  It turns out that I don&#8217;t actually have many such images on my laptop, and I can&#8217;t simply go and make a new one because we aren&#8217;t allowed in the lab right now!  Nonetheless the quality is sufficient for our purposes.</p>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" decoding="async" width="640" height="480" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/15170245.png?resize=640%2C480&#038;ssl=1" alt="" class="wp-image-3000" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/15170245.png?resize=1024%2C768&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/15170245.png?resize=300%2C225&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/15170245.png?resize=768%2C576&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/15170245.png?w=1154&amp;ssl=1 1154w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<p>First, we need to convert the image into an RGB matrix that we can work with.  I&#8217;m sure there&#8217;s a way to do this in R, but I couldn&#8217;t find an expedient method.  Python made it easy.</p>



<pre>## convert image to two matrices: a 3 column RGB matrix and
## 2 column xy matrix

import matplotlib.image as mpimg

name = '15170245.png'
name = name.rstrip('.png')

img = mpimg.imread(name + '.png')

with open(name + '.rgb4r.csv', 'w') as rgb_out, open(name + '.xy.csv', 'w') as xy_out:
    for i in range(0, img.shape[1]):
        for j in range(0, img.shape[0]):
            print(img[j, i, 0], img[j, i, 1], img[j, i, 2], sep = ',', file = rgb_out)
            print(i + 1, j + 1, sep = ',', file = xy_out)</pre>



<p>Next we break out R to do the actual analysis (which yes, could be done in Python&#8230;).  The basic strategy is to use a <a href="https://www.polarmicrobes.org/tutorial-self-organizing-maps-in-r/">self organizing map</a> (SOM) with 2 layers.  One layer will be color, the other will be position.  We&#8217;ll use this information to identify distinct classes corresponding to diagnostic features of ROIs.  Last, we&#8217;ll iterate across all the pixels that appear to belong to ROIs and attempt to draw an ellipse around each group of pixels that makes up a ROI.  First, we read in the data produced by the Python script:</p>



<pre>scope.rgb <- read.csv('15170245.rgb4r.csv', header = F)
scope.xy <- read.csv('15170245.xy.csv', header = F)

colnames(scope.rgb) <- c('red', 'green', 'blue')
colnames(scope.xy) <- c('X', 'Y')</pre>



<p>Then we define a function to render the image described by these matrices:</p>



<pre>plotImage <- function(scope.xy, scope.rgb){
  image.col <- rgb(scope.rgb[,"red"], scope.rgb[,"green"], scope.rgb[,"blue"], maxColorValue = 1)
  x.dim <- max(scope.xy$X)
  y.dim <- max(scope.xy$Y)
  
  temp.image <- 1:dim(scope.rgb)[1]
  dim(temp.image) <- c(y.dim, x.dim)
  image(0:x.dim,
        0:y.dim,
        t(temp.image),
        col = image.col,
        ylab = paste0('Y:', y.dim),
        xlab = paste0('X:', x.dim))
}

## give it a test

plotImage(scope.xy, scope.rgb)</pre>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="640" height="520" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-5.png?resize=640%2C520&#038;ssl=1" alt="" class="wp-image-3001" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-5.png?w=687&amp;ssl=1 687w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-5.png?resize=300%2C244&amp;ssl=1 300w" sizes="auto, (max-width: 640px) 100vw, 640px" /></figure>



<p>You'll note that the function flips the image.  While annoying, this doesn't matter at all for identifying ROIs.  If it bothers you go ahead and tweak the function :).  Now we need to train our SOM.  The SOM is what does the heavy lifting of identifying different types of pixels in the image.</p>



<pre>#### train som ####

som.grid <- somgrid(10, 10, 'hexagonal')
som.model <- supersom(list('rgb' = data.matrix(scope.rgb), 'coords' = data.matrix(scope.xy)), whatmap = c('rgb', 'coords'), user.weights = c(1, 9), grid = som.grid)</pre>



<p>Now partition the SOM into <em>k</em> classes with <em>k</em>-means clustering.  The value for <em>k</em> has to be determined experimentally but should be consistent for all the images in a set (<em>i.e.</em> a given type of microscopy image).</p>



<pre>som.codes <- som.model$codes[[1]]
som.codes.k <- kmeans(som.codes, centers = 6)

## Get mean colors for clusters (classes)

class.col <- c()

for(k in 1:max(som.codes.k$cluster)){
  temp.codes <- som.codes[which(som.codes.k$cluster == k),]
  temp.col <- colMeans(temp.codes)
  temp.col <- rgb(temp.col[1], temp.col[2], temp.col[3], maxColorValue = 1)
  class.col <- append(class.col, temp.col)
}

## Make a plot of the som with the map units colored according to mean color
## of owning class.

plot(som.model,
     type = 'mapping',
     bg = class.col[som.codes.k$cluster],
     keepMargins = F,
     col = NA)

text(som.model$grid$pts, labels = som.codes.k$cluster)
add.cluster.boundaries(som.model, som.codes.k$cluster)</pre>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="640" height="520" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-6.png?resize=640%2C520&#038;ssl=1" alt="" class="wp-image-3003" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-6.png?w=687&amp;ssl=1 687w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-6.png?resize=300%2C244&amp;ssl=1 300w" sizes="auto, (max-width: 640px) 100vw, 640px" /></figure>



<p>Here's where we have to be a bit subjective.  We need to make an informed decision about which classes constitute ROIs.  Looking at this map I'm gonna guess 3 and 6.  The classes and structure of your map will of course be totally different, even if you start with the same training image.  To make use of this information we first predict which classes our original pixels belong to.</p>



<pre>## predict for RGB only

image.predict <- predict(som.model, newdata = list('rgb' = data.matrix(scope.rgb)), whatmap = 'rgb')</pre>



<p>Then we identify those pixels that below to the classes we think describe ROIs.</p>



<pre>## select units that correspond to ROIs

target.units = which(som.codes.k$cluster %in% c(3, 6))
target.pixels <- scope.xy[which(image.predict$unit.classif %in% target.units), c('X', 'Y')]</pre>



<p>Now comes the tricky bit.  Knowing which pixels belong to ROIs isn't actually that useful, as each ROI is composed of many different pixels.  So we need to aggregate the pixels into ROIs.  Again, this requires a little experimentation, but once you figure it out for a given sample type it should work consistently.  The key parameter here is "resolution" which we define as how far apart two pixels of the same class need to be to constitute different ROIs.  The value 20 seems to work reasonably well for this image.</p>



<pre>## loop through all pixels.  if there's a pixel within n distance of it, check to
## see if that pixel belongs to an ROI.  If so, add the new pixel to that area.  If not,
## create a new ROI.  Currently a pixel can be "grabbed" by an ROI produced later.

findROI <- function(resolution = 20){
  roi <- 1
  roi.pixels <- as.data.frame(matrix(nrow = dim(target.pixels)[1], ncol = 3))
  colnames(aoi.pixels) <- c('X', 'Y', 'roi')
  
  for(i in 1:dim(target.pixels)[1]){
    
    if(is.na(roi.pixels[i, 'roi']) == T){
      pixel.x <- target.pixels[i, 'X']
      pixel.y <- target.pixels[i, 'Y']
      nns <- which(abs(target.pixels[, 'X'] - pixel.x) < resolution &#038; abs(target.pixels[, 'Y'] - pixel.y) < resolution)
      
      roi.pixels[nns, c('X', 'Y')] <- target.pixels[nns, c('X', 'Y')]
      roi.pixels[nns, 'roi'] <- roi
      roi <- roi + 1
    }
  }
  return(roi.pixels)
}
  
roi.pixels <- findROI()
roi.table <- table(roi.pixels$roi)</pre>



<p>To evaluate our discovery of ROIs we plot an ellipse around each ROI in the original image.</p>



<pre>## approximate each roi as an ellipse.  need x, y, a, b

plotROI <- function(roi.pixels){
  require(plotrix)
  
  for(roi in unique(roi.pixels$roi)){
    temp.pixels <- roi.pixels[which(roi.pixels$roi == roi),]
    temp.a <- max(temp.pixels$X) - min(temp.pixels$X)
    temp.b <- max(temp.pixels$Y) - min(temp.pixels$Y)
    temp.x <- mean(temp.pixels$X)
    temp.y <- mean(temp.pixels$Y)
    
    plot.y <- temp.y
    draw.ellipse(temp.x, plot.y, temp.a, temp.b, border = 'red')
  }
}

plotImage(scope.xy, scope.rgb)
plotROI(roi.pixels)</pre>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="640" height="520" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-7.png?resize=640%2C520&#038;ssl=1" alt="" class="wp-image-3005" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-7.png?w=687&amp;ssl=1 687w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-7.png?resize=300%2C244&amp;ssl=1 300w" sizes="auto, (max-width: 640px) 100vw, 640px" /></figure>



<p>It certainly isn't perfect, the two chained diatoms in particular throw off our count.  We did, however, do a reasonable job of finding all the small ROIs that represent the smaller, harder to count cells.  So how does the model perform for ROI identification on a new image?  Here's a new image acquired with the same exposure settings on the same scope.  We use the same Python code to convert it to RGB and XY matrices.</p>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="640" height="480" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/14000740.png?resize=640%2C480&#038;ssl=1" alt="" class="wp-image-3006" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/14000740.png?resize=1024%2C768&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/14000740.png?resize=300%2C225&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/14000740.png?resize=768%2C576&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/14000740.png?w=1155&amp;ssl=1 1155w" sizes="auto, (max-width: 640px) 100vw, 640px" /></figure>



<pre>## convert image to two matrices: a 3 column RGB matrix and
## 2 column xy matrix

import matplotlib.image as mpimg

name = '14000740.png'
name = name.rstrip('.png')

img = mpimg.imread(name + '.png')

with open(name + '.rgb4r.csv', 'w') as rgb_out, open(name + '.xy.csv', 'w') as xy_out:
    for i in range(0, img.shape[1]):
        for j in range(0, img.shape[0]):
            print(img[j, i, 0], img[j, i, 1], img[j, i, 2], sep = ',', file = rgb_out)
            print(i + 1, j + 1, sep = ',', file = xy_out)</pre>



<p>Then we predict and plot.</p>



<pre>scope.rgb <- read.csv('14000740.rgb4r.csv', header = F)
scope.xy <- read.csv('14000740.xy.csv', header = F)

colnames(scope.rgb) <- c('red', 'green', 'blue')
colnames(scope.xy) <- c('X', 'Y')

plotImage(scope.xy, scope.rgb)
image.predict <- predict(som.model, newdata = list('rgb' = data.matrix(scope.rgb)), whatmap = 'rgb') # predict for rgb only

target.units = which(som.codes.k$cluster %in% c(3,6))
target.pixels <- scope.xy[which(image.predict$unit.classif %in% target.units), c('X', 'Y')]

roi.pixels <- findROI()
roi.table <- table(roi.pixels$roi)

plotImage(scope.xy, scope.rgb)
plotROI(roi.pixels)</pre>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="640" height="520" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-8.png?resize=640%2C520&#038;ssl=1" alt="" class="wp-image-3007" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-8.png?w=687&amp;ssl=1 687w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-8.png?resize=300%2C244&amp;ssl=1 300w" sizes="auto, (max-width: 640px) 100vw, 640px" /></figure>



<p>Not bad!  Again, it isn't perfect, some ROIs are grouped together and some are missed (largely a function of the variable focal plane).  These can be fixed by experimenting with the model parameters and resolution.  We did accomplish the goal of improving objectivity and reproducibility; our approach isn't always right, but at least it's wrong in a consistent way!  Of course an additional advantage is if you had hundreds of such images, perhaps representing multiple randomly selected fields from many images, you could process in a few minutes what would take many hours to count.  </p>



<p>At this point I can feel the collective judgement of every environmental microbiologist since van Leeuwenhoek for promoting a method that might reduce the serendipitous discovery that comes with spending hours staring through a microscope.  So here's a reminder to spend time getting familiar with your samples under the microscope, regardless of how you identify ROIs!</p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-supersoms-and-an-r-script-for-detecting-regions-of-interest%2F&amp;linkname=Tutorial%3A%20SuperSOMS%20and%20an%20R%20script%20for%20detecting%20regions%20of%20interest" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-supersoms-and-an-r-script-for-detecting-regions-of-interest%2F&amp;linkname=Tutorial%3A%20SuperSOMS%20and%20an%20R%20script%20for%20detecting%20regions%20of%20interest" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-supersoms-and-an-r-script-for-detecting-regions-of-interest%2F&amp;linkname=Tutorial%3A%20SuperSOMS%20and%20an%20R%20script%20for%20detecting%20regions%20of%20interest" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-supersoms-and-an-r-script-for-detecting-regions-of-interest%2F&#038;title=Tutorial%3A%20SuperSOMS%20and%20an%20R%20script%20for%20detecting%20regions%20of%20interest" data-a2a-url="https://www.polarmicrobes.org/tutorial-supersoms-and-an-r-script-for-detecting-regions-of-interest/" data-a2a-title="Tutorial: SuperSOMS and an R script for detecting regions of interest"></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://www.polarmicrobes.org/tutorial-supersoms-and-an-r-script-for-detecting-regions-of-interest/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2998</post-id>	</item>
		<item>
		<title>Tutorial: Self Organizing Maps in R</title>
		<link>https://www.polarmicrobes.org/tutorial-self-organizing-maps-in-r/</link>
					<comments>https://www.polarmicrobes.org/tutorial-self-organizing-maps-in-r/#comments</comments>
		
		<dc:creator><![CDATA[Jeff]]></dc:creator>
		<pubDate>Sun, 10 May 2020 04:48:14 +0000</pubDate>
				<category><![CDATA[Computer tutorials]]></category>
		<guid isPermaLink="false">http://www.polarmicrobes.org/?p=2984</guid>

					<description><![CDATA[Self-organizing maps (SOMs) are a form of neural network and a wonderful way to partition complex data.  In our lab they’re a routine part of our flow cytometry and sequence analysis workflows, but we use them for all kinds of &#8230; <a href="https://www.polarmicrobes.org/tutorial-self-organizing-maps-in-r/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p>Self-organizing maps (SOMs) are a form of neural network and a wonderful way to partition complex data.  In our lab they’re a routine part of our flow cytometry and sequence analysis workflows, but we use them for all kinds of environmental data (like <a href="https://www.polarmicrobes.org/new-seascape-analysis-of-the-western-antarctic-peninsula/">this</a>).  All of the mainstream data analysis languages (R, Python, Matlab) have packages for training and working with SOMs.  My favorite is the R package <a href="https://cran.r-project.org/web/packages/kohonen/kohonen.pdf">Kohonen</a>, which is simple to use but can support some fairly complex analysis through SOMs with multiple data layers and supervised learning (superSOMs).  The Kohonen package has a nice, very accessible <a href="https://www.jstatsoft.org/article/view/v087i07">paper</a> that describe its key features, and some excellent examples.  This tutorial applies our basic workflow for a single-layer SOM to RGB color data.  RGB color space segmentation is a popular way to evaluate machine learning algorithms, as it is intrinsically multi-variate and inherently meaningful.  Get like colors grouping together and you know that you’ve set things up correctly!</p>



<p>This application of SOMs has two steps.&nbsp; Each of these steps can be thought of as an independent data reduction step.&nbsp; It’s important to remember that you’re not reducing dimensions <em>per se</em>, as you would in a PCA, you’re aggregating like data so that you can describe them as convenient units (instead of <em>n</em> individual observations).&nbsp; The final outcome, however, represents a reduction in dimensionality to a single parameter for all observations (<em>e.g.</em>, the color blue instead of (0, 0, 255) in RGB colorspace).&nbsp; The first step – training the SOM – assigns your observations to map units.&nbsp; The second step – clustering the map units into <em>classes</em> – finds the structure underlying the values associated with the map units after training.&nbsp; At the end of this procedure each observation belongs to a map unit, and each map unit belongs to a class.&nbsp; Thus each observation inherits the class of its associated map unit.&nbsp; If that’s not clear don’t sweat it.&nbsp; It will become clear as you go through the procedure.</p>



<p>First, let’s generate some random RGB data.&nbsp; This takes the form of a three column matrix where each row is a pixel (<em>i.e.</em> an observation).</p>



<pre class="wp-block-preformatted">#### generate some RGB data ####

## select the number of random RGB vectors for training data

sample.size &lt;- 10000

## generate dataframe of random RGB vectors

sample.rgb &lt;- as.data.frame(matrix(nrow = sample.size, ncol = 3))
colnames(sample.rgb) &lt;- c('R', 'G', 'B')

sample.rgb$R &lt;- sample(0:255, sample.size, replace = T)
sample.rgb$G &lt;- sample(0:255, sample.size, replace = T)
sample.rgb$B &lt;- sample(0:255, sample.size, replace = T)</pre>



<p>Next, we define a map space for the SOM and train the model.&nbsp; Picking the right grid size for the map space is non-trivial; you want about 5 elements from the training data per map unit, though you’ll likely find that they’re not uniformly distributed.&nbsp; It’s best to use a symmetrical map unless you have a very small training dataset, hexagonal map units, and a toroidal shape.&nbsp; The latter is important to avoid edge effects (a toroid has no edges).</p>



<p>One important caveat for the RGB data is that we’re not going to bother with any scaling or normalizing.&nbsp; The parameters are all on the same scale and evenly distributed between 0 and the max value of 255.&nbsp; Likely your data are not so nicely formed!&nbsp;</p>



<pre class="wp-block-preformatted">#### train the SOM ####

## define a grid for the SOM and train

library(kohonen)

grid.size &lt;- ceiling(sample.size ^ (1/2.5))
som.grid &lt;- somgrid(xdim = grid.size, ydim = grid.size, topo = 'hexagonal', toroidal = T)
som.model &lt;- som(data.matrix(sample.rgb), grid = som.grid)</pre>



<p>One you’ve trained the SOM it’s a good idea to explore the output of the `som` function to get a feel for the different items in there.&nbsp; The output takes the form of nested lists.&nbsp; Here we extract a couple of items that we’ll need later, and also create a distance matrix of the map units.&nbsp; We can do this because the fundamental purpose of map units is to have a codebook vector that mimics the structure of the training data.&nbsp; During training each codebook vector is iteratively updated along with its neighbors to match the training data.&nbsp; After sufficient iterations the codebook vectors reflect the underlying structure of the data.</p>



<pre class="wp-block-preformatted">## extract some data to make it easier to use

som.events &lt;- som.model$codes[[1]]
som.events.colors &lt;- rgb(som.events[,1], som.events[,2], som.events[,3], maxColorValue = 255)
som.dist &lt;- as.matrix(dist(som.events))</pre>



<p>Now that we have a trained SOM let’s generate a descriptive plot.&nbsp; Since the data are RGB colors, if we color the plot accordingly it should be sensible.&nbsp; For comparison, we first create a plot with randomized codebook vectors.&nbsp; This represents the SOM at the start of training.</p>



<pre class="wp-block-preformatted">## generate a plot of the untrained data.  this isn't really the configuration at first iteration, but
## serves as an example

plot(som.model,
     type = 'mapping',
     bg = som.events.colors[sample.int(length(som.events.colors), size = length(som.events.colors))],
     keepMargins = F,
     col = NA,
     main = '')</pre>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="640" height="520" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image.png?resize=640%2C520&#038;ssl=1" alt="" class="wp-image-2985" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image.png?w=687&amp;ssl=1 687w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image.png?resize=300%2C244&amp;ssl=1 300w" sizes="auto, (max-width: 640px) 100vw, 640px" /></figure>



<p>And now the trained SOM:</p>



<pre>## generate a plot after training.

plot(som.model,
     type = 'mapping',
     bg = som.events.colors,
     keepMargins = F,
     col = NA,
     main = '')</pre>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="640" height="520" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-1.png?resize=640%2C520&#038;ssl=1" alt="" class="wp-image-2986" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-1.png?w=687&amp;ssl=1 687w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-1.png?resize=300%2C244&amp;ssl=1 300w" sizes="auto, (max-width: 640px) 100vw, 640px" /></figure>



<p>So pretty!  The next step is to cluster the map units into classes.&nbsp; As with all clustering analysis, a key question is how many clusters (<em>k</em>) should we define?&nbsp; One way to inform our decision is to evaluate the distance between all items assigned to each cluster for many different values of <em>k</em>.&nbsp; Ideally, creating a scree plot of mean within-cluster distance vs. <em>k</em> will yield an inflection point that suggests a meaningful value of <em>k</em>.&nbsp; In practice this inflection point is extremely sensitive to the size of the underlying data (in this case, the number of map units), however, it can be a useful starting place.&nbsp; Consider that the RGB data were defined continuously, meaning that there is no underlying structure!&nbsp; Nonetheless we still get an inflection point.</p>



<pre class="wp-block-preformatted">#### look for a reasonable number of clusters ####

## Evaluate within cluster distances for different values of k.  This is
## more dependent on the number of map units in the SOM than the structure
## of the underlying data, but until we have a better way...

## Define a function to calculate mean distance within each cluster.  This
## is roughly analogous to the within clusters ss approach

clusterMeanDist &lt;- function(clusters){
  cluster.means = c()
  
  for(c in unique(clusters)){
    temp.members &lt;- which(clusters == c)
    
    if(length(temp.members) &gt; 1){
      temp.dist &lt;- som.dist[temp.members,]
      temp.dist &lt;- temp.dist[,temp.members]
      cluster.means &lt;- append(cluster.means, mean(temp.dist))
    }else(cluster.means &lt;- 0)
  }
  
  return(mean(cluster.means))
  
}

try.k &lt;- 2:100
cluster.dist.eval &lt;- as.data.frame(matrix(ncol = 3, nrow = (length(try.k))))
colnames(cluster.dist.eval) &lt;- c('k', 'kmeans', 'hclust')

for(i in 1:length(try.k)) {
  cluster.dist.eval[i, 'k'] &lt;- try.k[i]
  cluster.dist.eval[i, 'kmeans'] &lt;- clusterMeanDist(kmeans(som.events, centers = try.k[i], iter.max = 20)$cluster)
  cluster.dist.eval[i, 'hclust'] &lt;- clusterMeanDist(cutree(hclust(vegdist(som.events)), k = try.k[i]))
}

plot(cluster.dist.eval[, 'kmeans'] ~ try.k,
     type = 'l')

lines(cluster.dist.eval[, 'hclust'] ~ try.k,
      col = 'red')

legend('topright',
       legend = c('k-means', 'hierarchical'),
       col = c('black', 'red'),
       lty = c(1, 1))</pre>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="640" height="520" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-2.png?resize=640%2C520&#038;ssl=1" alt="" class="wp-image-2988" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-2.png?w=687&amp;ssl=1 687w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-2.png?resize=300%2C244&amp;ssl=1 300w" sizes="auto, (max-width: 640px) 100vw, 640px" /></figure>



<p>Having picked a reasonable value for <em>k</em> (let&#8217;s say <em>k</em> = 20) we can evaluate different clustering algorithms.&nbsp; For our data <em>k</em>-means almost always performs best, but you should choose what works best for your data.&nbsp; Here will evaluate <em>k</em>-means, hierarchical clustering, and model-based clustering.&nbsp; What we’re looking for in the plots is a clustering method that produces contiguous classes.&nbsp; If classes are spread all across the map, then the clustering algorithm isn’t capturing the structure of the SOM well.</p>



<pre class="wp-block-preformatted">#### evaluate clustering algorithms ####

## Having selected a reasonable value for k, evaluate different clustering algorithms.

library(pmclust)

## Define a function for make a simple plot of clustering output.
## This is the same as previousl plotting, but we define the function
## here as we wanted to play with the color earlier.

plotSOM &lt;- function(clusters){
  plot(som.model,
       type = 'mapping',
       bg = som.events.colors,
       keepMargins = F,
       col = NA)
  
  add.cluster.boundaries(som.model, clusters)
}

## Try several different clustering algorithms, and, if desired, different values for k

cluster.tries &lt;- list()

for(k in c(20)){
  
  ## model based clustering using pmclust
  
  som.cluster.pm.em &lt;- pmclust(som.events, K = k, algorithm = 'em')$class # model based
  som.cluster.pm.aecm &lt;- pmclust(som.events, K = k, algorithm = 'aecm')$class # model based
  som.cluster.pm.apecm &lt;- pmclust(som.events, K = k, algorithm = 'apecm')$class # model based
  som.cluster.pm.apecma &lt;- pmclust(som.events, K = k, algorithm = 'apecma')$class # model based
  som.cluster.pm.kmeans &lt;- pmclust(som.events, K = k, algorithm = 'kmeans')$class # model based
  
  ## k-means clustering
  
  som.cluster.k &lt;- kmeans(som.events, centers = k, iter.max = 100, nstart = 10)$cluster # k-means
  
  ## hierarchical clustering
  
  som.dist &lt;- dist(som.events) # hierarchical, step 1
  som.cluster.h &lt;- cutree(hclust(som.dist), k = k) # hierarchical, step 2
  
  ## capture outputs
  
  cluster.tries[[paste0('som.cluster.pm.em.', k)]] &lt;- som.cluster.pm.em
  cluster.tries[[paste0('som.cluster.pm.aecm.', k)]] &lt;- som.cluster.pm.aecm
  cluster.tries[[paste0('som.cluster.pm.apecm.', k)]] &lt;- som.cluster.pm.apecm
  cluster.tries[[paste0('som.cluster.pm.apecma.', k)]] &lt;- som.cluster.pm.apecma
  cluster.tries[[paste0('som.cluster.pm.kmeans.', k)]] &lt;- som.cluster.pm.kmeans
  cluster.tries[[paste0('som.cluster.k.', k)]] &lt;- som.cluster.k
  cluster.tries[[paste0('som.cluster.h.', k)]] &lt;- som.cluster.h
}

## Take a look at the various clusters.  You're looking for the algorithm that produces the
## least fragmented clusters.

plotSOM(cluster.tries$som.cluster.pm.em.20)
plotSOM(cluster.tries$som.cluster.pm.aecm.20)
plotSOM(cluster.tries$som.cluster.pm.apecm.20)
plotSOM(cluster.tries$som.cluster.pm.apecma.20)
plotSOM(cluster.tries$som.cluster.k.20)
plotSOM(cluster.tries$som.cluster.h.20)</pre>



<p>For brevity I&#8217;m not showing the plots produced for all the different clustering algorithms.  For these data the k-means and hierarchical clustering algorithms both look pretty good, I have a slight preference for the k-means version:  </p>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="640" height="520" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-3.png?resize=640%2C520&#038;ssl=1" alt="" class="wp-image-2990" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-3.png?w=687&amp;ssl=1 687w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-3.png?resize=300%2C244&amp;ssl=1 300w" sizes="auto, (max-width: 640px) 100vw, 640px" /></figure>



<p>The SOM and final map unit clustering represent a classification model that can be saved for use with later data.&nbsp; Once huge advantage to using SOMs over other analysis methods (<em>e.g.</em>, ordination techniques) is their usefulness for organizing newly collected data.&nbsp; New data, if necessary scared and normalized in the same way as the training data, can be classified by finding the map unit with the minimum distance to the new observation.&nbsp; To demonstrate this, we’ll generate and classify a small new RGB dataset (in reality classifying in this way is very efficient, and could accommodate a huge number of new observations).&nbsp; First, we save the SOM and final clustering.</p>



<pre>## The SOM and map unit clustering represent a classification model.  These can be saved for
## later use.

som.cluster <- som.cluster.k
som.notes <- c('Clustering based on k-means')

save(file = 'som_model_demo.Rdata', list = c('som.cluster', 'som.notes', 'som.model', 'som.events.colors'))</pre>



<p>Then we generate new RGB data, classify it, and make a plot to compare the original data, the color of the winning map unit, and the color of the cluster that map unit belongs to.</p>



<pre>#### classification ####

## make a new dataset to classify ##

new.data.size <- 20
new.data <- as.data.frame(matrix(nrow = new.data.size, ncol = 3))
colnames(new.data) <- c('R', 'G', 'B')

new.data$R <- sample(0:255, new.data.size, replace = T)
new.data$G <- sample(0:255, new.data.size, replace = T)
new.data$B <- sample(0:255, new.data.size, replace = T)

## get the closest map unit to each point

new.data.units <- map(som.model, newdata = data.matrix(new.data))

## get the classification for closest map units

new.data.classes <- som.cluster[new.data.units$unit.classif]

## compare colors of the new data, unit, and class, first define a function
## to calculate the mean colors for each cluster

clusterMeanColor <- function(clusters){
  cluster.means = c()
  som.codes <- som.model$codes[[1]]
  
  for(c in sort(unique(clusters))){
    temp.members <- which(clusters == c)
    
    if(length(temp.members) > 1){
      temp.codes <- som.codes[temp.members,]
      temp.means <- colMeans(temp.codes)
      temp.col <- rgb(temp.means[1], temp.means[2], temp.means[3], maxColorValue = 255)
      cluster.means <- append(cluster.means, temp.col)
    }else({
      temp.codes <- som.codes[temp.members,]
      temp.col <- rgb(temp.codes[1], temp.codes[2], temp.codes[3], maxColorValue = 255)
      cluster.means <- append(cluster.means, temp.col)
      })
  }
  
  return(cluster.means)
  
}

class.colors <- clusterMeanColor(som.cluster)

plot(1:length(new.data$R), rep(1, length(new.data$R)),
     col = rgb(new.data$R, new.data$G, new.data$B, maxColorValue = 255),
     ylim = c(0,4),
     pch = 19,
     cex = 3,
     xlab = 'New data',
     yaxt = 'n',
     ylab = 'Level')

axis(2, at = c(1, 2, 3), labels = c('New data', 'Unit', 'Class'))

points(1:length(new.data.units$unit.classif), rep(2, length(new.data.units$unit.classif)),
     col = som.events.colors[new.data.units$unit.classif],
     pch = 19,
     cex = 3)

points(1:length(new.data.classes), rep(3, length(new.data.classes)),
       col = class.colors[new.data.classes],
       pch = 19,
       cex = 3)</pre>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="640" height="520" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-4.png?resize=640%2C520&#038;ssl=1" alt="" class="wp-image-2992" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-4.png?w=687&amp;ssl=1 687w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2020/05/image-4.png?resize=300%2C244&amp;ssl=1 300w" sizes="auto, (max-width: 640px) 100vw, 640px" /></figure>



<p>Looks pretty good!  Despite defining only 20 classes, class seems to be a reasonable representation of the original data.  Only slight differences in color can be observed between the data, winning map unit, and class.</p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-self-organizing-maps-in-r%2F&amp;linkname=Tutorial%3A%20Self%20Organizing%20Maps%20in%20R" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-self-organizing-maps-in-r%2F&amp;linkname=Tutorial%3A%20Self%20Organizing%20Maps%20in%20R" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-self-organizing-maps-in-r%2F&amp;linkname=Tutorial%3A%20Self%20Organizing%20Maps%20in%20R" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-self-organizing-maps-in-r%2F&#038;title=Tutorial%3A%20Self%20Organizing%20Maps%20in%20R" data-a2a-url="https://www.polarmicrobes.org/tutorial-self-organizing-maps-in-r/" data-a2a-title="Tutorial: Self Organizing Maps in R"></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://www.polarmicrobes.org/tutorial-self-organizing-maps-in-r/feed/</wfw:commentRss>
			<slash:comments>19</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2984</post-id>	</item>
		<item>
		<title>Tutorial: Nanopore Analysis Pipeline</title>
		<link>https://www.polarmicrobes.org/tutorial-nanopore-analysis-pipeline/</link>
					<comments>https://www.polarmicrobes.org/tutorial-nanopore-analysis-pipeline/#comments</comments>
		
		<dc:creator><![CDATA[Sabeel Mansuri]]></dc:creator>
		<pubDate>Fri, 07 Dec 2018 15:12:19 +0000</pubDate>
				<category><![CDATA[Computer tutorials]]></category>
		<guid isPermaLink="false">http://www.polarmicrobes.org/?p=2443</guid>

					<description><![CDATA[Introduction Hi! I&#8217;m Sabeel Mansuri, an Undergraduate Research Assistant for the Bowman Lab at the Scripps Institute of Oceanography, University of California San Diego. The following is a tutorial that demonstrates a pipeline used to assemble and annotate a bacterial &#8230; <a href="https://www.polarmicrobes.org/tutorial-nanopore-analysis-pipeline/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<h2>Introduction</h2>
<p>Hi! I&#8217;m Sabeel Mansuri, an Undergraduate Research Assistant for the Bowman Lab at the Scripps Institute of Oceanography, University of California San Diego. The following is a tutorial that demonstrates a pipeline used to assemble and annotate a bacterial genome from Oxford Nanopore MinION data.</p>
<p>This tutorial will require the following (brief installation instructions are included below):</p>
<ol>
<li><a href="https://canu.readthedocs.io/en/latest/">Canu Assembler</a></li>
<li><a href="https://rrwick.github.io/Bandage/">Bandage</a></li>
<li><a href="https://github.com/tseemann/prokka">Prokka</a></li>
<li><a href="https://github.com/tseemann/barrnap">Barrnap</a></li>
<li><a href="https://www.sanger.ac.uk/science/tools/dnaplotter">DNAPlotter</a> (alternatively <a href="http://circos.ca/">circos</a>)</li>
</ol>
<h2>Software Installation</h2>
<h3>Canu</h3>
<p>Canu is a packaged correction, trimming, and assembly program that is forked from the Celera assembler codebase. Install the latest release by running the following:</p>
<pre><code>git clone https://github.com/marbl/canu.git
cd canu/src
make</code></pre>
<h3>Bandage</h3>
<p>Bandage is an assembly visualization software. Install it by visiting <a href="https://github.com/rrwick/Bandage/releases/">this link</a>, and downloading the version appropriate for your device.</p>
<h3>Prokka</h3>
<p>Prokka is a gene annotation program. Install it by visiting <a href="https://github.com/tseemann/prokka">this link</a>, and running the installation commands appropriate for your device.</p>
<h3>Barrnap</h3>
<p>Barrnap is an rRNA prediction software used by Prokka. Install it by visiting <a href="https://github.com/tseemann/barrnap">this link</a>, and running the installation commands appropriate for your device.</p>
<h3>DNAPlotter</h3>
<p>DNAPlotter is a gene annotation visualization software. Install it by visiting <a href="https://www.sanger.ac.uk/science/tools/dnaplotter">this link</a>, and running the installation commands appropriate for your device.</p>
<h2>Dataset</h2>
<p>Download the nanopore dataset located <a href="https://www.polarmicrobes.org/extras/nanopore.tar.gz">here</a>. This is an isolate from a sample taken from a local saline lake at <a href="https://en.wikipedia.org/wiki/South_Bay_Salt_Works" rel="nofollow">South Bay Salt Works</a> near San Diego, California.</p>
<p>The download will provide a tarball. Extract it:</p>
<pre><code>tar -xvf nanopore.tar.gz
</code></pre>
<p>This will create a runs_fastq folder containing 8 fastq files containing genetic data.</p>
<h2>Assembly</h2>
<p>Canu can be used directly on the data without any preprocessing. The only additional information needed is an estimate of the genome size of the sample. For the saline isolate, we estimate 3,000,000 base pairs. Then, use the following Canu command to assemble our data:</p>
<pre><code>canu -nanopore_raw -p test_canu -d test_canu runs_fastq/*.fastq genomeSize=3000000 gnuplotTested=true
</code></pre>
<p>A quick description of all flags and parameters:</p>
<ul>
<li>-nanopore_raw &#8211; specifies data is Oxford Nanopore with no data preprocessing</li>
<li>-p &#8211; specifies prefix for output files, use “test_canu” as default</li>
<li>-d &#8211; specifies directory to run test and output files in, use “test_canu” as default</li>
<li>genomeSize &#8211; estimated genome size of isolate</li>
<li>gnuplotTested &#8211; setting to true will skip gnuplot testing; gnuplot is not needed for this pipeline</li>
</ul>
<p>Running this command will output various files into the test_canu directory. The assembled contigs are located in the test.contigs.fasta file. These contigs can be better visualized using Bandage.</p>
<h2>Assembly Visualization</h2>
<p>Opening Bandage and a GUI window should pop up. In the toolbar, click File &gt; Load Graph, and select the test.contigs.gfa. You should see something like the following:</p>
<p><a href="https://i0.wp.com/github.com/sabeelmansuri/bowman_archive/blob/master/Bandage.png?ssl=1" target="_blank" rel="noopener noreferrer"><img data-recalc-dims="1" decoding="async" class="aligncenter" src="https://i0.wp.com/github.com/sabeelmansuri/bowman_archive/raw/master/Bandage.png?w=300&#038;ssl=1"  /></a></p>
<p>This graph reveals that one of our contigs appears to be a whole circular chromosome! A quick comparison with the test.contigs.fasta file reveals this is Contig 1. We extract only this sequence from the contigs file to examine further. Note that the first contig takes up the first 38,673 lines of the file, so use <code>head</code>:</p>
<pre><code>head -n38673 test_canu/test_canu.contigs.fasta &gt;&gt; test_canu/contig1.fasta 
</code></pre>
<h2><a id="user-content-ncbi-blast" class="anchor" href="https://github.com/sabeelmansuri/bowman_archive/blob/master/Nanopore_Tutorial.md#ncbi-blast" aria-hidden="true"></a>NCBI BLAST</h2>
<p>We blast this Contig using NCBI’s nucleotide BLAST database (linked <a href="https://blast.ncbi.nlm.nih.gov/Blast.cgi" rel="nofollow">here</a>) with all default options. The top hit is:</p>
<pre><code>Hit: Halomonas sp. hl-4 genome assembly, chromosome: I  
Organism: Halomonas sp. hl-4  
Phylogeny: Bacteria/Proteobacteria/Gammaproteobacteria/Oceanospirillales/Halomonadaceae/Halomonas  
Max score: 65370  
Query cover: 72%  
E value: 0.0  
Ident 87%</code></pre>
<p>It appears this chromosome is the genome of an organism in the genus <em>Halomonas</em>. We may now be interested in the gene annotation of this genome.</p>
<h2>Gene Annotation</h2>
<p>Prokka will take care of gene annotation, the only required input is the contig1.fasta file.</p>
<pre><code>prokka --outdir circular --prefix test_prokka test_canu/contig1.fasta
</code></pre>
<p>The newly created circular directory contains various files with data on the gene annotation. Take a look inside test_prokka.txt for a summary of the annotation. We can take a quick look at the annotation using the DNAPlotter GUI.  For a more customized circular plot use circos.</p>
<p><a href="https://www.polarmicrobes.org/tutorial-nanopore-analysis-pipeline/dnaplotter/" rel="attachment wp-att-2450"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter wp-image-2450 size-full" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/12/dnaplotter.png?resize=640%2C640&#038;ssl=1" alt="" width="640" height="640" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/12/dnaplotter.png?w=690&amp;ssl=1 690w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/12/dnaplotter.png?resize=150%2C150&amp;ssl=1 150w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/12/dnaplotter.png?resize=300%2C300&amp;ssl=1 300w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a></p>
<h2><a id="user-content-summary" class="anchor" href="https://github.com/sabeelmansuri/bowman_archive/blob/master/Nanopore_Tutorial.md#summary" aria-hidden="true"></a>Summary</h2>
<p>The analysis above has taken Oxford Nanopore sequenced data, assembled contigs, identified the closest matching organism, and annotated its genome.</p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-nanopore-analysis-pipeline%2F&amp;linkname=Tutorial%3A%20Nanopore%20Analysis%20Pipeline" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-nanopore-analysis-pipeline%2F&amp;linkname=Tutorial%3A%20Nanopore%20Analysis%20Pipeline" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-nanopore-analysis-pipeline%2F&amp;linkname=Tutorial%3A%20Nanopore%20Analysis%20Pipeline" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-nanopore-analysis-pipeline%2F&#038;title=Tutorial%3A%20Nanopore%20Analysis%20Pipeline" data-a2a-url="https://www.polarmicrobes.org/tutorial-nanopore-analysis-pipeline/" data-a2a-title="Tutorial: Nanopore Analysis Pipeline"></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://www.polarmicrobes.org/tutorial-nanopore-analysis-pipeline/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2443</post-id>	</item>
		<item>
		<title>Weighted Gene Correlation Network Analysis (WGCNA) Applied to Microbial Communities</title>
		<link>https://www.polarmicrobes.org/weighted-gene-correlation-network-analysis-wgcna-applied-to-microbial-communities/</link>
					<comments>https://www.polarmicrobes.org/weighted-gene-correlation-network-analysis-wgcna-applied-to-microbial-communities/#comments</comments>
		
		<dc:creator><![CDATA[Jesse Wilson]]></dc:creator>
		<pubDate>Mon, 22 Oct 2018 17:16:24 +0000</pubDate>
				<category><![CDATA[Computer tutorials]]></category>
		<guid isPermaLink="false">http://www.polarmicrobes.org/?p=2315</guid>

					<description><![CDATA[Weighted gene correlation network analysis (WGCNA) is a powerful network analysis tool that can be used to identify groups of highly correlated genes that co-occur across your samples. Thus genes are sorted into modules and these modules can then be &#8230; <a href="https://www.polarmicrobes.org/weighted-gene-correlation-network-analysis-wgcna-applied-to-microbial-communities/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p><span style="text-decoration: underline;"><strong>Weighted gene correlation network analysis (WGCNA)</strong></span> is a powerful network analysis tool that can be used to identify groups of highly correlated genes that co-occur across your samples. Thus genes are sorted into modules and these modules can then be correlated with other traits (that must be continuous variables).</p>
<p>Originally created to assess gene expression data in human patients, the authors of the WGCNA method and R package  have a thorough tutorial with in-depth explanations (https://horvath.genetics.ucla.edu/html/CoexpressionNetwork/Rpackages/WGCNA/Tutorials/). More recently, the method has been applied to microbial communities (Duran-Pinedo et al., 2011; Aylward et al., 2015; Guidi et al., 2016; Wilson et al., 2018)&#8211;the following is a walk though using microbial sequence abundances and environmental data from my 2018 work (https://www.ncbi.nlm.nih.gov/m/pubmed/29488352/).</p>
<p><span style="text-decoration: underline;"><strong>Background:</strong></span> WGCNA finds how clusters of genes (or in our case abundances of operational taxonomic units&#8211;OTUs) correlates with traits (or in our case environmental variables or biochemical rates) using hierarchical clusters, novel applications of weighted adjacency functions and topological overlap measures, and a dynamic tree cutting method.</p>
<p>Very simply, each OTU is going to be represented by a node in a vast network and the adjacency (a score between 0 and 1) between each set of nodes will be calculated. Many networks use hard-thresholding (where a connection score [e.g. a Pearson Correlation Coefficient] between any two nodes is noted as 1 if it is above a certain threshold and noted as 0 if it is below it). This ignores the actual strength of the connection so WGCNA constructs a weighted gene (or OTU) co-occurrence adjacency matrix in lieu of &#8216;hard&#8217; thresholding. Because our original matrix has abundance data the abundance of each OTU is also factored in.</p>
<p>For this method to work you also have to select a soft thresholding power (sft) to which each co-expression similarity is raised in order to make these scores &#8220;connection strengths&#8221;. I used a signed adjacency function:</p>
<ul>
<li>Adjacency = 0.5*(1+Pearson correlation)^sft</li>
</ul>
<p>because it preserves the sign of the connection (whether nodes are positively or negatively correlated) and this is recommendation by authors of WGCNA.</p>
<p>You pick your soft thresholding value by using a scale-free topology. This is based on the idea that the probability that a node is connected with k other nodes decays as a power law:</p>
<ul>
<li>p(k)~ k^(-γ)</li>
</ul>
<p>This idea is linked to the growth of networks&#8211;new nodes are more likely to be attached to already established nodes. In general, scale-free networks display a high degree of tolerance against errors (Zhang &amp; Horvath, 2005).</p>
<p>You then turn your adjacency matrix into a Topological Overlap Measure (TOM) to minimize the effects of noise and spurious associations. A topological overlap of two nodes also factors in all of their shared neighbors (their relative interrelatedness)&#8211;so you are basically taking a simple co-occurrence between two nodes and placing it in the framework of the entire network by factoring in all the other nodes each is connected to. For more information regarding adjacency matrices and TOMs please see Zhang &amp; Horvath (2005) and Langfelder &amp; Horvath (2007 &amp; 2008).</p>
<p><span style="text-decoration: underline;"><strong>Start:</strong></span> Obtain an OTU abundance matrix (<span class="css-truncate css-truncate-target"><a id="e60907d724ee77179604badfab8e4a0c-a3b4e2dfcbed06ec349df87293d0f7fc3e822732" class="js-navigation-open" title="MB.0.03.subsample.fn.txt" href="https://github.com/jesse889/WGCNA-R-Code/blob/master/MB.0.03.subsample.fn.txt">MB.0.03.subsample.fn.txt</a>)</span> and environmental data (<span class="css-truncate css-truncate-target"><a id="d7d191b0ca1b41559107dc3fd6cd566b-d674e442997bf5309b2786562b3b870f053b0289" class="js-navigation-open" title="OxygenMatrixMonterey.csv" href="https://github.com/jesse889/WGCNA-R-Code/blob/master/OxygenMatrixMonterey.csv">OxygenMatrixMonterey.csv</a></span>).</p>
<p>The OTU abundance matrix simply has all the different OTUs that were observed in a bunch of different samples (denoted in the Group column; e.g. M1401, M1402, etc.). These OTUs represent 16S rRNA sequences that were assessed with the universal primers 515F-Y (5&#8242;-GTGYCAGCMGCCGCGGTAA) and 926R (5&#8242;-CCGYCAATTYMTTTRAGTTT) and were created using a 97% similarity cutoff. These populations were previously subsampled to the smallest library size and all processing took place in mothur (https://www.mothur.org/). See Wilson et al. (2018) for more details.</p>
<p>The environmental data matrix tells you a little bit more about the different <strong>Samples</strong>, like the <strong>Date</strong> of collection, which of two site <strong>Locations</strong> it was collected from, the <strong>Depth</strong> or <strong>Zone</strong> of collection. You also see a bunch of different environmental variables like several different <strong>Upwelling</strong> indices (for different stations and different time spans), community respiration rate (<strong>CR</strong>), <strong>Oxygen</strong> <strong>Conc</strong>entration, and <strong>Temp</strong>erature. Again, see Wilson et al. (2018) for more details.</p>
<p><span style="text-decoration: underline;"><strong>Code&#8211;Initial Stuff:</strong></span></p>
<p>Read data in:</p>
<pre>data&lt;-read.table("MB.0.03.subsample.fn.txt",header=T,na.strings="NA")
</pre>
<p>For this particular file we have to get rid of first three columns since the OTUs don&#8217;t actually start until the 4th column:</p>
<pre>data1 = data[-1][-1][-1]
</pre>
<p>You should turn your raw abundance values into a relative abundance matrix and potentially transform it. I recommend a Hellinger Transformation (a square root of the relative abundance)&#8211;this effectively gives low weight to variables with low counts and many zeros. If you wanted you could do the Logarithmic transformation of Anderson et al. (2006) here in stead.</p>
<pre>library("vegan", lib.loc="~/R/win-library/3.3")
HellingerData&lt;-decostand(data1,method = "hellinger")
</pre>
<p>You have to limit the OTUs to the most frequent ones (ones that occur in multiple samples so that you can measure co-occurance across samples). I just looked at my data file and looked for where zeros became extremely common. This was easy because mothur sorts OTUs according to abundance. If you would like a more objective way of selecting the OTUs or if your OTUs are not sorted you then this code may help:</p>
<p>lessdata &lt;- data1[,colSums(data1) &gt; 0.05]</p>
<p>(though you will have to decide what cutoff works best for your data).</p>
<p><span style="text-decoration: underline;"><strong>Code&#8211;Making your relative abundance matrix:</strong></span></p>
<p>You have to reattach the Group Name column:</p>
<pre>RelAbun1 = data.frame(data[2],HellingerData[1:750])
</pre>
<p>Write file (this step isn&#8217;t absolutely necessary, but you may want this file later at some point):</p>
<pre>write.table(RelAbun1, file = "MontereyRelAbun.txt", sep="\t")
</pre>
<p><span style="text-decoration: underline;"><strong>Code&#8211;Visualizing your data at the sample level:</strong></span></p>
<p>Now load the WGCNA package:</p>
<pre>library("WGCNA", lib.loc="~/R/win-library/3.3")
</pre>
<p>Bring data in:</p>
<pre>OTUs&lt;-read.table("MontereyRelAbun.txt",header=T,sep="\t")
dim(OTUs);
names(OTUs);
</pre>
<p>Turn the first column (sample name) into row names (so that only OTUs make up actual columns):</p>
<pre>datExpr0 = as.data.frame((OTUs[,-c(1)]));
names(datExpr0) = names(OTUs)[-c(1)];
rownames(datExpr0) = OTUs$Group;
</pre>
<p>Check Data for excessive missingness:</p>
<pre>gsg = goodSamplesGenes(datExpr0[-1], verbose = 3);
gsg$allOK
</pre>
<p>You should get TRUE for this dataset given the parameters above. TRUE means that all OTUs have passed the cut. This means that when you limited your OTUs to the most common ones above that you didn&#8217;t leave any in that had too many zeros. It is still possible that you were too choosy though. If you got FALSE for your data then you have to follow some other steps that I don&#8217;t go over here.</p>
<p>Cluster the samples to see if there are any obvious outliers:</p>
<pre>sampleTree = hclust(dist(datExpr0), method = "average");

sizeGrWindow(12,9)

par(cex = 0.6);
par(mar = c(0,4,2,0))

plot(sampleTree, main = "Sample clustering to detect outliers", sub="", xlab="", cex.lab = 1.5, cex.axis = 1.5, cex.main = 2)
</pre>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Dendro.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-2316" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Dendro.png?resize=300%2C173&#038;ssl=1" alt="" width="300" height="173" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Dendro.png?resize=300%2C173&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Dendro.png?resize=768%2C443&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Dendro.png?w=828&amp;ssl=1 828w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>The sample dendrogram doesn&#8217;t show any obvious outliers so I didn&#8217;t remove any samples. If you need to remove some samples then you have to follow some code I don&#8217;t go over here.</p>
<p>Now read in trait (Environmental) data and match with expression samples:</p>
<pre>traitData = read.csv("OxygenMatrixMonterey.csv");
dim(traitData)
names(traitData)
</pre>
<p>Form a data frame analogous to expression data (relative abundances of OTUs) that will hold the Environmental traits:</p>
<pre>OTUSamples = rownames(datExpr0);
traitRows = match(OTUSamples, traitData$Sample);
datTraits = traitData[traitRows, -1];
rownames(datTraits) = traitData[traitRows, 1];
collectGarbage()
</pre>
<p><span style="text-decoration: underline;"><strong>Outcome:</strong></span> Now your OTU expression (or abundance) data are stored in the variable datExpr0 and the corresponding environmental traits are in the variable datTraits. Now you can visualize how the environmental traits relate to clustered samples.</p>
<p>Re-cluster samples:</p>
<pre>sampleTree2 = hclust(dist(datExpr0), method = "average")
</pre>
<p>Convert traits to a color representation: white means low, red means high, grey means missing entry:</p>
<pre>traitColors = numbers2colors(datTraits[5:13], signed = FALSE);
</pre>
<p>Plot the sample dendrogram and the colors underneath:</p>
<pre>plotDendroAndColors(sampleTree2, traitColors,
groupLabels = names(datTraits[5:13]),
main = "Sample dendrogram and trait heatmap")
</pre>
<p>Again: white means a low value, red means a high value, and gray means missing entry. This is just initial stuff&#8230; we haven&#8217;t looked at modules of OTUs that occur across samples yet.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/dendro-heatmap.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-2317" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/dendro-heatmap.png?resize=300%2C173&#038;ssl=1" alt="" width="300" height="173" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/dendro-heatmap.png?resize=300%2C173&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/dendro-heatmap.png?resize=768%2C443&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/dendro-heatmap.png?w=828&amp;ssl=1 828w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>Save:</p>
<pre>save(datExpr0, datTraits, file = "Monterey-dataInput.RData")
</pre>
<p><span style="text-decoration: underline;"><strong>Code&#8211;Network Analysis:</strong></span></p>
<p>Allow multi-threading within WGCNA. This helps speed up certain calculations.<br />
Any error here may be ignored but you may want to update WGCNA if you see one.</p>
<pre>options(stringsAsFactors = FALSE);
enableWGCNAThreads()
</pre>
<p>Load the data saved in the first part:</p>
<pre>lnames = load(file = "Monterey-dataInput.RData");
</pre>
<p>The variable lnames contains the names of loaded variables:</p>
<pre>lnames
</pre>
<p><span style="text-decoration: underline;"><strong>Note:</strong></span> You have a couple of options for how you create your weighted OTU co-expression network. I went with the step-by-step construction and module detection. Please see this document for information on the other methods (https://horvath.genetics.ucla.edu/html/CoexpressionNetwork/Rpackages/WGCNA/Tutorials/Simulated-05-NetworkConstruction.pdf).</p>
<p>Choose a set of soft-thresholding powers:</p>
<pre>powers = c(c(1:10), seq(from = 11, to=30, by=1))
</pre>
<p>Call the network topology analysis function:<br />
<span style="text-decoration: underline;"><strong>Note:</strong></span> I am using a signed network because it preserves the sign of the connection (whether nodes are positively or negatively correlated); this is recommendation by authors of WGCNA.</p>
<pre>sft = pickSoftThreshold(datExpr0, powerVector = powers, verbose = 5, networkType = "signed")
</pre>
<p><span style="text-decoration: underline;"><strong>Output: </strong></span></p>
<pre id="rstudio_console_output" class="GGHFMYIBMOB" tabindex="0">pickSoftThreshold: will use block size 750.
 pickSoftThreshold: calculating connectivity for given powers...
   ..working on genes 1 through 750 of 750
   Power SFT.R.sq slope truncated.R.sq  mean.k. median.k. max.k.
1      1   0.0299  1.47          0.852 399.0000  400.0000 464.00
2      2   0.1300 -1.74          0.915 221.0000  221.0000 305.00
3      3   0.3480 -2.34          0.931 128.0000  125.0000 210.00
4      4   0.4640 -2.41          0.949  76.3000   73.1000 150.00
5      5   0.5990 -2.57          0.966  47.2000   44.0000 111.00
6      6   0.7010 -2.52          0.976  30.1000   27.1000  83.40
7      7   0.7660 -2.47          0.992  19.8000   17.2000  64.30
8      8   0.8130 -2.42          0.986  13.3000   11.0000  50.30
9      9   0.8390 -2.34          0.991   9.2200    7.1900  40.00
10    10   0.8610 -2.24          0.992   6.5200    4.8800  32.20
11    11   0.8670 -2.19          0.987   4.7000    3.3700  26.20
12    12   0.8550 -2.18          0.959   3.4600    2.3300  21.50</pre>
<p>This is showing you the power (soft thresholding value), the r2 for the scale independence for each particular power (we shoot for an r2 higher than 0.8), the mean number of connections each node has at each power (mean.k), the median number of connections/node (median.k), and the maximum number of connections (max.k).</p>
<p>Plot the results:</p>
<pre>sizeGrWindow(9, 5)
par(mfrow = c(1,2));
cex1 = 0.9;
</pre>
<p>Scale-free topology fit index (r2) as a function of the soft-thresholding power:</p>
<pre>plot(sft$fitIndices[,1], -sign(sft$fitIndices[,3])*sft$fitIndices[,2],
xlab="Soft Threshold (power)",ylab="Scale Free Topology Model Fit,signed R^2",type="n",
main = paste("Scale independence"));
text(sft$fitIndices[,1], -sign(sft$fitIndices[,3])*sft$fitIndices[,2],
labels=powers,cex=cex1,col="red");
</pre>
<p>This line corresponds to using an R^2 cut-off of h:</p>
<pre>abline(h=0.8,col="red")
</pre>
<p>Mean connectivity as a function of the soft-thresholding power:</p>
<pre>plot(sft$fitIndices[,1], sft$fitIndices[,5],
xlab="Soft Threshold (power)",ylab="Mean Connectivity", type="n",
main = paste("Mean connectivity"))
text(sft$fitIndices[,1], sft$fitIndices[,5], labels=powers, cex=cex1,col="red")
</pre>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/ScaleIndependenceMeanConnectivity.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-2327" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/ScaleIndependenceMeanConnectivity.png?resize=300%2C173&#038;ssl=1" alt="" width="300" height="173" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/ScaleIndependenceMeanConnectivity.png?resize=300%2C173&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/ScaleIndependenceMeanConnectivity.png?resize=768%2C443&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/ScaleIndependenceMeanConnectivity.png?w=828&amp;ssl=1 828w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>I picked a soft thresholding value of 10 because it was well above an r2 of 0.8 (it is a local peak for the r2) and the mean connectivity is still above 0.</p>
<p>So now we just calculate the adjacencies, using the soft thresholding power of 10:</p>
<pre>softPower = 10;
adjacency = adjacency(datExpr0, power = softPower, type = "signed");
</pre>
<p>Then we transform the adjacency matrix into a Topological Overlap Matrix (TOM) and calculate corresponding dissimilarity:</p>
<p><span style="text-decoration: underline;"><strong>Remember:</strong></span> The TOM you calculate shows the topological similarity of nodes, factoring in the connection strength two nodes share with other &#8220;third party&#8221; nodes. This will minimize effects of noise and spurious associations:</p>
<pre>TOM = TOMsimilarity(adjacency, TOMType = "signed");
dissTOM = 1-TOM
</pre>
<p>Create a dendogram using a hierarchical clustering tree and then call the hierarchical clustering function:</p>
<pre>TaxaTree = hclust(as.dist(dissTOM), method = "average");
</pre>
<p>Plot the resulting clustering tree (dendrogram):</p>
<pre>sizeGrWindow(12,9)
plot(TaxaTree, xlab="", sub="", main = "Taxa clustering on TOM-based dissimilarity",
labels = FALSE, hang = 0.04);
</pre>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/TaxaClusteringInitial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-2331" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/TaxaClusteringInitial.png?resize=300%2C173&#038;ssl=1" alt="" width="300" height="173" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/TaxaClusteringInitial.png?resize=300%2C173&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/TaxaClusteringInitial.png?resize=768%2C443&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/TaxaClusteringInitial.png?w=828&amp;ssl=1 828w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>This image is showing us the clustering of all 750 OTUs based on the TOM dissimilarity index.</p>
<p>Now you have to decide the optimal module size for your system and should play around with this value a little. I wanted relatively large module so I set the minimum module size relatively high at 30:</p>
<pre>minModuleSize = 30;
</pre>
<p>Module identification using dynamic tree cut (there a couple of different ways to figure out your modules and so you should explore what works best for you in the tutorials by the authors):</p>
<pre>dynamicMods = cutreeDynamic(dendro = TaxaTree, distM = dissTOM,
deepSplit = 2, pamRespectsDendro = FALSE,
minClusterSize = minModuleSize);
table(dynamicMods)
</pre>
<p>Convert numeric labels into colors:</p>
<pre>dynamicColors = labels2colors(dynamicMods)
table(dynamicColors)
</pre>
<pre id="rstudio_console_output" class="GGHFMYIBMOB" tabindex="0">dynamicColors
    black      blue     brown     green       red turquoise    yellow 
       49       135       113        71        64       216       102</pre>
<p>You can see that there are a total of 7 modules (you should have seen that above too) and that now each module is named a different color. The numbers under the colors tells you how many OTUs were sorted into that module. Each OTU is in exactly 1 module, and you can see that if you add up all of the numbers from the various modules you get 750 (the number of OTUs that we limited our analysis to above).</p>
<p>Plot the dendrogram with module colors underneath:</p>
<pre>sizeGrWindow(8,6)
plotDendroAndColors(TaxaTree, dynamicColors, "Dynamic Tree Cut",
dendroLabels = FALSE, hang = 0.03,
addGuide = TRUE, guideHang = 0.05,
main = "Taxa dendrogram and module colors")
</pre>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/TaxaDendroSecond.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-2332" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/TaxaDendroSecond.png?resize=300%2C173&#038;ssl=1" alt="" width="300" height="173" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/TaxaDendroSecond.png?resize=300%2C173&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/TaxaDendroSecond.png?resize=768%2C443&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/TaxaDendroSecond.png?w=828&amp;ssl=1 828w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>Now we will quantify co-expression similarity of the entire modules using eigengenes and cluster them based on their correlation:<br />
<span style="text-decoration: underline;"><strong>Note:</strong></span> An eigengene is 1st principal component of a module expression matrix and represents a suitably defined average OTU community.</p>
<p>Calculate eigengenes:</p>
<pre>MEList = moduleEigengenes(datExpr0, colors = dynamicColors)
MEs = MEList$eigengenes
</pre>
<p>Calculate dissimilarity of module eigengenes:</p>
<pre>MEDiss = 1-cor(MEs);
</pre>
<p>Cluster module eigengenes:</p>
<pre>METree = hclust(as.dist(MEDiss), method = "average");
</pre>
<p>Plot the result:</p>
<pre>sizeGrWindow(7, 6)
plot(METree, main = "Clustering of module eigengenes",
xlab = "", sub = "")
</pre>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Eigengenes.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-2333" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Eigengenes.png?resize=300%2C173&#038;ssl=1" alt="" width="300" height="173" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Eigengenes.png?resize=300%2C173&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Eigengenes.png?resize=768%2C443&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Eigengenes.png?w=828&amp;ssl=1 828w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>Now we will see if any of the modules should be merged. I chose a height cut of 0.30, corresponding to a similarity of 0.70 to merge:</p>
<pre>MEDissThres = 0.30
</pre>
<p>Plot the cut line into the dendrogram:</p>
<pre>abline(h=MEDissThres, col = "red")
</pre>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Eigengenes2.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-2334" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Eigengenes2.png?resize=300%2C173&#038;ssl=1" alt="" width="300" height="173" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Eigengenes2.png?resize=300%2C173&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Eigengenes2.png?resize=768%2C443&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Eigengenes2.png?w=828&amp;ssl=1 828w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>You can see that, according to our cutoff, none of the modules should be merged.</p>
<p>If there were some modules that needed to be merged you can call an automatic merging function:</p>
<pre>merge = mergeCloseModules(datExpr0, dynamicColors, cutHeight = MEDissThres, verbose = 3)
</pre>
<p>The merged module colors:</p>
<pre>mergedColors = merge$colors;
</pre>
<p>Eigengenes of the new merged modules:</p>
<pre>mergedMEs = merge$newMEs;
</pre>
<p>If you had combined different modules then that would show in this plot:</p>
<pre>sizeGrWindow(12, 9)

plotDendroAndColors(TaxaTree, cbind(dynamicColors, mergedColors),
c("Dynamic Tree Cut", "Merged dynamic"),
dendroLabels = FALSE, hang = 0.03,
addGuide = TRUE, guideHang = 0.05)
</pre>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/ClusterDendro2.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-2335" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/ClusterDendro2.png?resize=300%2C173&#038;ssl=1" alt="" width="300" height="173" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/ClusterDendro2.png?resize=300%2C173&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/ClusterDendro2.png?resize=768%2C443&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/ClusterDendro2.png?w=828&amp;ssl=1 828w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>If we had merged some of the modules that would show up in the Merged dynamic color scheme.</p>
<p>Rename the mergedColors to moduleColors:</p>
<pre>moduleColors = mergedColors
</pre>
<p>Construct numerical labels corresponding to the colors:</p>
<pre>colorOrder = c("grey", standardColors(50));
moduleLabels = match(moduleColors, colorOrder)-1;
MEs = mergedMEs;
</pre>
<p>Save module colors and labels for use in subsequent parts:</p>
<pre>save(MEs, moduleLabels, moduleColors, TaxaTree, file = "Monterey-networkConstruction-stepByStep.RData")
</pre>
<p><span style="text-decoration: underline;"><strong>Code&#8211;Relating modules to external information and IDing important taxa:</strong></span></p>
<p>Here you are going to identify modules that are significantly associate with environmental traits/biogeochemical rates. You already have summary profiles for each module (eigengenes&#8211;remeber that an eigengene is 1st principal component of a module expression matrix and represents a suitably defined average OTU community), so we just have to correlate these eigengenes with environmental traits and look for significant associations.</p>
<p>Defining numbers of OTUs and samples:</p>
<pre>nTaxa = ncol(datExpr0);
nSamples = nrow(datExpr0);
</pre>
<p>Recalculate MEs (module eigengenes):</p>
<pre>MEs0 = moduleEigengenes(datExpr0, moduleColors)$eigengenes
MEs = orderMEs(MEs0)
moduleTraitCor = cor(MEs, datTraits, use = "p");
moduleTraitPvalue = corPvalueStudent(moduleTraitCor, nSamples);
</pre>
<p>Now we will visualize it:</p>
<pre>sizeGrWindow(10,6)

textMatrix = paste(signif(moduleTraitCor, 2), "\n(",
signif(moduleTraitPvalue, 1), ")", sep = "");
dim(textMatrix) = dim(moduleTraitCor)
par(mar = c(6, 8.5, 3, 3));

labeledHeatmap(Matrix = moduleTraitCor,
xLabels = names(datTraits),
yLabels = names(MEs),
ySymbols = names(MEs),
colorLabels = FALSE,
colors = greenWhiteRed(50),
textMatrix = textMatrix,
setStdMargins = FALSE,
cex.text = 0.5,
zlim = c(-1,1),
main = paste("Module-trait relationships"))
</pre>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Module-trait.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-2341" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Module-trait.png?resize=300%2C173&#038;ssl=1" alt="" width="300" height="173" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Module-trait.png?resize=300%2C173&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Module-trait.png?resize=768%2C443&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/Module-trait.png?w=828&amp;ssl=1 828w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>Each row corresponds to a module eigengene and each column corresponds to an environmental trait or biogeochemical rate (as long as it is continuous&#8211;notice that the categorical variables are gray and say NA). Each cell contains the corresponding Pearson correlation coefficient (top number) and a p-value (in parentheses). The table is color-coded by correlation according to the color legend.</p>
<p>You can see that the Brown module is positively correlated with many indices of upwelling while the Black module is negatively correlated with many indices of upwelling. For this work I was particularly interested in CR and so I focused on modules the positively or negatively correlated with CR. The Red module was negatively associated with CR while the Blue module was positively associated with CR.</p>
<p>Let&#8217;s look more at the Red module by quantifying the associations of individual taxa with CR:</p>
<p>First define the variable we are interested in from datTrait:</p>
<pre>CR = as.data.frame(datTraits$CR);
names(CR) = "CR"

modNames = substring(names(MEs), 3)
TaxaModuleMembership = as.data.frame(cor(datExpr0, MEs, use = "p"));
MMPvalue = as.data.frame(corPvalueStudent(as.matrix(TaxaModuleMembership), nSamples));
names(TaxaModuleMembership) = paste("MM", modNames, sep="");
names(MMPvalue) = paste("p.MM", modNames, sep="");
TaxaTraitSignificance = as.data.frame(cor(datExpr0, CR, use = "p"));
GSPvalue = as.data.frame(corPvalueStudent(as.matrix(TaxaTraitSignificance), nSamples));
names(TaxaTraitSignificance) = paste("GS.", names(CR), sep="");
names(GSPvalue) = paste("p.GS.", names(CR), sep="");

module = "red"
column = match(module, modNames);
moduleTaxa = moduleColors==module;
sizeGrWindow(7, 7);
par(mfrow = c(1,1));
verboseScatterplot(abs(TaxaModuleMembership[moduleTaxa, column]),
abs(TaxaTraitSignificance[moduleTaxa, 1]),
xlab = paste("Module Membership in", module, "module"),
ylab = "Taxa significance for CR",
main = paste("Module membership vs. Taxa significance\n"),
cex.main = 1.2, cex.lab = 1.2, cex.axis = 1.2, col = module)
</pre>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/ModuleMembershipvsTaxaSig.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-2343" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/ModuleMembershipvsTaxaSig.png?resize=300%2C173&#038;ssl=1" alt="" width="300" height="173" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/ModuleMembershipvsTaxaSig.png?resize=300%2C173&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/ModuleMembershipvsTaxaSig.png?resize=768%2C443&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/10/ModuleMembershipvsTaxaSig.png?w=828&amp;ssl=1 828w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>This graph shows you how each taxa (each red dot is an OTU that belongs in the Red module) correlated with 1) the Environmental trait of interest and 2) how important it is to the module. The taxa/OTUs that have high module membership tend to occur whenever the module is represented in the environment and are therefore often connected throughout the samples with other red taxa/OTUs. In this module, these hubs (Red OTUs that occur with other Red OTUs) are also the most important OTUs for predicting CR.</p>
<p>Now lets get more info about the taxa that make up the Red module:</p>
<p>First, merge the statistical info from previous section (modules with high assocation with trait of interest&#8211;e.g. CR or Temp) with taxa annotation and write a file that summarizes these results:</p>
<pre>names(datExpr0)
names(datExpr0)[moduleColors=="red"]
</pre>
<p>You will have to feed in an annotation file&#8211;a file listing what Bacteria/Archaea go with each OTU (I am not providing you will this file, but it just had a column with OTUs and a column with the Taxonomy).</p>
<pre>annot = read.table("MB.subsample.fn.0.03.cons.taxonomy",header=T,sep="\t");
dim(annot)
names(annot)
probes = names(datExpr0)
probes2annot = match(probes, annot$OTU)
</pre>
<p>Check for the number or probes without annotation (it should return a 0):</p>
<pre>sum(is.na(probes2annot))
</pre>
<p>Create the starting data frame:</p>
<pre>TaxaInfo0 = data.frame(Taxon = probes,
TaxaSymbol = annot$OTU[probes2annot],
LinkID = annot$Taxonomy[probes2annot],
moduleColor = moduleColors,
TaxaTraitSignificance,
GSPvalue)
</pre>
<p>Order modules by their significance for weight:</p>
<pre>modOrder = order(-abs(cor(MEs, CR, use = "p")));
</pre>
<p>Add module membership information in the chosen order:</p>
<pre>for (mod in 1:ncol(TaxaModuleMembership))
{
oldNames = names(TaxaInfo0)
TaxaInfo0 = data.frame(TaxaInfo0, TaxaModuleMembership[, modOrder[mod]],
MMPvalue[, modOrder[mod]]);
names(TaxaInfo0) = c(oldNames, paste("MM.", modNames[modOrder[mod]], sep=""),
paste("p.MM.", modNames[modOrder[mod]], sep=""))
}
</pre>
<p>Order the OTUs in the geneInfo variable first by module color, then by geneTraitSignificance:</p>
<pre>TaxaOrder = order(TaxaInfo0$moduleColor, -abs(TaxaInfo0$GS.CR));
TaxaInfo = TaxaInfo0[TaxaOrder, ]
</pre>
<p>Write file:</p>
<pre>write.csv(TaxaInfo, file = "TaxaInfo.csv")
</pre>
<p>Here is a bit of the output file I got:</p>
<table style="border-collapse: collapse; width: 1008pt;" border="0" width="1344" cellspacing="0" cellpadding="0">
<colgroup>
<col style="width: 48pt;" span="21" width="64" /> </colgroup>
<tbody>
<tr style="height: 14.4pt;">
<td style="height: 14.4pt; width: 48pt;" width="64" height="19"></td>
<td style="width: 48pt;" width="64">Taxon</td>
<td style="width: 48pt;" width="64">TaxaSymbol</td>
<td style="width: 48pt;" width="64">LinkID</td>
<td style="width: 48pt;" width="64">moduleColor</td>
<td style="width: 48pt;" width="64">GS.TotalRate</td>
<td style="width: 48pt;" width="64">p.GS.TotalRate</td>
<td style="width: 48pt;" width="64">MM.red</td>
<td style="width: 48pt;" width="64">p.MM.red</td>
<td style="width: 48pt;" width="64">MM.blue</td>
<td style="width: 48pt;" width="64">p.MM.blue</td>
<td style="width: 48pt;" width="64">MM.green</td>
<td style="width: 48pt;" width="64">p.MM.green</td>
<td style="width: 48pt;" width="64">MM.brown</td>
<td style="width: 48pt;" width="64">p.MM.brown</td>
<td style="width: 48pt;" width="64">MM.turquoise</td>
<td style="width: 48pt;" width="64">p.MM.turquoise</td>
<td style="width: 48pt;" width="64">MM.black</td>
<td style="width: 48pt;" width="64">p.MM.black</td>
<td style="width: 48pt;" width="64">MM.yellow</td>
<td style="width: 48pt;" width="64">p.MM.yellow</td>
</tr>
<tr style="height: 14.4pt;">
<td style="height: 14.4pt;" height="19">Otu00711</td>
<td>Otu00711</td>
<td>Otu00711</td>
<td>Bacteria(100);Proteobacteria(100);Alphaproteobacteria(100);SAR11_clade(100);Surface_4(100);</td>
<td>black</td>
<td align="right">0.461005</td>
<td align="right">0.00111</td>
<td align="right">0.005028</td>
<td align="right">0.973244</td>
<td align="right">0.243888</td>
<td align="right">0.098526</td>
<td align="right">-0.07719</td>
<td align="right">0.606075</td>
<td align="right">-0.25274</td>
<td align="right">0.086535</td>
<td align="right">0.058878</td>
<td align="right">0.694233</td>
<td align="right">0.502027</td>
<td align="right">0.000324</td>
<td align="right">0.132412</td>
<td align="right">0.374947</td>
</tr>
<tr style="height: 14.4pt;">
<td style="height: 14.4pt;" height="19">Otu00091</td>
<td>Otu00091</td>
<td>Otu00091</td>
<td>Bacteria(100);Bacteroidetes(100);Flavobacteriia(100);Flavobacteriales(100);Flavobacteriaceae(100);Formosa(100);</td>
<td>black</td>
<td align="right">0.378126</td>
<td align="right">0.008778</td>
<td align="right">-0.17243</td>
<td align="right">0.246462</td>
<td align="right">0.446049</td>
<td align="right">0.001676</td>
<td align="right">0.34467</td>
<td align="right">0.017667</td>
<td align="right">-0.55057</td>
<td class="xl63" align="right">6.08E-05</td>
<td align="right">0.492517</td>
<td align="right">0.000437</td>
<td align="right">0.615168</td>
<td class="xl63" align="right">4.20E-06</td>
<td align="right">0.367211</td>
<td align="right">0.011115</td>
</tr>
<tr style="height: 14.4pt;">
<td style="height: 14.4pt;" height="19">Otu00082</td>
<td>Otu00082</td>
<td>Otu00082</td>
<td>Bacteria(100);Bacteroidetes(100);Flavobacteriia(100);Flavobacteriales(100);Flavobacteriaceae(100);NS5_marine_group(100);</td>
<td>black</td>
<td align="right">-0.35649</td>
<td align="right">0.013911</td>
<td align="right">0.222515</td>
<td align="right">0.132755</td>
<td align="right">-0.06428</td>
<td align="right">0.667734</td>
<td align="right">0.175654</td>
<td align="right">0.237601</td>
<td align="right">-0.45502</td>
<td align="right">0.001312</td>
<td align="right">0.421756</td>
<td align="right">0.003151</td>
<td align="right">0.750195</td>
<td class="xl63" align="right">1.28E-09</td>
<td align="right">0.126362</td>
<td align="right">0.397349</td>
</tr>
<tr style="height: 14.4pt;">
<td style="height: 14.4pt;" height="19">Otu00341</td>
<td>Otu00341</td>
<td>Otu00341</td>
<td>Bacteria(100);Bacteroidetes(100);Cytophagia(100);Cytophagales(100);Flammeovirgaceae(100);Marinoscillum(100);</td>
<td>black</td>
<td align="right">-0.28242</td>
<td align="right">0.054435</td>
<td align="right">0.023927</td>
<td align="right">0.873162</td>
<td align="right">-0.07555</td>
<td align="right">0.613762</td>
<td align="right">0.144688</td>
<td align="right">0.331879</td>
<td align="right">-0.03144</td>
<td align="right">0.833838</td>
<td align="right">0.035147</td>
<td align="right">0.814565</td>
<td align="right">0.209255</td>
<td align="right">0.158058</td>
<td align="right">-0.06565</td>
<td align="right">0.661083</td>
</tr>
<tr style="height: 14.4pt;">
<td style="height: 14.4pt;" height="19">Otu00537</td>
<td>Otu00537</td>
<td>Otu00537</td>
<td>Bacteria(100);Verrucomicrobia(100);Verrucomicrobiae(100);Verrucomicrobiales(100);Verrucomicrobiaceae(100);Persicirhabdus(100);</td>
<td>black</td>
<td align="right">-0.23668</td>
<td align="right">0.109211</td>
<td align="right">0.123673</td>
<td align="right">0.40755</td>
<td align="right">-0.17362</td>
<td align="right">0.243171</td>
<td align="right">-0.05738</td>
<td align="right">0.701628</td>
<td align="right">-0.26399</td>
<td align="right">0.072961</td>
<td align="right">0.264411</td>
<td align="right">0.072493</td>
<td align="right">0.425082</td>
<td align="right">0.002897</td>
<td align="right">0.040045</td>
<td align="right">0.789278</td>
</tr>
<tr style="height: 14.4pt;">
<td style="height: 14.4pt;" height="19">Otu00262</td>
<td>Otu00262</td>
<td>Otu00262</td>
<td>Bacteria(100);Proteobacteria(100);Alphaproteobacteria(100);SAR11_clade(100);Surface_1(100);Candidatus_Pelagibacter(90);</td>
<td>black</td>
<td align="right">-0.23615</td>
<td align="right">0.110023</td>
<td align="right">0.327396</td>
<td align="right">0.02468</td>
<td align="right">-0.22748</td>
<td align="right">0.12411</td>
<td align="right">-0.13779</td>
<td align="right">0.355699</td>
<td align="right">-0.23708</td>
<td align="right">0.108594</td>
<td align="right">0.271968</td>
<td align="right">0.064409</td>
<td align="right">0.554592</td>
<td class="xl63" align="right">5.23E-05</td>
<td align="right">0.036113</td>
<td align="right">0.809563</td>
</tr>
<tr style="height: 14.4pt;">
<td style="height: 14.4pt;" height="19">Otu00293</td>
<td>Otu00293</td>
<td>Otu00293</td>
<td>Bacteria(100);Proteobacteria(100);Alphaproteobacteria(100);SAR11_clade(100);SAR11_clade_unclassified(100);</td>
<td>black</td>
<td align="right">0.223427</td>
<td align="right">0.131133</td>
<td align="right">0.142016</td>
<td align="right">0.34098</td>
<td align="right">0.209327</td>
<td align="right">0.157912</td>
<td align="right">0.234713</td>
<td align="right">0.112274</td>
<td align="right">-0.53032</td>
<td align="right">0.000126</td>
<td align="right">0.529907</td>
<td align="right">0.000128</td>
<td align="right">0.627937</td>
<td class="xl63" align="right">2.30E-06</td>
<td align="right">0.390714</td>
<td align="right">0.006621</td>
</tr>
<tr style="height: 14.4pt;">
<td style="height: 14.4pt;" height="19">Otu00524</td>
<td>Otu00524</td>
<td>Otu00524</td>
<td>Bacteria(100);Actinobacteria(100);Acidimicrobiia(100);Acidimicrobiales(100);OM1_clade(100);Candidatus_Actinomarina(100);</td>
<td>black</td>
<td align="right">-0.20559</td>
<td align="right">0.165629</td>
<td align="right">0.28312</td>
<td align="right">0.053809</td>
<td align="right">0.016758</td>
<td align="right">0.910982</td>
<td align="right">0.148756</td>
<td align="right">0.318316</td>
<td align="right">-0.34758</td>
<td align="right">0.016669</td>
<td align="right">0.376043</td>
<td align="right">0.009188</td>
<td align="right">0.494903</td>
<td align="right">0.000406</td>
<td align="right">0.377597</td>
<td align="right">0.00888</td>
</tr>
<tr style="height: 14.4pt;">
<td style="height: 14.4pt;" height="19">Otu00370</td>
<td>Otu00370</td>
<td>Otu00370</td>
<td>Bacteria(100);Verrucomicrobia(100);Opitutae(100);MB11C04_marine_group(100);MB11C04_marine_group_unclassified(100);</td>
<td>black</td>
<td align="right">-0.20397</td>
<td align="right">0.169074</td>
<td align="right">0.303984</td>
<td align="right">0.037771</td>
<td align="right">-0.06655</td>
<td align="right">0.656707</td>
<td align="right">0.009401</td>
<td align="right">0.949991</td>
<td align="right">-0.25451</td>
<td align="right">0.084275</td>
<td align="right">0.097595</td>
<td align="right">0.514</td>
<td align="right">0.642409</td>
<td class="xl63" align="right">1.13E-06</td>
<td align="right">0.224711</td>
<td align="right">0.128875</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>NOTES on output:</p>
<p>moduleColor is the module that the OTU was ultimately put into</p>
<p>GS stands for Gene Significance (for us it means taxon significance) while MM stands for module membership.</p>
<p>GS.Environmentaltrait = Pearson Correlation Coefficient for that OTU with the trait. GS allows incorporation of external info into the co-expression network by showing gene/OTU significance. The higher the absolute value of GS the more biologically significant the gene (or in our case taxa) to that external variable (e.g. CR).<br />
p.GS.Environmentaltrait = P value for the preceding relationship.</p>
<p>MM.color = Pearson Correlation Coefficient for Module Membership&#8211;i.e. how well that OTU correlates with that particular color module (each OTU has a value for each module but only belongs to one module). If close to 0 or negative then the taxa is not part of that color module (since each OTU has to be put in a module you may get some OTUs that are close to 0, but they aren&#8217;t important to that module). If it is close to 1 then it is highly connected to that color module, but will be placed with the color module that it is most connected to throughout the samples.<br />
p.MM.color = P value for the preceding relationship.</p>
<p>Modules will be ordered by their significance for the external variable you selected (e.g. CR), with the most significant ones to the left.<br />
Each of the modules (with each OTU assigned to exactly one module) will be represented for the environmental trait you selected.<br />
You will have to rerun this for each environmental trait you are interested in.</p>
<p>&nbsp;</p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Fweighted-gene-correlation-network-analysis-wgcna-applied-to-microbial-communities%2F&amp;linkname=Weighted%20Gene%20Correlation%20Network%20Analysis%20%28WGCNA%29%20Applied%20to%20Microbial%20Communities" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Fweighted-gene-correlation-network-analysis-wgcna-applied-to-microbial-communities%2F&amp;linkname=Weighted%20Gene%20Correlation%20Network%20Analysis%20%28WGCNA%29%20Applied%20to%20Microbial%20Communities" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Fweighted-gene-correlation-network-analysis-wgcna-applied-to-microbial-communities%2F&amp;linkname=Weighted%20Gene%20Correlation%20Network%20Analysis%20%28WGCNA%29%20Applied%20to%20Microbial%20Communities" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fwww.polarmicrobes.org%2Fweighted-gene-correlation-network-analysis-wgcna-applied-to-microbial-communities%2F&#038;title=Weighted%20Gene%20Correlation%20Network%20Analysis%20%28WGCNA%29%20Applied%20to%20Microbial%20Communities" data-a2a-url="https://www.polarmicrobes.org/weighted-gene-correlation-network-analysis-wgcna-applied-to-microbial-communities/" data-a2a-title="Weighted Gene Correlation Network Analysis (WGCNA) Applied to Microbial Communities"></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://www.polarmicrobes.org/weighted-gene-correlation-network-analysis-wgcna-applied-to-microbial-communities/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2315</post-id>	</item>
		<item>
		<title>Tutorial: How to make a map using QGIS</title>
		<link>https://www.polarmicrobes.org/tutorial-on-qgis-how-to-make-a-map/</link>
					<comments>https://www.polarmicrobes.org/tutorial-on-qgis-how-to-make-a-map/#comments</comments>
		
		<dc:creator><![CDATA[Natalia Erazo]]></dc:creator>
		<pubDate>Mon, 29 Jan 2018 21:31:12 +0000</pubDate>
				<category><![CDATA[Computer tutorials]]></category>
		<guid isPermaLink="false">http://www.polarmicrobes.org/?p=2122</guid>

					<description><![CDATA[Hi! I&#8217;m Natalia Erazo, currently working on the Ecuador project aimed at examining biogeochemical processes in mangrove forest. In this tutorial, we’ll learn the basics of (free) QGIS, how to import vector data, and make a map using data obtained from &#8230; <a href="https://www.polarmicrobes.org/tutorial-on-qgis-how-to-make-a-map/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>Hi! I&#8217;m Natalia Erazo, currently working on the <a href="https://www.polarmicrobes.org/ecuador-update/">Ecuador project</a> aimed at examining biogeochemical processes in mangrove forest. In this tutorial, we’ll learn the basics of (free) QGIS, how to import vector data, and make a map using data obtained from our recent field trip to the Ecological Reserve Cayapas Mataje in Ecuador!  We’ll also learn standard map elements and QGIS function: Print Composer to generate a map.</p>
<p><strong>Objectives: </strong></p>
<p>I. Install QGIS</p>
<p>II. Learn how to upload raster data using the Plugin OpenLayers and QuickMap services.</p>
<p>III. Learn how to import vector data: import latitude, longitude data and additional data. Learn how to select attributes from the data e.g., salinity values and plot them.</p>
<p>IV. Make a map using Print Composer in QGIS.</p>
<p><strong>I. QGIS- Installation </strong></p>
<p>QGIS is a very powerful tool and user friendly open source geographical system that runs on linux, unix, mac, and windows. QGIS can be downloaded <a href="https://www.qgis.org/en/site/forusers/alldownloads.html">here</a> . You should follow the instructions and install gdal complete.pkg, numpy.pkg, matplotlib.pkg, and qgis.pkg.</p>
<p><strong>II.Install QGIS Plug-in and Upload a base map.</strong></p>
<ol>
<li>Install QGIS Plug-in</li>
</ol>
<p>Go to Plugins and select Manage and Install plugins. This will open the plugins dialogue box and type OpenLayers Plugin and click on Install plugin.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/1_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter wp-image-2123" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/1_tutorial.png?resize=640%2C109&#038;ssl=1" alt="" width="640" height="109" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/1_tutorial.png?resize=300%2C51&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/1_tutorial.png?resize=768%2C131&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/1_tutorial.png?resize=1024%2C174&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/1_tutorial.png?w=1147&amp;ssl=1 1147w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a></p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/2_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class=" wp-image-2124 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/2_tutorial.png?resize=555%2C409&#038;ssl=1" alt="" width="555" height="409" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/2_tutorial.png?resize=300%2C221&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/2_tutorial.png?resize=768%2C566&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/2_tutorial.png?w=907&amp;ssl=1 907w" sizes="auto, (max-width: 555px) 100vw, 555px" /></a></p>
<p>This plugin will give you access to Google Maps, openStreet map layers and others, and it is very useful to make quick maps from Google satellite, physical, and street layers. However, the OpenLayers plugin could generate zoom errors in your maps.   There is another plug in: <strong>Quick Map Service</strong> which uses tile servers and not the direct api for getting Google layers and others. This is a very useful plugin which offers more options for base maps and less zoom errors. To install it you should follow the same steps as you did for the OpenLayers plugin except this time you’ll type <strong>QuickMap Service </strong>and install the plugin.</p>
<p>Also, If you want to experiment with QuickMap services you can expand the plugin: Go to Web-&gt;Quick Map Services-&gt;Settings-&gt;More services and click on get contributed pack. This will generate more options for mapping.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/3_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class=" wp-image-2125 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/3_tutorial.png?resize=640%2C350&#038;ssl=1" alt="" width="640" height="350" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/3_tutorial.png?resize=300%2C164&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/3_tutorial.png?resize=768%2C420&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/3_tutorial.png?resize=1024%2C560&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/3_tutorial.png?w=1506&amp;ssl=1 1506w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/3_tutorial.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a></p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/4_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class=" wp-image-2126 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/4_tutorial.png?resize=640%2C499&#038;ssl=1" alt="" width="640" height="499" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/4_tutorial.png?resize=300%2C234&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/4_tutorial.png?w=746&amp;ssl=1 746w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a></p>
<p>2. Add the base layer Map:</p>
<p>I recommend playing with the various options in either OpenLayers like the Google satellite, physical, and other maps layers, or QuickMap Service.</p>
<p>For this map, we will use ESRI library from QuickMap services. Go to&#8211;&gt; Web- -&gt;QuickMapServices&#8211;&gt; Esri&#8211;&gt; ESRI Satellite</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/5_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter wp-image-2127 size-full" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/5_tutorial.png?resize=640%2C304&#038;ssl=1" alt="" width="640" height="304" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/5_tutorial.png?w=1431&amp;ssl=1 1431w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/5_tutorial.png?resize=300%2C143&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/5_tutorial.png?resize=768%2C365&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/5_tutorial.png?resize=1024%2C487&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/5_tutorial.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>You should see your satellite map.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/6_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter wp-image-2128" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/6_tutorial.png?resize=640%2C386&#038;ssl=1" alt="" width="640" height="386" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/6_tutorial.png?resize=300%2C181&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/6_tutorial.png?resize=768%2C463&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/6_tutorial.png?resize=1024%2C618&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/6_tutorial.png?w=1604&amp;ssl=1 1604w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/6_tutorial.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>You can click on the zoom in icon to adjust the zoom, as shown in the map below where I  zoom in the Galapagos Islands. You’ll also notice that on the left side you have a <strong>Layers panel</strong> box, this box shows all the layers you add to your map. Layers can be raster data or vector data, in this case we see the layer: ESRI Satellite. At the far left you’ll see a list of <strong>icons</strong> that are used to import your layers. It is important to know what kind of data you are importing to QGIS to use the correct function.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/7_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class=" wp-image-2129 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/7_tutorial.png?resize=602%2C872&#038;ssl=1" alt="" width="602" height="872" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/7_tutorial.png?resize=207%2C300&amp;ssl=1 207w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/7_tutorial.png?w=686&amp;ssl=1 686w" sizes="auto, (max-width: 602px) 100vw, 602px" /></a><strong>III. Adding our vector data.</strong></p>
<p>We will now add our data file which contains latitude and longitude of all the sites we collected samples, in addition to values for salinity, temperature, and turbidity. You can do this with your own data by creating a file in excel  and have a column with longitude and latitude values and columns with other variables  and save it as a csv file. To input data you’ll go to the icons on the far left and click on &#8220;Add  Delimited Text Layer&#8221;. Or you can click on Layer-&gt; Add Layer-&gt; Add Delimited Text Layer.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/8_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class=" wp-image-2130 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/8_tutorial.png?resize=640%2C469&#038;ssl=1" alt="" width="640" height="469" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/8_tutorial.png?resize=300%2C220&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/8_tutorial.png?resize=768%2C562&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/8_tutorial.png?w=889&amp;ssl=1 889w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>You’ll browse to the file with your data. Make sure that csv is selected for File format. Additionally, make sure that <strong>X field</strong> represents the column for your longitude points and <strong>Y field</strong> for latitude. QGIS is smart enough to recognize longitude and latitude columns but double check! You can also see an overview of the data with columns for latitude, longitude, Barometer mmHg, conductivity, Salinity psu and other variables. You can leave everything else as default and click ok.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/9_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class=" wp-image-2131 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/9_tutorial.png?resize=640%2C435&#038;ssl=1" alt="" width="640" height="435" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/9_tutorial.png?resize=300%2C204&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/9_tutorial.png?resize=768%2C521&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/9_tutorial.png?w=927&amp;ssl=1 927w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>You’ll be prompt to select the coordinate reference system selector, and this is very important because if you do not select the right one you’ll get your points in the wrong location. For GPS coordinates, as the data we are using here, you need to select WGS 84 ESPG 43126.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/10_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class=" wp-image-2132 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/10_tutorial.png?resize=640%2C493&#038;ssl=1" alt="" width="640" height="493" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/10_tutorial.png?resize=300%2C231&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/10_tutorial.png?resize=768%2C591&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/10_tutorial.png?w=990&amp;ssl=1 990w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>Now we can see all the points where we collected data!</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/11_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter wp-image-2133 " src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/11_tutorial.png?resize=640%2C318&#038;ssl=1" alt="" width="640" height="318" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/11_tutorial.png?w=1912&amp;ssl=1 1912w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/11_tutorial.png?resize=300%2C149&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/11_tutorial.png?resize=768%2C381&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/11_tutorial.png?resize=1024%2C508&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/11_tutorial.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>As we saw earlier, the data contains environmental measurements such as: salinity, turbidity, temperature and others. We can style the layer with our sampling points based on the variables of our data. In this example we will  create a layer representing salinity values.</p>
<p>You’ll right click on the layer with our data in the Layer Panel, in this case our layer: 2017_ecuador_ysi_dat.. and select properties.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/12_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class=" wp-image-2134 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/12_tutorial.png?resize=640%2C493&#038;ssl=1" alt="" width="640" height="493" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/12_tutorial.png?resize=300%2C231&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/12_tutorial.png?w=689&amp;ssl=1 689w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>The are many styles you can choose for the layer and the styling options are located in the <strong>Style tab</strong> of the Properties dialogue. Clicking on the drop-down bottom in the Style dialogue, you’ll see there are five options available: Single Symbol, Categorized, Graduated, Rule Based and Point displacement. We’ll use <strong>Graduated</strong> which allows you to break down the data in unique classes. Here we will use the salinity values and will classify them into 3 classes: low, medium, and high salinity. There are 5 modes available in the Graduated style to do this: Equal interval, Quantile, Natural breaks, Standard deviation and Pretty breaks. You can read more about these options in <a href="https://docs.qgis.org/2.8/en/docs/user_manual/working_with_vector/vector_properties.html">qgis</a> <a href="https://docs.qgis.org/2.8/en/docs/user_manual/working_with_vector/vector_properties.html">documentation.</a></p>
<p>In this tutorial, for simplicity  we&#8217;ll use the <strong>Quantile </strong>option. This method will decide the classes such that number of values in each class are the same; for example, if there are 100 values and we want 4 classes, the quantile method decide the classes such that each class will have 25 values.</p>
<p>In the <strong>Style section</strong>: Select-&gt;<strong>Graduated</strong>, in <strong>Column</strong>-&gt;salinity psu, and in color ramp we’ll do colors ranging from yellow to red.</p>
<p>In the classes box write down <strong>3</strong> and  select mode&#8211;&gt;<strong>Quantile</strong>. Click on <strong>classify</strong>, and QGIS will classify your values in different ranges.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/graduated-1.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class=" wp-image-2186 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/graduated-1.png?resize=640%2C333&#038;ssl=1" alt="" width="640" height="333" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/graduated-1.png?resize=300%2C156&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/graduated-1.png?resize=768%2C400&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/graduated-1.png?resize=1024%2C534&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/graduated-1.png?w=1920&amp;ssl=1 1920w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/graduated-1.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>Now we have all the data points color in the 3 different ranges: low, medium, and high salinity.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/17_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="wp-image-2139 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/17_tutorial.png?resize=640%2C350&#038;ssl=1" alt="" width="640" height="350" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/17_tutorial.png?resize=300%2C164&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/17_tutorial.png?resize=768%2C420&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/17_tutorial.png?resize=1024%2C560&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/17_tutorial.png?w=1437&amp;ssl=1 1437w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/17_tutorial.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>However, we have a lot of points and it is hard to visualize the data points. We can edit the points by right clicking on the marker points and select edit symbol.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/18_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="wp-image-2140 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/18_tutorial.png?resize=640%2C352&#038;ssl=1" alt="" width="640" height="352" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/18_tutorial.png?resize=300%2C165&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/18_tutorial.png?resize=768%2C422&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/18_tutorial.png?resize=1024%2C563&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/18_tutorial.png?w=1439&amp;ssl=1 1439w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/18_tutorial.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>Now, I am going to get rid of the black outline to make the points easy to visualize. Select the point by clicking on <strong>Simple Marker</strong> and in <strong>Outline style</strong> select the <strong>No Pen</strong>. Do the same for the remaining two points.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/19_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class=" wp-image-2142 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/19_tutorial.png?resize=640%2C348&#038;ssl=1" alt="" width="640" height="348" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/19_tutorial.png?resize=300%2C163&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/19_tutorial.png?resize=768%2C418&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/19_tutorial.png?resize=1024%2C558&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/19_tutorial.png?w=1434&amp;ssl=1 1434w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/19_tutorial.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>Nice, now we can better see variations in our points based on salinity!</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/20_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class=" wp-image-2143 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/20_tutorial.png?resize=640%2C352&#038;ssl=1" alt="" width="640" height="352" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/20_tutorial.png?resize=300%2C165&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/20_tutorial.png?resize=768%2C421&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/20_tutorial.png?resize=1024%2C562&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/20_tutorial.png?w=1440&amp;ssl=1 1440w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/20_tutorial.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a><strong>IV. Print Composer: making a final map </strong></p>
<p>We can start to assemble the final version of our  map. QGIS has the option to create a Print composer where you can edit your map. Go to Project -&gt; New Print composer</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/21_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class=" wp-image-2144 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/21_tutorial.png?resize=640%2C343&#038;ssl=1" alt="" width="640" height="343" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/21_tutorial.png?resize=300%2C161&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/21_tutorial.png?resize=768%2C413&amp;ssl=1 768w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>You will be prompted to enter a title for the composer, enter the title name and hit ok. You will be taken to the Composer window.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/22_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class=" wp-image-2145 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/22_tutorial.png?resize=640%2C329&#038;ssl=1" alt="" width="640" height="329" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/22_tutorial.png?resize=300%2C154&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/22_tutorial.png?resize=768%2C396&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/22_tutorial.png?resize=1024%2C527&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/22_tutorial.png?w=1435&amp;ssl=1 1435w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/22_tutorial.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>In the Print composer window, we want to bring the map view that we see in the QGIS canvas to the composer. Go to Layout-&gt; Add a Map. Once the Add map button is active, hold the left mouse and drag a rectangle where you want to insert the map. You will see that the rectangle window will be rendered with the map from the main QGIS canvas.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/23_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class=" wp-image-2146 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/23_tutorial.png?resize=640%2C365&#038;ssl=1" alt="" width="640" height="365" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/23_tutorial.png?resize=300%2C171&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/23_tutorial.png?resize=768%2C438&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/23_tutorial.png?resize=1024%2C585&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/23_tutorial.png?w=1440&amp;ssl=1 1440w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/23_tutorial.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>You can see in the far right end the <strong>Items box;</strong> this  shows you the map you just added. If you want to make changes, you’ll select the map and edit it under <strong>item properties</strong>. Sometimes it is useful to edit the scale until you are happy with the map.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/24_tutorial.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class=" wp-image-2147 aligncenter" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/24_tutorial.png?resize=640%2C360&#038;ssl=1" alt="" width="640" height="360" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/24_tutorial.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/24_tutorial.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/24_tutorial.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/24_tutorial.png?w=1439&amp;ssl=1 1439w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/24_tutorial.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>We can also add a second map of the location of Cayapas Mataje in South America as a  geographic reference. Go to the main qgis canvas and zoom out the map until you can see where in South America the reserve is located.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-7.34.57-PM.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter wp-image-2173 size-full" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-7.34.57-PM.png?resize=640%2C349&#038;ssl=1" alt="" width="640" height="349" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-7.34.57-PM.png?w=1439&amp;ssl=1 1439w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-7.34.57-PM.png?resize=300%2C163&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-7.34.57-PM.png?resize=768%2C418&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-7.34.57-PM.png?resize=1024%2C558&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-7.34.57-PM.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>Now go back to Print Composer and add the map of  the entire region. You&#8217;ll do the same as with the first map. Go to Layout&#8211;&gt; Add map. Drag a rectangle where you want to insert the map. You will see that the rectangle window will be rendered with the map from the main QGIS canvas. In Items box, you can see you have Map 0 and Map 1. Select Map 1, and add a frame under Item properties, click on <strong>Frame</strong> to activate it and adjust the thickness to 0.40mm.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-7.57.38-PM.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter wp-image-2174 size-full" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-7.57.38-PM.png?resize=640%2C388&#038;ssl=1" alt="" width="640" height="388" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-7.57.38-PM.png?w=1440&amp;ssl=1 1440w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-7.57.38-PM.png?resize=300%2C182&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-7.57.38-PM.png?resize=768%2C465&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-7.57.38-PM.png?resize=1024%2C620&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-7.57.38-PM.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>We can add a North arrow to the map. The print composer comes with a collection of map related images including many North arrows. Click layout&#8211;&gt; add image.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.44.42-PM.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter wp-image-2175 size-full" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.44.42-PM.png?resize=640%2C355&#038;ssl=1" alt="" width="640" height="355" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.44.42-PM.png?w=1908&amp;ssl=1 1908w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.44.42-PM.png?resize=672%2C372&amp;ssl=1 672w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.44.42-PM.png?resize=1038%2C576&amp;ssl=1 1038w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.44.42-PM.png?resize=300%2C166&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.44.42-PM.png?resize=768%2C425&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.44.42-PM.png?resize=1024%2C567&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.44.42-PM.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>Hold on the left mouse button, draw a rectangle on the top-right corner of the map canvas.</p>
<p>On the right-hand panel, click on the Item Properties tab and expand the <strong>Search directories</strong> and select the north arrow image you like the most. Once you’ve selected your image, you can always edit the arrow under <strong>SVG parameters.</strong></p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.51.40-PM.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter wp-image-2176 size-full" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.51.40-PM.png?resize=640%2C333&#038;ssl=1" alt="" width="640" height="333" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.51.40-PM.png?w=1920&amp;ssl=1 1920w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.51.40-PM.png?resize=300%2C156&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.51.40-PM.png?resize=768%2C400&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.51.40-PM.png?resize=1024%2C533&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-8.51.40-PM.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>Now we’ll add a scale bar. Click on Layout&#8211;&gt; Add a Scale bar. Click on the layout where you want the scale bar to appear. Choose the Style and units that fit your requirement. In the<strong> Segments</strong> panel, you can adjust the number of segments and their size. Make sure Map 0 is selected under main properties.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/scalebar.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter wp-image-2177 size-full" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/scalebar.png?resize=640%2C320&#038;ssl=1" alt="" width="640" height="320" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/scalebar.png?w=1919&amp;ssl=1 1919w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/scalebar.png?resize=300%2C150&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/scalebar.png?resize=768%2C384&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/scalebar.png?resize=1024%2C512&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/scalebar.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>I’ll add a legend to the map. Go to Layout&#8211;&gt; add a Legend. Hold on the left mouse button, and draw a rectangle on the area you want the legend to appear. You can make any changes such as adding a title in the item properties, changing fonts and renaming your legend points by clicking on them and writing the text you want.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/legend.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter wp-image-2178 size-full" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/legend.png?resize=640%2C347&#038;ssl=1" alt="" width="640" height="347" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/legend.png?w=1920&amp;ssl=1 1920w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/legend.png?resize=300%2C163&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/legend.png?resize=768%2C416&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/legend.png?resize=1024%2C555&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/legend.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>It&#8217;s time to label our map. Click on Layout ‣ Add Label. Click on the map and draw a box where the label should be. In the Item Properties tab, expand the Label section and enter the text as shown below. You can also make additional changes to your font, size by editing the label under <strong>Appearance.</strong></p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-9.53.30-PM.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter wp-image-2179 size-full" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-9.53.30-PM.png?resize=640%2C309&#038;ssl=1" alt="" width="640" height="309" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-9.53.30-PM.png?w=1908&amp;ssl=1 1908w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-9.53.30-PM.png?resize=300%2C145&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-9.53.30-PM.png?resize=768%2C371&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-9.53.30-PM.png?resize=1024%2C495&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/Screen-Shot-2018-01-29-at-9.53.30-PM.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>Once you have your final version, you can export it as Image, PDF or SVG. For this tutorial, let’s export it as an image. Click Composer ‣ Export as Image.</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/export-map.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter wp-image-2180 size-full" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/export-map.png?resize=640%2C352&#038;ssl=1" alt="" width="640" height="352" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/export-map.png?w=1897&amp;ssl=1 1897w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/export-map.png?resize=300%2C165&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/export-map.png?resize=768%2C422&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/export-map.png?resize=1024%2C563&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/export-map.png?w=1280&amp;ssl=1 1280w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>Here is our final map!</p>
<p><a href="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/FINAL_IMAGE_MAP.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter wp-image-2181 size-full" src="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/FINAL_IMAGE_MAP.png?resize=640%2C453&#038;ssl=1" alt="" width="640" height="453" srcset="https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/FINAL_IMAGE_MAP.png?w=3507&amp;ssl=1 3507w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/FINAL_IMAGE_MAP.png?resize=300%2C212&amp;ssl=1 300w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/FINAL_IMAGE_MAP.png?resize=768%2C543&amp;ssl=1 768w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/FINAL_IMAGE_MAP.png?resize=1024%2C724&amp;ssl=1 1024w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/FINAL_IMAGE_MAP.png?w=1280&amp;ssl=1 1280w, https://i0.wp.com/www.polarmicrobes.org/wp-content/uploads/2018/01/FINAL_IMAGE_MAP.png?w=1920&amp;ssl=1 1920w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a>Now you can try the tutorial with your own data. Making maps is always a bit challenging but put your imagination to work!</p>
<p>Here is a list of links that could help with QGIS:</p>
<p>-QGIS blog with various tutorials and new info on functions to use: <a href="https://anitagraser.com/">here</a>.</p>
<p>-If you want more information on how QGIS handles symbol and vector data styling: here  is a good <a href="http://www.qgistutorials.com/en/docs/basic_vector_styling.html">tutorial.</a></p>
<p>-If you need data, a good place to start is <a href="http://www.naturalearthdata.com/">Natural Earth</a>: Free vector and raster basemap data used for almost any cartographic endeavor.</p>
<p>If you have specific questions please don&#8217;t hesitate to ask.</p>
<p>&nbsp;</p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-on-qgis-how-to-make-a-map%2F&amp;linkname=Tutorial%3A%20How%20to%20make%20a%20map%20using%20QGIS" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-on-qgis-how-to-make-a-map%2F&amp;linkname=Tutorial%3A%20How%20to%20make%20a%20map%20using%20QGIS" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-on-qgis-how-to-make-a-map%2F&amp;linkname=Tutorial%3A%20How%20to%20make%20a%20map%20using%20QGIS" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fwww.polarmicrobes.org%2Ftutorial-on-qgis-how-to-make-a-map%2F&#038;title=Tutorial%3A%20How%20to%20make%20a%20map%20using%20QGIS" data-a2a-url="https://www.polarmicrobes.org/tutorial-on-qgis-how-to-make-a-map/" data-a2a-title="Tutorial: How to make a map using QGIS"></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://www.polarmicrobes.org/tutorial-on-qgis-how-to-make-a-map/feed/</wfw:commentRss>
			<slash:comments>20</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2122</post-id>	</item>
		<item>
		<title>So you want to use your computer for science&#8230;</title>
		<link>https://www.polarmicrobes.org/so-you-want-to-use-your-computer-for-science/</link>
					<comments>https://www.polarmicrobes.org/so-you-want-to-use-your-computer-for-science/#respond</comments>
		
		<dc:creator><![CDATA[Jeff]]></dc:creator>
		<pubDate>Sun, 05 Nov 2017 22:04:21 +0000</pubDate>
				<category><![CDATA[Computer tutorials]]></category>
		<guid isPermaLink="false">http://www.polarmicrobes.org/?p=2027</guid>

					<description><![CDATA[It&#8217;s been a while since I was a new graduate student, and I&#8217;ve forgotten how little I knew about computers back then.  I was reminded recently while teaching a couple of lab members how to use ffmpeg, an excellent command &#8230; <a href="https://www.polarmicrobes.org/so-you-want-to-use-your-computer-for-science/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>It&#8217;s been a while since I was a new graduate student, and I&#8217;ve forgotten how little I knew about computers back then.  I was reminded recently while teaching a couple of lab members how to use ffmpeg, an excellent command line tool for building animations from images (as described in <a href="https://www.polarmicrobes.org/video-output-from-r-script/">this post</a>).  We got there, but I realized that we needed a basic computing tutorial before moving on to anything more advanced.  If you&#8217;re trying to use your laptop for science, but you&#8217;re not too sure about this whole &#8220;command line thing&#8221;, this post&#8217;s for you.  Be warned that this tutorial is intended as only the most cursory crash course to get you moving up the initial learning curve.  A comprehensive list of commands for Bash on OSX can be found <a href="https://ss64.com/osx/">here</a>.  At the end of this tutorial you will have a basic grasp of how to:</p>
<ul>
<li>Navigate the file system</li>
<li>Create and edit text files</li>
<li>Search text files</li>
<li>Create a shell script</li>
<li>Modify the PATH variable using startup files (.bash_profile)</li>
</ul>
<p><em><strong>Okay, so I want to get a computer to do some science.  What should I get?</strong></em></p>
<p>Whatever you want.  It really doesn&#8217;t matter.  Most grad students seem to get Macs these days, which I don&#8217;t love (they&#8217;re costly and epitomize form over function), but have the slight advantage of a Unix-like environment hiding behind all that OSX gibberish.  I use a Windows machine (which I also don&#8217;t love, as it epitomizes dysfunction over function) with <a href="https://www.cygwin.com/">Cygwin</a>, which gives me access to all the Linux tools that I need to carry out day-to-day operations.  Windows 10 users can also make use of the <a href="https://www.windowscentral.com/how-install-bash-shell-command-line-windows-10">Bash shell add-on for Windows</a>, but I haven&#8217;t found any advantage to this over Cygwin.  The point is that you need either a) A Mac, b) A Windows machine running Cygwin or the add-on, or c) A Linux machine.  The command prompt and output given below are what you will see in OSX (faked since I&#8217;m not actually using a Mac), but are similar to what you will get with Cygwin or one of the Linux distros.  The commands should work the same across all of these options.</p>
<p><em><strong>Getting familiar with &#8220;Bash&#8221;</strong></em></p>
<p>Bash stands for <a href="https://en.wikipedia.org/wiki/Bash_(Unix_shell)">Bourne-again shell</a>, which you can read all about in many other places on the web.  Bash is a very powerful tool for manipulating your computer&#8217;s file system, executing programs, and even creating programs.  It is a cornerstone of scientific computing and you should have at least some passing familiarity with it.  To open the Bash terminal in OSX, go to Applications/Utilities/Terminal in Finder.  A mysterious black (or white) window will open, with a white (black) cursor waiting for YOU.  Type &#8220;pwd&#8221; for print working directory and hit &#8220;Enter&#8221;.</p>
<pre>jeffscomputer:~ jeff$ pwd
/Users/jeff</pre>
<p>Bash will respond with your location, which should be something along the lines of /user/home.  Next type &#8220;ls&#8221; to list the contents of the directory.</p>
<pre>jeffscomputer:~ jeff$ ls
bin
Desktop
Documents
Downloads</pre>
<p>We can use the command &#8220;cd&#8221; to change directories.  For example, if you want to move to your Desktop directory type &#8220;cd Desktop&#8221;.</p>
<pre>jeffscomputer:~ jeff$ cd Desktop
jeffscomputer:Desktop jeff$ pwd
/Users/jeff/Desktop</pre>
<p>Because the directory &#8220;Desktop&#8221; was just one level down, in this case the relative path &#8220;Desktop&#8221; is equivalent to typing the full path &#8220;/Users/jeff/Desktop&#8221;.  Here&#8217;s a useful tip.  From any location on your system &#8220;cd ~&#8221; will get you back to your home directory.</p>
<pre>jeffscomputer:Desktop jeff$ cd ~
jeffscomputer:~ jeff$ pwd
/Users/jeff</pre>
<p>Now let&#8217;s create a directory to do some work.  The command for this is &#8220;mkdir temp&#8221;, for &#8220;make directory with name temp.&#8221;</p>
<pre>jeffscomputer:~ jeff$ mkdir temp
jeffscomputer:~ jeff$ cd temp</pre>
<p>Now move into that directory.  You already know how <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p><em><strong>Creating and editing text files</strong></em></p>
<p>You will frequently need to create and edit basic text files without all the fancy formatting of a word processing document.  The most user friendly way to do this is with the program nano, which is likely already present if you are using OSX or Cygwin.  Type &#8220;nano temp.txt&#8221; and nano will open a blank text file with name temp.txt.</p>
<pre>jeffscomputer:temp jeff$ nano temp.txt</pre>
<p>Type a couple lines of text and, when you&#8217;re ready to exit and save the file, hit ctrl-x.  Nano will prompt you about saving the output, hit yes.  List the contents of the directory and notice that the file temp.txt now exists.  Type &#8220;nano temp.txt&#8221; again and rather than create a new file, nano will open temp.txt for editing.</p>
<p>Having gone through the trouble of creating that file, let&#8217;s go ahead and delete it using the remove or &#8220;rm&#8221; command.</p>
<pre>jeffscomputer:temp jeff$ rm temp.txt</pre>
<p>To do some fancier things with files lets download one that has a little more information in it.  There are two programs to use to fetch files online, wget and curl.  I find wget much easier to use than curl.  If you&#8217;re using Cygwin or Linux you likely already have it, but for OSX you first need to install a package manager, which is a whole can of worms that I&#8217;m not going to tackle in this post.  So let&#8217;s use curl to download a text file, in this case &#8220;The Rime of the Ancient Mariner&#8221; by Samuel Coleridge.  The basic download command for curl is:</p>
<pre>jeffscomputer:temp jeff$ curl -O https://www.polarmicrobes.org/extras/ancient_mariner.txt</pre>
<p>This should create the file &#8220;ancient_mariner.txt&#8221; in your working directory (e.g., &#8220;/Users/jeff/temp&#8221;).</p>
<p><em><strong>Viewing file content</strong></em></p>
<p>The reason we downloaded this more complex text file (it&#8217;s a pretty long poem) is to simulate a longer data file than our &#8220;temp.txt&#8221; file.  Very often in scientific computing you have text files with hundreds, thousands, or even millions of lines.  Just opening such a file can be onerous, let alone finding some specific piece of information.  Fortunately there are tools that can help.  Type &#8220;head ancient_mariner.txt&#8221;, this returns the top 10 lines of the file.</p>
<pre>jeffscomputer:temp jeff$ head ancient_mariner.txt
PART THE FIRST
It is an ancient mariner,
And he stoppeth one of three.
"By thy long grey beard and glittering eye,
Now wherefore stopp'st thou me?
"The Bridegroom's doors are opened wide,
And I am next of kin;
The guests are met, the feast is set:
May'st hear the merry din."
He holds him with his skinny hand,</pre>
<p>Want to guess what &#8220;tail&#8221; does?  For either command you can use a &#8220;flag&#8221; to modify behavior, such as returning more lines.  Flags are always preceded by &#8220;-&#8221; or &#8220;&#8211;&#8220;, and generally come before the <em>positional arguments</em> of the command, in this case the file.  This is general syntax for Unix commands, and does not apply only to &#8220;head&#8221; and &#8220;tail&#8221;.</p>
<pre>jeffscomputer:temp jeff$ tail -15 ancient_mariner.txt
Both man and bird and beast.
He prayeth best, who loveth best
All things both great and small;
For the dear God who loveth us,
He made and loveth all.
The Mariner, whose eye is bright,
Whose beard with age is hoar,
Is gone: and now the Wedding-Guest
Turned from the bridegroom's door.
He went like one that hath been stunned,
And is of sense forlorn:
A sadder and a wiser man,
He rose the morrow morn.</pre>
<p>In the examples so far the the command output has printed to the screen, but what if we want to capture it in a file?  For example, what if we have a huge data file (millions of rows) and we want just the top few lines to test some code or share with a collaborator?  This is easily done by redirecting the output using &#8220;&gt;&#8221;.</p>
<pre>jeffscomputer:temp jeff$ tail -15 ancient_mariner.txt &gt; end_of_ancient_mariner.txt</pre>
<p><em><strong>Searching file content</strong></em></p>
<p>To find specific information in a file use the command &#8220;grep&#8221;.  Without launching into a full-on explanation of <a href="http://www.rexegg.com/regex-quickstart.html">regular expressions</a>, grep (very quickly) finds lines that match some given pattern.  You can either count or view the lines that match.  To find the lines with the word &#8220;albatross&#8221; in ancient_mariner.txt:</p>
<pre>jeffscomputer:temp jeff$ grep 'Albatross' ancient_mariner.txt
At length did cross and Albatross,
I shot the Albatross."
Instead of the cross, the Albatross
The Albatross fell off, and sank
The harmless Albatross."
The Albatross's blood.</pre>
<p>Seems there&#8217;s a typo in this version of the poem (and|an)!  At any rate, use the -c flag to count the lines.  Protip: use the &#8220;up&#8221; key to bring back the previous line, which you can then modify.</p>
<pre>jeffscomputer:temp jeff$ grep -c 'Albatross' ancient_mariner.txt
6</pre>
<p>Use the -v flag to select against lines with &#8220;Albatross&#8221;, which you can combine with the -c or other flags:</p>
<pre>jeffscomputer:temp jeff$ grep -cv 'Albatross' ancient_mariner.txt
634</pre>
<p><em><strong>Build a basic program</strong></em></p>
<p>So far we&#8217;ve been executing commands manually, from the command line.  Suppose we have a set of commands that we want to execute a lot, or that need a method to document our workflow.  To do this we create a shell script.  Fire up nano for a file named &#8220;temp.sh&#8221; and type:</p>
<pre>#!/bin/bash

echo "hello world!"
# hey, this line doesn't do anything!
f=ancient_mariner.txt
echo $f
grep -cv 'Albatross' $f</pre>
<p>Line by line here&#8217;s what&#8217;s going on:</p>
<ul>
<li>The first line is called the shebang and it tells your system what interpreter to use to run the script (in this case Bash).  /bin/bash is an actual location on your computer where the Bash program resides</li>
<li>The next line is just a bit of formality; by strictly adhered-to convention your first program should always be a little script that says &#8220;hello world!&#8221;.  It does however, illustrate the &#8220;echo&#8221; command, which prints out information.</li>
<li>The next line starts with &#8220;#&#8221; which denotes a comment.  Line that start with &#8220;#&#8221; are not read by Bash.  You can use that character to make notes, or to toggle commands on and off.</li>
<li>In the next line we assign a variable (f) a value (ancient_mariner.txt).  We can now call that variable using &#8220;$&#8221;.  The next two lines are examples of this.</li>
</ul>
<p>To execute the script we simply type the file name into bash.  Before we do that however, we need to set the file permissions, as files are not by fault executable.  To do that we use the &#8220;chmod&#8221; command with the &#8220;a+x&#8221; options (note that this is not a flag).</p>
<pre>jeffscomputer:temp jeff$ chmod a+x temp.sh</pre>
<p>You can run it now, but there is one final trick.  Bash doesn&#8217;t know to look in your working directory for the script, you have to specify that that&#8217;s where it is.  The location of the current working directory is always &#8220;./&#8221;, so the command looks like this:</p>
<pre>jeffscomputer:temp jeff$ ./temp.sh
hello world!
ancient_mariner.txt
634</pre>
<p><em><strong>Setting up your environment</strong></em></p>
<p>Okay, we&#8217;re going to ramp things up a bit for the grand finale and modify the Bash startup files to better use your new-found skills.  There are several possible startup files, and the whole startup file situation gets a <a href="http://hayne.net/MacDev/Notes/unixFAQ.html#loginShell">bit confusing</a>.   We will modify the .bash_profile file, which will handle the majority of user cases, but you should take the time to familiarize yourself with the different files.  The .bash_profile file is a hidden file (denoted by the .), you can see hidden files by using &#8220;ls&#8221; with the &#8220;-a&#8221; flag.</p>
<pre>jeffscomputer:temp jeff$ cd ~
jeffscomputer:~ jeff$ ls -a
bin
Desktop
Documents
Downloads
.bash_history
.bashrc
.profile
.ssh</pre>
<p>Don&#8217;t worry if you don&#8217;t see .bash_profile, we will create it shortly.  First, to understand why we need to modify the startup file in the first place, from your home directory try executing the shell script that we just created.</p>
<pre>jeffscomputer:~ jeff$ temp.sh
-bash: temp.sh: command not found</pre>
<p>The command would execute if you typed temp/temp.sh, but remembering the location of every script and program so that you can specify the complete path to it would be silly.  Instead, Bash stores this information in a variable named PATH.  To see what&#8217;s in PATH use &#8220;echo&#8221;:</p>
<pre>jeffscomputer:~ jeff$ echo $PATH
/usr/local/bin:/usr/bin:/usr/sbin</pre>
<p>If you created a script in /usr/local/bin, Bash would know to look there and would find the script.  It&#8217;s a good idea however, to keep user-generated scripts in the home directory to avoid cluttering up locations used by the operating system.  What we need to do is automatically update PATH with customized locations whenever we start a new Bash session.  We accomplish this by modifying PATH on startup using the startup file.  To do this use nano, but you will need to use nano as a super user or &#8220;sudo&#8221;.</p>
<pre>jeffscomputer:~ jeff$ sudo nano .bash_profile</pre>
<p>As you already know, if you don&#8217;t have .bash_profile this will create it for you.  Now, at the end of the .bash_profile file (or on the first line, if its empty), type (replacing &#8220;jeff&#8221; with your home directory):</p>
<pre>export PATH=/Users/jeff/temp:$PATH</pre>
<p>The command structure might look opaque at first but its really not.  This line is saying &#8220;export the variable PATH as this text, followed by the original PATH variable&#8221;.</p>
<p>Close nano.  Recall that .bash_profile is read by Bash at the start of the Bash session.  Your newly defined PATH variable will be read if you start a new session, but you can also force Bash to read it with the &#8220;source&#8221; command.</p>
<pre>jeffscomputer:~ jeff$ source .bash_profile</pre>
<p>Now try to execute your bash script.</p>
<pre>jeffscomputer:~ jeff$ temp.sh
hello world!
ancient_mariner.txt
634</pre>
<p>Last, let&#8217;s clean things up a little.  Previously we used &#8220;rm&#8221; to remove a file.  The same command with the -r flag will remove a directory.</p>
<pre>jeffscomputer:~ jeff$ rm -r temp</pre>
<p>Voila!  To keep your .bash_profile file looking pretty, don&#8217;t forget to remove the line adding temp to PATH (though it does no harm).  Or you can comment that line out and leave it as an example of the correct syntax for when you next add a new location to PATH.</p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Fso-you-want-to-use-your-computer-for-science%2F&amp;linkname=So%20you%20want%20to%20use%20your%20computer%20for%20science%E2%80%A6" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Fso-you-want-to-use-your-computer-for-science%2F&amp;linkname=So%20you%20want%20to%20use%20your%20computer%20for%20science%E2%80%A6" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Fwww.polarmicrobes.org%2Fso-you-want-to-use-your-computer-for-science%2F&amp;linkname=So%20you%20want%20to%20use%20your%20computer%20for%20science%E2%80%A6" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fwww.polarmicrobes.org%2Fso-you-want-to-use-your-computer-for-science%2F&#038;title=So%20you%20want%20to%20use%20your%20computer%20for%20science%E2%80%A6" data-a2a-url="https://www.polarmicrobes.org/so-you-want-to-use-your-computer-for-science/" data-a2a-title="So you want to use your computer for science…"></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://www.polarmicrobes.org/so-you-want-to-use-your-computer-for-science/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2027</post-id>	</item>
	</channel>
</rss>
