“The experiment has failed”

This is based on an interview with a whistleblower.

“So… we messed up. Yup. We won our first paid consultancy project and it ended with an unsatisfied client, repayment of our fees and binning our first, over-ambitious experiment in critical technical practice.

Fortunately, our livelihoods do not currently depend on international aid agencies so we could take a risk on what we said and ultimately walk away when we couldn’t say it right.

I am not big on writing so it was as much my failure to express myself clearly in writing as it was a failure to conform to the original terms of reference that led to this shambles.   

But how do you work critically without biting the hand that feeds?   

We tried to show that critical thinking is not criticism. So we emphasised that our aim was not to find fault: rather we wanted to learn by making space to explore narrative (by which we meant the stories and who gets to tell them) and practice (by which we meant the real life ways that thinking about and doing aid work intertwine).  

For us, this was all about asking:

  • Who is saying humanitarian innovation should happen? Why?

  • What analogies, stories, examples, evidence are being used to make the case for humanitarian innovation? What is missing?

  • According to the humanitarian narrative, what or who should be doing this innovation and why?

  • Who else is innovating?

  • Who else is humanitarian?

  • Who else is making change happen? 

But you were in London and writing in English so how critical and experimental could you really be? 

Ok. Good point. Perhaps it is impossible to do anything provocative or interesting as a London-based consultant to the international aid sector. But here are some of the things we tried…  

As a first step, we wanted to acknowledge where we were sitting. Most consultancy work is written as if it has not emerged from anywhere in particular. So in the writing, we tried to appeal to activists in London, get away from aid industry jargon and start by assuming that, as London activists ourselves, we might learn something from elsewhere and not vice versa. We tried to recognise what was specific and historical about activism in London by including case studies from our own neighbourhoods or initiatives where we had been personally involved.  

Secondly, we deliberately wanted to break with the tradition of assuming that accountability is all taken care of by capturing ‘local voices’. This is not because we think the opinions of people affected by international intervention are less important, less informed or less forthright.

We just think that ‘local voices’ already sounds un-powerful and for the aid industry interrogating inclusion is often done by asking questions:

  • after the fact (i.e. once a project has already been designed and delivered);

  • only in the places where a project has happened and not in places where there was no international support;

  • only of the most vulnerable people included in a project, rather than looking further to those already striving for change or, indeed, implicated in structural violence and injustice. Of course, international non-governmental organisations (INGOs) are mandated to be neutral and impartial but this does not get organisations off the critical thinking hook. In fact, it’s the opposite: it is hard to be neutral and impartial without a cursory attempt to look at where power lies. 

But how did you do this in practice? 

We tried to do this playfully. We wanted to draw attention to our own (and our client’s) power and privilege. 

  1. We started with the premise that there exist canons not just voices. We picked our words carefully because we felt that when the words “story” or “voice” are used by international organisations, they are often applied to small, un-powerful, domestic tales whereas the word “narrative” sounds driven and big. By drawing on canons, we draw on weighty sources of research and journalism produced outside aid organisations, far from headquarter countries or by diasporas and migrants fluent in navigating between stories and narratives about their predicaments.

  2. We referenced the authoritative London or Washington-based writing, especially opinion pieces or reports without peer-review as voices instead of claiming them as evidence in a literature review  

  3. We mischievously tilted the gaze by examining humanitarian innovation’s story of itself, where this story is being written and the language of innovation in what we deliberately called “headquarter countries” as opposed to “project countries”

  4. We brought into the same frame many countries and actors; ideas from public policy not just aid policy; and cited old (1978) and new texts to juxtapose what might well be considered old innovation with new dogma. We wanted to touch on trends and movements other than innovation – techno-optimism, austerity, declining trust in institutions, #metoo. For us this also meant explicitly acknowledging the recent alleged abuses of power within or emanating from UK-based aid agencies (breaking with the tradition of assuming that gender-based abuse is what ‘others’ do). We wanted to challenge the moments when these accusations were described as “a crisis for the humanitarian sector” by suggesting the accusations represented a crisis for the most exploitable people in the INGO orbit.

  5. We said out loud that the document was self-serving: it was to help people interested in humanitarian innovation. It was designed to encourage curiosity and healthy scepticism among people trying to muscle in on humanitarian space. It was a navigational aid for the powerful and privileged: newly nomadic entrepreneurs and technologists, management consultancies and multinationals recently invited to the humanitarian table and academics specialising in organisational or technological spheres but new to colonialism, history and politics  

  6. We used storyboards to test ways of organising and representing what we were learning from interviews. Sketches and drafts, text and diagrams so that the work could be corrected by busy people, fluent in different languages

  7. We gave an account of our biased evidence by stepping back from our bibliography to flag (and we know this could be way more intersectionally interesting) works by women in the reference list

  8. We sought reviews and contributions from people we thought could rebalance and foreground experiences from the places where the projects were happening. Yes – these were people we already knew: friends and colleagues, young, multi-lingual, tech-savvy, wry observers of INGO-culture, politically aware and thoughtful about what some of their compatriots face. But people who are rarely paid to write critically about international aid organisations.

  9. And, finally, we wanted to break with the traditional model of INGO payment structures where national and international staff are paid differently so all team members were paid the same daily rate regardless of location, country of graduation, gender or nationality.

 

What went wrong? 

Well, doing all of these things is hard! Even if our report had been brilliantly written and immaculately edited (it wasn’t), the formula and content were so unfamiliar and jarringly at odds with the original Terms of Reference, that even after 3 positive cycles of review with junior staff, senior gatekeepers panned it.

It wasn’t really research, it wasn’t an evaluation, it wasn’t a manual or a handbook, it wasn’t a brochure… It was the fun, experimental, draft document that we had enthusiastically reviewed together. How disappointing that so late in the process the formulaic write up that the client needed won through. In the end, after responding to 13 pages of feedback on our final deliverable, we were asked to restructure according to the original terms of reference.

Our client was paying for “a product not for our time” and “the experiment had failed”. The client’s biggest concern was that the money allocated for that deliverable was gone and there was no deliverable for the donor. Fair enough. We were out of time and mojo so we refunded all but the first invoice and bore the costs personally [30/09/2019 by the following year, we managed to recover these losses from other projects so lifesavings no longer in the red]. 

The irony was not lost on us. Again and again, the material on humanitarian innovation extolled the virtues of embracing failure, taking risks, experimenting and breaking with the inflexible models of INGO project management. We had even asked the question in our report: who bears the risk and cost of failure when the innovations of humanitarian organisations fail? Who bears the risk and cost when it is innovations and innovators coming forward from the most vulnerable populations whose time and resources have been invested in an INGO innovation project and failure follows?  

Sigh. We are happy that we could afford to fail.”

Energy inefficiency and ill-health

Back in 2014, the UK’s Department for Energy and Climate Change was under pressure to show that green subsidies were not driving up household energy bills.

DECC produced handy infographic offering a transparent breakdown of average energy costs per household.

It’s pretty obvious that we all have to pay the wholesale costs of fuel. We also pay to maintain the pipes and wires that deliver gas an electricity to our doors. We pay (a low rate of) VAT and we cover the margin and supply costs of energy companies.

But there were a few things missing… whether we like it or not we are all paying for the energy inefficiency of housing: the costs of air pollution from all those boilers straining to keep houses warm, the NHS costs of ill-health from damp and cold homes, the cost of climate impacts and, as I discovered, the tax we pay to subsidise fossil fuels.

So I redrew that infographic with all those invisible costs.

Since I originally did this, the department of Energy and Climate Change has been renamed Business, Energy and Industrial Strategy. The government dropped the bit about pesky climate change. But in 2019 we have Greta Thunberg, we have climate strikes, we have Extinction Rebellion and we have talk of a Green New Deal.

We also have even less time to act.

So, maybe in 2019 there is room to change the story about how we really pay for energy inefficiency.

mutualised_costs_titled.png

At about the same time that DECC published their infographic, the UK government was also publishing data on the health costs of poor quality housing, air pollution and climate impacts. The ODI and Oil Change International also conducted independent analysis of fossil fuel subsidies.

Where there was a range, I took a conservative estimate and where I had to make an approximation, I took the lowest possible numbers.

Health costs of poor quality housing

£ 857 million

Source: The cost of poor housing which gives annual savings to NHS: if excess cold in housing, dampness, carbon monoxide and excess heat in housing were fixed.

Government spending on fossil fuel subsidies (excluding spending on carbon capture and storage)

£ 7,089 million

Source: Empty promises G20 subsidies to oil, gas and coal production via tax relief (mainly decommisiong oil and gas), domestic public finance, overseas public finance and via shares in multilateral development banks

Health costs of air pollution, right down to the proportion of this pollution coming from domestic boilers (straining to heat that poor quality housing)

£ 1,500 million

Source: Air Pollution: Action in a Changing Climate costs of only PM2.5 air pollution in 2008 (best data I could find in 2014) estimated by government at £18 billion (in a range of £9-20billion) and according to the National Atmospheric Emissions Directory about 10% of PM2.5 pollution comes from ‘residential stationary combustion’ aka boilers.

Costs to the UK economy of climate change-related damage inside and outside the UK

£ 402 million

Source: Foresight Future Flooding very rough conservative estimate based on 10% of current average annual damage (1.4 bn) and management costs of flooding (0.8 bn) and International Dimensions of Climate Change with my very rough conservative estimate based on 10% of current overseas humanitarian aid costs ( due to climate change related conflict or disaster 435m + 600m) and aid spending on health (683m) and water and sanitation (106m). This is highly conservative as it does not cover costs to UK business with overseas assets, disruption of critical infrastructure.

The code is here and on github - please feel free to use it and improve it. I’ve left it a bit raw and clunky because it makes the laying out easier to tweak.

The data are crying out for an update with the latest and most reliable sources.


import pandas as pd
import matplotlib.pyplot as plt
import squarify    
# pip install squarify (algorithm for treemap) 
# find location by running squarify in a notebook
# modify the following 4 lines of squarify code to rotate the treemap by 90degs 
#x = [rect["y"] for rect in rects]
#y = [-rect["x"] for rect in rects]
#dx = [rect["dy"] for rect in rects]
#dy = [-rect["dx"] for rect in rects]
import seaborn as sns
import numpy as np
import matplotlib.gridspec as gridspec
# Activate Seaborn
sns.set()
# data
mutual_costs = {
    "Fossil fuel subsidy via tax": 314, 
    "Air pollution from housing":66,#cost of air pollution from housing
    "Poor housing":38,#cost of poor housing on health
    "C.I.":18}#climate impacts

UK_data_2014 = {
    "Wholesale energy costs":637,
    "Other supply costs and margins":291,
    "Network costs":286,
    "Support costs":89,    
    "VAT @5%":66
}
Support_Breakdown = {
    "Large-scale renewables, such as wind (RO)": 36, 
    "Carbon taxes":23, 
    "Small-scale renewables such as solar (FITs)": 9,    
    "Price reduction from low carbon policies":-5, 
    "ECO":36,  
    "Warm Home Discount Support":13, 
    "Smart Meters":3,   
    "Government Electricity Rebate":-12, 
    "Warm Home Discount rebate (average)":-13}

mutual = sum(mutual_costs.values())
household = sum(UK_data_2014.values()) 
subs = sum(Support_Breakdown.values()) 

# setting up scaling dimensions
total_costs = mutual+household
total_area = 100
b_house = 10
b_ext = 6

h_ext = (total_area * mutual/total_costs) / b_ext
b_subs = 4
h_subs = 3

# creating dataframes to play with
df1 = pd.DataFrame()
df1['Description'] = mutual_costs.keys()
df1['Costs'] = mutual_costs.values()
df2 = pd.DataFrame()
df2['Description'] = UK_data_2014.keys()
df2['Costs'] = UK_data_2014.values()
df3 = pd.DataFrame()
df3['Description'] = Support_Breakdown.keys()
df3['Costs'] = Support_Breakdown.values()
df3['AbsCosts'] = abs(df3.Costs)

# creating text labels for infographic
label_text1 = []
for row, col in df1.iterrows():
    #text = str(df1.loc[row,'Description'])+" £"+str(df1.loc[row,'Costs'])
    text = str(df1.loc[row,'Description'])
    label_text1.append(text)
label_text1
df1['Label'] = label_text1
df1

label_text2 = []
for row, col in df2.iterrows():
    #text = str(df2.loc[row,'Description'])+" £"+str(df2.loc[row,'Costs'])
    text = str(df2.loc[row,'Description'])
    label_text2.append(text)
label_text2
df2['Label'] = label_text2
df2

label_text3 = []
for row, col in df3.iterrows():
    text = str(df3.loc[row,'Description'])+" £"+str(df3.loc[row,'Costs'])
    label_text3.append(text)
label_text3
df3['Label'] = label_text3
df3
from textwrap import fill
labels1 = [fill(l, 15) for l in df1.loc[:,'Label']]
labels2 = [fill(l, 20) for l in df2.loc[:,'Label']]
labels3 = [fill(l, 20) for l in df3.loc[:,'Label']]

# generating squarify coordinates for house data
rect = squarify.squarify(df2['Costs'],0,0,np.sqrt(household),np.sqrt(household))
coords = pd.concat([
    pd.DataFrame.from_dict(rect[0],orient='index').T,
    pd.DataFrame.from_dict(rect[1],orient='index').T,
    pd.DataFrame.from_dict(rect[2],orient='index').T,
    pd.DataFrame.from_dict(rect[3],orient='index').T,
    pd.DataFrame.from_dict(rect[4],orient='index').T
],ignore_index=True)
coords
all_data = pd.concat([df2,coords],axis=1,sort=False)

# generating squarify coordinates for externalities data
rect_m = squarify.squarify(df1['Costs'],0,0,np.sqrt(mutual),np.sqrt(mutual))
coords_m = pd.concat([
    pd.DataFrame.from_dict(rect_m[0],orient='index').T,
    pd.DataFrame.from_dict(rect_m[1],orient='index').T,
    pd.DataFrame.from_dict(rect_m[2],orient='index').T,
    pd.DataFrame.from_dict(rect_m[3],orient='index').T,
],ignore_index=True)
coords_m
all_data_m = pd.concat([df1,coords_m],axis=1,sort=False)

font_size = []
for row, col in all_data.iterrows():
    if col[1] > 500:
        font_size.append(30)
    elif col[1] < 100:
        font_size.append(20)
    else:
        font_size.append(25)
font_size
all_data['font_size'] = font_size

font_size_m = []
for row, col in all_data_m.iterrows():
    if col[1] > 500:
        font_size.append(25)
    elif col[1] < 100:
        font_size_m.append(14)
    else:
        font_size_m.append(25)
font_size_m
all_data_m['font_size'] = font_size_m

wrapping = [25,20,25,12,5]
wrapping_m = [50,25,10,12]

all_data['wrapping'] = wrapping 
all_data_m['wrapping'] = wrapping_m

#Create plot 
plt.style.use('fivethirtyeight')
plt.figure(figsize= [b_ext,h_ext])
plt.rc('font', weight='bold')# controls default text sizes
plt.rc('text', color='w')

fig = plt.figure(figsize= [25,10])
fig.patch.set_facecolor('w')
fig.patch.set_alpha(0)

#split the plot into 3 axes on a grid
gs1 = gridspec.GridSpec(1, 3, figure=fig,wspace=0)
gs1.tight_layout(fig, rect=[0, 0, 1, 1],pad=0,w_pad=0,h_pad=0)

ax1 = fig.add_subplot(gs1[0])
ax2 = fig.add_subplot(gs1[1])
ax3 = fig.add_subplot(gs1[2])

# generate tree map
squarify.plot(sizes=df1['Costs'],ax=ax1,norm_x=np.sqrt(mutual),norm_y=np.sqrt(mutual),color='r',linewidth='10',edgecolor=(1,1,1,0),alpha=1) #color = colors,
squarify.plot(sizes=df2['Costs'],ax=ax2,norm_x=37,norm_y=37, color='#9d9a01',linewidth='10',edgecolor=(1,1,1,0),alpha=1) #color = colors,

# lay out of axis to plot areas so that they are equivalent
ax1.set_xlim(-(41-np.sqrt(mutual)),np.sqrt(mutual))
ax1.set_ylim(-np.sqrt(mutual),37+2)
ax2.set_xlim(-2,37+2)
ax2.set_ylim(-37,np.sqrt(mutual))
ax3.set_xlim(-.15,.85)
ax3.set_ylim(0,1)

# transparent background
ax1.patch.set_facecolor('w')
ax1.patch.set_alpha(0)
ax2.patch.set_facecolor('w')
ax2.patch.set_alpha(0)
ax3.patch.set_facecolor('w')
ax3.patch.set_alpha(0)

# data labels for household energy
for row, col in all_data.iterrows():
    x = col[4]
    y = (-col[3])
    ax2.text(x+1,y-5,fill(col[0],col[8]),ha='left',va='baseline',fontsize=16)
    ax2.text(x+1,(y-7.5),'£ ',ha='left',va='baseline',fontsize=16)
    ax2.text(x+2,(y-7.5),col[1],ha='left',va='baseline',fontsize=col[7])

# data labels for externalities
for row, col in all_data_m.iterrows():
    x = col[4]
    y = (-col[3])
    ax1.text(x+0.8,y-1,fill(col[0],col[8]),ha='left',va='top',fontsize=12)
    ax1.text(x+0.8,(y-5),'£ ',ha='left',va='baseline',fontsize=12)
    ax1.text(x+1.4,(y-5),col[1],ha='left',va='baseline',fontsize=col[7])
    
ax1.axis('off')
ax2.axis('off')
ax3.axis('off')

# disaggregated support costs with labels
ax3.text(0.01,.99,fill("Support for cleaner energy and keeping the lights on",35),ha='left',va='top',color='w',fontsize=18)
ax3.text(0.01,.67,fill("Support for vulnerable households, energy efficiency, and Government Electricity Rebate",35),ha='left',va='top',color='w',fontsize=18)

for row, col in df3.iterrows():
    if row in range(0,4):
        #print(row)
        x = col[0]
        y = col[1]
        #y = (-col[3])
        if len(str(y)) == 1:
            y = str('£    '+str(y))
            #print(str('£    '+str(y)))
        elif len(str(y)) == 2:
            y = str('£   '+str(y))
            #print(str('£   '+str(y)))
        elif len(str(y)) == 3:
            y = str('£  '+str(y))
        ax3.text(0.01,0.91-((1+row)/20),fill(col[0],45),ha='left',va='baseline',fontsize=12)
        ax3.text(.5,0.91-((1+row)/20),y,ha='left',va='baseline',fontsize=16)
    if row in range(4,8):  
        #print(row)
        x = col[0]
        y = col[1]
        if len(str(y)) == 1:
            y = str('£    '+str(y))
            #print(str('£    '+str(y)))
        elif len(str(y)) == 2:
            y = str('£   '+str(y))
            #print(str('£   '+str(y)))
        elif len(str(y)) == 3:
            y = str('£  '+str(y))
        ax3.text(0.01,.79-((1+row)/20),fill(col[0],45),ha='left',va='baseline',fontsize=12)
        ax3.text(0.5,.79-((1+row)/20),y,ha='left',va='baseline',fontsize=16)
    if row in range(8,9):  
        #print(row)
        x = col[0]
        y = col[1]
        if len(str(y)) == 1:
            y = str('£    '+str(y))
            #print(str('£    '+str(y)))
        elif len(str(y)) == 2:
            y = str('£   '+str(y))
            #print(str('£   '+str(y)))
        elif len(str(y)) == 3:
            y = str('£  '+str(y))
        ax3.text(0.01,.32,fill(col[0],40),ha='left',va='baseline',fontsize=12)
        ax3.text(0.5,.32,y,ha='left',va='baseline',fontsize=16)

#triangular roof
t2= plt.Polygon([[-2,-12.1], [(37)/2,8], [39,-12.1]], color='#9d9a01')
ax2.add_patch(t2)

#cleaner energy
t3= plt.Polygon([[0,0.7], [0,1], [.6,1],[.6,.7]], color='#9d9a01')
ax3.add_patch(t3)

#vulnerable groups
t4= plt.Polygon([[0,.38], [0,.68], [.6,.68],[.6,0.38]], color='#9d9a01')
ax3.add_patch(t4)

#rebate
t5= plt.Polygon([[0,0.3], [0,.36], [.6,.36],[.6,.3]], color='#616266')
ax3.add_patch(t5)

#arrows
a1= plt.Polygon([[-.15,.97], [-0.15,.99], [0,.99],[0,0.97]], color='#9d9a01')
a2= plt.Polygon([[-.15,.3], [-.15,.97], [-.13,.97],[-.13,0.3]], color='#9d9a01')
a3= plt.Polygon([[-.11,.64], [-.11,.66], [0,.66],[0,0.64]], color='#9d9a01')
a4= plt.Polygon([[-.11,.26], [-.11,.64], [-.09,.64],[-.09,0.26]], color='#9d9a01')
a5= plt.Polygon([[-.07,.32], [-.07,.34], [-0,.34],[0,0.32]], color='#9d9a01')
a6= plt.Polygon([[-.07,.22], [-.07,.32], [-.05,.32],[-.05,0.22]], color='#9d9a01')

a7= plt.Polygon([[-.15,.26], [-.15,.28], [-.11,.28],[-.11,0.26]], color='#9d9a01')
a8= plt.Polygon([[-.15,.22], [-.15,.24], [-.07,.24],[-.07,0.22]], color='#9d9a01')

ax3.add_patch(a1)
ax3.add_patch(a2)
ax3.add_patch(a3)
ax3.add_patch(a4)
ax3.add_patch(a5)
ax3.add_patch(a6)
ax3.add_patch(a7)
ax3.add_patch(a8)

yaxis_length = 37+np.sqrt(mutual)
x1 = 36
x2 = 39
y1 = -(0.32*yaxis_length)
y2 = y1 - (0.02*yaxis_length)
y21 = -(0.36*yaxis_length)
y22 = y21 - (0.02*yaxis_length)
y31 = -(0.40*yaxis_length)
y32 = y31 - (0.02*yaxis_length)

b1 =  plt.Polygon([[x1,y2], [x1,y1], [x2,y1],[x2,y2]], color='#9d9a01')
b2 =  plt.Polygon([[x1,y22], [x1,y21], [x2,y21],[x2,y22]], color='#9d9a01')
b3 =  plt.Polygon([[x1,y32], [x1,y31], [x2,y31],[x2,y32]], color='#9d9a01')
ax2.add_patch(b1)
ax2.add_patch(b2)
ax2.add_patch(b3)

plt.show()

Thanks to Kevin Wubert for the blog on how to embed python code in Squarespace.