It works!

This commit is contained in:
Aleks Rūtiņš 2024-12-25 15:17:50 -05:00
parent d9281ad53c
commit f42ff5da9b
14 changed files with 438 additions and 18 deletions

2
.idea/biocircuits.iml generated
View file

@ -12,9 +12,7 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="PROVIDED" name="bundler (v2.5.22, ruby-3.3.6-p108) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="markly (v0.12.1, ruby-3.3.6-p108) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="phlex (v1.11.0, ruby-3.3.6-p108) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="phlex-markdown (v0.3.0, ruby-3.3.6-p108) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="phlexite (v0.1.3, ruby-3.3.6-p108) [gem]" level="application" />
</component>
</module>

View file

@ -5,4 +5,4 @@ source "https://rubygems.org"
# gem "rails"
gem "phlex", "~> 1.11"
gem "phlexite", "~> 0.1.3"
gem "phlex-markdown", "~> 0.3.0"
gem "kramdown", "~> 2.5"

View file

@ -1,19 +1,21 @@
GEM
remote: https://rubygems.org/
specs:
markly (0.12.1)
kramdown (2.5.1)
rexml (>= 3.3.9)
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
phlex (1.11.0)
phlex-markdown (0.3.0)
markly (~> 0.7)
phlex (>= 0.5)
phlexite (0.1.3)
rexml (3.4.0)
PLATFORMS
x64-mingw-ucrt
DEPENDENCIES
kramdown (~> 2.5)
kramdown-parser-gfm (~> 1.1)
phlex (~> 1.11)
phlex-markdown (~> 0.3.0)
phlexite (~> 0.1.3)
BUNDLED WITH

View file

@ -2,15 +2,33 @@
require 'phlex'
require 'phlexite'
require 'kramdown'
require_relative 'views/base_layout'
require_relative 'views/nav_links'
require_relative 'views/section_link'
require_relative 'views/page_layout'
require_relative 'views/pages/index'
require_relative 'views/pages/markdown_page'
def pages = [
['concepts', 'Concepts of Biocircuits'],
['simplest-circuit', "The Simplest Circuit"],
['repressors', 'Repressors & Leaks'],
['activators', 'Activators'],
['hill-functions', 'Ultrasensitivity & the Hill Function'],
['activators-vs-repressors', 'Choosing Between Activators & Repressors'],
]
Phlexite::Site.new do |s|
s.mount 'assets', on: '/assets'
s.page 'index.html', BC::Views::Pages::Index.new
pages.each_index { |idx|
page = pages[idx]
prev = idx <= 0 ? nil : "/#{pages[idx - 1][0]}.html"
fwd = idx >= pages.length - 1 ? nil : "/#{pages[idx + 1][0]}.html"
s.page "#{page[0]}.html", BC::Views::Pages::MarkdownPage.new(File.read("./views/pages/#{page[0]}.md"), page[1], prev, fwd)
}
end

View file

@ -33,7 +33,7 @@ module BC
yield
footer do
p do
span { "&copy; 2024" }
plain "© 2024 "
a(href: "https://farthergate.com") { "Aleks Rūtiņš" }
end

View file

@ -2,7 +2,7 @@
module BC
module Views
class NavLinks
class NavLinks < ::Phlex::HTML
def initialize(back, fwd)
@back = back
@fwd = fwd
@ -10,9 +10,9 @@ module BC
def view_template
nav class: 'nav-links' do
@back ? a(href: @back) { "BACK" } : div
@back ? a(href: @back) { "BACK" } : div(style: "visibility: hidden") { "BACK" }
a(href: "/") { "HOME" }
@fwd ? a(href: @fwd) { "NEXT" } : div
@fwd ? a(href: @fwd) { "NEXT" } : div(style: "visibility: hidden") { "NEXT" }
end
end
end

View file

@ -0,0 +1,31 @@
<extends template="layouts/page.html" back="/hill-functions.html" title="Choosing Between Activators & Repressors"></extends>
# Choosing Between Activators & Repressors
We now have two ways of regulating gene expression, and they seem to be able to do the same things. Which should we use?
![An diagram of a gene with an activator and a gene with a repressor, side-by-side.](/assets/choosing-dg1.png)
<i class="cite">Credit: CalTech</i>
Michael Savageau researched this in the context of bacterial metabolic genes and digestive enzyme production in 1977.[^1] He found that genes in high demand were usually regulated by activators, while those in low demand were generally regulated by repressors.
![Low demand vs. high demand](/assets/choosing-dg2.png)
<i class="cite">Credit: CalTech</i>
He hypothesized the "use it or lose it" rule: essentially, the somewhat counterintuitive behavior was due to selection pressure that would eliminate the regulators if they were not used enough.
There have been other explanations, too:
- Shinar, et al. found the same result in 2006, but suggested a slightly more intuitive explanation.[^2] They suggested that proteins do not only bind to one receptor, but can bind to a range of similar receptors, even if a protein could cause problems in some of them. Since unoccupied receptors are more susceptible to binding errors, it's preferable to keep them occupied with the right protein than to take the risk of the wrong protein accidentally binding.
- Gerland and Hwa found the same results as Savageau in 2009, but restricted the scope of his reasoning.[^3] They suggested that, for small populations with long timescales (slow evolution), Savageau's reasoning was correct. In large populations with short timescales (fast evolution), though, they suggested that the opposite, more intuitive, option could occur: regulators could be used for the higher-demand proteins and activators for the lower-demand proteins, in the interest of reducing "wear and tear".
At this point, we're pretty sure that, in the majority of cases, regulators are used for lower-demand proteins, and activators are used for higher-demand proteins, as Savageau suggested. As shown by the varying ideas above, though, we still don't know why.
You've reached the end, for now. I hope to expand this site in the future. If you have any questions, comments, or suggestions, please feel free to [tell me about them](https://github.com/aleksrutins/biocircuits/issues/new).
[^1]: Savageau, M. A. (1977). Design of molecular control mechanisms and the demand for gene expression. Proceedings of the National Academy of Sciences, 74(12), 56475651. <https://doi.org/10.1073/pnas.74.12.5647>
[^2]: Shinar, G., Dekel, E., Tlusty, T., & Alon, U. (2006). Rules for biological regulation based on error minimization. Proceedings of the National Academy of Sciences, 103(11), 39994004. <https://doi.org/10.1073/pnas.0506610103>
[^3]: Gerland, U., & Hwa, T. (2009). Evolutionary selection between alternative modes of gene regulation. Proceedings of the National Academy of Sciences, 106(22), 88418846. <https://doi.org/10.1073/pnas.0808500106>

44
views/pages/activators.md Normal file
View file

@ -0,0 +1,44 @@
<extends template="layouts/page.html" back="/repressors.html" next="/hill-functions.html" title="Activators"></extends>
# Activators
Just like repressors can inhibit a gene, **activators** can enable it. Just like repressors, activators' behavior can also be changed by small molecule inputs. Another example from our bacterial friends is the LuxR activator, which only acts as an activator in the presence of the compound ligand.
Here's a diagram, with the activator labeled A:
![A diagram of a gene with and without an activator.](/assets/activator-dg.png)
<i class="cite">Credit: CalTech</i>
For activators, we have a different curve (seen below in red, contrasted to the repressor curve in blue):
$$\beta(a)=\beta_0\frac{p_\text{bound}}{p_\text{tot}}=\beta_0\frac{a/K_d}{1 + a/K_d}$$
<div class="graph">
<div id="binding-curve"></div>
<div>
<label for="kd">K<sub>d</sub</label>
<input type="range" id="kd" value=1>
</div>
<div>
<label for="beta0">β<sub>0</sub></label>
<input type="range" id="beta0" value=1>
</div>
</div>
As you can see, an activator has exactly the opposite effect as a repressor.
That was a short section. Onward!
<script>
plot('#binding-curve', (kd, beta0) => [`${beta0}/(1 + x/(${kd}))`, `${beta0} * ((x/${kd})/(1 + (x/${kd})))`], ['#kd', '#beta0'], [[0, 10], [0, 10]])
defineVars([
['P', 'The promoter of the DNA.'],
['A', 'The activator.'],
['p', 'A concentration of promoters, either unbound, bound (pbound), or total (ptot).'],
['x', 'The gene in question.'],
['K', 'Kd is the dissociation constant, a measure of the likelihood that the activator will unbind.'],
['β', 'β(x) is the simple binding curve. β0 is the maximum expression level.'],
['a', 'The concentration of activator.']
])
</script>

24
views/pages/concepts.md Normal file
View file

@ -0,0 +1,24 @@
# Concepts of Biocircuits
Before we start designing circuits, we need to talk about **natural** (evolved) circuits and **synthetic** circuits.
- We often don't understand natural circuits, and even synthetic biocircuits often use components (such as certain proteins) that we don't fully understand.
- Synthetic and natural circuits often use different design principles. In electronic circuits, for instance, interference is generally avoided, and a circuit is often designed to follow a relatively simple and traceable path; in natural circuits, by contrast, "crosstalk" and complex networks between components are common, and are used to do things that electronic circuits can't.
- There's a lot of noise and variation in biological processes. As mentioned above, some natural circuits take great advantage of this.
- Electrical systems use positive and negative voltages and currents, which allow for positive and negative effects. Biocircuits are built out of molecules whose concentrations cannot be negative, so they have to use other ways of inverting effects.
- From a practical standpoint, even with technologies like CRISPR, we have a very limited ability to construct, test, and compare designs of biological circuits. This is improving rapidly, though!
Because of these differences and challenges, biological circuit design is done using **phenomenological modeling**: modeling relationships at a high level, independent of underlying molecular details.
At a high level, biological circuit design can be approached the same way as electronic circuit design, but with a different set of components: instead of wires, resistors, transistors, and the like, biocircuits use DNA, RNA, and proteins.
Again, though, even though we know a lot about biocircuit design, there are still a lot of fundamental things that we don't know, such as:
- What does each circuit do for the cell? (functions, design principles)
- What parts of the circuit do what? (mechanism)
- How can we control cells in predictable ways using these circuits? (biomedical applications)
- How can we design circuits for predictable behaviors in living cells? (synthetic biology & bioengineering)
In theory, natural and synthetic circuits _should_ share a common set of design principles. These principles are generally expressed as a statement: _Circuit feature X enables function Y_. We know a few already, but new ones are still being discovered.
That's the introduction. Onward - let's design a circuit!

View file

@ -0,0 +1,70 @@
<extends template="layouts/page.html" back="/activators.html" next="/activators-vs-repressors.html" title="Ultrasensitivity & the Hill Function"></extends>
# Ultrasensitivity & the Hill Function
The models we've been using are all well and good to capture the general idea of the effects of activators and repressors, but in the real world, many responses respond in a more switch-like, or **ultrasensitive**, way. This can come from many different things; for instance, binding a protein at one site might increase the affinity for that protein at an adjacent site, or you could have a protein with an alternative shape that could be stabilized by binding agonist effector molecules (basically, molecules that change its shape) into a shape that has a higher affinity for those same molecules. What you generally see in an ultrasensitive response is that an increasing concentration has a little effect for a while, and then suddenly a large effect.
The **Hill function** is a phenomenological way of analyzing ultrasensitive systems. There are two versions of it, the activating Hill function (for analyzing activators, shown in blue):
$$f_\text{act}(x)=\frac{x^n}{k^n + x^n}=\frac{(x/k)^n}{1 + (x/k)^n}$$
And the repressive Hill function (for analyzing repressors, shown in red):
$$f_\text{rep}(x)=\frac{k^n}{k^n + x^n}=\frac{1}{1 + (x/k)^n}$$
This function has two parameters:
- $k$ is the concentration at which the function attains half of its maximum value. This is called the **Hill activation constant**.
- $n$ is the **Hill coefficient**. This is a way of parameterizing how ultrasensitive the response is. When $n=1$, the Hill function is identical to the simple binding curves. As $n$ increases, the function becomes sharper and more ultrasensitive. At the limit when $n=\infty$, the Hill function is a perfect step function.
<div class="graph">
<div id="hill-graph"></div>
<div>
<label for="k">k</label>
<input type="range" id="k" value=1>
</div>
<div>
<label for="n">n</label>
<input type="range" id="n" value=1>
</div>
</div>
To find production rates with the Hill function, just multiply by $\beta_0$:
- Activator (shown in blue): $\beta(a)=\beta_0f_\text{act}(a)=\beta_0\frac{(a/k)^n}{1 + (a/k)^n}$
- Repressor (shown in red): $\beta(r)=\beta_0f_\text{rep}(r)=\beta_0\frac{1}{1 + (r/k)^n}$
<div class="graph">
<div id="hill-graph-prod"></div>
<div>
<label for="k-prod">k</label>
<input type="range" id="k-prod" value=1>
</div>
<div>
<label for="n-prod">n</label>
<input type="range" id="n-prod" value=1>
</div>
<div>
<label for="b0">β<sub>0</sub></label>
<input type="range" id="b0" value=1>
</div>
</div>
Onwards!
<script>
plot('#hill-graph', (k, n) => [`((x/${k})^(${n}))/(1 + ((x/${k})^(${n})))`, `1/(1 + ((x/${k})^(${n})))`], ['#k', '#n'], [[0, 10], [0, 1]])
plot('#hill-graph-prod', (k, n, b0) => [`(${b0}) * ((x/${k})^(${n}))/(1 + ((x/${k})^(${n})))`, `(${b0})/(1 + ((x/${k})^(${n})))`], ['#k-prod', '#n-prod', '#b0'], [[0, 10], [0, 10]])
defineVars([
['f', 'The Hill function.'],
['P', 'The promoter of the DNA.'],
['A', 'The activator.'],
['p', 'A concentration of promoters, either unbound, bound (pbound), or total (ptot).'],
['k', 'The concentration at which the function attains half of its maximum value.'],
['n', 'The Hill coefficient, a measurement of how ultrasensitive the response is.'],
['β', 'β(x) is the simple binding curve. β0 is the maximum expression level.'],
['r', 'The concentration of repressor.'],
['a', 'The concentration of activator.']
])
</script>

View file

@ -5,12 +5,12 @@ module BC
module Pages
class Index < ::Phlex::HTML
def sections = {
"1. Concepts of Biocircuits" => "/concepts",
"2. The Simplest Circuit" => "/simplest-circuit",
"3. Repressors & Leaks" => "/repressors",
"4. Activators" => "/activators",
"5. Ultrasensitivity & the Hill Function" => "/hill-functions",
"6. Choosing Between Activators & Repressors" => "/activators-vs-repressors"
"1. Concepts of Biocircuits" => "/concepts.html",
"2. The Simplest Circuit" => "/simplest-circuit.html",
"3. Repressors & Leaks" => "/repressors.html",
"4. Activators" => "/activators.html",
"5. Ultrasensitivity & the Hill Function" => "/hill-functions.html",
"6. Choosing Between Activators & Repressors" => "/activators-vs-repressors.html"
}
def view_template

View file

@ -0,0 +1,20 @@
module BC
module Views
module Pages
class MarkdownPage < ::Phlex::HTML
def initialize(content, title, prev, fwd)
@content = content
@title = title
@prev = prev
@fwd = fwd
end
def view_template
render PageLayout.new(@title, @prev, @fwd) do
unsafe_raw Kramdown::Document.new(@content).to_html
end
end
end
end
end
end

98
views/pages/repressors.md Normal file
View file

@ -0,0 +1,98 @@
<extends template="layouts/page.html" back="/simplest-circuit.html" next="/activators.html" title="Repressors & Leaks"></extends>
# Repressors & Leaks
Theoretically, a single gene could keep producing a single protein indefinitely, if it had the energy. From a circuit design perspective, though, that's not very interesting. In order to do something more interesting, we need some way to regulate production.
**Repressors** enable gene regulation. They bind to specific binding sites at or near the promoter of a gene (remember, that's where transcription starts) and inhibit transcription initiation. An example of this in bacteria is the Lacl repressor in _E. coli_. Normally, it inhibits the gene for lactase production. When lactose is present, though, a modified form of lactose (allolactose) binds to Lacl, and prevents it from inhibiting lactase production. Lactase is then produced, and the lactose is digested. Lacl is then free to bind to the gene again, inhibiting lactase production until the next time lactose appears.
Here's a diagram, with the repressor labeled R:
![A diagram of a gene with and without a repressor.](/assets/repressor-dg.png)
<i class="cite">Credit: CalTech</i>
Binding and unbinding a repressor can be modeled through this chemical equation:
$$\ce{P + R <=>[k_+][k_-] P_\mathrm{bound}}$$
We can model the dynamics of this reaction using mass action kinetics: essentially, the rate of a reaction is proportional to the product of the concentrations of its products. Within a single cell, an individual site is either bound or unbound. Averaged over a population of cells, though, we can talk about the mean occupancy of a site. If \\(r\\) is the concentration of repressor, \\(p\\) is the concentration of unbound promoter, and \\(p_\text{bound}\\) is the concentration of bound promoter, we can say that:
$$\frac{dp}{dt}=-k_+pr+k_-p_\text{bound}$$
For this situation, we can assume a separation of timescales, because the rate at which the repressor binds to and unbinds from the DNA is generally very fast compared to the rates at which mRNA and protein concentrations vary. This is generally a reasonable assumption in bacteria, but be aware that in some situations, as in some genes in mammals, it might not work. Here, though, we can handily assume that the binding and unbinding is happening quickly enough that \\(\frac{dp}{dt}\approx0\\). To find the concentrations, then, we can set the above equal to zero and solve for whatever we want.
Specifically, if \\(p_\text{tot}\\) is the total concentration of promoters, both bound and unbound, then we can set \\(p_\text{bound}=p_\text{tot}-p\\) and rearrange the equation to give the fraction of free promoters:
$$\frac{p}{p_\text{tot}}=\frac1{(1+r/K_d)}$$
Where \\(K_d\\) is the **dissociation constant** &mdash; a measurement of the likelyhood that a repressor will unbind from its binding site &mdash; calculated as \\(\frac{k_-}{k_+}\\). Because we have a separation of timescales and can simplify things, the rate of production of gene product should be proportional to the probability of the promoter being unbound:
$$\beta(r)=\beta_0\frac{p}{p_\text{tot}}=\frac{\beta_0}{1 + r/K_d}$$
This is the **simple binding curve**. We'll be using and building on it over the course of the next few sections. It has three parameters:
- \\(K_d\\) is the concentration of repressor at which the production is reduced to half its maximum value.
- \\(\beta_0\\) is the maximum expression level, acting as a coefficient for the rest of the function.
- \\(r\\) is the concentration of repressor.
For small values of \\(r\\), note that the slope is \\(-\frac{\beta_0}{K_d}\\). Here's a graph to play around with (the line represents the initial slope):
<div class="graph">
<div id="binding-curve"></div>
<div>
<label for="kd">K<sub>d</sub</label>
<input type="range" id="kd" value=1>
</div>
<div>
<label for="beta0">β<sub>0</sub></label>
<input type="range" id="beta0" value=1>
</div>
</div>
## Leaky expression
Unfortunately, repressors aren't perfect. Many genes can never be entirely repressed, and have a baseline, or "basal", level or expression. We can represent this by adding another term, $\alpha_0$, to $\beta(r)$:
$$\beta(r)=\frac{\beta_0}{1 + r/K_d}+\alpha_0$$
<div class="graph">
<div id="binding-curve-leaky"></div>
<div>
<label for="leaky-kd">K<sub>d</sub</label>
<input type="range" id="leaky-kd" value=1>
</div>
<div>
<label for="leaky-beta0">β<sub>0</sub></label>
<input type="range" id="leaky-beta0" value=1>
</div>
<div>
<label for="leaky-alpha0">α<sub>0</sub></label>
<input type="range" id="leaky-alpha0" value=1>
</div>
</div>
Why does this happen, you ask? There are a couple of reasons:
1. Molecular interactions inside a cell are always probabilistic, and repressors are constantly binding and unbinding.
2. Even if there are more repressors than genes to repress, there is typically a small, but finite, amount of time between the unbinding and re-binding of a repressor. During this time, transcription initiation can still happen. Remember: repressors only bind to the promoter, so once transcription is initiated, protein synthesis can still happen, even if a repressor binds during the process.
Because leaks are so common, it's important to make sure that important parts of your circuits don't depend on the complete absence of leaky expression.
Onwards!
<script>
plot('#binding-curve', (kd, beta0) => [`${beta0}/(1 + x/(${kd}))`, `-(${beta0})x/(${kd}) + ${beta0}`], ['#kd', '#beta0'], [[0, 10], [0, 10]])
plot('#binding-curve-leaky', (kd, beta0, alpha0) => [`${beta0}/(1 + x/(${kd})) + ${alpha0}`, `-(${beta0})x/(${kd}) + ${beta0} + ${alpha0}`], ['#leaky-kd', '#leaky-beta0', '#leaky-alpha0'], [[0, 10], [0, 10]])
defineVars([
['P', 'The promoter of the DNA.'],
['R', 'The repressor.'],
['p', 'A concentration of promoters, either unbound, bound (pbound), or total (ptot).'],
['x', 'The gene in question.'],
['K', 'Kd is the dissociation constant, a measure of the likelihood that the repressor will unbind.'],
['β', 'β(x) is the simple binding curve. β0 is the maximum expression level.'],
['r', 'The concentration of repressor.'],
['α', 'α0 is the baseline, or "basal", level of expression of the gene.']
])
</script>

View file

@ -0,0 +1,115 @@
<extends template="layouts/page.html" back="/concepts.html" next="/repressors.html" title="The Simplest Circuit"></extends>
# The Simplest Circuit
The key idea for this section is that **steady-state expression levels depend on protein production and removal rates**.
Let's break that down.
First, steady-state conditions mean that all inputs to the system are constant forever. That simplifies things quite a bit.
Expression levels are just the net amount of proteins produced.
So, how many proteins there are, with no variables, depends on how many proteins are being created and how many are being removed. Simple, right?
Now, the circuit. This circuit is the simplest possible circuit: a single gene &mdash; let's call it \\(x\\) &mdash; coding for a single protein \\(p\\) at a rate of \\(\beta\\) molecules per unit time.
![A diagram of the simplest possible circuit, with one gene coding for one protein.](/assets/simplest-circuit-dg1.png)
<i class="cite">Credit: CalTech</i>
However, in real life, proteins aren't just made forever; they're also reduced, through both _active degradation_ (being broken down) and _dilution_ (the cell getting bigger, which reduces the protein's _concentration_). That's represented above by the dashed circle. For simplicity, let's say that it's being reduced at a rate constant \\(\gamma\\) (that letter is a gamma, for anyone who wanted to know). Note that this is not just a rate &mdash; it's a _rate constant_, meaning that the actual rate is proportional to the number of molecules. More molecules, more reduction.
There's a differential equation for this:
$$ \frac{dx}{dt} = \text{production} - (\text{degradation} + \text{dilution}) $$
Or:
$$ \frac{dx}{dt} = \beta - \gamma x $$
Since \\(\gamma\\) counts both degradation and dilution, we can say that:
$$ \gamma = \gamma_\text{degradation} + \gamma_\text{dilution} $$
Since we're getting into the math, a quick tip: if you (like me) forget what a variable does halfway through the page, just hover over it and it'll tell you what it does. Because of the way it's rendered, it might not work in some cases, but feel free to try it. Anyway, back to the show.
To find the net production of the protein under steady state conditions, set the derivative to zero and solve for \\(x\\):
$$0 = \beta - \gamma x$$
$$-\beta = -\gamma x$$
$$\frac{-\beta}{-\gamma} = x$$
$$\frac\beta\gamma = x$$
And we find that **steady-state protein concentration is proportional to the ratio of production and removal rates**. This is another core concept that should be built as intuition.
Since I haven't used the interactive graphing functions I took the bandwidth to import yet, let's graph the general shape of the protein concentration function under the simplest possible conditions (play with the sliders!):
$$f(t)=xt=\frac{\beta t}{\gamma}$$
<div class="graph">
<div id="concentration-graph"></div>
<div>
<label for="beta">β</label>
<input type="range" id="beta">
</div>
<div>
<label for="gamma">γ</label>
<input type="range" id="gamma">
</div>
</div>
It's a line &mdash; for now.
## Considering Transcription
Right now, we have protein synthesis as one process &mdash; no intermediate steps. In reality, it has two: transcription and translation. The mRNA made in transcription can _also_ be degraded and diluted, just like the proteins made in translation. Let's add another variable to represent mRNA &mdash; call it \\(m\\). This can be shown in a diagram:
![The simplest circuit, now considering both transcription and translation, with mRNA (m) being produced and reduced.](/assets/simplest-circuit-dg2.png)
<i class="cite">Credit: CalTech</i>
The reaction can now be described by two coupled differential equations:
$$\frac{dm}{dt} = \beta_m - \gamma_mm$$
$$\frac{dx}{dt} = \beta_pm - \gamma_px$$
Now, to find steady-state mRNA and protein concentrations, we set both derivatives to zero and solve, giving us:
$$m_{ss}=\frac{\beta_m}{\gamma_m}$$
$$x_{ss}=\frac{\beta_pm_{ss}}{\gamma_p}=\frac{\beta_p\beta_m}{\gamma_p\gamma_m}$$
This tells us that steady-state protein concentration, when we consider transcription and translation as separate steps, is proportional to the product of the two synthesis rates and inversely proportional to the product of the two degradation rates. Again, if you think about it, that's pretty intuitive.
Here's a graph to play with:
<div class="graph">
<div id="concentration-graph-2step"></div>
<div>
<label for="betap">β<sub>p</sub></label>
<input type="range" id="betap">
<label for="gammap">γ<sub>p</sub></label>
<input type="range" id="gammap">
</div>
<div>
<label for="betam">β<sub>m</sub></label>
<input type="range" id="betam">
<label for="gammam">γ<sub>m</sub></label>
<input type="range" id="gammam">
</div>
</div>
It's still a line. Onwards!
<script>
plot('#concentration-graph', (beta, gamma) => [`(${beta}x)/${gamma}`], ['#beta', '#gamma'])
plot('#concentration-graph-2step', (betap, gammap, betam, gammam) => [`((${betap})(${betam})x)/((${gammap})(${gammam}))`], ['#betap', '#gammap', '#betam', '#gammam'])
defineVars([
['γ', 'The rate constant for reduction of concentration.'],
['β', 'The rate of production, in molecules per unit time.'],
['x', 'The gene in question.'],
['m', 'The mRNA in question.'],
['p', 'The protein in question.'],
['ss', 'steady-state']
])
</script>