|
137 | 137 | <div>
|
138 | 138 | <span style="font-size: 18px; font-weight:bold;">
|
139 | 139 | <div class="tooltip">
|
140 |
| - {{ card.name }} |
| 140 | + {{ card.name|regex_replace('(?<!^)(?=[A-Z][a-z])', ' ') }} |
141 | 141 | <div class="tooltiptext">
|
142 | 142 | {{ card.tooltip }}
|
143 | 143 | <div class="arrow-up"></div>
|
|
161 | 161 | <span style="font-size: 40px; color: gray;">─</span>
|
162 | 162 | {% endif %}
|
163 | 163 | </span>
|
164 |
| - <span style="display: inline-block; line-height:1;"> |
165 |
| - <span style="font-size: 14px">{{card.threshold}}<br>minimum<br>threshold</span> |
| 164 | + <span style="display: inline-block; line-height:1; margin-bottom: 10px;"> |
| 165 | + <span style="font-size: 14px;">{{card.threshold}}<br>minimum<br>threshold</span> |
166 | 166 | </span>
|
167 | 167 | <div id="model-card-plot-{{idx}}">
|
168 | 168 | </div>
|
|
184 | 184 | {% endmacro %}
|
185 | 185 |
|
186 | 186 | {% macro render_perf_over_time(name, comp)%}
|
187 |
| -<div class="card" id={{name}} style="display: block; flex-basis: 100%"> |
| 187 | +<div class="card" id={{name}} style="display: block;"> |
188 | 188 | <h3 style="color: black; font-weight:normal;">How is your model doing over time?</h3><br>
|
189 | 189 | <h3 style="color: gray; font-weight:normal;">See how your model is performing over several metrics and subgroups over time.</h3>
|
190 | 190 | <div style="display: flex; align-items: center; justify-content: center; padding: 10px; margin-bottom: 20px;">
|
|
197 | 197 | </div>
|
198 | 198 | </div>
|
199 | 199 | <div class="column" style="float: left;">
|
200 |
| - <div class="subcard_overview" style="padding:10px; margin-bottom:20px; max-width:500px;"> |
| 200 | + <div class="subcard_overview" style="padding:10px; margin-bottom:20px; width:15vw;"> |
201 | 201 | <h4>Metrics</h4>
|
202 | 202 | <div class="radio-buttons" id="slice-selection">
|
203 | 203 | <input type="radio" id="{{comp.metric_cards.metrics[0]}}" name="metric" value="{{comp.metric_cards.metrics[0]}}" checked>
|
|
212 | 212 | </div>
|
213 | 213 | {% else %}
|
214 | 214 | <div class="tooltip">
|
215 |
| - <label for="{{comp.metric_cards.metrics[0]}}">{{comp.metric_cards.metrics[0]}}</label> |
| 215 | + <label for="{{comp.metric_cards.metrics[0]}}">{{comp.metric_cards.metrics[0]|regex_replace('(?<!^)(?=[A-Z][a-z])', ' ')}}</label> |
216 | 216 | <div class="tooltiptext">
|
217 | 217 | {{ comp.metric_cards.tooltips[0] }}
|
218 | 218 | <div class="arrow-up"></div>
|
|
233 | 233 | </div>
|
234 | 234 | {% else %}
|
235 | 235 | <div class="tooltip">
|
236 |
| - <label for="{{metric}}">{{metric}}</label> |
| 236 | + <label for="{{metric}}">{{metric|regex_replace('(?<!^)(?=[A-Z][a-z])', ' ')}}</label> |
237 | 237 | <div class="tooltiptext">
|
238 | 238 | {{ tooltip }}
|
239 | 239 | <div class="arrow-up"></div>
|
|
244 | 244 | </div>
|
245 | 245 | </div>
|
246 | 246 | {% for slice, values in comp.metric_cards.slices|zip(comp.metric_cards.values) %}
|
247 |
| - <div class="subcard_overview" style="padding:10px; margin-bottom:10px; max-width:500px;"> |
248 |
| - <h4>{{slice|regex_replace('(?<!^)(?=[A-Z])', ' ')|title}}</h4> |
| 247 | + <div class="subcard_overview" style="padding:10px; margin-bottom:10px; width:15vw;"> |
| 248 | + <h4>{{slice|regex_replace('(?<!^)(?=[A-Z][a-z])', ' ')}}</h4> |
249 | 249 | <div class="radio-buttons" id="slice-selection">
|
250 | 250 | <input type="radio" id="overall_{{slice}}" name="{{slice}}" value="overall_{{slice}}" checked>
|
251 | 251 | <label for="overall_{{slice}}">All</label>
|
252 | 252 | {% for value in values %}
|
253 | 253 | <input type="radio" id="{{value}}" name="{{slice}}" value="{{value}}">
|
254 |
| - <label for="{{value}}">{{value|regex_replace('_+', ' ')|title}}</label> |
| 254 | + {% if value|regex_search("\((.*?)\)")|length != 0 %} |
| 255 | + {% set acronym = value|regex_search("\((.*?)\)") %} |
| 256 | + <label for="{{value}}">{{acronym[0]}}</label> |
| 257 | + {% else %} |
| 258 | + <label for="{{value}}">{{value|regex_replace('(?<!^)(?=[A-Z][a-z])', ' ')}}</label> |
| 259 | + {% endif %} |
255 | 260 | {% endfor %}
|
256 | 261 | </div>
|
257 | 262 | </div>
|
258 | 263 | {% endfor %}
|
259 | 264 | </div>
|
260 |
| - <div class="subcard_overview" style="margin:auto; float:right;"> |
| 265 | + <div class="subcard_overview" style="margin: 0px; margin-left:25px; float:left; min-width:500px; max-width:100%;"> |
261 | 266 | <div id="plot"></div>
|
262 | 267 | </div>
|
263 | 268 | </div>
|
264 | 269 | {% endmacro %}
|
265 | 270 |
|
266 | 271 | {% macro render_overview(name, comp) %}
|
267 | 272 | {{ render_perf(name, comp) }}
|
268 |
| -{% set val = {'history': false} %} |
| 273 | +{# {% set val = {'history': false} %} |
269 | 274 | {% for metric_card in comp.metric_cards.collection%}
|
270 | 275 | {% if metric_card.history|length > 1 %}
|
271 | 276 | {% set _ = val.update({'history':true}) %}
|
272 | 277 | {% endif %}
|
273 | 278 | {% endfor %}
|
274 |
| -{% if val['history'] %} |
275 |
| - {{ render_perf_over_time(name, comp) }} |
276 |
| -{% endif %} |
| 279 | +{% if val['history'] %} #} |
| 280 | +{{ render_perf_over_time(name, comp) }} |
| 281 | +{# {% endif %} #} |
277 | 282 | {% endmacro %}
|
278 | 283 |
|
279 | 284 | {% macro render_objects(section)%}
|
|
326 | 331 | {% endfor %}
|
327 | 332 | {# Display global plots from GraphicsCollection in Datasets, temporary fix #}
|
328 | 333 | {% if section is hasattr "graphics" %}
|
329 |
| - <div class="subcard" style="min-width:1400px;"> |
| 334 | + <div class="subcard" style="flex-basis:100%;"> |
330 | 335 | <h3>{{ "Graphics" }}</h3>
|
331 | 336 | {{ render_if_exist_list(section.graphics) }}
|
332 | 337 | </div>
|
|
339 | 344 | {% endfor %}
|
340 | 345 | {% if section is hasattr "graphics"%}
|
341 | 346 | {% if section.graphics is not none%}
|
342 |
| - <div class="subcard" style="min-width:1400px;"> |
| 347 | + <div class="subcard" style="flex-basis:100%;"> |
343 | 348 | <h3>{{ "Graphics" }}</h3>
|
344 | 349 | {{ render_if_exist_list(section.graphics) }}
|
345 | 350 | </div>
|
|
401 | 406 |
|
402 | 407 | body {
|
403 | 408 | font-family: Arial, Helvetica, sans-serif;
|
| 409 | + min-width: 1150px; |
404 | 410 | }
|
405 | 411 |
|
406 | 412 | h2 {
|
|
412 | 418 | color: #0073e4;
|
413 | 419 | flex-basis: 100%;
|
414 | 420 | }
|
415 |
| -
|
416 | 421 | .card {
|
417 | 422 | display: flex;
|
418 | 423 | flex-wrap: wrap;
|
|
432 | 437 | background-color: #f3f4f6;
|
433 | 438 | border-radius: 5px;
|
434 | 439 | box-shadow: 4px 4px 4px 0px rgba(0, 0, 0, 0.1);
|
435 |
| - {# display: none; #} |
436 | 440 | }
|
437 | 441 |
|
438 | 442 | .subcard_overview {
|
|
450 | 454 | }
|
451 | 455 |
|
452 | 456 | .img-item {
|
453 |
| - min-width: 1024px; |
454 |
| - width: 100%; |
455 |
| - height: auto; |
456 | 457 | flex-basis: 100%;
|
457 | 458 | margin-top: 10px;
|
458 | 459 | margin-bottom: 10px;
|
|
725 | 726 |
|
726 | 727 | .radio-buttons {
|
727 | 728 | display: flex;
|
| 729 | + row-gap: 15px; |
728 | 730 | flex-direction: row;
|
729 | 731 | flex-wrap: wrap;
|
730 | 732 | justify-content: left;
|
|
747 | 749 | transition: background-color 0.3s ease;
|
748 | 750 | background-color: #ffffff;
|
749 | 751 | border: 2px solid #DADCE0;
|
| 752 | + white-space: nowrap; |
750 | 753 | }
|
751 | 754 |
|
752 | 755 | .radio-buttons label:not(:first-child):not(:last-child) {
|
|
848 | 851 | </body>
|
849 | 852 | </html>
|
850 | 853 | <script>
|
| 854 | + function multipleStringLines(title) { |
| 855 | + if (title.length > 50) { // check if greater than threshold! |
| 856 | + let y_axis = title.split(' '); //break into words |
| 857 | + let interval = title.split(' ').length / 2; //2-lines |
| 858 | + return y_axis.slice(0, interval).join(' ') + '<br>' + y_axis.slice(interval, y_axis.length).join(' '); |
| 859 | + } |
| 860 | + return title; |
| 861 | + } |
| 862 | +
|
851 | 863 | function isInView(element) {
|
852 | 864 | // return true if element is in view
|
853 | 865 | var rect = element.getBoundingClientRect(),
|
|
934 | 946 | plot_bgcolor: "rgba(0,0,0,0)",
|
935 | 947 | xaxis: {
|
936 | 948 | zeroline: false,
|
937 |
| - showticklabels: false, |
938 |
| - showgrid: false |
| 949 | + showticklabels: true, |
| 950 | + showgrid: false, |
| 951 | + tickformat: '%b\n %Y' |
939 | 952 | },
|
940 | 953 | yaxis: {
|
941 |
| - gridcolor: "#ffffff" |
| 954 | + gridcolor: "#ffffff", |
| 955 | + zeroline: false, |
| 956 | + showticklabels: true, |
| 957 | + showgrid: true, |
| 958 | + range: [-0.10, 1.10], |
942 | 959 | },
|
943 |
| - margin: { l: 0, r: 0, t: 0, b: 0 }, |
944 |
| - height: 125, |
945 |
| - width: 250 |
| 960 | + margin: { l: 30, r: 0, t: 0, b: 30 }, |
| 961 | + padding: { l: 0, r: 0, t: 0, b: 0 }, |
| 962 | + height: 150, |
| 963 | + width: 300 |
946 | 964 | }
|
947 | 965 | };
|
948 | 966 | if (history.length > 0) {
|
|
1261 | 1279 |
|
1262 | 1280 | // create title for plot: Current {metric name} is trending {trend_keyword} and is {passed_keyword} the threshold.
|
1263 | 1281 | // get number of nulls in selections, if 9 then plot title, else don't plot title
|
1264 |
| - console.log(selections) |
1265 | 1282 | var nulls = 0;
|
1266 | 1283 | for (let i = 0; i < selections.length; i++) {
|
1267 | 1284 | if (selections[i] === null) {
|
|
1270 | 1287 | }
|
1271 | 1288 | if (nulls === 10) {
|
1272 | 1289 | var plot_title = "Current " + name + " is trending " + trend_keyword + " and is " + passed_keyword + " the threshold.";
|
| 1290 | + var plot_title = multipleStringLines(plot_title); |
1273 | 1291 | var showlegend = false;
|
1274 | 1292 | }
|
1275 | 1293 | else {
|
|
1324 | 1342 | };
|
1325 | 1343 | traces.push(threshold_trace);
|
1326 | 1344 | }
|
| 1345 | + var width = Math.max(parent.innerWidth - 900, 500); |
1327 | 1346 | var layout = {
|
1328 | 1347 | title: {
|
1329 | 1348 | text: plot_title,
|
|
1336 | 1355 | plot_bgcolor: 'rgba(0,0,0,0)',
|
1337 | 1356 | xaxis: {
|
1338 | 1357 | zeroline: false,
|
1339 |
| - showticklabels: false, |
| 1358 | + showticklabels: true, |
1340 | 1359 | showgrid: false,
|
| 1360 | + tickformat: '%b\n %Y' |
1341 | 1361 | },
|
1342 | 1362 | yaxis: {
|
1343 | 1363 | gridcolor: '#ffffff',
|
| 1364 | + zeroline: false, |
| 1365 | + showticklabels: true, |
| 1366 | + showgrid: true, |
| 1367 | + range: [-0.10, 1.10], |
1344 | 1368 | },
|
1345 | 1369 | showlegend: showlegend,
|
| 1370 | + // show legend at top |
| 1371 | + legend: { |
| 1372 | + orientation: "h", |
| 1373 | + yanchor: "top", |
| 1374 | + y: 1.1, |
| 1375 | + xanchor: "left", |
| 1376 | + x: 0.1 |
| 1377 | + }, |
1346 | 1378 | margin: {
|
1347 | 1379 | l: 50,
|
1348 | 1380 | r: 50,
|
|
1352 | 1384 | },
|
1353 | 1385 | // set height and width of plot to extra-wide to fit the plot
|
1354 | 1386 | height: 500,
|
1355 |
| - width: 900, |
| 1387 | + // get size of window and set width of plot to size of window |
| 1388 | + width: width, |
1356 | 1389 | }
|
1357 | 1390 | Plotly.newPlot(plot, traces, layout, {displayModeBar: false});
|
1358 | 1391 | }
|
|
1565 | 1598 | }
|
1566 | 1599 | if (nulls === 10) {
|
1567 | 1600 | var plot_title = "Current " + name + " is trending " + trend_keyword + " and is " + passed_keyword + " the threshold.";
|
| 1601 | + var plot_title = multipleStringLines(plot_title); |
1568 | 1602 | var showlegend = false;
|
1569 | 1603 | }
|
1570 | 1604 | else {
|
|
1619 | 1653 | };
|
1620 | 1654 | traces.push(threshold_trace);
|
1621 | 1655 | }
|
| 1656 | + var width = Math.max(parent.innerWidth - 900, 500); |
1622 | 1657 | var layout = {
|
1623 | 1658 | title: {
|
1624 | 1659 | text: plot_title,
|
|
1631 | 1666 | plot_bgcolor: 'rgba(0,0,0,0)',
|
1632 | 1667 | xaxis: {
|
1633 | 1668 | zeroline: false,
|
1634 |
| - showticklabels: false, |
| 1669 | + showticklabels: true, |
1635 | 1670 | showgrid: false,
|
| 1671 | + tickformat: '%b\n %Y' |
1636 | 1672 | },
|
1637 | 1673 | yaxis: {
|
1638 | 1674 | gridcolor: '#ffffff',
|
| 1675 | + zeroline: false, |
| 1676 | + showticklabels: true, |
| 1677 | + showgrid: true, |
| 1678 | + range: [-0.10, 1.10], |
1639 | 1679 | },
|
1640 | 1680 | showlegend: showlegend,
|
| 1681 | + // show legend at top |
| 1682 | + legend: { |
| 1683 | + orientation: "h", |
| 1684 | + yanchor: "top", |
| 1685 | + y: 1.1, |
| 1686 | + xanchor: "left", |
| 1687 | + x: 0.1 |
| 1688 | + }, |
1641 | 1689 | margin: {
|
1642 | 1690 | l: 50,
|
1643 | 1691 | r: 50,
|
1644 | 1692 | b: 50,
|
1645 | 1693 | t: 50,
|
1646 | 1694 | pad: 4
|
1647 | 1695 | },
|
1648 |
| - // set height and width of plot to extra-wide to fit the plot |
| 1696 | + // set height and width of plot to width of card minus 500px |
1649 | 1697 | height: 500,
|
1650 |
| - width: 900, |
| 1698 | + width: width, |
1651 | 1699 | }
|
1652 | 1700 | Plotly.newPlot(plot, traces, layout, {displayModeBar: false});
|
1653 | 1701 | }
|
1654 | 1702 | // Add event listeners to radio buttons
|
1655 | 1703 | for (let input of inputs_all) {
|
1656 | 1704 | input.addEventListener('change', updatePlot);
|
1657 | 1705 | }
|
| 1706 | + // Add event listener to update plot when window is resized |
| 1707 | + window.addEventListener('resize', updatePlot); |
1658 | 1708 | for (let selection of plot_selection) {
|
1659 | 1709 | selection.addEventListener('change', updatePlotSelection);
|
1660 | 1710 | }
|
|
1673 | 1723 | for (let i = 0; i < collapsible.length; i++) {
|
1674 | 1724 | collapsible[i].addEventListener("click", function() {
|
1675 | 1725 | let arrow = collapsible[i];
|
1676 |
| -
|
1677 | 1726 | if (arrow.classList.contains('down-arrow')) {
|
1678 | 1727 | arrow.classList.add('right-arrow');
|
1679 | 1728 | arrow.classList.remove('down-arrow');
|
|
1691 | 1740 |
|
1692 | 1741 | let collapsible_bar = card.getElementsByClassName("collapsible-bar")[0];
|
1693 | 1742 | collapsible_bar.style.display = collapsible_bar.style.display === 'block' ? 'none' : 'block';
|
| 1743 | + refreshPlotlyPlots(); |
1694 | 1744 | });
|
1695 | 1745 | }
|
1696 | 1746 | }
|
1697 | 1747 | document.addEventListener('DOMContentLoaded', setCollapseButton);
|
1698 | 1748 |
|
| 1749 | + // function to refresh plotly plots |
| 1750 | + function refreshPlotlyPlots() { |
| 1751 | + const img_items = document.getElementsByClassName("img-item"); |
| 1752 | + for (let i = 0; i < img_items.length; i++) { |
| 1753 | + if (img_items[i].getElementsByTagName("div").length > 0) { |
| 1754 | + id = img_items[i].getElementsByClassName("plotly-graph-div")[0].id; |
| 1755 | + var gd = document.getElementById(id); |
| 1756 | + data = gd.data; |
| 1757 | + layout = gd.layout; |
| 1758 | + Plotly.update(id, data, layout); |
| 1759 | + } |
| 1760 | + } |
| 1761 | + } |
| 1762 | +
|
1699 | 1763 | </script>
|
0 commit comments