Skip to content

Commit a4949f6

Browse files
authored
Merge pull request #802 from SolarArbiter/sort_tables
Sort tables and graphs
2 parents d4d85a3 + 81916a6 commit a4949f6

File tree

10 files changed

+481
-62
lines changed

10 files changed

+481
-62
lines changed

.codecov.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,7 @@ coverage:
2323
target: 95%
2424
paths:
2525
- "solarforecastarbiter/**/tests/.*"
26+
ignore:
27+
- "solarforecastarbiter/reports/templates/*"
2628

2729
comment: off

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
# -- Project information -----------------------------------------------------
2626

2727
project = 'Solar Forecast Arbiter Core'
28-
copyright = '2019, Solar Forecast Arbiter Team'
28+
copyright = '2023, Solar Forecast Arbiter Team'
2929
author = 'Solar Forecast Arbiter Team'
3030

3131
# The short X.Y version

docs/source/whatsnew/1.0.14.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.. _whatsnew_1014:
2+
3+
.. py:currentmodule:: solarforecastarbiter
4+
5+
6+
1.0.14 (TBD)
7+
--------------------------
8+
9+
Fixed
10+
~~~~~~~~~~~~
11+
* Added table sorting in html reports.
12+
* Added total metrics sorting in html reports.
13+
* Updating some dependency requirements for tests.
14+
15+
Contributors
16+
~~~~~~~~~~~~
17+
18+
* Adam Wigington (:ghuser:`awig`)
19+
* David Larson (:ghuser:`dplarson`)

docs/source/whatsnew/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ These are new features and improvements of note in each release.
99
.. toctree::
1010
:maxdepth: 2
1111

12+
1.0.14
13+
1.0.13
1214
1.0.12
1315
1.0.11
1416
1.0.10

setup.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
'matplotlib',
2020
'plotly>=4.9.0, <5',
2121
'selenium<4',
22-
'jinja2',
22+
'jinja2<3.1',
2323
'kaleido'
2424
],
2525
'doc': ['sphinx<2.0', 'sphinx_rtd_theme']
@@ -54,12 +54,13 @@
5454
'click',
5555
'netCDF4',
5656
'numpy>=1.18.2',
57-
'pandas>=1.0.3',
57+
'pandas>=1.0.3, <1.4',
5858
'requests<=2.25.1', # https://github.com/psf/requests/pull/5810
5959
'xarray',
6060
'tables',
61+
'importlib-metadata<5',
6162
'pvlib==0.8.0',
62-
'scipy',
63+
'scipy<1.9',
6364
'statsmodels',
6465
'jsonschema',
6566
'pytz',

solarforecastarbiter/reports/figures/plotly_figures.py

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
from matplotlib import cm
1919
from matplotlib.colors import Normalize
2020

21-
2221
from solarforecastarbiter import datamodel
2322
from solarforecastarbiter.metrics.event import _event2count
2423
import solarforecastarbiter.plotting.utils as plot_utils
@@ -62,6 +61,44 @@ def gen_grays(num_colors):
6261
'font': {'size': 14}
6362
}
6463

64+
SORT_UPDATEMENU_DROPDOWN = [{
65+
"buttons": [
66+
dict(
67+
method="restyle",
68+
label="Original Order",
69+
args=[{'visible': [True, False, False, False, False]}],
70+
),
71+
dict(
72+
method="restyle",
73+
label="ᐁ Value",
74+
args=[{'visible': [False, True, False, False, False]}],
75+
),
76+
dict(
77+
method="restyle",
78+
label="ᐃ Value",
79+
args=[{'visible': [False, False, True, False, False]}],
80+
),
81+
dict(
82+
method="restyle",
83+
label="ᐁ Name",
84+
args=[{'visible': [False, False, False, True, False]}],
85+
),
86+
dict(
87+
method="restyle",
88+
label="ᐃ Name",
89+
args=[{'visible': [False, False, False, False, True]}],
90+
)
91+
],
92+
"direction": "down",
93+
"showactive": True,
94+
"xanchor": 'center',
95+
"x": 0.025,
96+
"yanchor": 'bottom',
97+
"pad": {'b': 5},
98+
"active": 0,
99+
}
100+
]
101+
65102
# Used to adjust plot height when many x axis labels or long labels are
66103
# present. The length of the longest label of the plot will be multiplies by
67104
# this value and added o the height of PLOT_LAYOUT_DEFAULTS to determine the
@@ -900,6 +937,7 @@ def bar(df, metric):
900937
x_values = pd.Series(x_values, name='abbrev')
901938
palette = cycle(PALETTE)
902939
palette = [next(palette) for _ in x_values]
940+
data = data.assign(palette=palette)
903941
metric_name = datamodel.ALLOWED_METRICS[metric]
904942

905943
# remove height limit when long abbreviations are used or there are more
@@ -921,14 +959,45 @@ def bar(df, metric):
921959
elif longest_x_label > 30:
922960
x_axis_kwargs.update({'tickangle': 45})
923961

962+
# Create dataframes for each sort (name, value)
963+
data_val_asc = data.sort_values(by=['value', 'name'], ascending=True)
964+
data_val_desc = data.sort_values(by=['value', 'name'], ascending=False)
965+
data_name_asc = data.sort_values(by=['name'], ascending=True)
966+
data_name_desc = data.sort_values(by=['name'], ascending=False)
967+
924968
fig = go.Figure()
925969
fig.add_trace(go.Bar(x=x_values, y=data['value'],
926970
text=data['name'],
971+
visible=True,
927972
marker=go.bar.Marker(color=palette),
928973
hovertemplate='(%{text}, %{y})<extra></extra>'))
974+
fig.add_trace(go.Bar(x=data_val_asc['name'], y=data_val_asc['value'],
975+
text=data_val_asc['abbrev'],
976+
visible=False,
977+
marker=go.bar.Marker(color=data_val_asc['palette']),
978+
hovertemplate='(%{text}, %{y})<extra></extra>'))
979+
fig.add_trace(go.Bar(x=data_val_desc['name'], y=data_val_desc['value'],
980+
text=data_val_desc['abbrev'],
981+
visible=False,
982+
marker=go.bar.Marker(color=data_val_desc['palette']),
983+
hovertemplate='(%{text}, %{y})<extra></extra>'))
984+
fig.add_trace(go.Bar(x=data_name_asc['name'], y=data_name_asc['value'],
985+
text=data_name_asc['abbrev'],
986+
visible=False,
987+
marker=go.bar.Marker(color=data_name_asc['palette']),
988+
hovertemplate='(%{text}, %{y})<extra></extra>'))
989+
fig.add_trace(go.Bar(x=data_name_desc['name'], y=data_name_desc['value'],
990+
text=data_name_desc['abbrev'],
991+
visible=False,
992+
marker=go.bar.Marker(color=data_name_desc['palette']),
993+
hovertemplate='(%{text}, %{y})<extra></extra>'))
994+
updatemenus = SORT_UPDATEMENU_DROPDOWN
995+
if len(x_values) <= 1:
996+
updatemenus = None
929997
fig.update_layout(
930998
title=f'<b>{metric_name}</b>',
931999
xaxis_title=metric_name,
1000+
updatemenus=updatemenus,
9321001
**plot_layout_args)
9331002
configure_axes(fig, x_axis_kwargs, y_range)
9341003
return fig

solarforecastarbiter/reports/templates/html/body.html

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@
5454
.obsfx-table td:first-child {
5555
font-weight: 700;
5656
}
57+
58+
.report-table-wrapper table.table tr th.sortable {
59+
cursor: pointer;
60+
}
61+
.report-table-wrapper table.table tr th.sortable:hover {
62+
background-color: #d1ecf1;
63+
font-weight: 900;
64+
}
65+
.report-table-wrapper table.table tr th.sortable span {
66+
color: #dddddd;
67+
}
68+
5769
details {
5870
border-bottom: 1px solid #dee2e6;
5971
padding: 0.5em;
@@ -70,6 +82,7 @@
7082
margin-bottom: 0.5em;
7183
padding-bottom: 0.5em;
7284
}
85+
7386
</style>
7487
{% block report_title %}
7588
<h1 id="report-title">{{ report_name }}</h1>
@@ -366,6 +379,99 @@ <h3 id="{{ category }}-analysis">{{ human_categories[category].title() }} Analys
366379
{% endblock %}
367380

368381

382+
383+
{% block javascript %}
384+
<script>
385+
/**
386+
* Sorts the table rows by the specified column
387+
* @param {[String]} element_id The table's id
388+
* @param {[Number]} n_column Column number to sort by
389+
* @param {[Number]} row_ofsset Number of rows to offset (for use with multiple headers lines)
390+
* @param {[Bool]} is_number If true, convert to numeric, else keep as text
391+
* Notes:
392+
* Based on the w3 Schools switching example
393+
* from: https://www.w3schools.com/howto/howto_js_sort_table.asp
394+
* accessed Dec, 2022
395+
*/
396+
function sortTable(element_id, n_column = 1, row_offset = 0, is_number=true) {
397+
var table, do_switch, find_switch, i, r1, r2, val1, val2, dir, counter = 0;
398+
var spansUp, spansDown;
399+
table = document.getElementById(element_id)
400+
do_switch = true;
401+
dir = 'desc';
402+
403+
console.log("n_columns = ", n_column);
404+
/* Loop that continues until switching rows is complete */
405+
while (do_switch) {
406+
do_switch = false;
407+
408+
// Check if should be switched
409+
for (i = 1 + row_offset; i < (table.rows.length - 1); i++) {
410+
find_switch = false;
411+
412+
/* Loop through all table rows (except the first) */
413+
r1 = table.rows[i].getElementsByTagName("td")[n_column];
414+
r2 = table.rows[i+1].getElementsByTagName("td")[n_column];
415+
val1 = r1.innerHTML.toLowerCase();
416+
val2 = r2.innerHTML.toLowerCase();
417+
if (is_number) {
418+
val1 = Number(val1);
419+
val2 = Number(val2);
420+
}
421+
// console.log("compare in column ", n_column, " ", r1.innerHTML, " vs ", r2.innerHTML);
422+
423+
/* check if switch */
424+
if (dir == "desc") {
425+
if (val1 < val2) {
426+
find_switch = true;
427+
// console.log("Switching for desc");
428+
break;
429+
}
430+
}
431+
else if (dir == "asc") {
432+
if (val1 > val2) {
433+
find_switch = true;
434+
// console.log("Switching for asc");
435+
break;
436+
}
437+
}
438+
}
439+
440+
// Perform Switching
441+
if (find_switch) {
442+
console.log("swtiching ");
443+
table.rows[i].parentNode.insertBefore(table.rows[i + 1], table.rows[i]);
444+
do_switch = true;
445+
counter++;
446+
}
447+
// If not swtiching, change direction
448+
else {
449+
if (counter == 0 && dir == "desc") {
450+
dir = "asc";
451+
do_switch = true;
452+
}
453+
}
454+
455+
// Select only the up/down arrow in the sorted column
456+
spansDown = table.getElementsByClassName('down');
457+
spansUp = table.getElementsByClassName('up');
458+
for (i = 0; i < spansDown.length; i++) {
459+
spansDown[i].style.color = '#dddddd';
460+
}
461+
for (i = 0; i < spansUp.length; i++) {
462+
spansUp[i].style.color = '#dddddd';
463+
}
464+
if (dir == "asc") {
465+
spansDown[n_column].style.color = '#333333';
466+
}
467+
else {
468+
spansUp[n_column].style.color = '#333333';
469+
}
470+
}
471+
}
472+
</script>
473+
{% endblock %}
474+
369475
{% block versions %}
370476
<h2 id="versions">Versions</h2>
371477
{% include "versions.html" %}

0 commit comments

Comments
 (0)