🗳️

How popular is Emmanuel Macron?

Published on
November 24, 2021
Updated on
May 8, 2023

Evolution of approval rates

Approval rate is in green, disapproval rate in orange. Each point represent a poll, and lines are centered 30-day moving averages.

super-embed:
<iframe src="https://storage.googleapis.com/charlse/charlse/macron_popularity.html" height="520"><iframe>
Plotly code
# Plotly graph

## Colors
color_approval = {
    'Approve': 'darkgreen',
    'approval': 'darkgreen',
    'Disapprove': 'darkorange', 
    'disapproval': 'darkorange',
    'Neutral': 'grey',
}

## Line graph for rolling means
fig1 = px.line(
    df_popularity, x='date', y=['Approve', 'Disapprove'], 
    color_discrete_map=color_approval)
fig1.update_traces(hovertemplate='%{y:.1%}', showlegend=True, line=dict(width=3))
fig1.add_hline(y=.5)

## Scatter graph
fig2 = px.scatter(
    df_popularity, x='date', y=['approval', 'disapproval'], 
    opacity=.3, color_discrete_map=color_approval)
fig2.update_traces(hovertemplate=None, hoverinfo='skip', showlegend=False)

## Group both plots
fig3 = go.Figure(
    data=fig1.data + fig2.data,
    layout=go.Layout(
        template='simple_white',
        height=500, width=740, 
        margin=dict(l=5, r=5, b=5,t=5),
        yaxis_tickformat='.0%', yaxis_range=[0, 1], 
        yaxis_tickfont=dict(size=11, family='Arial'),
        xaxis_tickfont=dict(size=11, family='Arial'),
        showlegend=False, 
        hovermode='x unified',
    )
)

## Display result
fig3.show()

Latest polls
Polling institute
Poll date
Sample size
Approval rate
Disapproval rate
Harris Interactive
2023-04-25
1078
39%
61%
Odoxa
2023-04-19
1005
30%
70%
BVA
2023-04-18
1002
26%
73%
Ifop
2023-04-14
1955
26%
72%
Ipsos
2023-04-12
1000
28%
69%
Harris Interactive
2023-03-28
1062
39%
61%
BVA
2023-03-24
1000
28%
72%
Odoxa
2023-03-22
1004
30%
70%
Ifop
2023-03-09
1928
28%
70%
Ipsos
2023-02-24
1014
32%
64%
BVA
2023-02-22
1001
34%
66%
Odoxa
2023-02-21
1005
36%
63%
Harris Interactive
2023-02-21
1008
42%
58%
Ifop
2023-02-09
1952
32%
66%
Ifop-Fiducial
2023-02-01
1012
34%
66%

Compared to Previous French Presidents

Comparaison of Emmanuel Macron popularity vs previous French presidents, monthly since their election or re-election. Note: since 2002 (Chirac II), the duration of a presidential mandate decreased from 7 years to 5 years.

super-embed:
<iframe src="https://storage.googleapis.com/charlse/charlse/presidents.html" height="820"><iframe>
Plotly code
# Plot Macron vs previous presidents

## Selection
presidents = [
    'Mitterrand I', 'Mitterrand II',
    'Chirac I', 'Chirac II',
    'Sarkozy', 'Hollande'
]

## Plot 
fig = make_subplots(
    rows=(len(presidents)+1)//2, cols=2, 
    vertical_spacing = 0.1,
    subplot_titles=["{}".format(i) for i in presidents]
)
fig.update_annotations(font_size=14, font_family='Arial')

## Loop over candidates couples
for i,v in enumerate(presidents):

    ### Macron 1st or 2nd mandate
    if v[-2:] == 'II':
        macron = 'Macron II' 
    else:
        macron = 'Macron I'

    ### Previous president
    fig.add_trace(go.Scatter(
        x=df_presidents.loc[lambda x: x['president'] == v, 'months'],
        y=df_presidents.loc[lambda x: x['president'] == v, 'trust']/100, 
        line=dict(shape='hv', width=1, color='dimgray'),
        mode='lines', 
        hovertemplate='<extra>{}</extra>%{}'.format(v, '{y:.0%}') 
    ), 
    row=i//2+1, col=i%2+1)

    ### Trick for fill area
    fig.add_trace(go.Scatter(
        x=df_presidents.loc[lambda x: x['president'] == macron, 'months'], 
        y=df_presidents.loc[lambda x: x['president'] == v, 'trust']/100, 
        line=dict(shape='hv', color='dimgray', width=0),
        mode='lines', 
        hoverinfo='skip'
    ), 
    row=i//2+1, col=i%2+1)

    ### Macron score
    fig.add_trace(go.Scatter(
        x=df_presidents.loc[lambda x: x['president'] == macron, 'months'], 
        y=df_presidents.loc[lambda x: x['president'] == macron, 'trust']/100, 
        line=dict(shape='hv', width=2, color='steelblue'),
        mode='lines', 
        hovertemplate='<extra>{}</extra>%{}'.format(macron, '{y:.0%}'),
        fill='tonexty', fillcolor='rgba(70,130,180,0.2)'
    ), 
    row=i//2+1, col=i%2+1)

    ### Axes formatting
    fig.update_yaxes(tickformat='.0%', range=[0, 1], 
        tickfont=dict(size=11, family='Arial'))
    fig.update_xaxes(
        tickmode = 'array',
        tickvals=[12, 24, 36, 48, 60, 72, 84],
        ticktext = ['1 year', '2 years', '3 years', '4 years', '5 years', '6 years', '7 years'],
        tickfont=dict(size=11, family='Arial'),
        ticksuffix=' months',
    )

## Figure formatting
fig.update_layout(
    template='simple_white',
    width=740, height=800, 
    showlegend=False, 
    margin=dict(l=15, r=25, b=15,t=40),
    hovermode='x unified',
)

## Display results 
fig.show()

Sources