08. Energy forecast 2050 (sankey)

This script creates a Sankey diagram to visualize the projected flow of energy for the year 2050. It begins by fetching the necessary data from a JSON file hosted on GitHub.

Before plotting, the script processes the data to customize the diagram’s appearance, notably adjusting the colors and opacity so that each flow (or link) inherits the color of its source node. This enhances readability and makes the chart more intuitive. Finally, it uses plotly.graph_objects to construct and display the Sankey diagram, which effectively illustrates the distribution of energy from various sources through to their final consumption sectors.

Out:

{'data': [{'type': 'sankey', 'domain': {'x': [0, 1], 'y': [0, 1]}, 'orientation': 'h', 'valueformat': '.0f', 'valuesuffix': 'TWh', 'node': {'pad': 15, 'thickness': 15, 'line': {'color': 'black', 'width': 0.5}, 'label': ["Agricultural 'waste'", 'Bio-conversion', 'Liquid', 'Losses', 'Solid', 'Gas', 'Biofuel imports', 'Biomass imports', 'Coal imports', 'Coal', 'Coal reserves', 'District heating', 'Industry', 'Heating and cooling - commercial', 'Heating and cooling - homes', 'Electricity grid', 'Over generation / exports', 'H2 conversion', 'Road transport', 'Agriculture', 'Rail transport', 'Lighting & appliances - commercial', 'Lighting & appliances - homes', 'Gas imports', 'Ngas', 'Gas reserves', 'Thermal generation', 'Geothermal', 'H2', 'Hydro', 'International shipping', 'Domestic aviation', 'International aviation', 'National navigation', 'Marine algae', 'Nuclear', 'Oil imports', 'Oil', 'Oil reserves', 'Other waste', 'Pumped heat', 'Solar PV', 'Solar Thermal', 'Solar', 'Tidal', 'UK land based bioenergy', 'Wave', 'Wind'], 'color': ['rgba(31, 119, 180, 0.8)', 'rgba(255, 127, 14, 0.8)', 'rgba(44, 160, 44, 0.8)', 'rgba(214, 39, 40, 0.8)', 'rgba(148, 103, 189, 0.8)', 'rgba(140, 86, 75, 0.8)', 'rgba(227, 119, 194, 0.8)', 'rgba(127, 127, 127, 0.8)', 'rgba(188, 189, 34, 0.8)', 'rgba(23, 190, 207, 0.8)', 'rgba(31, 119, 180, 0.8)', 'rgba(255, 127, 14, 0.8)', 'rgba(44, 160, 44, 0.8)', 'rgba(214, 39, 40, 0.8)', 'rgba(148, 103, 189, 0.8)', 'rgba(140, 86, 75, 0.8)', 'rgba(227, 119, 194, 0.8)', 'rgba(127, 127, 127, 0.8)', 'rgba(188, 189, 34, 0.8)', 'rgba(23, 190, 207, 0.8)', 'rgba(31, 119, 180, 0.8)', 'rgba(255, 127, 14, 0.8)', 'rgba(44, 160, 44, 0.8)', 'rgba(214, 39, 40, 0.8)', 'rgba(148, 103, 189, 0.8)', 'rgba(140, 86, 75, 0.8)', 'rgba(227, 119, 194, 0.8)', 'rgba(127, 127, 127, 0.8)', 'rgba(188, 189, 34, 0.8)', 'rgba(23, 190, 207, 0.8)', 'rgba(31, 119, 180, 0.8)', 'rgba(255, 127, 14, 0.8)', 'rgba(44, 160, 44, 0.8)', 'rgba(214, 39, 40, 0.8)', 'rgba(148, 103, 189, 0.8)', 'rgba(255,0,255, 0.8)', 'rgba(227, 119, 194, 0.8)', 'rgba(127, 127, 127, 0.8)', 'rgba(188, 189, 34, 0.8)', 'rgba(23, 190, 207, 0.8)', 'rgba(31, 119, 180, 0.8)', 'rgba(255, 127, 14, 0.8)', 'rgba(44, 160, 44, 0.8)', 'rgba(214, 39, 40, 0.8)', 'rgba(148, 103, 189, 0.8)', 'rgba(140, 86, 75, 0.8)', 'rgba(227, 119, 194, 0.8)', 'rgba(127, 127, 127, 0.8)']}, 'link': {'source': [0, 1, 1, 1, 1, 6, 7, 8, 10, 9, 11, 11, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 23, 25, 5, 5, 5, 5, 5, 27, 17, 17, 28, 29, 2, 2, 2, 2, 2, 2, 2, 2, 34, 24, 35, 35, 36, 38, 37, 39, 39, 40, 40, 41, 42, 43, 43, 4, 4, 4, 26, 26, 26, 44, 45, 46, 47, 35, 35], 'target': [1, 2, 3, 4, 5, 2, 4, 9, 9, 4, 12, 13, 14, 16, 14, 17, 12, 18, 19, 13, 3, 20, 21, 22, 24, 24, 13, 3, 26, 19, 12, 15, 28, 3, 18, 15, 12, 30, 18, 31, 32, 19, 33, 20, 1, 5, 26, 26, 37, 37, 2, 4, 1, 14, 13, 15, 14, 42, 41, 19, 26, 12, 15, 3, 11, 15, 1, 15, 15, 26, 26], 'value': [124.729, 0.597, 26.862, 280.322, 81.144, 35, 35, 11.606, 63.965, 75.571, 10.639, 22.505, 46.184, 104.453, 113.726, 27.14, 342.165, 37.797, 4.412, 40.858, 56.691, 7.863, 90.008, 93.494, 40.719, 82.233, 0.129, 1.401, 151.891, 2.096, 48.58, 7.013, 20.897, 6.242, 20.897, 6.995, 121.066, 128.69, 135.835, 14.458, 206.267, 3.64, 33.218, 4.413, 14.375, 122.952, 500, 139.978, 504.287, 107.703, 611.99, 56.587, 77.81, 193.026, 70.672, 59.901, 19.263, 19.263, 59.901, 0.882, 400.12, 46.477, 525.531, 787.129, 79.329, 9.452, 182.01, 19.013, 289.366, 100, 100], 'color': ['rgba(31, 119, 180, 0.4)', 'rgba(255, 127, 14, 0.4)', 'rgba(255, 127, 14, 0.4)', 'rgba(255, 127, 14, 0.4)', 'rgba(255, 127, 14, 0.4)', 'rgba(227, 119, 194, 0.4)', 'rgba(127, 127, 127, 0.4)', 'rgba(188, 189, 34, 0.4)', 'rgba(31, 119, 180, 0.4)', 'rgba(23, 190, 207, 0.4)', 'rgba(255, 127, 14, 0.4)', 'rgba(255, 127, 14, 0.4)', 'rgba(255, 127, 14, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(214, 39, 40, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(127, 127, 127, 0.4)', 'rgba(127, 127, 127, 0.4)', 'rgba(127, 127, 127, 0.4)', 'rgba(188, 189, 34, 0.4)', 'rgba(23, 190, 207, 0.4)', 'rgba(44, 160, 44, 0.4)', 'rgba(44, 160, 44, 0.4)', 'rgba(44, 160, 44, 0.4)', 'rgba(44, 160, 44, 0.4)', 'rgba(44, 160, 44, 0.4)', 'rgba(44, 160, 44, 0.4)', 'rgba(44, 160, 44, 0.4)', 'rgba(44, 160, 44, 0.4)', 'rgba(148, 103, 189, 0.4)', 'rgba(148, 103, 189, 0.4)', 'rgba(255,0,255, 0.4)', 'rgba(255,0,255, 0.4)', 'rgba(227, 119, 194, 0.4)', 'rgba(188, 189, 34, 0.4)', 'rgba(127, 127, 127, 0.4)', 'rgba(23, 190, 207, 0.4)', 'rgba(23, 190, 207, 0.4)', 'rgba(31, 119, 180, 0.4)', 'rgba(31, 119, 180, 0.4)', 'rgba(255, 127, 14, 0.4)', 'rgba(44, 160, 44, 0.4)', 'rgba(214, 39, 40, 0.4)', 'rgba(214, 39, 40, 0.4)', 'rgba(148, 103, 189, 0.4)', 'rgba(148, 103, 189, 0.4)', 'rgba(148, 103, 189, 0.4)', 'rgba(227, 119, 194, 0.4)', 'rgba(227, 119, 194, 0.4)', 'rgba(227, 119, 194, 0.4)', 'rgba(148, 103, 189, 0.4)', 'rgba(140, 86, 75, 0.4)', 'rgba(227, 119, 194, 0.4)', 'rgba(127, 127, 127, 0.4)', 'rgba(255,0,255, 0.4)', 'rgba(255,0,255, 0.4)'], 'label': ['stream 1', '', '', '', 'stream 1', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'stream 1', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'Old generation plant (made-up)', 'New generation plant (made-up)', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']}}], 'layout': {'title': {'text': "Energy forecast for 2050, UK — Department of Energy & Climate Change<br>Imperfect copy of <a href='https://bost.ocks.org/mike/sankey/'>Mike Bostock's example</a><br>with numerous <a href='https://plotly.com/javascript/'>Plotly</a> features"}, 'width': 1118, 'height': 772, 'font': {'size': 10, 'weight': 'bold', 'style': 'italic', 'variant': 'small-caps'}, 'updatemenus': [{'y': 1, 'buttons': [{'label': 'Light', 'method': 'relayout', 'args': ['paper_bgcolor', 'white']}, {'label': 'Dark', 'method': 'relayout', 'args': ['paper_bgcolor', 'black']}]}, {'y': 0.9, 'buttons': [{'label': 'Thick', 'method': 'restyle', 'args': ['node.thickness', 15]}, {'label': 'Thin', 'method': 'restyle', 'args': ['node.thickness', 8]}]}, {'y': 0.8, 'buttons': [{'label': 'Small gap', 'method': 'restyle', 'args': ['node.pad', 15]}, {'label': 'Large gap', 'method': 'restyle', 'args': ['node.pad', 20]}]}, {'y': 0.7, 'buttons': [{'label': 'Snap', 'method': 'restyle', 'args': ['arrangement', 'snap']}, {'label': 'Perpendicular', 'method': 'restyle', 'args': ['arrangement', 'perpendicular']}, {'label': 'Freeform', 'method': 'restyle', 'args': ['arrangement', 'freeform']}, {'label': 'Fixed', 'method': 'restyle', 'args': ['arrangement', 'fixed']}]}, {'y': 0.6, 'buttons': [{'label': 'Horizontal', 'method': 'restyle', 'args': ['orientation', 'h']}, {'label': 'Vertical', 'method': 'restyle', 'args': ['orientation', 'v']}]}]}}

18 import plotly.graph_objects as go
19 import urllib.request, json
20
21 url = 'https://raw.githubusercontent.com/plotly/plotly.js/master/test/image/mocks/sankey_energy.json'
22 response = urllib.request.urlopen(url)
23 data = json.loads(response.read())
24
25 # override gray link colors with 'source' colors
26 opacity = 0.4
27 # change 'magenta' to its 'rgba' value to add opacity
28 data['data'][0]['node']['color'] = \
29     ['rgba(255,0,255, 0.8)' if color == "magenta" else color
30         for color in data['data'][0]['node']['color']]
31 data['data'][0]['link']['color'] = \
32     [data['data'][0]['node']['color'][src].replace("0.8", str(opacity))
33         for src in data['data'][0]['link']['source']]
34
35 print(data)
36
37 fig = go.Figure(data=[go.Sankey(
38     valueformat = ".0f",
39     valuesuffix = "TWh",
40     # Define nodes
41     node = dict(
42       pad = 15,
43       thickness = 15,
44       line = dict(color = "black", width = 0.5),
45       label =  data['data'][0]['node']['label'],
46       color =  data['data'][0]['node']['color']
47     ),
48     # Add links
49     link = dict(
50       source =  data['data'][0]['link']['source'],
51       target =  data['data'][0]['link']['target'],
52       value =  data['data'][0]['link']['value'],
53       label =  data['data'][0]['link']['label'],
54       color =  data['data'][0]['link']['color']
55 ))])
56
57 title = """Energy forecast for 2050<br>Source: Department of Energy & Climate
58 Change, Tom Counsell ia <a href='https://bost.ocks.org/mike/sankey/'>Mike Bostock</a>","""
59
60 fig.update_layout(title_text=title, font_size=10)
61 #fig.show()
62
63 # Show
64 from plotly.io import show
65 show(fig)

Total running time of the script: ( 0 minutes 1.857 seconds)

Gallery generated by Sphinx-Gallery