Skip to content

Commit ba11fe2

Browse files
committed
Replace the Wt::Chart based ShieldingSourceDisplay::Chi2Graphic with D3.js based ShieldingSourceFitPlot.
This improves chart behaviour inside InterSpec (nicer tool-tips over data points, better rendering/looking, etc), but also allows including this chart inside the HTML report files (which was also implemented). AI was used to assist in developing of this feature.
1 parent b759278 commit ba11fe2

File tree

12 files changed

+1440
-681
lines changed

12 files changed

+1440
-681
lines changed

CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,7 @@ if( USE_REL_ACT_TOOL )
558558
src/RelActAutoGuiFreePeak.cpp
559559
src/RelActAutoReport.cpp
560560
src/RelActAutoDev.cpp
561+
src/ShieldingSourceFitPlot.cpp
561562
)
562563

563564
list( APPEND headers
@@ -572,6 +573,7 @@ if( USE_REL_ACT_TOOL )
572573
InterSpec/RelActTxtResults.h
573574
InterSpec/RelEffChart.h
574575
InterSpec/RelEffShieldWidget.h
576+
InterSpec/ShieldingSourceFitPlot.h
575577
InterSpec/RelActAutoGuiRelEffOptions.h
576578
InterSpec/RelActAutoGuiEnergyRange.h
577579
InterSpec/RelActAutoGuiNuclide.h
@@ -634,7 +636,11 @@ deploy_js_resource("${CMAKE_CURRENT_SOURCE_DIR}/external_libs/SpecUtils/d3_resou
634636

635637

636638

637-
list( APPEND OTHER_InterSpec_SUPPORT_FILES ${CMAKE_CURRENT_SOURCE_DIR}/InterSpec_resources/D3TimeChart.js )
639+
list( APPEND OTHER_InterSpec_SUPPORT_FILES
640+
${CMAKE_CURRENT_SOURCE_DIR}/InterSpec_resources/D3TimeChart.js
641+
${CMAKE_CURRENT_SOURCE_DIR}/InterSpec_resources/ShieldingSourceFitPlot.js
642+
${CMAKE_CURRENT_SOURCE_DIR}/InterSpec_resources/ShieldingSourceFitPlot.css
643+
)
638644

639645
deploy_js_resource("${CMAKE_CURRENT_SOURCE_DIR}/external_libs/SpecUtils/d3_resources/SpectrumChartD3.js"
640646
"${CMAKE_CURRENT_BINARY_DIR}/InterSpec_resources/SpectrumChartD3.js"

InterSpec/BatchInfoLog.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,18 @@ namespace BatchInfoLog
9797
"D3_JS": contents of `InterSpec_resources/d3.v3.min.js`
9898
"SpectrumChart_JS": contents of `InterSpec_resources/SpectrumChartD3.js`
9999
"SpectrumChart_CSS": contents of `InterSpec_resources/SpectrumChartD3.css`
100-
100+
101101
*/
102102
std::vector<std::pair<std::string,std::string>> load_spectrum_chart_js_and_css();
103+
104+
/** Returns key-value pairs of the file contents of the JS and CSS files needed for ShieldingSourceFitPlot. Specifically returns:
105+
106+
"D3_JS": contents of `InterSpec_resources/d3.v3.min.js`
107+
"ShieldingSourceFitPlot_JS": contents of `InterSpec_resources/ShieldingSourceFitPlot.js`
108+
"ShieldingSourceFitPlot_CSS": contents of `InterSpec_resources/ShieldingSourceFitPlot.css`
109+
110+
*/
111+
std::vector<std::pair<std::string,std::string>> load_shielding_fit_plot_js_and_css();
103112

104113
/** An enum to provide context of what default templates names "csv", "txt", and "html" refer to for `render_template(...)` */
105114
enum class TemplateRenderType : int

InterSpec/ShieldingSourceDisplay.h

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@
3434
#include <boost/optional.hpp>
3535
#endif
3636

37-
#include <Wt/WRectF>
3837
#include <Wt/WColor>
38+
#include <Wt/WRectF>
3939
#include <Wt/WPainter>
4040
#include <Wt/WModelIndex>
4141
#include <Wt/WGridLayout>
4242
#include <Wt/WContainerWidget>
4343
#include <Wt/WAbstractItemModel>
44-
#include <Wt/Chart/WCartesianChart>
4544

45+
#include "InterSpec/ShieldingSourceFitPlot.h"
4646
#include "InterSpec/DetectorPeakResponse.h" //DetectorPeakResponse::EffGeometryType
4747
#include "InterSpec/ShieldingSourceFitCalc.h"
4848

@@ -490,8 +490,11 @@ class ShieldingSourceDisplay : public Wt::WContainerWidget
490490
void handleShieldingChange();
491491

492492
void handleDetectorChanged( std::shared_ptr<DetectorPeakResponse> new_det );
493-
493+
494494
void updateChi2Chart();
495+
496+
/** Callback for when the user toggles between Chi and Mult display modes in the chart */
497+
void handleChi2ChartDisplayModeChanged( bool showChi );
495498

496499
void showCalcLog();
497500
void closeCalcLogWindow();
@@ -691,8 +694,7 @@ class ShieldingSourceDisplay : public Wt::WContainerWidget
691694
Wt::WText *m_fixedGeometryTxt;
692695

693696
Wt::WText *m_showChi2Text;
694-
Wt::WStandardItemModel *m_chi2Model;
695-
Chi2Graphic *m_chi2Graphic;
697+
ShieldingSourceFitPlot *m_chi2Plot;
696698

697699

698700
Wt::WCheckBox *m_multiIsoPerPeak;
@@ -732,30 +734,6 @@ class ShieldingSourceDisplay : public Wt::WContainerWidget
732734
std::shared_ptr<GammaInteractionCalc::ShieldingSourceChi2Fcn> m_currentFitFcn;
733735

734736
//A class to draw the chi2 distribution of the fit to activity/shielding.
735-
// We have to overide the Paint(...) method to draw some text on chart
736-
// indicating the chi2
737-
class Chi2Graphic : public Wt::Chart::WCartesianChart
738-
{
739-
public:
740-
Chi2Graphic( Wt::WContainerWidget *parent = 0 );
741-
virtual ~Chi2Graphic();
742-
virtual void paint( Wt::WPainter &painter,
743-
const Wt::WRectF &rectangle = Wt::WRectF() ) const;
744-
virtual void paintEvent( Wt::WPaintDevice *paintDevice );
745-
void setNumFitForParams( unsigned int npar );
746-
747-
void setShowChiOnChart( const bool show_chi );
748-
void setTextPenColor( const Wt::WColor &color );
749-
void setColorsFromTheme( std::shared_ptr<const ColorTheme> theme );
750-
protected:
751-
void calcAndSetAxisRanges();
752-
void calcAndSetAxisPadding( double yHeightPx );
753-
754-
int m_nFitForPar;
755-
bool m_showChi;
756-
Wt::WColor m_textPenColor;
757-
};//class WCartesianChart
758-
759737
static const int sm_xmlSerializationMajorVersion;
760738
static const int sm_xmlSerializationMinorVersion;
761739

InterSpec/ShieldingSourceFitPlot.h

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#ifndef ShieldingSourceFitPlot_h
2+
#define ShieldingSourceFitPlot_h
3+
4+
#include "InterSpec_config.h"
5+
6+
#include <map>
7+
#include <memory>
8+
#include <string>
9+
#include <vector>
10+
11+
#include <Wt/WContainerWidget>
12+
#include <Wt/WString>
13+
14+
//Forward declarations
15+
namespace Wt
16+
{
17+
class WColor;
18+
class WCssTextRule;
19+
}//namespace Wt
20+
21+
namespace ShieldingSourceFitCalc
22+
{
23+
struct ModelFitResults;
24+
}//namespace ShieldingSourceFitCalc
25+
26+
27+
class ShieldingSourceFitPlot : public Wt::WContainerWidget
28+
{
29+
public:
30+
ShieldingSourceFitPlot( Wt::WContainerWidget *parent = 0 );
31+
virtual ~ShieldingSourceFitPlot();
32+
33+
/** Set data from activity/shielding fit results. */
34+
void setData( const ShieldingSourceFitCalc::ModelFitResults &results );
35+
36+
/** Set whether to show Chi or Mult mode. */
37+
void setShowChi( bool show_chi );
38+
39+
/** Generate JSON string from ModelFitResults for passing to JavaScript or static HTML. */
40+
static std::string jsonForData( const ShieldingSourceFitCalc::ModelFitResults &results );
41+
42+
/** Set the x-axis title. */
43+
void setXAxisTitle( const Wt::WString &title );
44+
45+
/** Set the y-axis title for Chi mode. */
46+
void setYAxisTitleChi( const Wt::WString &title );
47+
48+
/** Set the y-axis title for Mult mode. */
49+
void setYAxisTitleMult( const Wt::WString &title );
50+
51+
/** Set the chart content margins (e.g. how many pixels inside the <svg /> element the titles or axises should be drawn).
52+
*/
53+
void setContentMargins( int top, int right, int bottom, int left );
54+
55+
/** Signal emitted when user toggles between Chi and Mult display modes.
56+
Argument is the new state of showChi (true = Chi mode, false = Mult mode).
57+
*/
58+
Wt::Signal<bool> &displayModeChanged();
59+
60+
/** Signal emitted when user clicks on a data point.
61+
Argument is the energy of the clicked point.
62+
*/
63+
Wt::Signal<double> &dataPointClicked();
64+
65+
protected:
66+
void defineJavaScript();
67+
68+
void setCssRules();
69+
70+
virtual void render( Wt::WFlags<Wt::RenderFlag> flags );
71+
72+
virtual void refresh();
73+
74+
/** Generate JSON object with localized strings for JavaScript. */
75+
std::string localizedStringsJson();
76+
77+
/** Send data JSON to JavaScript chart. */
78+
void sendDataToJavaScript( const std::string &jsonData );
79+
80+
/** Callback for when display mode is changed in JavaScript */
81+
void handleDisplayModeChanged( bool showChi );
82+
83+
/** Callback for when a data point is clicked in JavaScript */
84+
void handleDataPointClicked( double energy );
85+
86+
private:
87+
/** The javascript variable name used to refer to the ShieldingSourceFitPlot object.
88+
Currently is `jsRef() + ".chart"`.
89+
*/
90+
const std::string m_jsgraph;
91+
92+
Wt::WString m_xAxisTitle;
93+
Wt::WString m_yAxisTitleChi;
94+
Wt::WString m_yAxisTitleMult;
95+
96+
/** Margins between the edge of the SVG, and where the plot contents start getting drawn, in pixels.
97+
It would be reasonable to instead implement this as CSS margin on the <div /> object the SVG is in,
98+
but leaving for the moment.
99+
*/
100+
int m_topMargin;
101+
int m_rightMargin;
102+
int m_bottomMargin;
103+
int m_leftMargin;
104+
105+
/** The distance between the axis title (if present), and the axis numbers. Defaults to -3 to make compact. */
106+
int m_titlePadding;
107+
108+
/** Whether to show Chi mode (true) or Mult mode (false). */
109+
bool m_showChi;
110+
111+
std::map<std::string,Wt::WCssTextRule *> m_cssRules;
112+
113+
/** JS calls requested before the widget has been rendered, so wouldnt have
114+
ended up doing anything are saved here, and then executed once the widget
115+
is rendered.
116+
Note that not all calls to the D3 chart before Wt's rendering need to go
117+
here as they will be options set to the D3 chart during first rendering.
118+
*/
119+
std::vector<std::string> m_pendingJs;
120+
121+
/** JSignal for display mode changes from JavaScript. */
122+
std::unique_ptr<Wt::JSignal<bool>> m_displayModeChangedJS;
123+
124+
/** JSignal for data point clicks from JavaScript. */
125+
std::unique_ptr<Wt::JSignal<double>> m_dataPointClickedJS;
126+
127+
/** Wt::Signal for display mode changes. */
128+
Wt::Signal<bool> m_displayModeChanged;
129+
130+
/** Wt::Signal for data point clicks. */
131+
Wt::Signal<double> m_dataPointClicked;
132+
133+
};//class ShieldingSourceFitPlot
134+
135+
136+
#endif //ShieldingSourceFitPlot_h
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
CSS variables InterSpec will define for colors:
3+
--d3spec-axis-color
4+
--d3spec-text-color
5+
--d3spec-background-color
6+
--d3spec-chart-area-color
7+
*/
8+
9+
.ShieldingSourceFitPlot {
10+
}
11+
12+
.ShieldingSourceFitPlot > svg {
13+
background: var(--d3spec-background-color, none);
14+
}
15+
16+
.ShieldingSourceFitPlot .chartarea {
17+
background: var(--d3spec-chart-area-color, white);
18+
}
19+
20+
.ShieldingSourceFitPlot .xaxistitle {
21+
fill: var(--d3spec-text-color, black);
22+
font-size: 14px;
23+
}
24+
25+
.ShieldingSourceFitPlot .yaxistitle {
26+
fill: var(--d3spec-text-color, black);
27+
font-size: 14px;
28+
cursor: pointer;
29+
}
30+
31+
.ShieldingSourceFitPlot .xAxis path.domain,
32+
.ShieldingSourceFitPlot .yAxis path.domain,
33+
.ShieldingSourceFitPlot .xAxisMinor path.domain {
34+
fill: none;
35+
stroke: var(--d3spec-axis-color, grey);
36+
}
37+
38+
.ShieldingSourceFitPlot .xAxis .tick line,
39+
.ShieldingSourceFitPlot .yAxis .tick line,
40+
.ShieldingSourceFitPlot .xAxisMinor .tick line {
41+
fill: none;
42+
stroke: var(--d3spec-axis-color, grey);
43+
stroke-width: 1px;
44+
shape-rendering: crispEdges;
45+
}
46+
47+
.ShieldingSourceFitPlot .xAxis text,
48+
.ShieldingSourceFitPlot .yAxis text {
49+
fill: var(--d3spec-text-color, black);
50+
}
51+
52+
.ShieldingSourceFitPlot circle {
53+
cursor: pointer;
54+
}
55+
56+
.ShieldingSourceFitPlot .yaxisarea {
57+
cursor: pointer;
58+
}
59+
60+
.ShieldingSourceFitPlot .errorbar {
61+
fill: none;
62+
stroke-width: 1;
63+
}
64+
65+
.ShieldingSourceFitPlot .refline {
66+
stroke: grey;
67+
stroke-width: 1;
68+
stroke-dasharray: 5,5;
69+
fill: none;
70+
}
71+
72+
.ShieldingSourceFitPlot .devtext {
73+
fill: var(--d3spec-text-color, black);
74+
}
75+
76+
div.ShieldingSourceFitPlotTooltip {
77+
position: fixed;
78+
padding: 6px;
79+
font: 12px sans-serif;
80+
background: #ffffcc;
81+
border: 0px;
82+
border-radius: 8px;
83+
pointer-events: none;
84+
color: #444422;
85+
}

0 commit comments

Comments
 (0)