Skip to content

Commit

Permalink
Work towards supporting spectra with y values less than one.
Browse files Browse the repository at this point in the history
Initial solution towards issue #33 - still todo is to detect spectra with all very small counts, and automatically adjust y-range (current app logic expects roughly 1 count per channel as smallest non-zero y-values - roughly)
  • Loading branch information
wcjohns committed Oct 12, 2024
1 parent bfd3567 commit 95272d4
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 18 deletions.
3 changes: 3 additions & 0 deletions InterSpec/D3SpectrumDisplayDiv.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ class D3SpectrumDisplayDiv : public Wt::WContainerWidget
*/
void setLogYAxisMin( const double ymin );

/** Returns the `m_logYAxisMin` value */
double logYAxisMin() const;

// These 3 functions retrieve the corresponding info from the model.
std::shared_ptr<const SpecUtils::Measurement> data() const;
std::shared_ptr<const SpecUtils::Measurement> secondData() const;
Expand Down
3 changes: 3 additions & 0 deletions InterSpec/InterSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,9 @@ class InterSpec : public Wt::WContainerWidget
(e.g., a negative lower counts was specified, but its currently log-scale)
*/
bool setYAxisRange( float lower_counts, float upper_counts );

/** When displaying the spectrum in log-y, sets the lower y-axis value to show, if there are channels with zero counts. */
bool setLogYAxisMin( const double lower_value );

//displayedSpectrumRange(): Grab the ranges in y and y that are currently
// displayed to the user.
Expand Down
2 changes: 2 additions & 0 deletions InterSpec/TerminalModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class TerminalModel {
ClearVarCommand,
SetEnergyRangeCommand,
SetYaxisRangeCommand,
SetLogYAxisMinCommand,
SearchPeakCommand,
DeletePeakCommand,
RefitPeakCommand,
Expand All @@ -175,6 +176,7 @@ class TerminalModel {
std::string lighten ( const std::string& arguments );
std::string setEnergyRange( const std::string& arguments );
std::string setYRange ( const std::string& arguments );
std::string setLogYAxisMin( const std::string& arguments );
std::string searchforPeak ( const std::string& arguments );
std::string deletePeak ( const std::string& arguments );
std::string refitPeak ( const std::string& arguments );
Expand Down
7 changes: 6 additions & 1 deletion src/D3SpectrumDisplayDiv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1801,8 +1801,13 @@ void D3SpectrumDisplayDiv::setLogYAxisMin( const double ymin )
doJavaScript( m_jsgraph + ".setLogYAxisMin(" + std::to_string(ymin) + ");" );

scheduleUpdateForeground(); //JIC, the JS setPeakLabelRotation(...) wont cause a re-draw
}//void setPeakLabelRotation( const double rotation )
}//void setLogYAxisMin( const double ymin )


double D3SpectrumDisplayDiv::logYAxisMin() const
{
return m_logYAxisMin;
}

void D3SpectrumDisplayDiv::saveChartToImg( const std::string &filename, const bool asPng )
{
Expand Down
78 changes: 76 additions & 2 deletions src/InterSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12219,10 +12219,72 @@ bool InterSpec::setYAxisRange( float lower_counts, float upper_counts )
if( upper_counts < lower_counts )
std::swap( lower_counts, upper_counts );

if( (lower_counts <= 1.0E-6) && (upper_counts <= 1.0E-6) )
if( upper_counts == lower_counts )
return false;

if( (lower_counts < 9.9E-7) && m_spectrum->yAxisIsLog() )
const bool isLogY = m_spectrum->yAxisIsLog();

// If user is setting suspiciously small values, lets do some sanity checks.
// If log-y, there is a minimum lower y-value on the client side - we may need
// to adjust this.
if( (isLogY &&
((lower_counts < m_spectrum->logYAxisMin())
|| (lower_counts < std::numeric_limits<float>::min())))
|| (!isLogY && (lower_counts <= 1.0E-6) && (upper_counts <= 1.0E-6)) )
{
const auto hist = displayedHistogram(SpecUtils::SpectrumType::Foreground);
if( !hist || !hist->gamma_counts() || (hist->gamma_counts()->size() < 2) )
return false;

const shared_ptr<const vector<float>> &channels = hist->gamma_counts();

// Lets check the y-range - ignoring we may be showing multiple channels per display-bin,
// to see if the requested range is reasonable
double xmin, xmax, ymin, ymax;
m_spectrum->visibleRange( xmin, xmax, ymin, ymax );

const size_t lower_channel = hist->find_gamma_channel(xmin);
const size_t upper_channel = hist->find_gamma_channel(xmax);
float min_nonzero_value = std::numeric_limits<float>::max();
float max_value = -std::numeric_limits<float>::max();

for( size_t channel = lower_channel; channel <= upper_channel; ++channel )
{
if( channel < channels->size() )
{
const float val = (*channels)[channel];
max_value = std::max( max_value, val );
if( val > 0.0f )
min_nonzero_value = std::min( min_nonzero_value, val );
}//if( channel < channels->size() )
}//for( loop over visible channels )

if( upper_counts <= min_nonzero_value )
return false;

if( isLogY )
{
if( lower_counts <= 0.0f )
{
success = false;
lower_counts = 0.9 * min_nonzero_value;
}
if( upper_counts <= lower_counts )
{
success = false;
upper_counts = 10.0*lower_counts;
}

const double prevMinLogY = m_spectrum->logYAxisMin();
if( lower_counts < prevMinLogY )
m_spectrum->setLogYAxisMin( lower_counts );
}//if( isLogY )

m_spectrum->setYAxisRange( lower_counts, upper_counts );
return success;
}//

if( (lower_counts < 9.9E-7) && isLogY )
{
success = false;
lower_counts = 1.0E-6;
Expand All @@ -12236,7 +12298,19 @@ bool InterSpec::setYAxisRange( float lower_counts, float upper_counts )
}//bool setYAxisRange(...)


bool InterSpec::setLogYAxisMin( const double lower_value )
{
try
{
m_spectrum->setLogYAxisMin( lower_value );
}catch( std::exception & )
{
return false;
}
return true;
}//setLogYAxisMin( float lower_value )


void InterSpec::displayedSpectrumRange( double &xmin, double &xmax, double &ymin, double &ymax ) const
{
m_spectrum->visibleRange( xmin, xmax, ymin, ymax );
Expand Down
62 changes: 47 additions & 15 deletions src/TerminalModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,7 @@ TerminalModel::TerminalModel( InterSpec* viewer )
addDropDownListHeader( "Spectrum Viewer Commands" );
addCommand( "setRange" , SetEnergyRangeCommand );
addCommand( "setYRange" , SetYaxisRangeCommand );
addCommand( "setLogYAxisMin" , SetLogYAxisMinCommand );
addDropDownListSeparator();

addDropDownListHeader( "Nuclide Commands" );
Expand Down Expand Up @@ -1718,7 +1719,12 @@ void TerminalModel::addCommand(const std::string& command, CommandType type)
"Sets the displayed y-axis range of the current spectrum."
" Outputs if action was a success or not." );
break;


case SetLogYAxisMinCommand:
addDropDownListItem( "setLogYAxisMin( lower_y_counts )",
"y axis zooming counts range yrange axis zoom",
"Sets the minimum displayed y-axis value when there is zero counts." );
break;

default: break;
}//switch( m_commandMap.at(command) )
Expand All @@ -1735,17 +1741,18 @@ std::string TerminalModel::doCommand(const std::string& input)
const std::string& arguments = match[2];

switch ( m_commandMap.at(command) ) {
case VarmapCommand: return variableMapStr( arguments );
case SetEnergyRangeCommand: return setEnergyRange( arguments );
case SetYaxisRangeCommand: return setYRange( arguments );
case SearchPeakCommand: return searchforPeak ( arguments );
case DeletePeakCommand: return deletePeak ( arguments );
case RefitPeakCommand: return refitPeak ( arguments );
case DarkenCommand: return darken ( arguments );
case LightenCommand: return lighten ( arguments );
case SetNuclideCommand: return setNuclide ( arguments );
case SaveCommand: return saveFile ( arguments );
case ClearVarCommand: return clearVar ( arguments );
case VarmapCommand: return variableMapStr( arguments );
case SetEnergyRangeCommand: return setEnergyRange( arguments );
case SetYaxisRangeCommand: return setYRange( arguments );
case SetLogYAxisMinCommand: return setLogYAxisMin( arguments );
case SearchPeakCommand: return searchforPeak ( arguments );
case DeletePeakCommand: return deletePeak ( arguments );
case RefitPeakCommand: return refitPeak ( arguments );
case DarkenCommand: return darken ( arguments );
case LightenCommand: return lighten ( arguments );
case SetNuclideCommand: return setNuclide ( arguments );
case SaveCommand: return saveFile ( arguments );
case ClearVarCommand: return clearVar ( arguments );
default: break;
}
return "Error: unsupported command";
Expand Down Expand Up @@ -1902,9 +1909,10 @@ std::string TerminalModel::setYRange( const std::string& arguments )
if (lower > upper)
std::swap(lower, upper);

if( std::abs(upper - lower) <= 0.01 )
throw mup::ParserError( "Invalid arguments for function (setYRange). Lower and upper bound"
" must not have difference less than or equal to 0.01." );
//const float diff = upper - lower;
//if( diff <= 0.0 )
// throw mup::ParserError( "Invalid arguments for function (setYRange). Lower and upper bound"
// " must not have difference less than or equal to 0.01." );

const bool success = m_viewer->setYAxisRange(lower, upper);

Expand All @@ -1923,6 +1931,30 @@ std::string TerminalModel::setYRange( const std::string& arguments )
}//string TerminalModel::setYRange(string)


std::string TerminalModel::setLogYAxisMin( const std::string& arguments )
{
try
{
m_parser->SetExpr( arguments );
const double counts = m_parser->Eval().GetFloat();

if( counts <= 0 )
throw std::runtime_error( "value must be larger than zero" );

if( !m_viewer->setLogYAxisMin(counts) )
return "Failed to set lower value.";
}catch( const mup::ParserError &e )
{
return errorMessage(e);
}catch( const std::exception &e )
{
return "Error: " + std::string(e.what());
}

return "";
}//string TerminalModel::setYRange(string)


// Command: searchpeak - does the work of double-clicking a peak inside the spectrum
// Syntax: searchpeak( x )
// Return value: none, basically highlights a peak on the spectrum and outputs whether or not it was successful or not
Expand Down

0 comments on commit 95272d4

Please sign in to comment.