Python Visual Exercises

Purpose

This appendix collects visual exercises used in NREC4410. Each exercise combines a short trade question, a small numerical setup, and a Python graph.

The purpose is not to teach advanced programming. The purpose is to help students see how trade models behave when prices, quantities, tariffs, and policy assumptions change.

TipHow to use this appendix

Read the economic question first. Then run the code and interpret the figure. In exams and projects, the important part is the economic interpretation, not memorizing the code.

Exercise 1. Ricardian PPF and TPF

Economic question

Oman and Kuwait both produce food and cloth using labor only. Oman is more efficient in food, while Kuwait is more efficient in cloth.

Country Labor needed for 1 food Labor needed for 1 cloth Labor supply
Oman 1 2 2000
Kuwait 2 1 2000

Tasks:

  1. Draw the production possibility frontier for each country.
  2. Identify comparative advantage.
  3. Draw the trade possibility frontier when 1 unit of food trades for 1 unit of cloth.

Interpretation before graphing

Oman can produce at most 2000 units of food or 1000 units of cloth. Kuwait can produce at most 1000 units of food or 2000 units of cloth.

Oman has comparative advantage in food. Kuwait has comparative advantage in cloth.

Code
import numpy as np
import matplotlib.pyplot as plt

countries = {
    "Oman": {"a_food": 1, "a_cloth": 2, "L": 2000, "specializes": "Food"},
    "Kuwait": {"a_food": 2, "a_cloth": 1, "L": 2000, "specializes": "Cloth"}
}

world_price_food_in_cloth = 1

fig, axes = plt.subplots(1, 2, figsize=(9, 4.5))

for ax, (country, pars) in zip(axes, countries.items()):
    a_f = pars["a_food"]
    a_c = pars["a_cloth"]
    L = pars["L"]

    max_food = L / a_f
    max_cloth = L / a_c

    food = np.linspace(0, max_food, 200)
    cloth_ppf = (L - a_f * food) / a_c

    if pars["specializes"] == "Food":
        food_tpf = np.linspace(0, max_food, 200)
        cloth_tpf = (max_food - food_tpf) * world_price_food_in_cloth
    else:
        max_food_trade = max_cloth / world_price_food_in_cloth
        food_tpf = np.linspace(0, max_food_trade, 200)
        cloth_tpf = max_cloth - food_tpf * world_price_food_in_cloth

    ax.plot(food, cloth_ppf, label="PPF")
    ax.plot(food_tpf, cloth_tpf, linestyle="--", label="TPF after trade")
    ax.fill_between(food, cloth_ppf, alpha=0.15)
    ax.set_title(country)
    ax.set_xlabel("Food")
    ax.set_ylabel("Cloth")
    ax.set_xlim(0, max(max_food, food_tpf.max()) * 1.05)
    ax.set_ylim(0, max(max_cloth, cloth_tpf.max()) * 1.05)
    ax.legend()

plt.tight_layout()
plt.show()
Figure 24.1: Ricardian production and trade possibility frontiers for Oman and Kuwait.

Key lesson

Trade expands consumption possibilities. A country gains from specializing in the good where its opportunity cost is lower, not necessarily the good where its absolute productivity is highest.

Exercise 2. Heckscher-Ohlin PPF with labor and capital constraints

Economic question

A country produces automobiles and textiles. Both labor and capital are limited. The feasible production area is determined by the labor and capital constraints.

Good Labor requirement Capital requirement
Automobile 2 4
Textile 4 2

Available resources:

Resource Amount
Labor 4000
Capital 6000

Tasks:

  1. Draw the labor constraint.
  2. Draw the capital constraint.
  3. Identify the production possibility frontier.
  4. Interpret why the PPF is shaped by the more binding constraint.
Code
import numpy as np
import matplotlib.pyplot as plt

labor = 4000
capital = 6000

aL_auto, aL_textile = 2, 4
aK_auto, aK_textile = 4, 2

auto = np.linspace(0, 2000, 400)
textile_labor = (labor - aL_auto * auto) / aL_textile
textile_capital = (capital - aK_auto * auto) / aK_textile
textile_ppf = np.minimum(textile_labor, textile_capital)
textile_ppf = np.maximum(textile_ppf, 0)

fig, ax = plt.subplots(figsize=(7, 5))
ax.plot(auto, textile_labor, label="Labor constraint")
ax.plot(auto, textile_capital, label="Capital constraint")
ax.plot(auto, textile_ppf, linewidth=2.5, label="PPF")
ax.fill_between(auto, textile_ppf, alpha=0.15, label="Feasible area")
ax.set_xlabel("Automobiles")
ax.set_ylabel("Textiles")
ax.set_title("PPF with labor and capital constraints")
ax.set_xlim(0, 1700)
ax.set_ylim(0, 2100)
ax.legend()
plt.tight_layout()
plt.show()
Figure 24.2: Heckscher-Ohlin production constraints and PPF.

Key lesson

With more than one factor of production, production is constrained by the availability of each factor. A country cannot simply expand both goods if one factor becomes binding.

Exercise 3. Factor prices after a goods-price change

Economic question

Suppose the unit cost equations are:

\[ 2w + 2r = P_C \]

\[ w + 3r = P_F \]

where \(w\) is the wage, \(r\) is the rental rate of capital, \(P_C\) is the price of cloth, and \(P_F\) is the price of food.

Initially:

\[ P_C = 4, \quad P_F = 4 \]

After trade, suppose the price of cloth rises:

\[ P_C = 6, \quad P_F = 4 \]

Tasks:

  1. Solve for the initial wage and rental rate.
  2. Solve for the new wage and rental rate.
  3. Interpret who gains and who loses.
Code
import numpy as np
import matplotlib.pyplot as plt

w = np.linspace(0, 3.2, 300)

# Equations: 2w + 2r = Pc and w + 3r = Pf
r_cloth_initial = (4 - 2 * w) / 2
r_food = (4 - w) / 3
r_cloth_new = (6 - 2 * w) / 2

# Solved values
initial_w, initial_r = 1, 1
new_w, new_r = 2.5, 0.5

fig, ax = plt.subplots(figsize=(7, 5))
ax.plot(w, r_cloth_initial, label="Cloth price equation, Pc = 4")
ax.plot(w, r_food, label="Food price equation, Pf = 4")
ax.plot(w, r_cloth_new, linestyle="--", label="Cloth price equation, Pc = 6")
ax.scatter([initial_w], [initial_r], label="Initial factor prices")
ax.scatter([new_w], [new_r], label="New factor prices")
ax.axvline(initial_w, linestyle=":")
ax.axhline(initial_r, linestyle=":")
ax.axvline(new_w, linestyle=":")
ax.axhline(new_r, linestyle=":")
ax.set_xlabel("Wage, w")
ax.set_ylabel("Rental rate, r")
ax.set_title("Goods prices and factor prices")
ax.set_xlim(0, 3.2)
ax.set_ylim(0, 3.2)
ax.legend()
plt.tight_layout()
plt.show()
Figure 24.3: Factor-price equations before and after a rise in the price of cloth.

Key lesson

When the price of the labor-intensive good rises, the wage can rise by more than the goods price, while the rental rate can fall. This is the basic Stolper-Samuelson logic.

Exercise 4. Welfare before and after trade

Economic question

There are two countries. Demand and supply are:

Country 1:

\[ Q_D = 80 - P, \quad Q_S = P \]

Country 2:

\[ Q_D = 100 - 0.5P, \quad Q_S = 0.5P \]

Tasks:

  1. Compute autarky equilibrium in both countries.
  2. Find the world price under free trade.
  3. Compare consumer surplus, producer surplus, and total surplus before and after trade.
Code
import numpy as np
import matplotlib.pyplot as plt

# Country 1
P1_autarky = 40
Q1_autarky = 40
P_world = 60
Qd1_world = 20
Qs1_world = 60

# Country 2
P2_autarky = 100
Q2_autarky = 50
Qd2_world = 70
Qs2_world = 30

P1 = np.linspace(0, 80, 300)
Qd1 = 80 - P1
Qs1 = P1

P2 = np.linspace(0, 200, 300)
Qd2 = 100 - 0.5 * P2
Qs2 = 0.5 * P2

fig, axes = plt.subplots(2, 2, figsize=(9, 7))

# Country 1 autarky
ax = axes[0, 0]
ax.plot(Qd1, P1, label="Demand")
ax.plot(Qs1, P1, label="Supply")
ax.fill_betweenx(P1, 0, Qd1, where=(P1 >= P1_autarky), alpha=0.15, label="CS")
ax.fill_betweenx(P1, 0, Qs1, where=(P1 <= P1_autarky), alpha=0.15, label="PS")
ax.scatter([Q1_autarky], [P1_autarky])
ax.set_title("Country 1 before trade")
ax.set_xlabel("Quantity")
ax.set_ylabel("Price")
ax.set_xlim(0, 85)
ax.set_ylim(0, 85)
ax.legend()

# Country 1 after trade
ax = axes[0, 1]
ax.plot(Qd1, P1, label="Demand")
ax.plot(Qs1, P1, label="Supply")
ax.axhline(P_world, linestyle="--", label="World price")
ax.fill_betweenx(P1, 0, Qd1, where=(P1 >= P_world), alpha=0.15, label="CS")
ax.fill_betweenx(P1, 0, Qs1, where=(P1 <= P_world), alpha=0.15, label="PS")
ax.scatter([Qd1_world, Qs1_world], [P_world, P_world])
ax.text(40, 63, "Exports = 40", ha="center")
ax.set_title("Country 1 after trade")
ax.set_xlabel("Quantity")
ax.set_ylabel("Price")
ax.set_xlim(0, 85)
ax.set_ylim(0, 85)
ax.legend()

# Country 2 autarky
ax = axes[1, 0]
ax.plot(Qd2, P2, label="Demand")
ax.plot(Qs2, P2, label="Supply")
ax.fill_betweenx(P2, 0, Qd2, where=(P2 >= P2_autarky), alpha=0.15, label="CS")
ax.fill_betweenx(P2, 0, Qs2, where=(P2 <= P2_autarky), alpha=0.15, label="PS")
ax.scatter([Q2_autarky], [P2_autarky])
ax.set_title("Country 2 before trade")
ax.set_xlabel("Quantity")
ax.set_ylabel("Price")
ax.set_xlim(0, 105)
ax.set_ylim(0, 205)
ax.legend()

# Country 2 after trade
ax = axes[1, 1]
ax.plot(Qd2, P2, label="Demand")
ax.plot(Qs2, P2, label="Supply")
ax.axhline(P_world, linestyle="--", label="World price")
ax.fill_betweenx(P2, 0, Qd2, where=(P2 >= P_world), alpha=0.15, label="CS")
ax.fill_betweenx(P2, 0, Qs2, where=(P2 <= P_world), alpha=0.15, label="PS")
ax.scatter([Qs2_world, Qd2_world], [P_world, P_world])
ax.text(50, 65, "Imports = 40", ha="center")
ax.set_title("Country 2 after trade")
ax.set_xlabel("Quantity")
ax.set_ylabel("Price")
ax.set_xlim(0, 105)
ax.set_ylim(0, 205)
ax.legend()

plt.tight_layout()
plt.show()
Figure 24.4: Consumer and producer surplus before and after trade.

Key lesson

The exporting country’s producers gain and consumers lose. The importing country’s consumers gain and producers lose. In both countries, the gain to winners is larger than the loss to losers, so total surplus rises.

Exercise 5. Supply shock in the exporting country

Economic question

Start from the same two-country model. Now suppose Country 1’s supply becomes less favorable:

\[ Q_S = 0.5P \]

Tasks:

  1. Recompute the world price.
  2. Compare the new trade volume with the original free-trade case.
  3. Explain why the importer is also affected by the exporter’s supply shock.
Code
import numpy as np
import matplotlib.pyplot as plt

P_world_new = 72
Qd1_new = 8
Qs1_new = 36
Qd2_new = 64
Qs2_new = 36

P1 = np.linspace(0, 80, 300)
Qd1 = 80 - P1
Qs1_new_curve = 0.5 * P1

P2 = np.linspace(0, 200, 300)
Qd2 = 100 - 0.5 * P2
Qs2 = 0.5 * P2

fig, axes = plt.subplots(1, 2, figsize=(9, 4.5))

ax = axes[0]
ax.plot(Qd1, P1, label="Demand")
ax.plot(Qs1_new_curve, P1, label="New supply")
ax.axhline(P_world_new, linestyle="--", label="New world price")
ax.scatter([Qd1_new, Qs1_new], [P_world_new, P_world_new])
ax.text(22, 75, "Exports = 28", ha="center")
ax.set_title("Country 1 after supply shock")
ax.set_xlabel("Quantity")
ax.set_ylabel("Price")
ax.set_xlim(0, 85)
ax.set_ylim(0, 85)
ax.legend()

ax = axes[1]
ax.plot(Qd2, P2, label="Demand")
ax.plot(Qs2, P2, label="Supply")
ax.axhline(P_world_new, linestyle="--", label="New world price")
ax.scatter([Qs2_new, Qd2_new], [P_world_new, P_world_new])
ax.text(50, 77, "Imports = 28", ha="center")
ax.set_title("Country 2 after supply shock")
ax.set_xlabel("Quantity")
ax.set_ylabel("Price")
ax.set_xlim(0, 105)
ax.set_ylim(0, 205)
ax.legend()

plt.tight_layout()
plt.show()
Figure 24.5: Free trade after a negative supply shock in the exporting country.

Key lesson

A supply shock in the exporting country raises the world price and reduces trade volume. Importing countries are affected even if their own demand and supply curves do not change.

Exercise 6. Trade creation and trade diversion in an FTA

Economic question

The UK imports all compact cars. Its import demand is:

\[ Q = 70 - 0.01P \]

Quantities are in thousand cars and prices are in US dollars per car.

Before an FTA:

  • Japan price = $5000
  • Germany price = $5500
  • UK tariff = $1000 on all imports

After an FTA with Germany, the tariff is removed only on German cars.

Tasks:

  1. Show the delivered prices before and after the FTA.
  2. Identify whether trade diversion occurs.
  3. Calculate whether the FTA produces a welfare gain or welfare loss.
Code
import numpy as np
import matplotlib.pyplot as plt

P = np.linspace(4500, 6500, 300)
Q = 70 - 0.01 * P

price_before = 6000
price_after = 5500
quantity_before = 70 - 0.01 * price_before
quantity_after = 70 - 0.01 * price_after

fig, ax = plt.subplots(figsize=(7, 5))
ax.plot(Q, P, label="Import demand")
ax.axhline(price_before, linestyle="--", label="Before FTA: Japan with tariff")
ax.axhline(price_after, linestyle="--", label="After FTA: Germany duty-free")
ax.axvline(quantity_before, linestyle=":")
ax.axvline(quantity_after, linestyle=":")
ax.scatter([quantity_before, quantity_after], [price_before, price_after])
ax.text(quantity_before + 0.5, price_before + 40, "Q0")
ax.text(quantity_after + 0.5, price_after + 40, "Q1")
ax.set_xlabel("Imports, thousand cars")
ax.set_ylabel("Price per car, USD")
ax.set_title("FTA effect in the UK compact car market")
ax.set_xlim(0, 25)
ax.set_ylim(4500, 6500)
ax.legend()
plt.tight_layout()
plt.show()
Figure 24.6: UK compact car import demand and delivered prices before and after an FTA.

Key lesson

An FTA can lower the price paid by consumers, but it can also divert imports from the world’s lower-cost supplier to a higher-cost partner. The welfare effect depends on whether the consumer-surplus gain is larger than the lost tariff revenue and trade-diversion cost.

Exercise 7. Effective rate of protection

Economic question

Cheese is worth $20 per kg at world prices. Producing 1 kg of cheese requires:

  • 10 liters of milk at $1 per liter
  • 10 grams of starting culture at $0.50 per gram

A country imposes:

  • 20 percent tariff on cheese
  • 10 percent tariff on milk
  • 10 percent tariff on starting culture

Tasks:

  1. Compute value added at world prices.
  2. Compute value added at domestic tariff-inclusive prices.
  3. Calculate the effective rate of protection.
Code
import pandas as pd
import matplotlib.pyplot as plt

world_output = 20
world_inputs = 10 * 1 + 10 * 0.5
world_value_added = world_output - world_inputs

domestic_output = 20 * 1.20
domestic_inputs = 10 * 1 * 1.10 + 10 * 0.5 * 1.10
domestic_value_added = domestic_output - domestic_inputs

erp = (domestic_value_added - world_value_added) / world_value_added * 100

values = pd.DataFrame({
    "Scenario": ["World prices", "Domestic prices after tariffs"],
    "Output value": [world_output, domestic_output],
    "Input cost": [world_inputs, domestic_inputs],
    "Value added": [world_value_added, domestic_value_added]
})

print(values)
print(f"Effective rate of protection = {erp:.1f}%")

ax = values.set_index("Scenario")[["Output value", "Input cost", "Value added"]].plot(kind="bar")
ax.set_ylabel("US dollars per kg")
ax.set_title("Effective protection in cheese production")
plt.xticks(rotation=0)
plt.tight_layout()
plt.show()
                        Scenario  Output value  Input cost  Value added
0                   World prices          20.0        15.0          5.0
1  Domestic prices after tariffs          24.0        16.5          7.5
Effective rate of protection = 50.0%
Figure 24.7: World and domestic value added in the cheese example.

Key lesson

The nominal tariff on the final good does not fully describe the protection received by domestic producers. The effective rate of protection depends on tariffs on both outputs and inputs.

Exercise 8. Oman-India CEPA simulation results

Economic question

The Oman-India CEPA can be studied using product-level partial-equilibrium simulations. The TINA simulation separates total trade effects into trade creation and trade diversion.

Tasks:

  1. Compare trade creation and trade diversion for Oman exports to India and Indian exports to Oman.
  2. Explain why India’s gains are spread across more products.
  3. Discuss why Oman’s gains are more concentrated.
Code
import pandas as pd
import matplotlib.pyplot as plt

cepa = pd.DataFrame({
    "Direction": ["Oman exports to India", "Indian exports to Oman"],
    "Trade creation": [402.80, 550.61],
    "Trade diversion": [164.67, 106.02]
})

ax = cepa.set_index("Direction").plot(kind="bar")
ax.set_ylabel("USD million")
ax.set_title("CEPA trade creation and trade diversion")
plt.xticks(rotation=0)
plt.tight_layout()
plt.show()
Figure 24.8: Aggregate Oman-India CEPA simulation outcomes from TINA.

Key lesson

Both partners gain trade, but the pattern is asymmetric. Oman’s gains are more concentrated in energy and chemical products, while India’s gains are broader and include food-related products.

Summary checklist

After completing these visual exercises, students should be able to:

  • draw and interpret PPF and TPF diagrams,
  • identify comparative advantage,
  • interpret factor-price diagrams,
  • calculate CS, PS, and TS,
  • explain exporter and importer welfare changes,
  • interpret supply shocks in world markets,
  • distinguish trade creation from trade diversion,
  • calculate effective rate of protection,
  • connect TINA simulation outputs to policy interpretation.