NEW: Added new JKQTPCALabelType elements (JKQTPCALTfrac...), so axis label ticks can be displayed as fractions 1/2 instead of 0.5

NEW: Added new JKQTPCALabelType element JKQTPCALTscientific, so axis label ticks can be displayed as numbers in scientific notation like 1.2E-34
auto-generate JKQTPCALabelType documentation
This commit is contained in:
jkriege2 2022-09-22 00:44:54 +02:00
parent e65cd82fbb
commit 60a4656dd8
25 changed files with 446 additions and 195 deletions

View File

@ -114,6 +114,14 @@ if(JKQtPlotter_BUILD_TOOLS)
) )
add_dependencies(JKQTPlotter_GenerateDocImages JKQTPlotter_GenerateDocImages_listerrorindicators) add_dependencies(JKQTPlotter_GenerateDocImages JKQTPlotter_GenerateDocImages_listerrorindicators)
add_custom_target(JKQTPlotter_GenerateDocImages_listaxislabeltype
COMMENT "Building JKQTPlotter Documentation Images: listaxislabeltype"
COMMAND ${JKQTPlotter_GenerateDocImages_COMMAND} --listaxislabeltype --background=lightgrey --iconsize=50 --outputdir="${JKQTPlotter_GenerateDocImages_OutputDir}/"
WORKING_DIRECTORY ${JKQtPlotter_QT_BINDIR}
DEPENDS jkqtplotter_doc_imagegenerator
)
add_dependencies(JKQTPlotter_GenerateDocImages JKQTPlotter_GenerateDocImages_listaxislabeltype)
endif(JKQtPlotter_BUILD_TOOLS) endif(JKQtPlotter_BUILD_TOOLS)

View File

@ -52,6 +52,8 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
<li>NEW: barcharts (derived from JKQTPBarGraphBase) can be configured to use different fill styles above and below the baseline, see JKQTPBarGraphBase::FillMode </li> <li>NEW: barcharts (derived from JKQTPBarGraphBase) can be configured to use different fill styles above and below the baseline, see JKQTPBarGraphBase::FillMode </li>
<li>NEW: added new error indicator styles JKQTPErrorHalfBarsOutwards, JKQTPErrorHalfBarsInwards, JKQTPErrorHalfBarsAbove, JKQTPErrorHalfBarsBelow which are especially useful for barcharts</li> <li>NEW: added new error indicator styles JKQTPErrorHalfBarsOutwards, JKQTPErrorHalfBarsInwards, JKQTPErrorHalfBarsAbove, JKQTPErrorHalfBarsBelow which are especially useful for barcharts</li>
<li>NEW: Added signals JKQTBasePlotter::beforeExporting()/JKQTBasePlotter::afterExporting() and JKQTBasePlotterJKQTBasePlotter:beforePrinting()/JKQTBasePlotter::afterPrinting() which allow to modify the plot just before and just after an export/print</li> <li>NEW: Added signals JKQTBasePlotter::beforeExporting()/JKQTBasePlotter::afterExporting() and JKQTBasePlotterJKQTBasePlotter:beforePrinting()/JKQTBasePlotter::afterPrinting() which allow to modify the plot just before and just after an export/print</li>
<li>NEW: Added new JKQTPCALabelType elements (JKQTPCALTfrac...), so axis label ticks can be displayed as fractions 1/2 instead of 0.5</li>
<li>NEW: Added new JKQTPCALabelType element JKQTPCALTscientific, so axis label ticks can be displayed as numbers in scientific notation like \c 1.2E-34 </li>
</ul></li> </ul></li>
<li>JKQTMathText:<ul> <li>JKQTMathText:<ul>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -22,3 +22,42 @@
#include <cmath> #include <cmath>
uint64_t jkqtp_gcd(uint64_t a, uint64_t b)
{
if (a == 0)
return b;
else if (b == 0)
return a;
if (a < b)
return jkqtp_gcd(a, b % a);
else
return jkqtp_gcd(b, a % b);
}
void jkqtp_estimateFraction(double input, int& sign, uint64_t &intpart, uint64_t &num, uint64_t &denom, unsigned int precision)
{
// see https://stackoverflow.com/a/28662740
// https://stackoverflow.com/questions/4819075/how-to-output-fraction-instead-of-decimal-number
// https://stackoverflow.com/a/64828741
// https://stackoverflow.com/questions/26643695/converting-a-floating-point-decimal-value-to-a-fraction
sign=+1;
if (input<0.0) {
sign=-1;
input=fabs(input);
}
// now input is guaranteed positive and sign stores the sign +1 or -1
const double integral = std::floor(input);
const double frac = input - integral;
const double prec = pow(10,precision); // This is the accuracy.
uint64_t gcd_ = jkqtp_gcd(static_cast<uint64_t>(round(frac * prec)), static_cast<uint64_t>(prec));
denom = static_cast<uint64_t>(prec / gcd_);
num = static_cast<uint64_t>(round(frac * prec) / gcd_);
intpart=static_cast<uint64_t>(integral);
}

View File

@ -528,4 +528,15 @@ QString jkqtp_polynomialModel2Latex(PolyItP firstP, PolyItP lastP) {
return str; return str;
} }
/*! \brief calculate the grwates common divisor (GCD) of \a a and \a b
\ingroup jkqtptools_math_basic
*/
JKQTCOMMON_LIB_EXPORT uint64_t jkqtp_gcd(uint64_t a, uint64_t b);
/*! \brief calculates numeratur integer part \a intpart , \a num and denominator \a denom of a fraction, representing a given floating-point number \a input
\ingroup jkqtptools_math_basic
*/
JKQTCOMMON_LIB_EXPORT void jkqtp_estimateFraction(double input, int &sign, uint64_t &intpart, uint64_t& num, uint64_t& denom, unsigned int precision=9);
#endif // jkqtpmathtools_H_INCLUDED #endif // jkqtpmathtools_H_INCLUDED

View File

@ -170,22 +170,23 @@ std::string jkqtp_tolower(const std::string& s){
}; };
std::string jkqtp_floattounitstr(double data, int past_comma, bool remove_trail0){ std::string jkqtp_floattounitstr(double data, int past_comma, bool remove_trail0, double belowIsZero){
if (data==0) return "0"; if (fabs(data)<=belowIsZero) return "0";
std::string form="%."+jkqtp_inttostr(past_comma)+"lf"; std::string form="%."+jkqtp_inttostr(past_comma)+"lf";
std::string res=jkqtp_format(form,data); std::string res=jkqtp_format(form,data);
if (fabs(data)>=1e3) res=jkqtp_format(form,data/1e3)+"k"; std::string unit="";
if (fabs(data)>=1e6) res=jkqtp_format(form,data/1e6)+"M"; if (fabs(data)>=1e3) {res=jkqtp_format(form,data/1e3); unit="k";}
if (fabs(data)>=1e9) res=jkqtp_format(form,data/1e9)+"G"; if (fabs(data)>=1e6) {res=jkqtp_format(form,data/1e6); unit="M";}
if (fabs(data)>=1e12) res=jkqtp_format(form,data/1e12)+"T"; if (fabs(data)>=1e9) {res=jkqtp_format(form,data/1e9); unit="G";}
if (fabs(data)>=1e15) res=jkqtp_format(form,data/1e15)+"P"; if (fabs(data)>=1e12) {res=jkqtp_format(form,data/1e12); unit="T";}
if (fabs(data)<1) res=jkqtp_format(form,data/1e-3)+"m"; if (fabs(data)>=1e15) {res=jkqtp_format(form,data/1e15); unit="P";}
if (fabs(data)<1e-3) res=jkqtp_format(form,data/1e-6)+"u"; if (fabs(data)<1) {res=jkqtp_format(form,data/1e-3); unit="m";}
if (fabs(data)<1e-6) res=jkqtp_format(form,data/1e-9)+"n"; if (fabs(data)<1e-3) {res=jkqtp_format(form,data/1e-6); unit="u";}
if (fabs(data)<1e-9) res=jkqtp_format(form,data/1e-12)+"f"; if (fabs(data)<1e-6) {res=jkqtp_format(form,data/1e-9); unit="n";}
if (fabs(data)<1e-9) {res=jkqtp_format(form,data/1e-12); unit="f";}
if (fabs(data)==0) res=jkqtp_format(form,data); if (fabs(data)==0) res=jkqtp_format(form,data);
if (remove_trail0) { if (remove_trail0) {
if (data==0) return "0"; if (fabs(data)<=belowIsZero) return "0";
if (res.find('.')==std::string::npos) return res; if (res.find('.')==std::string::npos) return res;
size_t i=res.size()-1; size_t i=res.size()-1;
while (i>0 && res[i]=='0') { while (i>0 && res[i]=='0') {
@ -194,10 +195,39 @@ std::string jkqtp_tolower(const std::string& s){
if (res[i]=='.') i--; // remove decimal divider if (res[i]=='.') i--; // remove decimal divider
return res.erase(i+1); return res.erase(i+1);
} }
return res; return res+unit;
} }
std::string jkqtp_floattolatexstr(double data, int past_comma, bool remove_trail0, double belowIsZero, double minNoExponent, double maxNoExponent, bool ensurePlusMinus){
std::string jkqtp_floattolatexunitstr(double data, int past_comma, bool remove_trail0, double belowIsZero){
if (fabs(data)<=belowIsZero) return "0";
std::string form="%."+jkqtp_inttostr(past_comma)+"lf";
std::string res=jkqtp_format(form,data);
std::string unit="";
if (fabs(data)>=1e3) {res=jkqtp_format(form,data/1e3); unit="\\mathrm{k}";}
if (fabs(data)>=1e6) {res=jkqtp_format(form,data/1e6); unit="\\;\\mathrm{M}";}
if (fabs(data)>=1e9) {res=jkqtp_format(form,data/1e9); unit="\\;\\mathrm{G}";}
if (fabs(data)>=1e12) {res=jkqtp_format(form,data/1e12); unit="\\;\\mathrm{T}";}
if (fabs(data)>=1e15) {res=jkqtp_format(form,data/1e15); unit="\\;\\mathrm{P}";}
if (fabs(data)<1) {res=jkqtp_format(form,data/1e-3); unit="\\;\\mathrm{m}";}
if (fabs(data)<1e-3) {res=jkqtp_format(form,data/1e-6); unit="\\;\\mathrm{\\mu}";}
if (fabs(data)<1e-6) {res=jkqtp_format(form,data/1e-9); unit="\\;\\mathrm{n}";}
if (fabs(data)<1e-9) {res=jkqtp_format(form,data/1e-12); unit="\\;\\mathrm{f}";}
if (fabs(data)==0) res=jkqtp_format(form,data);
if (remove_trail0) {
if (fabs(data)<=belowIsZero) return "0";
if (res.find('.')==std::string::npos) return res+unit;
size_t i=res.size()-1;
while (i>0 && res[i]=='0') {
i--;
}
if (res[i]=='.') i--; // remove decimal divider
return res.erase(i+1)+unit;
}
return res+unit;
}
std::string jkqtp_floattolatexstr(double data, int past_comma, bool remove_trail0, double belowIsZero, double minNoExponent, double maxNoExponent, bool ensurePlusMinus, const std::string &multOperator){
if ((belowIsZero>0) && (fabs(data)<belowIsZero)) { if ((belowIsZero>0) && (fabs(data)<belowIsZero)) {
if (ensurePlusMinus) return "+\\rm{0}"; if (ensurePlusMinus) return "+\\rm{0}";
else return "\\rm{0}"; else return "\\rm{0}";
@ -214,7 +244,7 @@ std::string jkqtp_tolower(const std::string& s){
if ((minNoExponent>fabs(data)) || (fabs(data)>maxNoExponent)) { if ((minNoExponent>fabs(data)) || (fabs(data)>maxNoExponent)) {
std::string v=jkqtp_floattostr(data/pow(10.0, static_cast<double>(exp)), past_comma, remove_trail0); std::string v=jkqtp_floattostr(data/pow(10.0, static_cast<double>(exp)), past_comma, remove_trail0);
if (v!="1" && v!="10") { if (v!="1" && v!="10") {
res=v+std::string("{\\times}10^{")+jkqtp_inttostr(exp)+"}"; res=v+std::string("{")+multOperator+std::string("}10^{")+jkqtp_inttostr(exp)+"}";
} else { } else {
if (v=="10") exp=exp+1; if (v=="10") exp=exp+1;
res=std::string("10^{")+jkqtp_inttostr(exp)+"}"; res=std::string("10^{")+jkqtp_inttostr(exp)+"}";

View File

@ -26,6 +26,7 @@
#include <QLocale> #include <QLocale>
#include <string> #include <string>
#include <QtGlobal> #include <QtGlobal>
#include <limits>
/** \brief converts a QT::PenStyle into a string /** \brief converts a QT::PenStyle into a string
* \ingroup jkqtptools_string * \ingroup jkqtptools_string
@ -231,11 +232,15 @@ JKQTCOMMON_LIB_EXPORT std::string jkqtp_to_valid_variable_name(const std::string
/** \brief convert a double to a string, encoding powers of ten as characters, e.g. \c jkqtp_floattounitstr(1000) will result in "1k" /** \brief convert a double to a string, encoding powers of ten as characters, e.g. \c jkqtp_floattounitstr(1000) will result in "1k"
* \ingroup jkqtptools_string * \ingroup jkqtptools_string
*/ */
JKQTCOMMON_LIB_EXPORT std::string jkqtp_floattounitstr(double data, int past_comma=5, bool remove_trail0=false); JKQTCOMMON_LIB_EXPORT std::string jkqtp_floattounitstr(double data, int past_comma=5, bool remove_trail0=false, double belowIsZero=std::numeric_limits<double>::min()*4);
/** \brief convert a double to a LaTeX-encoded string, encoding powers of ten as characters, e.g. \c jkqtp_floattounitstr(1000) will result in "1k"
* \ingroup jkqtptools_string
*/
JKQTCOMMON_LIB_EXPORT std::string jkqtp_floattolatexunitstr(double data, int past_comma=5, bool remove_trail0=false, double belowIsZero=std::numeric_limits<double>::min()*4);
/** \brief convert a double to a string, encoding powers of ten as exponent in LaTeX notation (e.g. <code>-1.23\\cdot 10^{-5}</code>) /** \brief convert a double to a string, encoding powers of ten as exponent in LaTeX notation (e.g. <code>-1.23\\cdot 10^{-5}</code>)
* \ingroup jkqtptools_string * \ingroup jkqtptools_string
*/ */
JKQTCOMMON_LIB_EXPORT std::string jkqtp_floattolatexstr(double data, int past_comma=5, bool remove_trail0=false, double belowIsZero=1e-16, double minNoExponent=1e-3, double maxNoExponent=1e4, bool ensurePlusMinus=false); JKQTCOMMON_LIB_EXPORT std::string jkqtp_floattolatexstr(double data, int past_comma=5, bool remove_trail0=false, double belowIsZero=1e-16, double minNoExponent=1e-3, double maxNoExponent=1e4, bool ensurePlusMinus=false, const std::string& multOperator="\\times");
/** \brief convert a double to a string, encoding powers of ten as exponent with HTML tags /** \brief convert a double to a string, encoding powers of ten as exponent with HTML tags
* \ingroup jkqtptools_string * \ingroup jkqtptools_string
*/ */

View File

@ -345,10 +345,14 @@ JKQTPCALabelTypeComboBox::JKQTPCALabelTypeComboBox(QWidget *parent):
setEditable(false); setEditable(false);
addLabelType(JKQTPCALTexponent, tr("exponent"), QIcon(":/JKQTPlotter/jkqtp_ticks_exp.png")); addLabelType(JKQTPCALTexponent, tr("exponent"), QIcon(":/JKQTPlotter/jkqtp_ticks_exp.png"));
addLabelType(JKQTPCALTdefault, tr("default"), QIcon(":/JKQTPlotter/jkqtp_ticks_default.png")); addLabelType(JKQTPCALTdefault, tr("default"), QIcon(":/JKQTPlotter/jkqtp_ticks_default.png"));
addLabelType(JKQTPCALTdefault, tr("scientific"), QIcon(":/JKQTPlotter/jkqtp_ticks_scientific.png"));
addLabelType(JKQTPCALTexponentCharacter, tr("character"), QIcon(":/JKQTPlotter/jkqtp_ticks_expchar.png")); addLabelType(JKQTPCALTexponentCharacter, tr("character"), QIcon(":/JKQTPlotter/jkqtp_ticks_expchar.png"));
addLabelType(JKQTPCALTtime, tr("time"), QIcon(":/JKQTPlotter/jkqtp_ticks_time.png")); addLabelType(JKQTPCALTtime, tr("time"), QIcon(":/JKQTPlotter/jkqtp_ticks_time.png"));
addLabelType(JKQTPCALTdate, tr("date"), QIcon(":/JKQTPlotter/jkqtp_ticks_date.png")); addLabelType(JKQTPCALTdate, tr("date"), QIcon(":/JKQTPlotter/jkqtp_ticks_date.png"));
addLabelType(JKQTPCALTdatetime, tr("datetime"), QIcon(":/JKQTPlotter/jkqtp_ticks_datetime.png")); addLabelType(JKQTPCALTdatetime, tr("datetime"), QIcon(":/JKQTPlotter/jkqtp_ticks_datetime.png"));
addLabelType(JKQTPCALTfrac, tr("fraction"), QIcon(":/JKQTPlotter/jkqtp_ticks_frac.png"));
addLabelType(JKQTPCALTsfrac, tr("\\sfrac fraction"), QIcon(":/JKQTPlotter/jkqtp_ticks_sfrac.png"));
addLabelType(JKQTPCALTslashfrac, tr("slash fraction"), QIcon(":/JKQTPlotter/jkqtp_ticks_slashfrac.png"));
setCurrentIndex(0); setCurrentIndex(0);
} }

View File

@ -21,6 +21,7 @@
#include "jkqtplotter/jkqtpbaseplotter.h" #include "jkqtplotter/jkqtpbaseplotter.h"
#include "jkqtcommon/jkqtpdrawingtools.h" #include "jkqtcommon/jkqtpdrawingtools.h"
#include "jkqtcommon/jkqtpgeometrytools.h" #include "jkqtcommon/jkqtpgeometrytools.h"
#include "jkqtcommon/jkqtpmathtools.h"
#include <QDebug> #include <QDebug>
#include <QDateTime> #include <QDateTime>
#include <cfloat> #include <cfloat>
@ -85,6 +86,7 @@ const JKQTMathText* JKQTPCoordinateAxis::getParentMathText() const {
return parent->getMathText(); return parent->getMathText();
} }
void JKQTPCoordinateAxis::clearAxisTickLabels() { void JKQTPCoordinateAxis::clearAxisTickLabels() {
tickLabels.clear(); tickLabels.clear();
redrawPlot(); redrawPlot();
@ -360,9 +362,38 @@ double JKQTPCoordinateAxis::calcLogTickSpacing() {
} }
QString JKQTPCoordinateAxis::floattostringWithFormat(const QLocale & loc, double data, char format, int past_comma, bool remove_trail0) const
{
QString res=loc.toString(data, format, past_comma);
if (remove_trail0 && res.contains(QLocale::system().decimalPoint())) {
QString expo="";
const int expIdx=res.toLower().indexOf('e');
if (expIdx>=0) {
expo=res.mid(expIdx);
res=res.left(expIdx);
}
while (res.size()>0 && res[res.size()-1]=='0') {
res=res.left(res.size()-1);
}
if (res.size()>0 && res[res.size()-1]==loc.decimalPoint()) res=res.left(res.size()-1);
res=res+expo;
}
return res;
}
QString JKQTPCoordinateAxis::floattostringWithFormat(double data, char format, int past_comma, bool remove_trail0) const
{
QLocale loc=QLocale::system();
loc.setNumberOptions(QLocale::OmitGroupSeparator);
return floattostringWithFormat(loc, data, format, past_comma, remove_trail0);
}
QString JKQTPCoordinateAxis::floattolabel(double data) const { QString JKQTPCoordinateAxis::floattolabel(double data) const {
int past_comma=axisStyle.labelDigits; const int past_comma=axisStyle.labelDigits;
return floattolabel(data, past_comma);
}
QString JKQTPCoordinateAxis::floattolabel(double data, int past_comma) const {
const bool remove_trail0=true; const bool remove_trail0=true;
QLocale loc= QLocale::system(); QLocale loc= QLocale::system();
loc.setNumberOptions(QLocale::OmitGroupSeparator); loc.setNumberOptions(QLocale::OmitGroupSeparator);
@ -373,22 +404,60 @@ QString JKQTPCoordinateAxis::floattolabel(double data) const {
} }
switch(axisStyle.labelType) { switch(axisStyle.labelType) {
case JKQTPCALTdefault: { case JKQTPCALTcount:
QString res=loc.toString(data, 'f', past_comma); return "";
if (remove_trail0 && res.contains(QLocale::system().decimalPoint())) { case JKQTPCALTdefault:
while (res.size()>0 && res[res.size()-1]=='0') { return floattostringWithFormat(loc, data, 'f', past_comma, remove_trail0);
res=res.left(res.size()-1); case JKQTPCALTscientific:
} return floattostringWithFormat(loc, data, 'e', past_comma, remove_trail0);
if (res.size()>0 && res[res.size()-1]==loc.decimalPoint()) res=res.left(res.size()-1); case JKQTPCALTexponent:
}
return res;
}; break;
case JKQTPCALTexponent: {
return QString(jkqtp_floattolatexstr(data, past_comma, remove_trail0, belowIsZero, pow(10, -past_comma), pow(10, past_comma+1)).c_str()); return QString(jkqtp_floattolatexstr(data, past_comma, remove_trail0, belowIsZero, pow(10, -past_comma), pow(10, past_comma+1)).c_str());
}; break; case JKQTPCALTexponentCharacter:
case JKQTPCALTexponentCharacter: { return QString(jkqtp_floattolatexunitstr(data, past_comma, remove_trail0).c_str());
return QString(jkqtp_floattounitstr(data, past_comma, remove_trail0).c_str()); case JKQTPCALTintfrac:
}; break; case JKQTPCALTintsfrac:
case JKQTPCALTintslashfrac:
case JKQTPCALTfrac:
case JKQTPCALTsfrac:
case JKQTPCALTslashfrac: {
uint64_t num=0;
uint64_t denom=0;
uint64_t intpart=0;
int sign=+1;
const double powfac=pow(10,past_comma);
const double rounded=round(data*powfac)/powfac;
jkqtp_estimateFraction(rounded, sign, intpart, num, denom);
//std::cout<<"\n"<<data<<" => "<<rounded<<", "<<sign<<"*( "<<intpart<<" + "<<num<<"/"<<denom<<" )\n";
if (axisStyle.labelType==JKQTPCALTfrac || axisStyle.labelType==JKQTPCALTsfrac || axisStyle.labelType==JKQTPCALTslashfrac) {
if (intpart>0) {
num=num+denom*intpart;
intpart=0;
}
}
//std::cout<<data<<" => "<<rounded<<", "<<sign<<"*( "<<intpart<<" + "<<num<<"/"<<denom<<" )\n";
QString res;
if (rounded==0.0 || (intpart==0 && num==0)) res= "0";
else {
if (intpart==0 && sign<0) res+="-";
if (intpart!=0) res+=QString::number(intpart);
if (num!=0) {
if (denom==1) res=QString::number(num);
else {
if (axisStyle.labelType==JKQTPCALTfrac || axisStyle.labelType==JKQTPCALTintfrac) res+=QString("\\frac{%1}{%2}").arg(num).arg(denom);
else if (axisStyle.labelType==JKQTPCALTsfrac || axisStyle.labelType==JKQTPCALTintsfrac) res+=QString("\\sfrac{%1}{%2}").arg(num).arg(denom);
else {
if (res.size()>0 && res[res.size()-1].isDigit()) {
if (sign<0) res+="-";
else res+="+";
}
res+=QString("%1/%2").arg(num).arg(denom);
}
}
}
}
//std::cout<<data<<" => "<<rounded<<", "<<res.toStdString()<<"\n";
return res;
}
case JKQTPCALTdate: { case JKQTPCALTdate: {
QDateTime dt; QDateTime dt;
dt.setMSecsSinceEpoch(uint64_t(data)); dt.setMSecsSinceEpoch(uint64_t(data));
@ -404,36 +473,8 @@ QString JKQTPCoordinateAxis::floattolabel(double data) const {
dt.setMSecsSinceEpoch(uint64_t(data)); dt.setMSecsSinceEpoch(uint64_t(data));
return dt.toString(axisStyle.tickDateTimeFormat); return dt.toString(axisStyle.tickDateTimeFormat);
}; break; }; break;
default: }
return QString(); return QString();
break;
}
/*
axisStyle.tickTimeFormat
axisStyle.tickDateFormat
axisStyle.tickDateTimeFormat
**/
return QString();
}
QString JKQTPCoordinateAxis::floattolabel(double data, int past_comma) const {
bool remove_trail0=true;
QLocale loc=QLocale::system();
loc.setNumberOptions(QLocale::OmitGroupSeparator);
if (axisStyle.labelType==JKQTPCALTdefault) {
QString res=loc.toString(data, 'f', past_comma);//QString::number(data, 'f', past_comma);
if (remove_trail0 && res.contains(QLocale::system().decimalPoint())) {
while (res.size()>0 && res[res.size()-1]=='0') {
res=res.left(res.size()-1);
}
if (res.size()>0 && res[res.size()-1]==loc.decimalPoint()) res=res.left(res.size()-1);
}
return res;
} else if (axisStyle.labelType==JKQTPCALTexponent) return QString(jkqtp_floattolatexstr(data, past_comma, remove_trail0, 1e-300, pow(10, -past_comma), pow(10, past_comma+1)).c_str());
else if (axisStyle.labelType==JKQTPCALTexponentCharacter) return QString(jkqtp_floattounitstr(data, past_comma, remove_trail0).c_str());
return "";
} }
int JKQTPCoordinateAxis::calcLinearUnitDigits() { int JKQTPCoordinateAxis::calcLinearUnitDigits() {

View File

@ -588,6 +588,10 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPCoordinateAxis: public QObject {
const JKQTMathText* getParentMathText() const; const JKQTMathText* getParentMathText() const;
/** \brief convert a float to a string using \a format (\c f|e|E|g|G ) with given number of decimals after comma \a past_comma and optional removal of trailing zeros behind decimal separator \a remove_trail0. Uses current local, disables not use Group-Separator */
QString floattostringWithFormat(const QLocale & loc, double data, char format, int past_comma, bool remove_trail0=true) const;
/** \brief convert a float to a string using \a format (\c f|e|E|g|G ) with given number of decimals after comma \a past_comma and optional removal of trailing zeros behind decimal separator \a remove_trail0. Uses current local, disables not use Group-Separator */
QString floattostringWithFormat(double data, char format, int past_comma, bool remove_trail0=true) const;
/** \brief convert a float to a tick label string */ /** \brief convert a float to a tick label string */
QString floattolabel(double data) const; QString floattolabel(double data) const;

View File

@ -101,18 +101,32 @@ QString JKQTPCALabelType2String(JKQTPCALabelType pos) {
case JKQTPCALTtime: return "time"; case JKQTPCALTtime: return "time";
case JKQTPCALTdate: return "date"; case JKQTPCALTdate: return "date";
case JKQTPCALTdatetime: return "datetime"; case JKQTPCALTdatetime: return "datetime";
case JKQTPCALTscientific: return "scientific";
case JKQTPCALTintfrac: return "intfrac";
case JKQTPCALTintsfrac: return "intsfrac";
case JKQTPCALTintslashfrac: return "intslashfrac";
case JKQTPCALTfrac: return "frac";
case JKQTPCALTsfrac: return "sfrac";
case JKQTPCALTslashfrac: return "slashfrac";
} }
return ""; return "";
} }
JKQTPCALabelType String2JKQTPCALabelType(const QString& pos) { JKQTPCALabelType String2JKQTPCALabelType(const QString& pos) {
QString s=pos.trimmed().toLower(); QString s=pos.trimmed().toLower();
if (s=="default") return JKQTPCALTdefault; if (s=="default" || s=="f") return JKQTPCALTdefault;
if (s=="scientifc" || s=="g") return JKQTPCALTscientific;
if (s=="exponent_character") return JKQTPCALTexponentCharacter; if (s=="exponent_character") return JKQTPCALTexponentCharacter;
if (s=="exponent") return JKQTPCALTexponent; if (s=="exponent") return JKQTPCALTexponent;
if (s=="time") return JKQTPCALTtime; if (s=="time") return JKQTPCALTtime;
if (s=="date") return JKQTPCALTdate; if (s=="date") return JKQTPCALTdate;
if (s=="datetime") return JKQTPCALTdatetime; if (s=="datetime") return JKQTPCALTdatetime;
if (s=="frac") return JKQTPCALTfrac;
if (s=="sfrac") return JKQTPCALTsfrac;
if (s=="slashfrac") return JKQTPCALTslashfrac;
if (s=="intfrac") return JKQTPCALTintfrac;
if (s=="intsfrac") return JKQTPCALTintsfrac;
if (s=="intslashfrac") return JKQTPCALTintslashfrac;
return JKQTPCALTdefault; return JKQTPCALTdefault;
} }

View File

@ -439,13 +439,21 @@ JKQTPLOTTER_LIB_EXPORT JKQTPCADrawMode String2JKQTPCADrawMode(const QString& pos
* \ingroup jkqtpplottersupprt */ * \ingroup jkqtpplottersupprt */
enum JKQTPCALabelType { enum JKQTPCALabelType {
JKQTPCALTdefault, /*!< \brief simply print the numbers \image html JKQTPCALTdefault.png */ JKQTPCALTdefault, /*!< \brief simply print the numbers \image html JKQTPCALTdefault.png */
JKQTPCALTexponentCharacter, /*!< \brief print the numbers and show a unit character, i.e. 5&mu; for \f$ 5\cdot 10^{-6} \f$ , \c 3k for \f$ 3\cdot 10^3 \f$ ... */ JKQTPCALTscientific, /*!< \brief print the numbers in scientific notation, e.g. \c "1.23e-4" \image html JKQTPCALTscientific.png */
JKQTPCALTexponentCharacter, /*!< \brief print the numbers and show a unit character, i.e. 5&mu; for \f$ 5\cdot 10^{-6} \f$ , \c 3k for \f$ 3\cdot 10^3 \f$ ... \image html JKQTPCALTexponentCharacter.png */
JKQTPCALTexponent, /*!< \brief show numbers in exponential for, e.g. \f$ 3\cdot 10^5 \f$ ... \image html JKQTPCALTexponent.png */ JKQTPCALTexponent, /*!< \brief show numbers in exponential for, e.g. \f$ 3\cdot 10^5 \f$ ... \image html JKQTPCALTexponent.png */
JKQTPCALTdate, /*!< \brief show numbers as dates \image html JKQTPCALTdate.png */ JKQTPCALTdate, /*!< \brief show numbers as dates \image html JKQTPCALTdate.png */
JKQTPCALTtime, /*!< \brief show numbers as times \image html JKQTPCALTtime.png*/ JKQTPCALTtime, /*!< \brief show numbers as times \image html JKQTPCALTtime.png*/
JKQTPCALTdatetime, /*!< \brief show numbers as times */ JKQTPCALTdatetime, /*!< \brief show numbers as times \image html JKQTPCALTdatetime.png */
JKQTPCALTfrac, /*!< \brief show numbers as fraction, the number is first rounded to the given precision and then a fraction is calculated and displayed like \$ \frac{1}{2} \f$ \image html JKQTPCALTfrac.png */
JKQTPCALTslashfrac, /*!< \brief show numbers as fraction, the number is first rounded to the given precision and then a fraction is calculated and displayed like \c 1/2 \image html JKQTPCALTslashfrac.png */
JKQTPCALTsfrac, /*!< \brief show numbers as fraction, the number is first rounded to the given precision and then a fraction is calculated and displayed using \c \\sfrac{1}{2} \f$ \image html JKQTPCALTsfrac.png */
JKQTPCALTintfrac, /*!< \brief show numbers as integral+fraction, the number is first rounded to the given precision and then a fraction is calculated and displayed like \$ \frac{1}{2} \f$ \image html JKQTPCALTintfrac.png */
JKQTPCALTintslashfrac, /*!< \brief show numbers as integral+fraction, the number is first rounded to the given precision and then a fraction is calculated and displayed like \c 1/2 \image html JKQTPCALTintslashfrac.png */
JKQTPCALTintsfrac, /*!< \brief show numbers as integral+fraction, the number is first rounded to the given precision and then a fraction is calculated and displayed using \c \\sfrac{1}{2} \f$ \image html JKQTPCALTintsfrac.png */
JKQTPCALTmax=JKQTPCALTdatetime JKQTPCALTcount,
JKQTPCALTmax=JKQTPCALTcount-1
}; };

View File

@ -14,6 +14,7 @@
#include <QDir> #include <QDir>
#include <QTextStream> #include <QTextStream>
#include <algorithm> #include <algorithm>
#include <QDateTime>
#if (QT_VERSION>=QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION>=QT_VERSION_CHECK(6, 0, 0))
#include<QRegularExpression> #include<QRegularExpression>
#include<QRegularExpressionMatch> #include<QRegularExpressionMatch>
@ -47,38 +48,7 @@ void stopPaintingAndSave(QImage& img, JKQTPEnhancedPainter& p, const QString& fi
img.save(filename); img.save(filename);
} }
int main(int argc, char* argv[]) void doListSymbols(const QDir& outputDir, int iconsize, QColor backgroundColor) {
{
// 1. create Qt Appcilation object and a QCommandLineParser to go with it
QApplication app(argc, argv);
QCommandLineParser parser;
parser.setApplicationDescription("JKQTPlotter command line tool that renders diverse images for the documentation");
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption outputDirectoryOption("outputdir", "write results into this directory.", "outputdir", app.applicationDirPath());
parser.addOption(outputDirectoryOption);
QCommandLineOption listsymbolsOption("listsymbols", "generate example images for all symbols.");
parser.addOption(listsymbolsOption);
QCommandLineOption listlinedecoratorsOption("listlinedecorators", "generate example images for all line-decorators.");
parser.addOption(listlinedecoratorsOption);
QCommandLineOption listerrorindicatorsOption("listerrorindicators", "generate example images for all error-indicators.");
parser.addOption(listerrorindicatorsOption);
QCommandLineOption iconsizeOption("iconsize", "typical size of the generatued images.", "iconsize", "24");
parser.addOption(iconsizeOption);
QCommandLineOption backgroundOption("background", "background color.", "background", "white");
parser.addOption(backgroundOption);
parser.process(app);
const QDir outputDir(parser.value(outputDirectoryOption));
const bool listsymbols=parser.isSet(listsymbolsOption);
const bool listlinedecorators=parser.isSet(listlinedecoratorsOption);
const bool listerrorindicators=parser.isSet(listerrorindicatorsOption);
const int iconsize=parser.value(iconsizeOption).toInt();
const QColor backgroundColor = jkqtp_String2QColor(parser.value(backgroundOption));
if (listsymbols) {
for (uint64_t i=0; i<JKQTPSymbolCount; i++) { for (uint64_t i=0; i<JKQTPSymbolCount; i++) {
const JKQTPGraphSymbols s=static_cast<JKQTPGraphSymbols>(i); const JKQTPGraphSymbols s=static_cast<JKQTPGraphSymbols>(i);
QImage img; QImage img;
@ -125,7 +95,7 @@ int main(int argc, char* argv[])
stopPaintingAndSave(img, p, outputDir.absoluteFilePath("symbol_custom.png")); stopPaintingAndSave(img, p, outputDir.absoluteFilePath("symbol_custom.png"));
} }
if (listlinedecorators) { void doListLineDecorators(const QDir& outputDir, int iconsize, QColor backgroundColor) {
for (uint64_t i=0; i<JKQTPLineDecoratorCount; i++) { for (uint64_t i=0; i<JKQTPLineDecoratorCount; i++) {
const JKQTPLineDecoratorStyle s=static_cast<JKQTPLineDecoratorStyle>(i); const JKQTPLineDecoratorStyle s=static_cast<JKQTPLineDecoratorStyle>(i);
QImage img; QImage img;
@ -144,7 +114,8 @@ int main(int argc, char* argv[])
} }
} }
if (listerrorindicators) {
void doListErrorIndicators(const QDir& outputDir, int iconsize, QColor backgroundColor) {
JKQTBasePlotter plot(true); JKQTBasePlotter plot(true);
JKQTPDatastore* ds=plot.getDatastore(); JKQTPDatastore* ds=plot.getDatastore();
size_t cx=ds->addCopiedColumn(QVector<double>{-1.5,-0.5,0.5,1.5,2.5},"x"); size_t cx=ds->addCopiedColumn(QVector<double>{-1.5,-0.5,0.5,1.5,2.5},"x");
@ -205,8 +176,122 @@ int main(int argc, char* argv[])
plot.saveAsPixelImage(outputDir.absoluteFilePath(std::get<0>(d)+".png"), false, "png"); plot.saveAsPixelImage(outputDir.absoluteFilePath(std::get<0>(d)+".png"), false, "png");
} }
}
void doListJKQTPCALabelType(const QDir& outputDir, int iconsize, QColor backgroundColor) {
JKQTBasePlotter plot(true);
plot.setXY(0,1,0.9,110);
plot.setWidgetSize(iconsize*4,4*iconsize);
plot.setShowKey(false);
plot.setGrid(true);
plot.setExportBackgroundColor(QColor("lightgrey"));
plot.getXAxis()->setShowZeroAxis(false);
plot.getYAxis()->setShowZeroAxis(false);
plot.getXAxis()->setDrawMode1(JKQTPCADMLine);
plot.getXAxis()->setDrawMode2(JKQTPCADMLine);
plot.getXAxis()->setDrawGrid(false);
plot.getYAxis()->setDrawMode1(JKQTPCADMLineTicksTickLabels);
plot.getYAxis()->setDrawMode2(JKQTPCADMnone);
plot.getYAxis()->setAxisLabel("");
plot.getYAxis()->setLabelType(JKQTPCALTdefault);
plot.setY(0,110);
plot.grabPixelImage(QSize(plot.getWidth(),plot.getHeight()), false).copy(0,0,iconsize,plot.getHeight()).save(outputDir.absoluteFilePath("JKQTPCALTdefault.png"), "png");
plot.setY(1e-6,1.1e3);
plot.getYAxis()->setMinTicks(7);
plot.getYAxis()->setLabelType(JKQTPCALTexponentCharacter);
plot.getYAxis()->setLogAxis(true);
plot.grabPixelImage(QSize(plot.getWidth(),plot.getHeight()), false).copy(0,0,iconsize*2,plot.getHeight()).save(outputDir.absoluteFilePath("JKQTPCALTexponentCharacter.png"), "png");
plot.getYAxis()->setLogAxis(false);
plot.setY(-1.3, 1.55);
plot.getYAxis()->setMinTicks(5);
plot.getYAxis()->setLabelType(JKQTPCALTintfrac);
plot.grabPixelImage(QSize(plot.getWidth(),plot.getHeight()), false).copy(0,0,iconsize*2,plot.getHeight()).save(outputDir.absoluteFilePath("JKQTPCALTintfrac.png"), "png");
plot.getYAxis()->setLabelType(JKQTPCALTintsfrac);
plot.grabPixelImage(QSize(plot.getWidth(),plot.getHeight()), false).copy(0,0,iconsize*2,plot.getHeight()).save(outputDir.absoluteFilePath("JKQTPCALTintsfrac.png"), "png");
plot.getYAxis()->setLabelType(JKQTPCALTintslashfrac);
plot.grabPixelImage(QSize(plot.getWidth(),plot.getHeight()), false).copy(0,0,iconsize*2,plot.getHeight()).save(outputDir.absoluteFilePath("JKQTPCALTintslashfrac.png"), "png");
plot.getYAxis()->setLabelType(JKQTPCALTfrac);
plot.grabPixelImage(QSize(plot.getWidth(),plot.getHeight()), false).copy(0,0,iconsize*2,plot.getHeight()).save(outputDir.absoluteFilePath("JKQTPCALTfrac.png"), "png");
plot.getYAxis()->setLabelType(JKQTPCALTsfrac);
plot.grabPixelImage(QSize(plot.getWidth(),plot.getHeight()), false).copy(0,0,iconsize*2,plot.getHeight()).save(outputDir.absoluteFilePath("JKQTPCALTsfrac.png"), "png");
plot.getYAxis()->setLabelType(JKQTPCALTslashfrac);
plot.grabPixelImage(QSize(plot.getWidth(),plot.getHeight()), false).copy(0,0,iconsize*2,plot.getHeight()).save(outputDir.absoluteFilePath("JKQTPCALTslashfrac.png"), "png");
plot.setY(0.000008,100000);
plot.getYAxis()->setMinTicks(4);
plot.getYAxis()->setLabelType(JKQTPCALTexponent);
plot.getYAxis()->setLogAxis(true);
plot.grabPixelImage(QSize(plot.getWidth(),plot.getHeight()), false).copy(0,0,iconsize,plot.getHeight()).save(outputDir.absoluteFilePath("JKQTPCALTexponent.png"), "png");
plot.setY(0.000008,100000);
plot.getYAxis()->setMinTicks(4);
plot.getYAxis()->setLabelType(JKQTPCALTscientific);
plot.getYAxis()->setLogAxis(true);
plot.grabPixelImage(QSize(plot.getWidth(),plot.getHeight()), false).copy(0,0,iconsize,plot.getHeight()).save(outputDir.absoluteFilePath("JKQTPCALTscientific.png"), "png");
plot.getYAxis()->setMinTicks(4);
plot.setY(QDateTime(QDate(1999,10,1),QTime(0,0,0)).toMSecsSinceEpoch(),
QDateTime(QDate(2000,2,1),QTime(0,0,0)).toMSecsSinceEpoch());
plot.getYAxis()->setLabelType(JKQTPCALTdate);
plot.getYAxis()->setLogAxis(false);
plot.grabPixelImage(QSize(plot.getWidth(),plot.getHeight()), false).copy(0,0,iconsize*2,plot.getHeight()).save(outputDir.absoluteFilePath("JKQTPCALTdate.png"), "png");
plot.setY(QDateTime(QDate(2000,2,1),QTime(12,0,0)).toMSecsSinceEpoch(),
QDateTime(QDate(2000,2,1),QTime(24,0,0)).toMSecsSinceEpoch());
plot.getYAxis()->setLabelType(JKQTPCALTtime);
plot.grabPixelImage(QSize(plot.getWidth(),plot.getHeight()), false).copy(0,0,iconsize*1.0,plot.getHeight()).save(outputDir.absoluteFilePath("JKQTPCALTtime.png"), "png");
plot.setY(QDateTime(QDate(2010,10,1),QTime(12,0,0)).toMSecsSinceEpoch(),
QDateTime(QDate(2010,10,2),QTime(12,0,0)).toMSecsSinceEpoch());
plot.getYAxis()->setLabelType(JKQTPCALTdatetime);
plot.grabPixelImage(QSize(plot.getWidth(),plot.getHeight()), false).copy(0,0,iconsize*2.5,plot.getHeight()).save(outputDir.absoluteFilePath("JKQTPCALTdatetime.png"), "png");
} }
int main(int argc, char* argv[])
{
// 1. create Qt Appcilation object and a QCommandLineParser to go with it
QApplication app(argc, argv);
QCommandLineParser parser;
parser.setApplicationDescription("JKQTPlotter command line tool that renders diverse images for the documentation");
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption outputDirectoryOption("outputdir", "write results into this directory.", "outputdir", app.applicationDirPath());
parser.addOption(outputDirectoryOption);
QCommandLineOption listsymbolsOption("listsymbols", "generate example images for all symbols.");
parser.addOption(listsymbolsOption);
QCommandLineOption listlinedecoratorsOption("listlinedecorators", "generate example images for all line-decorators.");
parser.addOption(listlinedecoratorsOption);
QCommandLineOption listerrorindicatorsOption("listerrorindicators", "generate example images for all error-indicators.");
parser.addOption(listerrorindicatorsOption);
QCommandLineOption listaxislabeltypeOption("listaxislabeltype", "generate example images for JKQTPCALabelType.");
parser.addOption(listaxislabeltypeOption);
QCommandLineOption iconsizeOption("iconsize", "typical size of the generatued images.", "iconsize", "24");
parser.addOption(iconsizeOption);
QCommandLineOption backgroundOption("background", "background color.", "background", "white");
parser.addOption(backgroundOption);
parser.process(app);
const QDir outputDir(parser.value(outputDirectoryOption));
const bool listsymbols=parser.isSet(listsymbolsOption);
const bool listlinedecorators=parser.isSet(listlinedecoratorsOption);
const bool listerrorindicators=parser.isSet(listerrorindicatorsOption);
const bool listaxislabeltype=parser.isSet(listaxislabeltypeOption);
const int iconsize=parser.value(iconsizeOption).toInt();
const QColor backgroundColor = jkqtp_String2QColor(parser.value(backgroundOption));
if (listsymbols) doListSymbols(outputDir, iconsize, backgroundColor);
if (listlinedecorators) doListLineDecorators(outputDir, iconsize, backgroundColor);
if (listsymbols) doListErrorIndicators(outputDir, iconsize, backgroundColor);
if (listaxislabeltype) doListJKQTPCALabelType(outputDir, iconsize, backgroundColor);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }