diff --git a/lineage/Lineage_collections.py b/lineage/Lineage_collections.py index 4b66dad09..dc68cac50 100644 --- a/lineage/Lineage_collections.py +++ b/lineage/Lineage_collections.py @@ -1,7 +1,7 @@ """ This file is to collect those lineages that have the same condition, and have 3 or greater number of cells in their lineages. """ from .LineageInputOutput import import_exp_data -from .import_lineage import MCF10A +from .import_lineage import MCF10A, import_taxol from .states.StateDistributionGaPhs import StateDistribution from .states.StateDistributionGamma import StateDistribution as StDist from .LineageTree import LineageTree @@ -217,3 +217,15 @@ def popout_single_lineages(lineages): AllLapatinib = [Lapatinib_Control + Gemcitabine_Control, Lapt25uM, Lapt50uM, Lap250uM] AllGemcitabine = [Lapatinib_Control + Gemcitabine_Control, Gem5uM, Gem10uM, Gem30uM] GFs = [pbs, egf, hgf, osm] + +########################################################## +# NEW PACLITAXEL DATA +untreated, taxol_05, taxol_1, taxol_15, taxol_2, taxol_25, taxol_3, taxol_4 = import_taxol() +# 555, 1119, 486, 382, 272, 365, 246, 266 +untreated_taxol = [LineageTree(list_cells, E) for list_cells in untreated] # 555 cells +Taxol_1 = [LineageTree(list_cells, E) for list_cells in taxol_1] # 486 cells +Taxol_2 = [LineageTree(list_cells, E) for list_cells in taxol_2] # 272 cells +Taxol_3 = [LineageTree(list_cells, E) for list_cells in taxol_3] # 246 cells +Taxol_4 = [LineageTree(list_cells, E) for list_cells in taxol_4] # 266 cells + +taxols = [untreated_taxol, Taxol_1, Taxol_2, Taxol_4] \ No newline at end of file diff --git a/lineage/figures/figureS18.py b/lineage/figures/figureS18.py new file mode 100644 index 000000000..3d43942ea --- /dev/null +++ b/lineage/figures/figureS18.py @@ -0,0 +1,45 @@ +""" In this file we plot the raw data before fitting from paclitaxel treated HCC1143 cells """ +# from ..Lineage_collections import taxols as Taxol_lin_list +import numpy as np +from ..import_lineage import import_taxol_file, trim_taxol +from ..plotTree import plotLineage +from .common import getSetup +from string import ascii_lowercase +from ..states.StateDistributionGaPhs import StateDistribution +from ..LineageTree import LineageTree + +desired_num_states = 2 +E = [StateDistribution() for _ in range(desired_num_states)] +untreated_t = import_taxol_file() +untreated_taxol = [LineageTree(list_cells, E) for list_cells in untreated_t] +c = 0 +for lins in untreated_t: + for cell in lins: + c += 1 +# counts = len(untreated_taxol) +counts = 100 +print("number of lineages", len(untreated_taxol), " and the number of total cells: ", c) + +def makeFigure(): + """ + Makes figure S18. + """ + titles = ["Untreated", "Taxol 1 nM", "Taxol 2 nM", "Taxol 3 nM", "Taxol 4 nM"] + ax, f = getSetup((17, 35), (counts, 4)) + + for i in range(counts): + ax[4 * i].axis('off') + # ax[4 * i + 1].axis('off') + # ax[4 * i + 2].axis('off') + # ax[4 * i + 3].axis('off') + plotLineage(untreated_taxol[i], ax[4 * i], color=False) + # plotLineage(Taxol_lin_list[1][i], ax[4 * i + 1], color=False) + # plotLineage(Taxol_lin_list[2][i], ax[4 * i + 2], color=False) + # plotLineage(Taxol_lin_list[3][i], ax[4 * i + 3], color=False) + + for i in range(4): + ax[i].axis('off') + ax[i].text(-0.2, 1.55, ascii_lowercase[i], transform=ax[i].transAxes, fontsize=20, fontweight="bold", va="top") + ax[i].text(0.0, 1.55, titles[i], transform=ax[i].transAxes, fontsize=20, va="top") + + return f \ No newline at end of file diff --git a/lineage/figures/figureS19.py b/lineage/figures/figureS19.py new file mode 100644 index 000000000..a7aaccb72 --- /dev/null +++ b/lineage/figures/figureS19.py @@ -0,0 +1,35 @@ +""" BIC for Taxol data.""" +from ..Lineage_collections import taxols as Taxol_lin_list +from ..Analyze import run_Analyze_over, Analyze_list +from .common import getSetup +from .figure9 import find_BIC + +import pickle +import numpy as np +from matplotlib.ticker import MaxNLocator + +desired_num_states = np.arange(1, 8) + +def makeFigure(): + """ + Makes figure 9. + """ + ax, f = getSetup((14, 4), (1, 3)) + + BIC, Obj = find_BIC(Taxol_lin_list, desired_num_states, num_cells=1041) + + # create a pickle file + pik1 = open("taxols.pkl", "wb") + for taxol_tHMMobj_list in Obj: + for laps in taxol_tHMMobj_list: + pickle.dump(laps, pik1) + pik1.close() + + i = 0 + ax[i].set_xlabel("Number of States Predicted") + ax[i].set_ylabel("Normalized BIC") + ax[i].xaxis.set_major_locator(MaxNLocator(integer=True)) + + ax[0].set_title("Taxol Treated Populations") + + return f \ No newline at end of file diff --git a/lineage/import_lineage.py b/lineage/import_lineage.py index 479997436..15fc9ad02 100644 --- a/lineage/import_lineage.py +++ b/lineage/import_lineage.py @@ -1,6 +1,7 @@ """ This file includes functions to import the new lineage data. """ import pandas as pd import itertools +from copy import copy import numpy as np from .CellVar import CellVar @@ -227,3 +228,283 @@ def MCF10A(condition: str): else: raise ValueError("condition does not exist. choose between [PBS, EGF, HGF, OSM]") + + +def assign_observs_Taxol(cell, cell_lineage, label: int): + """Given a cell, the lineage, and the unique id of the cell, it assigns the observations of that cell, and returns it. + :param cell: a CellVar object to be assigned observations. + :param cell_lineage: the dataframe of cells in a file. + :param label: the id given to the cell from the experiment. + """ + # initialize + cell.obs = [1, 1, 0, 0, 1, 1] # [G1_fate, S_G2_fate, G1_length, SG2_length, G1_censored?, SG2_censored?] + t_end = 5760 + + all_parent_ids = cell_lineage["parent"].unique() + cell_df = cell_lineage.loc[cell_lineage["label"] == label] + + parent_id = cell_df["parent"].unique()[0] + if parent_id == 0: + cell.gen = 1 + + threshold = 0.7 # greater than this ==> SG2 + G1_df = cell_df.loc[cell_df['Cell_CC_mean_intensity_ratio'] <= threshold] + SG2_df = cell_df.loc[cell_df['Cell_CC_mean_intensity_ratio'] > threshold] + + ## G1 calculations: + if G1_df.empty: + # means the cell has no G1 component + cell.obs[0] = np.nan # if no G1, then there is SG2, so it has definitely transitioned from G1 to SG2 + cell.obs[2] = np.nan + cell.obs[4] = np.nan + + else: + # G1 length + cell.obs[2] = (np.nanmax(G1_df["elapsed_minutes"]) - np.nanmin(G1_df["elapsed_minutes"])) / 60 # G1 duration + if np.nanmin(G1_df["elapsed_minutes"]) == 0: # means left censored + cell.obs[4] = 0 + if not(SG2_df.empty): # has transitioned from G1 -> SG2 + cell.obs[0] = 1 + + if np.nanmax(G1_df["elapsed_minutes"]) == t_end: # cell existed and the experiment ended + cell.obs[4] = 0 + assert not(label in all_parent_ids) # definitely is not a parent because we reached end of exp + cell.obs[0] = np.nan + + if np.nanmax(G1_df["elapsed_minutes"]) < t_end and SG2_df.empty: # cell died in G1 + cell.obs[0] = 0 + + ## SG2 calculations: + if SG2_df.empty: + # means the cell has no SG2 component + cell.obs[1] = np.nan + cell.obs[3] = np.nan + cell.obs[5] = np.nan + else: + # SG2 length + cell.obs[3] = (np.nanmax(SG2_df["elapsed_minutes"]) - np.nanmin(SG2_df["elapsed_minutes"])) / 60 # SG2 + if np.nanmin(SG2_df["elapsed_minutes"]) == 0: # cell existed when the experiment started + cell.obs[5] = 0 + if label in all_parent_ids: + cell.obs[1] = 1 + + if np.nanmax(SG2_df["elapsed_minutes"]) == t_end: # cell existed and the experiment ended + cell.obs[5] = 0 + assert not(label in all_parent_ids) # definitely is not a parent because we reached end of exp + cell.obs[1] = np.nan + + if np.nanmax(SG2_df["elapsed_minutes"]) < t_end and not(label in all_parent_ids): # cell died in SG2 + cell.obs[1] = 0 + + return cell + +### The following two functions are used to make a list from labels that belong to the same lineage +def sep_lineages(data): + labels = list(data["label"].unique()) + all_parent_ids = list(data["parent"].unique()) + root_parent_labels = data.loc[data["parent"] == 0]["label"].unique() + lin = [[[item]] for item in root_parent_labels] + + # remove singleton lineages that only existed in 1 frame + xxx = 0 + remains = [] + for value in root_parent_labels: + dff = data.loc[data["label"]==value] + if len(dff) == 1: + # print(dff[["label", "well", "field", "time_slice", "row", "column", "plateID"]]) + xxx += 1 + lin.remove([[value]]) + elif len(dff) > 1: + remains.append(value) + + for i, val in enumerate(remains): + df = data.loc[data["label"]==val] # cell itself + # if it only appeard in one frame, discard + assert len(df) > 1 + + # if it has divided + if np.all(df["is_parent"] == True): + assert val in all_parent_ids + df_children = data.loc[data["parent"] == val] # cell's children + # if the cell has two children + child_labels = list(df_children["label"].unique()) + if len(child_labels) == 2: + lin[i] += [child_labels] + else: + print("not two children. cell label: ", val, "child label: ", child_labels) + else: + # singleton lineage + continue + print("number of cells that only appear in 1 frame: ", xxx) + + out1 = separate_lineages(data, all_parent_ids, lin, 2) + out2 = separate_lineages(data, all_parent_ids, out1, 3) + out3 = separate_lineages(data, all_parent_ids, out2, 4) + out4 = separate_lineages(data, all_parent_ids, out3, 5) + out5 = separate_lineages(data, all_parent_ids, out4, 6) + + return out5 + +def separate_lineages(data, all_parent_ids, ls, k): + """Given the lineages that only includes up to k generations of cells, add the k+1 generation to those lineages that have it.""" + lss = ls.copy() + for j, val in enumerate(ls): + if len(val) == k: + temp = [] + k_th = val[k-1] + for i in k_th: + if np.isnan(i): + temp += [np.nan, np.nan] + else: + if i in all_parent_ids: + if len(data.loc[data["parent"]==i]["label"].unique()) == 2: + temp += list(data.loc[data["parent"]==i]["label"].unique()) + else: + temp += [np.nan, np.nan] + else: + temp += [np.nan, np.nan] + else: + continue + if np.all(np.isnan(temp)): + pass + else: + lss[j].append(temp) + return lss + + +def import_taxol_file(filename="HC00801_A1_field_1_level_1.csv"): + """To import the new Taxol data""" + + data = pd.read_csv("lineage/data/taxol/"+filename) + + lineage_codes = sep_lineages(data) + lineages = [] + for i, lin in enumerate(lineage_codes): + + parent_cell = CellVar(parent=None) + parent_cell = assign_observs_Taxol(parent_cell, data, lin[0][0]) + lin_temp = [[parent_cell]] + + if len(lin) >= 2: + for kk in range(1, len(lin)): + tmp = [] # for each lineage + for ix, l in enumerate(lin[kk]): + if ix % 2 == 1: # only iterate through one of two daughter cells + pass + else: + if not np.isnan(l): + cell = lin_temp[kk-1][int(ix/2)] + if type(cell) == CellVar: + a = assign_observs_Taxol(CellVar(parent=cell), data, l) + b = assign_observs_Taxol(CellVar(parent=cell), data, lin[kk][ix+1]) + cell.left = a + cell.right = b + tmp.append([cell.left, cell.right]) + else: + tmp.append([np.nan, np.nan]) + else: + tmp.append([np.nan, np.nan]) + + lin_temp.append(list(itertools.chain(*tmp))) + lineages.append(list(itertools.chain(*lin_temp))) + new_lins = [] + counts_ = 0 + # remove nans + for jj, lin in enumerate(lineages): + n = [x for x in lin if str(x) != 'nan'] + + for kk, cells in enumerate(n): + # remove those lineages with cells that have NaN intensity ratio + if np.all(np.isnan(cells.obs[2:4])): + counts_ += 1 + n = [] + break + else: + pass + + new_lins.append(n) + print("this is counts of NaN ratio lineages", counts_) + + # remove empty lineages and return + return [s for s in new_lins if s] + +def trim_taxol(lineages): + """removed messed up lineages. e.g., those that divided but either didn't have G1 or SG2 although were in middle generations.. """ + + trimed_lineages = copy(lineages) + counts, countsG1, countsG2 = 0, 0, 0 + for ix, lin in enumerate(lineages): + rm = 0 + for cell in lin: + # cells with only one daughter + if not(cell.left and cell.right) and not(cell.isLeaf()): + rm += 1 + counts += 1 + + # if it divided + if cell.left: + assert cell.right + # but also died in either phase + if cell.obs[0] == 0: + # discrepancy... get rid of the lineage + rm += 1 + countsG1 += 1 + elif cell.obs[1] == 0: + countsG2 += 1 + + # # if it didn't start the lineage, and doesn't have a G1, remove lineage + if cell.gen > 1: + if (np.isnan(cell.obs[2]) or cell.obs[2] == 0.0) and cell.obs[3] > 0.0: + rm += 1 + counts += 1 + break + + if rm > 0: + trimed_lineages.remove(lin) + # print("number of cells that divided but also died G1: ", countsG1, "For G2: ", countsG2) + # print("number of cells that started their cycle with SG2: ", counts) + return [x for x in trimed_lineages if x] + + +def import_taxol(HC="HC00801"): + """Import taxol data by condition""" + untreated = [trim_taxol(import_taxol_file(HC + "_A1_field_1_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_A1_field_2_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_A1_field_4_level_1.csv"))] + + taxol_05 = [trim_taxol(import_taxol_file(HC + "_A2_field_1_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_A2_field_2_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_A2_field_3_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_A2_field_4_level_1.csv"))] + + taxol_1 = [trim_taxol(import_taxol_file(HC + "_B1_field_1_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_B1_field_2_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_B1_field_3_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_B1_field_4_level_1.csv"))] + + taxol_15 = [trim_taxol(import_taxol_file(HC + "_B2_field_1_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_B2_field_2_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_B2_field_3_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_B2_field_4_level_1.csv"))] + + taxol_2 = [trim_taxol(import_taxol_file(HC + "_C1_field_1_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_C1_field_2_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_C1_field_3_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_C1_field_4_level_1.csv"))] + + taxol_25 = [trim_taxol(import_taxol_file(HC + "_C2_field_1_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_C2_field_2_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_C2_field_3_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_C2_field_4_level_1.csv"))] + + taxol_3 = [trim_taxol(import_taxol_file(HC + "_D1_field_1_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_D1_field_2_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_D1_field_3_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_D1_field_4_level_1.csv"))] + + taxol_4 = [trim_taxol(import_taxol_file(HC + "_D2_field_1_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_D2_field_2_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_D2_field_3_level_1.csv")) + + trim_taxol(import_taxol_file(HC + "_D2_field_4_level_1.csv"))] + + return untreated, taxol_05, taxol_1, taxol_15, taxol_2, taxol_25, taxol_3, taxol_4 diff --git a/lineage/plotTree.py b/lineage/plotTree.py index 3d7d36b9a..bf85509a4 100644 --- a/lineage/plotTree.py +++ b/lineage/plotTree.py @@ -92,9 +92,11 @@ def plotLineage(lineage, axes, censor=True, color=True): else: length = root.obs[2] assert np.isfinite(length) - else: # the lineage starts from S/G2 phase + elif np.isfinite(root.obs[5]): # the lineage starts from S/G2 phase length = root.obs[3] assert np.isfinite(length) + else: + length=0.01 a = [Clade(length)] # input the root cell @@ -487,6 +489,10 @@ def draw_clade(clade, x_start, color, lw): axes.set_ylabel("taxa") # Add margins around the tree to prevent overlapping the axes xmax = max(x_posns.values()) + if xmax <= 1.0: + xmax = 1.0 + else: + pass axes.set_xlim(-0.05 * xmax, 1.25 * xmax) # Also invert the y-axis (origin at the top) # Add a small vertical margin, but avoid including 0 and N+1 on the y axis diff --git a/output/figureS18.svg b/output/figureS18.svg new file mode 100644 index 000000000..f02105279 --- /dev/null +++ b/output/figureS18.svg @@ -0,0 +1,18987 @@ + + + + + + + + 2023-01-12T10:53:03.790247 + image/svg+xml + + + Matplotlib v3.6.1, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a + + + Untreated + + + + + + + + + + + + + + + + + + + + + + + + + + b + + + Taxol 1 nM + + + + + + + + + + + + + + + + + + + + + + + + + + c + + + Taxol 2 nM + + + + + + + + + + + + + + + + + + + + + + + + + + d + + + Taxol 3 nM + + + + + + + + + + + + + + + + + + + + + + + + + + e + + + Taxol 4 nM + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +