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
@ -114,6 +114,14 @@ if(JKQtPlotter_BUILD_TOOLS)
|
||||
)
|
||||
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)
|
||||
|
||||
|
||||
|
@ -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: 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 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>
|
||||
|
||||
<li>JKQTMathText:<ul>
|
||||
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 2.9 KiB |
BIN
doc/images/JKQTPCALTdatetime.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.2 KiB |
BIN
doc/images/JKQTPCALTexponentCharacter.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
doc/images/JKQTPCALTfrac.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
doc/images/JKQTPCALTintfrac.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
doc/images/JKQTPCALTintsfrac.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
doc/images/JKQTPCALTintslashfrac.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
doc/images/JKQTPCALTscientific.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
doc/images/JKQTPCALTsfrac.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
doc/images/JKQTPCALTslashfrac.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 1.8 KiB |
@ -22,3 +22,42 @@
|
||||
#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);
|
||||
|
||||
}
|
||||
|
@ -528,4 +528,15 @@ QString jkqtp_polynomialModel2Latex(PolyItP firstP, PolyItP lastP) {
|
||||
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
|
||||
|
@ -170,22 +170,23 @@ std::string jkqtp_tolower(const std::string& s){
|
||||
};
|
||||
|
||||
|
||||
std::string jkqtp_floattounitstr(double data, int past_comma, bool remove_trail0){
|
||||
if (data==0) return "0";
|
||||
std::string jkqtp_floattounitstr(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);
|
||||
if (fabs(data)>=1e3) res=jkqtp_format(form,data/1e3)+"k";
|
||||
if (fabs(data)>=1e6) res=jkqtp_format(form,data/1e6)+"M";
|
||||
if (fabs(data)>=1e9) res=jkqtp_format(form,data/1e9)+"G";
|
||||
if (fabs(data)>=1e12) res=jkqtp_format(form,data/1e12)+"T";
|
||||
if (fabs(data)>=1e15) res=jkqtp_format(form,data/1e15)+"P";
|
||||
if (fabs(data)<1) res=jkqtp_format(form,data/1e-3)+"m";
|
||||
if (fabs(data)<1e-3) res=jkqtp_format(form,data/1e-6)+"u";
|
||||
if (fabs(data)<1e-6) res=jkqtp_format(form,data/1e-9)+"n";
|
||||
if (fabs(data)<1e-9) res=jkqtp_format(form,data/1e-12)+"f";
|
||||
std::string unit="";
|
||||
if (fabs(data)>=1e3) {res=jkqtp_format(form,data/1e3); unit="k";}
|
||||
if (fabs(data)>=1e6) {res=jkqtp_format(form,data/1e6); unit="M";}
|
||||
if (fabs(data)>=1e9) {res=jkqtp_format(form,data/1e9); unit="G";}
|
||||
if (fabs(data)>=1e12) {res=jkqtp_format(form,data/1e12); unit="T";}
|
||||
if (fabs(data)>=1e15) {res=jkqtp_format(form,data/1e15); unit="P";}
|
||||
if (fabs(data)<1) {res=jkqtp_format(form,data/1e-3); unit="m";}
|
||||
if (fabs(data)<1e-3) {res=jkqtp_format(form,data/1e-6); unit="u";}
|
||||
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 (remove_trail0) {
|
||||
if (data==0) return "0";
|
||||
if (fabs(data)<=belowIsZero) return "0";
|
||||
if (res.find('.')==std::string::npos) return res;
|
||||
size_t i=res.size()-1;
|
||||
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
|
||||
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 (ensurePlusMinus) 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)) {
|
||||
std::string v=jkqtp_floattostr(data/pow(10.0, static_cast<double>(exp)), past_comma, remove_trail0);
|
||||
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 {
|
||||
if (v=="10") exp=exp+1;
|
||||
res=std::string("10^{")+jkqtp_inttostr(exp)+"}";
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <QLocale>
|
||||
#include <string>
|
||||
#include <QtGlobal>
|
||||
#include <limits>
|
||||
|
||||
/** \brief converts a QT::PenStyle into a 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"
|
||||
* \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>)
|
||||
* \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
|
||||
* \ingroup jkqtptools_string
|
||||
*/
|
||||
|
@ -345,10 +345,14 @@ JKQTPCALabelTypeComboBox::JKQTPCALabelTypeComboBox(QWidget *parent):
|
||||
setEditable(false);
|
||||
addLabelType(JKQTPCALTexponent, tr("exponent"), QIcon(":/JKQTPlotter/jkqtp_ticks_exp.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(JKQTPCALTtime, tr("time"), QIcon(":/JKQTPlotter/jkqtp_ticks_time.png"));
|
||||
addLabelType(JKQTPCALTdate, tr("date"), QIcon(":/JKQTPlotter/jkqtp_ticks_date.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);
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "jkqtplotter/jkqtpbaseplotter.h"
|
||||
#include "jkqtcommon/jkqtpdrawingtools.h"
|
||||
#include "jkqtcommon/jkqtpgeometrytools.h"
|
||||
#include "jkqtcommon/jkqtpmathtools.h"
|
||||
#include <QDebug>
|
||||
#include <QDateTime>
|
||||
#include <cfloat>
|
||||
@ -85,6 +86,7 @@ const JKQTMathText* JKQTPCoordinateAxis::getParentMathText() const {
|
||||
return parent->getMathText();
|
||||
}
|
||||
|
||||
|
||||
void JKQTPCoordinateAxis::clearAxisTickLabels() {
|
||||
tickLabels.clear();
|
||||
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 {
|
||||
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;
|
||||
QLocale loc= QLocale::system();
|
||||
loc.setNumberOptions(QLocale::OmitGroupSeparator);
|
||||
@ -373,22 +404,60 @@ QString JKQTPCoordinateAxis::floattolabel(double data) const {
|
||||
}
|
||||
|
||||
switch(axisStyle.labelType) {
|
||||
case JKQTPCALTdefault: {
|
||||
QString res=loc.toString(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;
|
||||
}; break;
|
||||
case JKQTPCALTexponent: {
|
||||
case JKQTPCALTcount:
|
||||
return "";
|
||||
case JKQTPCALTdefault:
|
||||
return floattostringWithFormat(loc, data, 'f', past_comma, remove_trail0);
|
||||
case JKQTPCALTscientific:
|
||||
return floattostringWithFormat(loc, data, 'e', past_comma, remove_trail0);
|
||||
case JKQTPCALTexponent:
|
||||
return QString(jkqtp_floattolatexstr(data, past_comma, remove_trail0, belowIsZero, pow(10, -past_comma), pow(10, past_comma+1)).c_str());
|
||||
}; break;
|
||||
case JKQTPCALTexponentCharacter: {
|
||||
return QString(jkqtp_floattounitstr(data, past_comma, remove_trail0).c_str());
|
||||
}; break;
|
||||
case JKQTPCALTexponentCharacter:
|
||||
return QString(jkqtp_floattolatexunitstr(data, past_comma, remove_trail0).c_str());
|
||||
case JKQTPCALTintfrac:
|
||||
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: {
|
||||
QDateTime dt;
|
||||
dt.setMSecsSinceEpoch(uint64_t(data));
|
||||
@ -404,36 +473,8 @@ QString JKQTPCoordinateAxis::floattolabel(double data) const {
|
||||
dt.setMSecsSinceEpoch(uint64_t(data));
|
||||
return dt.toString(axisStyle.tickDateTimeFormat);
|
||||
}; break;
|
||||
default:
|
||||
}
|
||||
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() {
|
||||
|
@ -588,6 +588,10 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPCoordinateAxis: public QObject {
|
||||
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 */
|
||||
QString floattolabel(double data) const;
|
||||
|
||||
|
@ -101,18 +101,32 @@ QString JKQTPCALabelType2String(JKQTPCALabelType pos) {
|
||||
case JKQTPCALTtime: return "time";
|
||||
case JKQTPCALTdate: return "date";
|
||||
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 "";
|
||||
}
|
||||
|
||||
JKQTPCALabelType String2JKQTPCALabelType(const QString& pos) {
|
||||
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") return JKQTPCALTexponent;
|
||||
if (s=="time") return JKQTPCALTtime;
|
||||
if (s=="date") return JKQTPCALTdate;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -439,13 +439,21 @@ JKQTPLOTTER_LIB_EXPORT JKQTPCADrawMode String2JKQTPCADrawMode(const QString& pos
|
||||
* \ingroup jkqtpplottersupprt */
|
||||
enum JKQTPCALabelType {
|
||||
JKQTPCALTdefault, /*!< \brief simply print the numbers \image html JKQTPCALTdefault.png */
|
||||
JKQTPCALTexponentCharacter, /*!< \brief print the numbers and show a unit character, i.e. 5μ 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μ 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 */
|
||||
JKQTPCALTdate, /*!< \brief show numbers as dates \image html JKQTPCALTdate.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
|
||||
};
|
||||
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <QDir>
|
||||
#include <QTextStream>
|
||||
#include <algorithm>
|
||||
#include <QDateTime>
|
||||
#if (QT_VERSION>=QT_VERSION_CHECK(6, 0, 0))
|
||||
#include<QRegularExpression>
|
||||
#include<QRegularExpressionMatch>
|
||||
@ -47,38 +48,7 @@ void stopPaintingAndSave(QImage& img, JKQTPEnhancedPainter& p, const QString& fi
|
||||
img.save(filename);
|
||||
}
|
||||
|
||||
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 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) {
|
||||
void doListSymbols(const QDir& outputDir, int iconsize, QColor backgroundColor) {
|
||||
for (uint64_t i=0; i<JKQTPSymbolCount; i++) {
|
||||
const JKQTPGraphSymbols s=static_cast<JKQTPGraphSymbols>(i);
|
||||
QImage img;
|
||||
@ -125,7 +95,7 @@ int main(int argc, char* argv[])
|
||||
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++) {
|
||||
const JKQTPLineDecoratorStyle s=static_cast<JKQTPLineDecoratorStyle>(i);
|
||||
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);
|
||||
JKQTPDatastore* ds=plot.getDatastore();
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|