GEUS-Glaciology-and-Climate / mass_balance

Greenland ice sheet mass balance from 1840 through next week
https://doi.org/10.5194/essd-13-5001-2021
GNU Lesser General Public License v3.0
6 stars 2 forks source link

Greenland mass flow Sankey diagram #28

Closed mankoff closed 1 month ago

mankoff commented 4 months ago

A future version of this paper should include a graphic like this. The numbers here are approximate and some are just guesses/placeholders. Ideally each number should have a reference. It is unlikely the equation will balance, and there should be losses (and gains?) to/from 'uncertainty'.

image

Code ```python import numpy as np import pandas as pd import plotly.graph_objects as go import plotly.express as px df = pd.DataFrame(columns=['value','source','target','meta']) df.index.name = 'label' df.loc['rain:freeze'] = [50/2, 'rain', 'GL', 'A2019'] # Alexander 2019 df.loc['snow:fall'] = [750, 'snow fall', 'GL', 'A2019'] # fudge from A2019 df.loc['DEFICIT'] = [160, 'DEFICIT', 'GL', ''] df.loc['condensation'] = [10, 'condensation', 'GL', 'guess'] df.loc['drifting_out'] = [100, 'GL', 'drift', 'guess'] df.loc['drifting_in'] = [100 , 'drift', 'GL', 'guess'] df.loc['rain:runoff'] = [50/2, 'rain', 'runoff', 'A2019'] df.loc['rain:runoff:liquid'] = [50/2, 'runoff', 'liquid', 'A2019'] df.loc['SMB (loss)'] = [400, 'GL', 'SMB (loss)', 'A2019'] df.loc['dynamics'] = [500, 'GL', 'dynamics', ''] df.loc['icebergs'] = [250, 'dynamics', 'icebergs', 'M2020 & E2014'] # Enderlin & Mankoff df.loc['frontal melt'] = [250, 'dynamics', 'frontal melt', 'E2014'] df.loc['runoff'] = [400, 'SMB (loss)','runoff', ''] df.loc['refreeze'] = [250, 'GL','refreeze', ''] df.loc['refreeze1'] = [250, 'refreeze','GL', ''] # df.loc['runoff'] = [400, 'melt','runoff', ''] #df.loc['basal melt'] = [25, 'basal melt', 'liquid', 'K2020'] # Karlsson df.loc['basal melt'] = [25, 'GL', 'basal melt', 'K2020'] # Karlsson df.loc['basal melt1'] = [25, 'basal melt', 'runoff', 'K2020'] # Karlsson df.loc['basal melt2'] = [25, 'runoff', 'liquid', 'K2020'] # Karlsson # df.loc['basal melt2'] = [50, 'runoff', 'liquid', 'K2020'] df.loc['evaporation'] = [10, 'GL', 'evaporation', ''] df.loc['sublimation'] = [10, 'GL', 'sublimation', ''] # Sum all the liquid terms to a liquid budget (solid is just 'iceberg') for i,v in enumerate(['runoff','frontal melt']): df.loc[f'liquid_{v}'] = [df.loc[v]['value'], v, 'liquid', ''] # QC Check for s in df['source'].unique(): if s in df['target'].unique(): sv = df[df['source'] == s]['value'].sum() tv = df[df['target'] == s]['value'].sum() if( sv != tv ): print(f"Error: {s} inputs != outputs [{sv} != {tv}]") # # Add numeric values in parentheses for t in np.unique(df['source'].values.astype(str)): v = (df[df["source"] == t]["value"].sum()).round().astype(int).astype(str) df = df.replace(to_replace=t, value=f'{t} ({v})') for t in np.unique(df['target'].values.astype(str)): if t[-1] == ')': continue v = (df[df["target"] == t]["value"].sum()).round().astype(int).astype(str) df = df.replace(to_replace=t, value=f'{t} ({v})') # print(df) ## Plotly # uniqify columns: Convert strings to numbers. Sequential. Across columns keys = np.unique(df[['source','target']].values.flatten().astype(str)) df = df.replace(to_replace=keys, value=np.arange(len(keys))) fig = go.Figure(go.Sankey( arrangement = "snap", node = { "label": keys, 'color': "#666666", 'pad':10}, # 10 Pixels link = { "source": df['source'].values, "target": df['target'].values, # "color": "#DDDDDD", "value": df['value'].values})) # fig.show() fig.write_image("plotly.png") # interactive HTML: drag to re-arrange and clean up, then screenshot. fig.write_html("plotly.html") ```

See also LaTeX examples for more control: https://us.mirrors.cicku.me/ctan/graphics/pgf/contrib/sankey/sankey.pdf

mankoff commented 4 months ago

This version might be a better representation:

image

Code ```python import numpy as np import pandas as pd import plotly.graph_objects as go import plotly.express as px df = pd.DataFrame(columns=['value','source','target']) df.index.name = 'label' df.loc['SMB:in'] = [400, 'SMB in', 'SMB gain'] df.loc['rain:freeze'] = [40, 'rain', 'SMB in'] # Alexander 2019 df.loc['snow:fall'] = [750, 'snow fall', 'SMB in'] # fudge from A2019 df.loc['condensation'] = [10, 'condensation', 'SMB in'] # df.loc['drifting_out'] = [100, 'SMB in', 'drift'] # df.loc['drifting_in'] = [100, 'drift', 'SMB in'] df.loc['refreeze1'] = [250, 'refreeze','SMB in'] df.loc['Melt'] = [650, 'SMB in', 'Melt'] df.loc['refreeze'] = [250, 'Melt','refreeze'] df.loc['SMB:out'] = [400, 'Melt', 'runoff'] df.loc['MB:in'] = [400, 'SMB gain', 'MB'] df.loc['MB:D'] = [500, 'MB', 'dynamics'] df.loc['MB:BMB'] = [25, 'MB', 'basal melt'] df.loc['liquid_1'] = [25, 'basal melt', 'liquid'] df.loc['liquid_2'] = [25, 'rain', 'runoff'] df.loc['liquid_3'] = [425, 'runoff', 'liquid'] df.loc['liquid_4'] = [250, 'dynamics', 'liquid'] df.loc['iceberg'] = [250, 'dynamics', 'iceberg'] df.loc['DEFICIT'] = [125, 'DEFICIT', 'MB'] # QC Check for s in df['source'].unique(): if s in df['target'].unique(): sv = df[df['source'] == s]['value'].sum() tv = df[df['target'] == s]['value'].sum() if( sv != tv ): print(f"Error: {s} inputs != outputs [{sv} != {tv}]") # # Add numeric values in parentheses for t in np.unique(df['source'].values.astype(str)): v = (df[df["source"] == t]["value"].sum()).round().astype(int).astype(str) df = df.replace(to_replace=t, value=f'{t} ({v})') for t in np.unique(df['target'].values.astype(str)): if t[-1] == ')': continue v = (df[df["target"] == t]["value"].sum()).round().astype(int).astype(str) df = df.replace(to_replace=t, value=f'{t} ({v})') # print(df) ## Plotly # uniqify columns: Convert strings to numbers. Sequential. Across columns keys = np.unique(df[['source','target']].values.flatten().astype(str)) df = df.replace(to_replace=keys, value=np.arange(len(keys))) fig = go.Figure(go.Sankey( arrangement = "snap", node = { "label": keys, 'color': "#666666", 'pad':10}, # 10 Pixels link = { "source": df['source'].values, "target": df['target'].values, # "color": "#DDDDDD", "value": df['value'].values})) # fig.show() fig.write_image("plotly.png") # interactive HTML: drag to re-arrange and clean up, then screenshot. fig.write_html("plotly.html") ```
mankoff commented 1 month ago

See https://github.com/mankoff/sankey/