From 7645240c94eade6160587433a5fe64f30a8f0823 Mon Sep 17 00:00:00 2001 From: Marc LABADIE Date: Mon, 26 Apr 2021 16:12:26 +0200 Subject: [PATCH 1/9] add transpose_dataframe function --- src/openalea/strawberry/analysis.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/openalea/strawberry/analysis.py b/src/openalea/strawberry/analysis.py index ee99dff..b3b3e30 100644 --- a/src/openalea/strawberry/analysis.py +++ b/src/openalea/strawberry/analysis.py @@ -820,4 +820,23 @@ def date(vid, g): # _date = g.property('Sample_date')[cpx] return g.property('Sample_date')[cpx] +######################### Transformation of dataframe ###################################### +def transpose_dataframe(df,date_selected,index,variable): + ''' + Transpose dataframe by variable with plant in columns and rank or order in index + This function are available for extraction at node scale (index='rank') and + extraction at module scale (index= 'order') + Parameters: + ----------- + df: dataframe from extract function at differente scale (modules and nodes scale) + date_selected: date which must be processed + variable: variable which must be processed + + Returns: + -------- + a dataframe transposed for date and variable processed + ''' + data=df[df['date']==date_selected] + res= data.pivot(index=index,columns='plant',values=variable) + return res From 1cf06e6589fd8afbcb3f8859d87fef26583a1e1d Mon Sep 17 00:00:00 2001 From: pomme-abricot Date: Wed, 28 Apr 2021 12:33:01 +0200 Subject: [PATCH 2/9] add waffle transformation & plot --- src/openalea/strawberry/analysis.py | 94 ++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/src/openalea/strawberry/analysis.py b/src/openalea/strawberry/analysis.py index b3b3e30..9d8e5d4 100644 --- a/src/openalea/strawberry/analysis.py +++ b/src/openalea/strawberry/analysis.py @@ -10,6 +10,11 @@ from openalea.mtg.algo import orders from openalea.mtg import stat, algo, traversal +import numpy as np +from matplotlib.colors import to_rgb +import matplotlib.patches as mpatches +import plotly.express as px + import six from six.moves import map from six.moves import range @@ -821,7 +826,7 @@ def date(vid, g): return g.property('Sample_date')[cpx] ######################### Transformation of dataframe ###################################### -def transpose_dataframe(df,date_selected,index,variable): +def df2waffle(df, date, index, variable, aggfunc=None, *args, **kwargs): ''' Transpose dataframe by variable with plant in columns and rank or order in index This function are available for extraction at node scale (index='rank') and @@ -837,6 +842,89 @@ def transpose_dataframe(df,date_selected,index,variable): a dataframe transposed for date and variable processed ''' - data=df[df['date']==date_selected] - res= data.pivot(index=index,columns='plant',values=variable) + data=df[df['date']==date] + + if index=='rank': + res = data.pivot(index='rank',columns='plant',values=variable) + elif index=='order': + res= data.pivot_table(index='order',columns='plant',values=variable, aggfunc=aggfunc) + + res = res.fillna('') + res = res.sort_index(ascending=False) return res + + +def plot_waffle(df, ylabel): + """ + Plot a dataframe in "waffle" shape + """ + + colormap_used = plt.cm.coolwarm + + # Sort the variables. When variables are int or float, remove the str('') (that replaced the NaN) before sorting + values = list(set(df.values.flatten())) + values.remove('') + values.sort() + values.insert(0,'') + + height = len(df.index) + width = len(df.columns) + color_map = {val: colormap_used(i/len(values)) for i, val in enumerate(values)} + + # Add the "empty" variable - and set its color as white + color_map[''] = (1., 1., 1., 1.) + + data = np.array(df) + + # Create an array where each cell is a colormap value RGBA + data_3d = np.ndarray(shape=(data.shape[0], data.shape[1], 4), dtype=float) + for i in range(0, data.shape[0]): + for j in range(0, data.shape[1]): + data_3d[i][j] = color_map[data[i][j]] + + # # drop the A + # data_3d_rgb = np.array([[to_rgb([v for v in row]) for row in col] for col in data_3d], dtype=np.float64) + + # create the plot + _t=list(range(1,height+1)) + _t.reverse() + fig = px.imshow(data_3d_rgb, + labels={'x': 'Plant', 'y': ylabel}, + ) + + + # OLD: Used matplotly + # display the plot + # fig, ax = plt.subplots(1,1) + # fig.set_size_inches(18.5, 10.5) + # fig = ax.imshow(data_3d) + +# # Get the axis. +# ax = plt.gca() + +# # Minor ticks +# ax.set_xticks(np.arange(-.5, (width), 1), minor=True); +# ax.set_yticks(np.arange(-.5, (height), 1), minor=True); + +# # Gridlines based on minor ticks +# ax.grid(which='minor', color='w', linestyle='-', linewidth=2) + +# # Manually constructing a legend solves your "catagorical" problem. +# legend_handles = [] +# for i, val in enumerate(values): +# if val!= "": +# lable_str = val +# color_val = color_map[val] +# legend_handles.append(mpatches.Patch(color=color_val, label=lable_str)) + +# # Add the legend. +# plt.legend(handles=legend_handles, loc=(1,0)) +# plt.xlabel("Plant") +# plt.ylabel(ylabel) + +# _t=list(range(1,height+1)) +# _t.reverse() +# plt.xticks(ticks=range(0,width), labels=range(1,width+1)) +# plt.yticks(ticks=range(0,height), labels=_t) + + return fig From 517ba388867f9aaeb06697c40a0875a80cbf55cc Mon Sep 17 00:00:00 2001 From: pomme-abricot Date: Wed, 28 Apr 2021 12:44:46 +0200 Subject: [PATCH 3/9] add df2waffle test --- src/openalea/strawberry/visu3d.py | 5 ----- test/test_waffle.py | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 test/test_waffle.py diff --git a/src/openalea/strawberry/visu3d.py b/src/openalea/strawberry/visu3d.py index 05afe49..a6de8b3 100644 --- a/src/openalea/strawberry/visu3d.py +++ b/src/openalea/strawberry/visu3d.py @@ -241,8 +241,3 @@ def color_code(g): nid.color = (0, int(127+127/(len(stades)-1)*(i)),255) else: nid.color = (153, 102, 51) - - -# 2D visualization -############################################################################# -# TODO: add visualization functions \ No newline at end of file diff --git a/test/test_waffle.py b/test/test_waffle.py new file mode 100644 index 0000000..b459366 --- /dev/null +++ b/test/test_waffle.py @@ -0,0 +1,26 @@ +from pathlib import Path +import os +from openalea.mtg.io import read_mtg_file, write_mtg +from openalea.strawberry.analysis import extract_at_node_scale, extract_at_module_scale +from openalea.deploy.shared_data import shared_data +import openalea.strawberry + +from openalea.strawberry.analysis import df2waffle + +def name(f): + return f.basename().splitext()[0] + +def test_df2waffle(): + files = shared_data(openalea.strawberry).glob('*.mtg') + mtg_path = dict((name(f), f) for f in files) + mtg = read_mtg_file(mtg_path['Capriss']) + + df = extract_at_node_scale(mtg) + + node_scale = df2waffle(df, index='rank', date='2015/03/02', variable='branching_type') + assert node_scale.shape == (20, 9) + + df = extract_at_module_scale(mtg) + module_scale=df2waffle(df, index='order', date='2015/03/02', variable='crown_status', aggfunc='median') + assert module_scale.shape == (3, 9) + From 133ab2a44b6d5edc4b2670e1003b52c96abd1d20 Mon Sep 17 00:00:00 2001 From: pomme-abricot Date: Fri, 30 Apr 2021 08:58:23 +0200 Subject: [PATCH 4/9] fix rgba to rgb for plot --- src/openalea/strawberry/analysis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openalea/strawberry/analysis.py b/src/openalea/strawberry/analysis.py index 9d8e5d4..ca6801d 100644 --- a/src/openalea/strawberry/analysis.py +++ b/src/openalea/strawberry/analysis.py @@ -883,7 +883,7 @@ def plot_waffle(df, ylabel): data_3d[i][j] = color_map[data[i][j]] # # drop the A - # data_3d_rgb = np.array([[to_rgb([v for v in row]) for row in col] for col in data_3d], dtype=np.float64) + data_3d_rgb = np.array([[to_rgb([v for v in row]) for row in col] for col in data_3d], dtype=np.float64) # create the plot _t=list(range(1,height+1)) From 5a2b0d702e4fb4a15d6f736eb2f2bfd78dcc9952 Mon Sep 17 00:00:00 2001 From: pomme-abricot Date: Wed, 5 May 2021 16:09:43 +0200 Subject: [PATCH 5/9] fix ploting waffle & add crosstab waffle type --- src/openalea/strawberry/analysis.py | 276 ++++++++++++++++++++-------- 1 file changed, 199 insertions(+), 77 deletions(-) diff --git a/src/openalea/strawberry/analysis.py b/src/openalea/strawberry/analysis.py index ca6801d..054f825 100644 --- a/src/openalea/strawberry/analysis.py +++ b/src/openalea/strawberry/analysis.py @@ -14,6 +14,8 @@ from matplotlib.colors import to_rgb import matplotlib.patches as mpatches import plotly.express as px +import plotly.graph_objs as go + import six from six.moves import map @@ -369,7 +371,8 @@ def _module_variables(g): module_variables['type_of_crown'] = type_of_crown # Type de crowns (Primary Crown:1, Branch crown:2 extension crown:3) module_variables['crown_status'] = Crown_status module_variables['complete_module'] = complete #(True: complete, False: incomplete) - + module_variables['stage']= stage + return module_variables @@ -604,6 +607,12 @@ def mean_leaf_area(vid,g): def complete(vid, g): return g.property("complete").get(vid, False) + +def stage(vid, g): + _stage = g.property('Stade') + return next(iter(list(_stage[cid] for cid in g.components(vid) if cid in _stage)), None) + + ########################## Extraction on node scale ############################################ def extract_at_node_scale(g, vids=[], convert=convert): @@ -617,7 +626,7 @@ def extract_at_node_scale(g, vids=[], convert=convert): orders = algo.orders(g,scale=2) # Define all the rows - props = ['node_id', 'rank', 'branching_type', 'complete','nb_modules_branching','nb_branch_crown_branching','nb_extension_crown_branching','branching_length', 'Genotype', 'order', 'date','plant'] + props = ['node_id', 'rank', 'branching_type', 'complete','nb_modules_branching','nb_branch_crown_branching','nb_extension_crown_branching','branching_length', 'stage', 'Genotype', 'order', 'date','plant'] for prop in props: node_df[prop] = [] @@ -640,6 +649,7 @@ def extract_at_node_scale(g, vids=[], convert=convert): node_df['order'].append(orders[g.complex(vid)]) #scale=2 node_df['plant'].append(plant(vid, g)) #scale=1 node_df['date'].append(date(vid, g)) #scale=1 + node_df['stage'].append(stage(vid, g)) # scale=3 df = pd.DataFrame(node_df) @@ -800,33 +810,13 @@ def nb_visible_leaves_tree(v, g): else: return sum(nb_visible_leaves(m,g) for m in module_tree(v, g)) -def genotype(vid, g): - cpx = g.complex_at_scale(vid, scale=1) - _genotype = property(g, 'Genotype')[cpx] - return _genotype - -def plant(vid, g): - cpx = g.complex_at_scale(vid, scale=1) - return property(g, 'Plante')[cpx] +def stage_tree(vid, g): + return list(stage(m,g) for m in module_tree(v, g)) -def date(vid, g): - # Capriss: 1:'2014/12/10', 2:'2015/01/07',3:'2015/02/15',4:'2015/03/02',5:'2015/04/03',6:'2015/05/27 - # Ciflorette: 1:'2014/12/04',2:'2015/01/07',3:'2015/02/13',4:'2015/03/02',5:'2015/03/30',6:'2015/05/27' - # Cir107: 1:'2014/12/10',2:'2015/01/08',3:'2015/02/11',4:'2015/03/04',5:'2015/04/02',6:'2015/05/20' - # Clery: 1:'2014/12/10', 2:'2015/01/07',3:'2015/02/15',4:'2015/03/02',5:'2015/04/03',6:'2015/05/27' - # Darselect: 1:'2014/12/10', 2:'2015/01/09', 3:'2015/02/11', 4:'2015/03/06',5:'2015/04/03',6:'2015/05/20' - # Gariguette: 1:'2014/12/10', 2:'2015/01/08', 3:'2015/02/12',4:'2015/03/06',5:'2015/04/02',6:'2015/05/19' - # d = {'2014/12/10':1,'2015/01/07':2,'2015/02/15':3,'2015/03/02':4,'2015/04/03':5,'2015/05/27':6, - # '2014/12/04':1,'2015/02/13':3,'2015/03/30':5, - # '2015/01/08':2,'2015/02/11':3,'2015/03/04':4,'2015/04/02':5,'2015/05/20':6, - # '2015/01/09':2,'2015/02/12':3,'2015/03/06':4,'2015/05/19':6} - cpx = g.complex_at_scale(vid, scale=1) - # _date = g.property('Sample_date')[cpx] - return g.property('Sample_date')[cpx] ######################### Transformation of dataframe ###################################### -def df2waffle(df, date, index, variable, aggfunc=None, *args, **kwargs): +def df2waffle(df, date, index, variable, aggfunc=None, crosstab=None, *args, **kwargs): ''' Transpose dataframe by variable with plant in columns and rank or order in index This function are available for extraction at node scale (index='rank') and @@ -839,7 +829,7 @@ def df2waffle(df, date, index, variable, aggfunc=None, *args, **kwargs): Returns: -------- - a dataframe transposed for date and variable processed + a dataframe in "waffle" shape: index=date, & columns=variable ''' data=df[df['date']==date] @@ -847,28 +837,134 @@ def df2waffle(df, date, index, variable, aggfunc=None, *args, **kwargs): if index=='rank': res = data.pivot(index='rank',columns='plant',values=variable) elif index=='order': - res= data.pivot_table(index='order',columns='plant',values=variable, aggfunc=aggfunc) + if crosstab: + res = pd.crosstab(index=data['order'], columns=data[variable], normalize='index') + res=res*100 # percentage (0-100) + res = res.round(2) + else: + # Catch data error: when values are string and aggfunc compute numbers + try: + res= data.pivot_table(index='order',columns='plant',values=variable, aggfunc=aggfunc) + except DataError: + print("ERROR, the aggregate function does not handle the data type (float func on str?)") + return pd.DataFrame() + + else: + res = data.pivot(index=index,columns='plant',values=variable) - res = res.fillna('') + # If use plotly heatmap -> comment "res = res.fillna('')" + if res.isnull().values.any(): + res = res.fillna('') res = res.sort_index(ascending=False) return res -def plot_waffle(df, ylabel): - """ - Plot a dataframe in "waffle" shape - """ +def plot_waffle_plotly_heatmap(df, layout={}, legend_name={}): + + def df_to_plotly(df): + return {'z': df.values.tolist(), + 'x': df.columns.tolist(), + 'y': df.index.tolist()} + + height = layout.get('height', 500) + width = layout.get('width', 500) + xlabel = layout.get('xlabel', 'Plant') + xticks = layout.get('xticks', range(0,len(df.columns))) + xticks_label = layout.get('xticks_label', range(1,len(df.columns)+1)) + ylabel = layout.get('ylabel', '') + yticks = layout.get('yticks', range(0,len(df.index))) + yticks_label = layout.get('yticks_label', list(range(0,len(df.index)))) + title = layout.get('title', '') + + hm_layout = go.Layout(plot_bgcolor='rgba(0,0,0,0)', + # xaxis=dict(zeroline=False), + # yaxis=dict(zeroline=False, ), + autosize=False, + width=width, height=height + ) + + data = go.Heatmap(df_to_plotly(df), + xgap=1, + ygap=1, + colorscale="aggrnyl" + ) + + fig = go.Figure(data=data, layout=hm_layout) + + return fig + +def plot_waffle_plotly_imshow(df, layout={}, legend_name={}): + colormap_used = plt.cm.coolwarm + + values = list(set(df.values.flatten())) + if '' in values: + values.remove('') + try: + values.sort() + except TypeError: + values = [str(i) for i in values] + values.sort() + values.insert(0,'') + + color_map = {val: colormap_used(i/len(values)) for i, val in enumerate(values)} + + # Add the "empty" variable - and set its color as white + color_map[''] = (1., 1., 1., 1.) + + data = np.array(df) + + # Create an array where each cell is a colormap value RGBA + data_3d = np.ndarray(shape=(data.shape[0], data.shape[1], 4), dtype=float) + for i in range(0, data.shape[0]): + for j in range(0, data.shape[1]): + data_3d[i][j] = color_map[data[i][j]] + + # drop the A + data_3d_rgb = np.array([[to_rgb([v for v in row]) for row in col] for col in data_3d], dtype=np.float64) + + yticks = list(range(0,data.shape[0])) + yticks.reverse() + + fig = px.imshow(data, + labels={'x':'Plant', 'y':'Node'}, + x=list(range(1,data.shape[1]+1)), + y=yticks, + origin='lower', + color_continuous_scale='aggrnyl', + # colorbar={} + ) + fig.update_layout(plot_bgcolor='rgba(0,0,0,0)', + ) + return fig + + +def plot_waffle_matplotlib(df, layout={}, legend_name={}): + height = layout.get('height', 18.5) + width = layout.get('width', 10.5) + xlabel = layout.get('xlabel', 'Plant') + xticks = layout.get('xticks', range(0,len(df.columns))) + xticks_label = layout.get('xticks_label', range(1,len(df.columns)+1)) + ylabel = layout.get('ylabel', '') + yticks = layout.get('yticks', range(0,len(df.index))) + yticks_label = layout.get('yticks_label', list(range(0,len(df.index)))) + title = layout.get('title', '') + colormap_used = plt.cm.coolwarm # Sort the variables. When variables are int or float, remove the str('') (that replaced the NaN) before sorting values = list(set(df.values.flatten())) - values.remove('') - values.sort() + if '' in values: + values.remove('') + try: + values.sort() + except TypeError: + values = [str(i) for i in values] + values.sort() values.insert(0,'') - height = len(df.index) - width = len(df.columns) + w_height = len(df.index) + w_width = len(df.columns) color_map = {val: colormap_used(i/len(values)) for i, val in enumerate(values)} # Add the "empty" variable - and set its color as white @@ -881,50 +977,76 @@ def plot_waffle(df, ylabel): for i in range(0, data.shape[0]): for j in range(0, data.shape[1]): data_3d[i][j] = color_map[data[i][j]] + +# display the plot + fig, ax = plt.subplots(1,1) + fig.set_size_inches(height, width) + fig = ax.imshow(data_3d) - # # drop the A - data_3d_rgb = np.array([[to_rgb([v for v in row]) for row in col] for col in data_3d], dtype=np.float64) + # Get the axis. + ax = plt.gca() + + # Minor ticks + ax.set_xticks(np.arange(-.5, (w_width), 1), minor=True); + ax.set_yticks(np.arange(-.5, (w_height), 1), minor=True); - # create the plot - _t=list(range(1,height+1)) - _t.reverse() - fig = px.imshow(data_3d_rgb, - labels={'x': 'Plant', 'y': ylabel}, - ) + # Gridlines based on minor ticks + ax.grid(which='minor', color='w', linestyle='-', linewidth=2) + # Manually constructing a legend solves your "catagorical" problem. + legend_handles = [] + + for i, val in enumerate(values): + if val!= "": + color_val = color_map[val] + legend_handles.append(mpatches.Patch(color=color_val, label=legend_name.get(val, val))) + + # Add the legend. + plt.legend(handles=legend_handles, loc=(1,0)) + plt.xlabel(xlabel) + plt.ylabel(ylabel) + + plt.xticks(ticks=xticks, labels=xticks_label) + plt.yticks(ticks=yticks, labels=yticks_label) - # OLD: Used matplotly - # display the plot - # fig, ax = plt.subplots(1,1) - # fig.set_size_inches(18.5, 10.5) - # fig = ax.imshow(data_3d) - -# # Get the axis. -# ax = plt.gca() - -# # Minor ticks -# ax.set_xticks(np.arange(-.5, (width), 1), minor=True); -# ax.set_yticks(np.arange(-.5, (height), 1), minor=True); - -# # Gridlines based on minor ticks -# ax.grid(which='minor', color='w', linestyle='-', linewidth=2) - -# # Manually constructing a legend solves your "catagorical" problem. -# legend_handles = [] -# for i, val in enumerate(values): -# if val!= "": -# lable_str = val -# color_val = color_map[val] -# legend_handles.append(mpatches.Patch(color=color_val, label=lable_str)) - -# # Add the legend. -# plt.legend(handles=legend_handles, loc=(1,0)) -# plt.xlabel("Plant") -# plt.ylabel(ylabel) - -# _t=list(range(1,height+1)) -# _t.reverse() -# plt.xticks(ticks=range(0,width), labels=range(1,width+1)) -# plt.yticks(ticks=range(0,height), labels=_t) + plt.title(title) + + return fig + + +def plot_waffle(df, layout={}, legend_name={}, savepath=None, plot_func='matplotlib'): + """ + Plot a dataframe in "waffle" shape + + layout: dict of layout parameters: + height/width: size of the picture in inch + x/ylabel: label of the x/y axis + x/yticks: ticks of the x/y axis + x/yticks_labels: labels of the ticks on the x/y axis + title: title + plot_func: library used for the ploting: + matplotlib: matplotlib.pyplot.subplot.imshow + plotly.imshow: plotly.express.imshow + plotly.heatmap: plotly.graph_objs.heatmap + """ + + ## Axes not working - Plotly heatmap + if plot_func=='plotly.heatmap': + fig= plot_waffle_plotly_heatmap(df=df, layout=layout, legend_name=legend_name) + + # Plotly imshow + elif plot_func=='plotly.imshow': + fig= plot_waffle_plotly_imshow(df=df, layout=layout, legend_name=legend_name) + + # With matplotlib + elif plot_func=='matplotlib': + fig= plot_waffle_matplotlib(df=df, layout=layout, legend_name=legend_name) + + if savepath: + plt.savefig(savepath) return fig + + +def plot_pie(df): + return px.pie(df, values=df.mean(axis=0), names=df.columns) From 64ffbbf1c805507d8f497e838954ee3a36541941 Mon Sep 17 00:00:00 2001 From: pomme-abricot Date: Tue, 11 May 2021 17:50:56 +0200 Subject: [PATCH 6/9] fix default waffle plot layout --- src/openalea/strawberry/analysis.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/openalea/strawberry/analysis.py b/src/openalea/strawberry/analysis.py index 054f825..a0c4cf5 100644 --- a/src/openalea/strawberry/analysis.py +++ b/src/openalea/strawberry/analysis.py @@ -10,6 +10,8 @@ from openalea.mtg.algo import orders from openalea.mtg import stat, algo, traversal +from pandas.core.groupby.groupby import DataError + import numpy as np from matplotlib.colors import to_rgb import matplotlib.patches as mpatches @@ -816,7 +818,7 @@ def stage_tree(vid, g): ######################### Transformation of dataframe ###################################### -def df2waffle(df, date, index, variable, aggfunc=None, crosstab=None, *args, **kwargs): +def df2waffle(df, date, index, variable, order=None, aggfunc=None, crosstab=None, *args, **kwargs): ''' Transpose dataframe by variable with plant in columns and rank or order in index This function are available for extraction at node scale (index='rank') and @@ -832,14 +834,17 @@ def df2waffle(df, date, index, variable, aggfunc=None, crosstab=None, *args, **k a dataframe in "waffle" shape: index=date, & columns=variable ''' - data=df[df['date']==date] + if order: + data=df[(df['date']==date) & (df['order']==order)] + else: + data=df[df['date']==date] if index=='rank': res = data.pivot(index='rank',columns='plant',values=variable) elif index=='order': if crosstab: res = pd.crosstab(index=data['order'], columns=data[variable], normalize='index') - res=res*100 # percentage (0-100) + res=res*100 res = res.round(2) else: # Catch data error: when values are string and aggfunc compute numbers @@ -859,6 +864,7 @@ def df2waffle(df, date, index, variable, aggfunc=None, crosstab=None, *args, **k return res + def plot_waffle_plotly_heatmap(df, layout={}, legend_name={}): def df_to_plotly(df): @@ -870,9 +876,9 @@ def df_to_plotly(df): width = layout.get('width', 500) xlabel = layout.get('xlabel', 'Plant') xticks = layout.get('xticks', range(0,len(df.columns))) - xticks_label = layout.get('xticks_label', range(1,len(df.columns)+1)) + xticks_label = layout.get('xticks_label', list(df.columns)) ylabel = layout.get('ylabel', '') - yticks = layout.get('yticks', range(0,len(df.index))) + yticks = layout.get('yticks', [l-1 for l in list(df.index)]) yticks_label = layout.get('yticks_label', list(range(0,len(df.index)))) title = layout.get('title', '') @@ -1011,6 +1017,8 @@ def plot_waffle_matplotlib(df, layout={}, legend_name={}): plt.title(title) + plt.show() + return fig @@ -1040,7 +1048,10 @@ def plot_waffle(df, layout={}, legend_name={}, savepath=None, plot_func='matplot # With matplotlib elif plot_func=='matplotlib': - fig= plot_waffle_matplotlib(df=df, layout=layout, legend_name=legend_name) + try: + fig= plot_waffle_matplotlib(df=df, layout=layout, legend_name=legend_name) + except ValueError: + fig={} if savepath: plt.savefig(savepath) From 6398e723832fa08b87b20ff1165a9d63bd08c9c3 Mon Sep 17 00:00:00 2001 From: pomme-abricot Date: Tue, 25 May 2021 08:31:22 +0200 Subject: [PATCH 7/9] change default layout for waffle plot --- src/openalea/strawberry/analysis.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/openalea/strawberry/analysis.py b/src/openalea/strawberry/analysis.py index a0c4cf5..65540cf 100644 --- a/src/openalea/strawberry/analysis.py +++ b/src/openalea/strawberry/analysis.py @@ -946,13 +946,13 @@ def plot_waffle_plotly_imshow(df, layout={}, legend_name={}): def plot_waffle_matplotlib(df, layout={}, legend_name={}): - height = layout.get('height', 18.5) - width = layout.get('width', 10.5) + height = layout.get('height', 500) + width = layout.get('width', 500) xlabel = layout.get('xlabel', 'Plant') xticks = layout.get('xticks', range(0,len(df.columns))) - xticks_label = layout.get('xticks_label', range(1,len(df.columns)+1)) + xticks_label = layout.get('xticks_label', list(df.columns)) ylabel = layout.get('ylabel', '') - yticks = layout.get('yticks', range(0,len(df.index))) + yticks = layout.get('yticks', [l-1 for l in list(df.index)]) yticks_label = layout.get('yticks_label', list(range(0,len(df.index)))) title = layout.get('title', '') From 1213ffe62a1d2fcf3332d575c3bbf38f0a2f26da Mon Sep 17 00:00:00 2001 From: pomme-abricot Date: Tue, 25 May 2021 14:50:39 +0200 Subject: [PATCH 8/9] fix import order --- src/openalea/strawberry/analysis.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/openalea/strawberry/analysis.py b/src/openalea/strawberry/analysis.py index 65540cf..0b5ee47 100644 --- a/src/openalea/strawberry/analysis.py +++ b/src/openalea/strawberry/analysis.py @@ -7,9 +7,6 @@ import matplotlib.pyplot as plt from itertools import chain -from openalea.mtg.algo import orders -from openalea.mtg import stat, algo, traversal - from pandas.core.groupby.groupby import DataError import numpy as np @@ -18,11 +15,13 @@ import plotly.express as px import plotly.graph_objs as go - import six from six.moves import map from six.moves import range +from openalea.mtg.algo import orders +from openalea.mtg import stat, algo, traversal + convert = dict(Stade='Stade', Fleurs_ouverte='FLWRNUMBER_OPEN', From 71d56b112b8836679a13b2c072b774d7ae759e90 Mon Sep 17 00:00:00 2001 From: pomme-abricot Date: Tue, 25 May 2021 15:59:44 +0200 Subject: [PATCH 9/9] fix iter list for stage --- src/openalea/strawberry/analysis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openalea/strawberry/analysis.py b/src/openalea/strawberry/analysis.py index 0b5ee47..b260c86 100644 --- a/src/openalea/strawberry/analysis.py +++ b/src/openalea/strawberry/analysis.py @@ -611,7 +611,7 @@ def complete(vid, g): def stage(vid, g): _stage = g.property('Stade') - return next(iter(list(_stage[cid] for cid in g.components(vid) if cid in _stage)), None) + return next((_stage[cid] for cid in g.components(vid) if cid in _stage), None) ########################## Extraction on node scale ############################################