Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Html repr with JupyterLab TOC #902

Merged
merged 9 commits into from Jul 7, 2023
5 changes: 3 additions & 2 deletions lmfit/minimizer.py
Expand Up @@ -339,8 +339,9 @@

def _repr_html_(self, show_correl=True, min_correl=0.1):
"""Return a HTML representation of parameters data."""
return fitreport_html_table(self, show_correl=show_correl,
min_correl=min_correl)
report = fitreport_html_table(self, show_correl=show_correl,

Check warning on line 342 in lmfit/minimizer.py

View check run for this annotation

Codecov / codecov/patch

lmfit/minimizer.py#L342

Added line #L342 was not covered by tests
min_correl=min_correl)
return f"<h2>Fit Result</h2> {report}"

Check warning on line 344 in lmfit/minimizer.py

View check run for this annotation

Codecov / codecov/patch

lmfit/minimizer.py#L344

Added line #L344 was not covered by tests


class Minimizer:
Expand Down
2 changes: 1 addition & 1 deletion lmfit/model.py
Expand Up @@ -1725,7 +1725,7 @@ def _repr_html_(self, show_correl=True, min_correl=0.1):
report = fitreport_html_table(self, show_correl=show_correl,
min_correl=min_correl)
modname = self.model._reprstring(long=True)
return f"<h2> Model</h2> {modname} {report}"
return f"<h2>Fit Result</h2> <p>Model: {modname}</p> {report}"

def summary(self):
"""Return a dictionary with statistics and attributes of a ModelResult.
Expand Down
57 changes: 38 additions & 19 deletions lmfit/printfuncs.py
Expand Up @@ -224,6 +224,26 @@ def fit_report(inpars, modelpars=None, show_correl=True, min_correl=0.1,
return '\n'.join(buff)


def lcol(s, cat='td'):
"html left column"
return f"<{cat} style='text-align:left'>{s}</{cat}>"


def rcol(s, cat='td'):
"html right column"
return f"<{cat} style='text-align:right'>{s}</{cat}>"


def trow(columns, cat='td'):
"html row"
nlast = len(columns)-1
rows = []
for i, col in enumerate(columns):
cform = rcol if i == nlast else lcol
rows.append(cform(col, cat=cat))
return rows


def fitreport_html_table(result, show_correl=True, min_correl=0.1):
"""Generate a report of the fitting result as an HTML table.

Expand All @@ -246,11 +266,15 @@ def fitreport_html_table(result, show_correl=True, min_correl=0.1):
html = []
add = html.append

def stat_row(label, val, val2=''):
add(f'<tr><td>{label}</td><td>{val}</td><td>{val2}</td></tr>')
def stat_row(label, val, val2=None, cat='td'):
if val2 is None:
rows = trow([label, val], cat=cat)
else:
rows = trow([label, val, val2], cat=cat)
add(f"<tr>{''.join(rows)}</tr>")

add('<h2>Fit Statistics</h2>')
add('<table>')
add('<table class="jp-toc-ignore">')
add('<caption class="jp-toc-ignore">Fit Statistics</caption>')
stat_row('fitting method', result.method)
stat_row('# function evals', result.nfev)
stat_row('# data points', result.ndata)
Expand All @@ -262,7 +286,6 @@ def stat_row(label, val, val2=''):
if hasattr(result, 'rsquared'):
stat_row('R-squared', gformat(result.rsquared))
add('</table>')
add('<h2>Variables</h2>')
add(params_html_table(result.params))
if show_correl:
correls = []
Expand All @@ -279,9 +302,10 @@ def stat_row(label, val, val2=''):
if len(correls) > 0:
sort_correls = sorted(correls, key=lambda val: abs(val[2]))
sort_correls.reverse()
extra = f'(unreported correlations are < {min_correl:.3f})'
add(f'<h2>Correlations {extra}</h2>')
add('<table>')
extra = f'(unreported values are < {min_correl:.3f})'
add('<table class="jp-toc-ignore">')
add(f'<caption>Correlations {extra}</caption>')
stat_row('Parameter1', 'Parameter 2', 'Correlation', cat='th')
for name1, name2, val in sort_correls:
stat_row(name1, name2, f"{val:+.4f}")
add('</table>')
Expand Down Expand Up @@ -345,10 +369,7 @@ def params_html_table(params):
html = []
add = html.append

def cell(x, cat='td'):
return add(f'<{cat}> {x} </{cat}>')

add('<table><tr>')
add('<table class="jp-toc-ignore"><caption>Parameters</caption>')
headers = ['name', 'value']
if has_err:
headers.extend(['standard error', 'relative error'])
Expand All @@ -357,9 +378,9 @@ def cell(x, cat='td'):
headers.append('expression')
if has_brute:
headers.append('brute step')
for h in headers:
cell(h, cat='th')
add('</tr>')

hrow = trow(headers, cat='th')
add(f"<tr>{''.join(hrow)}</tr>")

for par in params.values():
rows = [par.name, gformat(par.value)]
Expand All @@ -386,10 +407,8 @@ def cell(x, cat='td'):
brute_step = gformat(par.brute_step)
rows.append(brute_step)

add('<tr>')
for r in rows:
cell(r)
add('</tr>')
hrow = trow(rows, cat='td')
add(f"<tr>{''.join(hrow)}</tr>")
add('</table>')
return ''.join(html)

Expand Down
2 changes: 1 addition & 1 deletion tests/test_parameters.py
Expand Up @@ -383,7 +383,7 @@ def test_parameters__repr_html_(parameters):
repr_html = pars._repr_html_()

assert isinstance(repr_html, str)
assert '<table><tr><th> name </th><th> value </th>' in repr_html
assert '<table class="jp-toc-ignore"><caption>Parameters</caption>' in repr_html


def test_parameters_add():
Expand Down
5 changes: 2 additions & 3 deletions tests/test_printfuncs.py
Expand Up @@ -142,9 +142,8 @@ def test_reports_created(fitresult):

html_report = fitresult._repr_html_()
assert len(html_report) > 1000
for header in report_headers:
header_title = header.replace('[', '').replace(']', '').strip()
assert header_title in html_report
for header in ('Model', 'Fit Statistics', 'Parameters', 'Correlations'):
assert header in html_report


def test_fitreports_init_values(fitresult):
Expand Down