Skip to content

Commit

Permalink
added residual plot and cleaned up a little
Browse files Browse the repository at this point in the history
  • Loading branch information
j-brady committed Mar 19, 2024
1 parent 305c18d commit a31da53
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 244 deletions.
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.PHONY: test

test:
pytest test/test_core.py
pytest test/test_main.py
pytest test/test_fit.py
pytest test/test_cli.py
24 changes: 16 additions & 8 deletions peakipy/cli/check_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,15 @@ def get_cluster(cluster):
return df_pane


@dataclass
class PlotContainer:
main_figure: pn.pane.Plotly
residual_figure: pn.pane.Plotly


def create_plotly_pane(cluster, plane):
data = data_singleton()
fig = check(
fig, residual_fig = check(
fits=data.fits_path,
data_path=data.data_path,
clusters=[cluster],
Expand All @@ -69,7 +75,8 @@ def create_plotly_pane(cluster, plane):

fig["layout"].update(height=800, width=800)
fig = fig.to_dict()
return pn.pane.Plotly(fig)
residual_fig = residual_fig.to_dict()
return pn.Column(pn.pane.Plotly(fig), pn.pane.Plotly(residual_fig))


app = typer.Typer()
Expand All @@ -96,22 +103,23 @@ def create_check_panel(
select_plane = pn.widgets.Select(
name="Plane", options={f"{plane}": plane for plane in data.df.plane.unique()}
)
interactive_cluster_pane = pn.bind(get_cluster, select_cluster)
result_table_pane = pn.bind(get_cluster, select_cluster)
interactive_plotly_pane = pn.bind(
create_plotly_pane, cluster=select_cluster, plane=select_plane
)
info_pane = pn.pane.Markdown(
"Select a cluster and plane to look at from the dropdown menus"
)
check_pane = pn.Card(
info_pane,
pn.Row(select_cluster, select_plane),
# info_pane,
# pn.Row(select_cluster, select_plane),
pn.Row(
pn.Column(
pn.Card(interactive_plotly_pane, title="Fitted cluster"),
pn.Card(
interactive_cluster_pane, title="Fitted parameters for cluster"
pn.Row(
pn.Card(interactive_plotly_pane, title="Fitted cluster"),
pn.Column(info_pane, select_cluster, select_plane),
),
pn.Card(result_table_pane, title="Fitted parameters for cluster"),
)
),
title="Peakipy check",
Expand Down
27 changes: 8 additions & 19 deletions peakipy/cli/edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,14 @@

import panel as pn

from bokeh.io import curdoc
from bokeh.events import ButtonClick, DoubleTap
from bokeh.layouts import row, column, grid
from bokeh.models import ColumnDataSource, Tabs, TabPanel, InlineStyleSheet
from bokeh.layouts import row, column
from bokeh.models import ColumnDataSource
from bokeh.models.tools import HoverTool
from bokeh.models.widgets import (
Slider,
Select,
Button,
DataTable,
TableColumn,
NumberFormatter,
NumberEditor,
IntEditor,
SelectEditor,
TextInput,
RadioButtonGroup,
CheckboxGroup,
Expand Down Expand Up @@ -136,9 +129,15 @@ def tabulator_columns(self):
]
return columns

@property
def tabulator_non_editable_columns(self):
editors = {"X_RADIUS_PPM": None, "Y_RADIUS_PPM": None}
return editors

def make_tabulator_widget(self):
self.tablulator_widget = pn.widgets.Tabulator(
self.peakipy_data.df[self.tabulator_columns],
editors=self.tabulator_non_editable_columns,
)
return self.tablulator_widget

Expand Down Expand Up @@ -321,10 +320,7 @@ def setup_plot(self):
self.contour_start = TextInput(
value="%.2e" % self.thres, title="Contour level:", width=100
)
# contour_factor = Slider(title="contour factor", value=1.20, start=1., end=2.,step=0.05)
self.contour_start.on_change("value", self.update_contour)
# for w in [contour_num,contour_start,contour_factor]:
# w.on_change("value",update_contour)

#  plot mask outlines
el = self.p.ellipse(
Expand Down Expand Up @@ -540,13 +536,6 @@ def fit_selected(self, event):
selectionIndex = self.source.selected.indices
current = self.peakipy_data.df.iloc[selectionIndex]

# self.peakipy_data.df.loc[selectionIndex, "X_RADIUS_PPM"] = (
# self.slider_X_RADIUS.value
# )
# self.peakipy_data.df.loc[selectionIndex, "Y_RADIUS_PPM"] = (
# self.slider_Y_RADIUS.value
# )

self.peakipy_data.df.loc[selectionIndex, "X_DIAMETER_PPM"] = (
current["X_RADIUS_PPM"] * 2.0
)
Expand Down
4 changes: 2 additions & 2 deletions peakipy/cli/edit_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ def fit_peaks_button_click(event):
button.on_click(fit_peaks_button_click)

def update_source_selected_indices(event):
print(event)
print(bs.tablulator_widget.selection)
# print(event)
# print(bs.tablulator_widget.selection)
bs.source.selected.indices = bs.tablulator_widget.selection

bs.tablulator_widget.on_click(update_source_selected_indices)
Expand Down
62 changes: 21 additions & 41 deletions peakipy/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,6 @@ def read(
"""

# verbose_mode = args.get("--verb")
# if verbose_mode:
# print("Using arguments:", args)

clust_args = {
"struc_el": struc_el,
"struc_size": struc_size,
Expand All @@ -241,7 +237,6 @@ def read(
posF1=y_ppm_column_name,
posF2=x_ppm_column_name,
)
# peaks.adaptive_clusters(block_size=151,offset=0)

case peaklist_format.a3:
peaks = Peaklist(
Expand Down Expand Up @@ -292,9 +287,6 @@ def read(
if fuda:
peaks.to_fuda()

# if verbose_mode:
# print(data.head())

match outfmt.value:
case "csv":
outname = outname.with_suffix(".csv")
Expand Down Expand Up @@ -1053,12 +1045,10 @@ def create_matplotlib_figure(
# axes will appear inverted
ax.view_init(30, 120)

# names = ",".join(plane.assignment)
title = f"Plane={plot_data.plane_id},Cluster={plot_data.plane_lineshape_parameters.clustid.iloc[0]}"
plt.title(title)
print(f"[green]Plotting: {title}[/green]")
out_str = "Volumes (Heights)\n===========\n"
# chi2s = []
for _, row in plot_data.plane_lineshape_parameters.iterrows():
out_str += f"{row.assignment} = {row.amp:.3e} ({row.height:.3e})\n"
if label:
Expand Down Expand Up @@ -1199,20 +1189,30 @@ def create_plotly_surfaces(plot_data: PlottingDataForPlane):


def create_residual_contours(plot_data: PlottingDataForPlane):
data = []
contours = go.Contour(x=plot_data.x_plot, y=plot_data.y_plot, z=plot_data.residual)
data.append(contours)
return data
contours = go.Contour(
x=plot_data.x_plot[0], y=plot_data.y_plot.T[0], z=plot_data.residual
)
return contours


def create_residual_figure(plot_data: PlottingDataForPlane):
data = create_residual_contours(plot_data)
fig = go.Figure(data=data)
fig.update_layout(
title="Fit residuals",
xaxis_title=f"{plot_data.pseudo3D.f2_label} ppm",
yaxis_title=f"{plot_data.pseudo3D.f1_label} ppm",
xaxis=dict(range=[plot_data.x_plot.max(), plot_data.x_plot.min()]),
yaxis=dict(range=[plot_data.y_plot.max(), plot_data.y_plot.min()]),
)
return fig


def create_plotly_figure(plot_data: PlottingDataForPlane):
lines = create_plotly_wireframe_lines(plot_data)
surfaces = create_plotly_surfaces(plot_data)
# residuals = create_residual_contours(plot_data)
fig = go.Figure(data=lines + surfaces)
# layout = go.Layout(showlegend=True)
# fig.update_layout(layout)
# fig.update_traces(showlegend=True)
fig = update_axis_ranges(fig, plot_data)
return fig

Expand All @@ -1222,6 +1222,8 @@ def update_axis_ranges(fig, plot_data: PlottingDataForPlane):
scene=dict(
xaxis=dict(range=[plot_data.x_plot.max(), plot_data.x_plot.min()]),
yaxis=dict(range=[plot_data.y_plot.max(), plot_data.y_plot.min()]),
xaxis_title=f"{plot_data.pseudo3D.f2_label} ppm",
yaxis_title=f"{plot_data.pseudo3D.f1_label} ppm",
annotations=make_annotations(plot_data),
)
)
Expand Down Expand Up @@ -1474,41 +1476,19 @@ def check(
# fig = create_plotly_figure(plot_data)
if plotly:
fig = create_plotly_figure(plot_data)
return fig
residual_fig = create_residual_figure(plot_data)
return fig, residual_fig
else:
plt = matplotlib.pyplot
create_matplotlib_figure(
plot_data, pdf, individual, label, ccpn_flag, show
)
# surf = pn.pane.plotly.Plotly(fig)
# app = pn.Column(surf)
# app.show(threaded=True)
if first:
break

run_log()


@app.command(help="Interactive Bokeh dashboard for configuring fitting parameters")
def edit(
peaklist_path: Path,
data_path: Path,
test: bool = False,
):
from bokeh.util.browser import view
from bokeh.server.server import Server
from .edit import BokehScript

run_log()
bs = BokehScript(peaklist_path=peaklist_path, data_path=data_path)
if not test:
server = Server({"/edit": bs.init})
server.start()
print("[green]Opening peakipy: Edit fits on http://localhost:5006/edit[/green]")
server.io_loop.add_callback(server.show, "/edit")
server.io_loop.start()


def make_yaml_file(name, yaml_file=yaml_file):
if os.path.exists(name):
print(f"Copying {name} to {name}.bak")
Expand Down
24 changes: 1 addition & 23 deletions peakipy/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import json
from datetime import datetime
from pathlib import Path
from typing import List, Optional
from typing import List
from enum import Enum
from dataclasses import dataclass, field

Expand Down Expand Up @@ -1515,28 +1515,6 @@ def clusters(
)
return ClustersResult(labeled_array, num_features, closed_data, peaks)

# def adaptive_clusters(self, block_size, offset, l_struc=None):

# self.thresh = threshold_otsu(self.data[0])

# peaks = [[y, x] for y, x in zip(self.df.Y_AXIS, self.df.X_AXIS)]

# binary_adaptive = threshold_adaptive(
# self.data[0], block_size=block_size, offset=offset
# )

# labeled_array, num_features = ndimage.label(binary_adaptive, l_struc)
# # print(labeled_array, num_features)

# self.df["CLUSTID"] = [labeled_array[i[0], i[1]] for i in peaks]

# #  renumber "0" clusters
# max_clustid = self.df["CLUSTID"].max()
# n_of_zeros = len(self.df[self.df["CLUSTID"] == 0]["CLUSTID"])
# self.df.loc[self.df[self.df["CLUSTID"] == 0].index, "CLUSTID"] = np.arange(
# max_clustid + 1, n_of_zeros + max_clustid + 1, dtype=int
# )

def mask_method(self, overlap=1.0, l_struc=None):
"""connect clusters based on overlap of fitting masks
Expand Down
Loading

0 comments on commit a31da53

Please sign in to comment.