Skip to content

Commit

Permalink
Merge pull request #802 from SolarArbiter/sort_tables
Browse files Browse the repository at this point in the history
Sort tables and graphs
  • Loading branch information
dplarson committed Jan 24, 2023
2 parents d4d85a3 + 81916a6 commit a4949f6
Show file tree
Hide file tree
Showing 10 changed files with 481 additions and 62 deletions.
2 changes: 2 additions & 0 deletions .codecov.yml
Expand Up @@ -23,5 +23,7 @@ coverage:
target: 95%
paths:
- "solarforecastarbiter/**/tests/.*"
ignore:
- "solarforecastarbiter/reports/templates/*"

comment: off
2 changes: 1 addition & 1 deletion docs/source/conf.py
Expand Up @@ -25,7 +25,7 @@
# -- Project information -----------------------------------------------------

project = 'Solar Forecast Arbiter Core'
copyright = '2019, Solar Forecast Arbiter Team'
copyright = '2023, Solar Forecast Arbiter Team'
author = 'Solar Forecast Arbiter Team'

# The short X.Y version
Expand Down
19 changes: 19 additions & 0 deletions docs/source/whatsnew/1.0.14.rst
@@ -0,0 +1,19 @@
.. _whatsnew_1014:

.. py:currentmodule:: solarforecastarbiter
1.0.14 (TBD)
--------------------------

Fixed
~~~~~~~~~~~~
* Added table sorting in html reports.
* Added total metrics sorting in html reports.
* Updating some dependency requirements for tests.

Contributors
~~~~~~~~~~~~

* Adam Wigington (:ghuser:`awig`)
* David Larson (:ghuser:`dplarson`)
2 changes: 2 additions & 0 deletions docs/source/whatsnew/index.rst
Expand Up @@ -9,6 +9,8 @@ These are new features and improvements of note in each release.
.. toctree::
:maxdepth: 2

1.0.14
1.0.13
1.0.12
1.0.11
1.0.10
Expand Down
7 changes: 4 additions & 3 deletions setup.py
Expand Up @@ -19,7 +19,7 @@
'matplotlib',
'plotly>=4.9.0, <5',
'selenium<4',
'jinja2',
'jinja2<3.1',
'kaleido'
],
'doc': ['sphinx<2.0', 'sphinx_rtd_theme']
Expand Down Expand Up @@ -54,12 +54,13 @@
'click',
'netCDF4',
'numpy>=1.18.2',
'pandas>=1.0.3',
'pandas>=1.0.3, <1.4',
'requests<=2.25.1', # https://github.com/psf/requests/pull/5810
'xarray',
'tables',
'importlib-metadata<5',
'pvlib==0.8.0',
'scipy',
'scipy<1.9',
'statsmodels',
'jsonschema',
'pytz',
Expand Down
71 changes: 70 additions & 1 deletion solarforecastarbiter/reports/figures/plotly_figures.py
Expand Up @@ -18,7 +18,6 @@
from matplotlib import cm
from matplotlib.colors import Normalize


from solarforecastarbiter import datamodel
from solarforecastarbiter.metrics.event import _event2count
import solarforecastarbiter.plotting.utils as plot_utils
Expand Down Expand Up @@ -62,6 +61,44 @@ def gen_grays(num_colors):
'font': {'size': 14}
}

SORT_UPDATEMENU_DROPDOWN = [{
"buttons": [
dict(
method="restyle",
label="Original Order",
args=[{'visible': [True, False, False, False, False]}],
),
dict(
method="restyle",
label="ᐁ Value",
args=[{'visible': [False, True, False, False, False]}],
),
dict(
method="restyle",
label="ᐃ Value",
args=[{'visible': [False, False, True, False, False]}],
),
dict(
method="restyle",
label="ᐁ Name",
args=[{'visible': [False, False, False, True, False]}],
),
dict(
method="restyle",
label="ᐃ Name",
args=[{'visible': [False, False, False, False, True]}],
)
],
"direction": "down",
"showactive": True,
"xanchor": 'center',
"x": 0.025,
"yanchor": 'bottom',
"pad": {'b': 5},
"active": 0,
}
]

# Used to adjust plot height when many x axis labels or long labels are
# present. The length of the longest label of the plot will be multiplies by
# this value and added o the height of PLOT_LAYOUT_DEFAULTS to determine the
Expand Down Expand Up @@ -900,6 +937,7 @@ def bar(df, metric):
x_values = pd.Series(x_values, name='abbrev')
palette = cycle(PALETTE)
palette = [next(palette) for _ in x_values]
data = data.assign(palette=palette)
metric_name = datamodel.ALLOWED_METRICS[metric]

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

# Create dataframes for each sort (name, value)
data_val_asc = data.sort_values(by=['value', 'name'], ascending=True)
data_val_desc = data.sort_values(by=['value', 'name'], ascending=False)
data_name_asc = data.sort_values(by=['name'], ascending=True)
data_name_desc = data.sort_values(by=['name'], ascending=False)

fig = go.Figure()
fig.add_trace(go.Bar(x=x_values, y=data['value'],
text=data['name'],
visible=True,
marker=go.bar.Marker(color=palette),
hovertemplate='(%{text}, %{y})<extra></extra>'))
fig.add_trace(go.Bar(x=data_val_asc['name'], y=data_val_asc['value'],
text=data_val_asc['abbrev'],
visible=False,
marker=go.bar.Marker(color=data_val_asc['palette']),
hovertemplate='(%{text}, %{y})<extra></extra>'))
fig.add_trace(go.Bar(x=data_val_desc['name'], y=data_val_desc['value'],
text=data_val_desc['abbrev'],
visible=False,
marker=go.bar.Marker(color=data_val_desc['palette']),
hovertemplate='(%{text}, %{y})<extra></extra>'))
fig.add_trace(go.Bar(x=data_name_asc['name'], y=data_name_asc['value'],
text=data_name_asc['abbrev'],
visible=False,
marker=go.bar.Marker(color=data_name_asc['palette']),
hovertemplate='(%{text}, %{y})<extra></extra>'))
fig.add_trace(go.Bar(x=data_name_desc['name'], y=data_name_desc['value'],
text=data_name_desc['abbrev'],
visible=False,
marker=go.bar.Marker(color=data_name_desc['palette']),
hovertemplate='(%{text}, %{y})<extra></extra>'))
updatemenus = SORT_UPDATEMENU_DROPDOWN
if len(x_values) <= 1:
updatemenus = None
fig.update_layout(
title=f'<b>{metric_name}</b>',
xaxis_title=metric_name,
updatemenus=updatemenus,
**plot_layout_args)
configure_axes(fig, x_axis_kwargs, y_range)
return fig
Expand Down
106 changes: 106 additions & 0 deletions solarforecastarbiter/reports/templates/html/body.html
Expand Up @@ -54,6 +54,18 @@
.obsfx-table td:first-child {
font-weight: 700;
}

.report-table-wrapper table.table tr th.sortable {
cursor: pointer;
}
.report-table-wrapper table.table tr th.sortable:hover {
background-color: #d1ecf1;
font-weight: 900;
}
.report-table-wrapper table.table tr th.sortable span {
color: #dddddd;
}

details {
border-bottom: 1px solid #dee2e6;
padding: 0.5em;
Expand All @@ -70,6 +82,7 @@
margin-bottom: 0.5em;
padding-bottom: 0.5em;
}

</style>
{% block report_title %}
<h1 id="report-title">{{ report_name }}</h1>
Expand Down Expand Up @@ -366,6 +379,99 @@ <h3 id="{{ category }}-analysis">{{ human_categories[category].title() }} Analys
{% endblock %}



{% block javascript %}
<script>
/**
* Sorts the table rows by the specified column
* @param {[String]} element_id The table's id
* @param {[Number]} n_column Column number to sort by
* @param {[Number]} row_ofsset Number of rows to offset (for use with multiple headers lines)
* @param {[Bool]} is_number If true, convert to numeric, else keep as text
* Notes:
* Based on the w3 Schools switching example
* from: https://www.w3schools.com/howto/howto_js_sort_table.asp
* accessed Dec, 2022
*/
function sortTable(element_id, n_column = 1, row_offset = 0, is_number=true) {
var table, do_switch, find_switch, i, r1, r2, val1, val2, dir, counter = 0;
var spansUp, spansDown;
table = document.getElementById(element_id)
do_switch = true;
dir = 'desc';

console.log("n_columns = ", n_column);
/* Loop that continues until switching rows is complete */
while (do_switch) {
do_switch = false;

// Check if should be switched
for (i = 1 + row_offset; i < (table.rows.length - 1); i++) {
find_switch = false;

/* Loop through all table rows (except the first) */
r1 = table.rows[i].getElementsByTagName("td")[n_column];
r2 = table.rows[i+1].getElementsByTagName("td")[n_column];
val1 = r1.innerHTML.toLowerCase();
val2 = r2.innerHTML.toLowerCase();
if (is_number) {
val1 = Number(val1);
val2 = Number(val2);
}
// console.log("compare in column ", n_column, " ", r1.innerHTML, " vs ", r2.innerHTML);

/* check if switch */
if (dir == "desc") {
if (val1 < val2) {
find_switch = true;
// console.log("Switching for desc");
break;
}
}
else if (dir == "asc") {
if (val1 > val2) {
find_switch = true;
// console.log("Switching for asc");
break;
}
}
}

// Perform Switching
if (find_switch) {
console.log("swtiching ");
table.rows[i].parentNode.insertBefore(table.rows[i + 1], table.rows[i]);
do_switch = true;
counter++;
}
// If not swtiching, change direction
else {
if (counter == 0 && dir == "desc") {
dir = "asc";
do_switch = true;
}
}

// Select only the up/down arrow in the sorted column
spansDown = table.getElementsByClassName('down');
spansUp = table.getElementsByClassName('up');
for (i = 0; i < spansDown.length; i++) {
spansDown[i].style.color = '#dddddd';
}
for (i = 0; i < spansUp.length; i++) {
spansUp[i].style.color = '#dddddd';
}
if (dir == "asc") {
spansDown[n_column].style.color = '#333333';
}
else {
spansUp[n_column].style.color = '#333333';
}
}
}
</script>
{% endblock %}

{% block versions %}
<h2 id="versions">Versions</h2>
{% include "versions.html" %}
Expand Down

0 comments on commit a4949f6

Please sign in to comment.