将常规值轴更改为对数轴的问题

Problem Changing Regular Value Axis to Log Axis

我有一个带有常规值轴的 QT 图表。当我切换复选框时,我想将 X 轴从 QValueAxis 更改为 QLogValueAxis。问题是,当我这样做时,我的数据不再绘制到正确的点。

我已经尝试了两种方法(以及它们的一系列变体)来使对数刻度起作用,但我没有尝试过,似乎数据本身会缩放以适应 window 线性地完全忽略对数轴。

方法 1 - 替换旧轴:

QLogValueAxis* xLogAxis = new QLogValueAxis();
xLogAxis->setBase(10);
xLogAxis->setMinorTickCount(10);

dataSeries->attachedAxes()[0] = xLogAxis; //Replace the old X Axis on the series
chart->setAxisX(xLogAxis);

方法 2 - 制作全新图表:

chart->removeSeries(data); //release the data so you don't destroy it
QChart* newChart = new QChart();
ui->graphView->setChart(newChart); //Swap the old chart out then delete it 
delete chart;
chart = newChart;

//get rid of the old axes on the data
for(QAbstractAxis* axis : data->attachedAxes()){
    data->detachAxis(axis);
}

QValueAxis* yAxis = new QValueAxis();

data->attachAxis(xLogAxis);
data->attachAxis(yAxis);
chart->addAxis(xLogAxis, Qt::AlignBottom);
chart->addAxis(yAxis, Qt::AlignLeft);
chart->addSeries(data);
chart->legend()->setVisible(false);

关于如何在运行时热交换到日志轴的任何想法?提前致谢!

在下面的例子中如何交换轴类型:

#include <QtWidgets>
#include <QtCharts>

QT_CHARTS_USE_NAMESPACE

typedef std::function<qreal (const qreal &)> function;

static std::vector<std::pair<function, std::string>> functions{
    {[](const qreal & v){ return v;}, "linear"},
    {[](const qreal & v){ return v*v; }, "quadratic"},
    {[](const qreal & v){ return std::exp(0.01*v);}, "exponential"},
    {[](const qreal & v){ return std::sqrt(1 + std::abs(v));}, "square root"}
};

class Widget: public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent=nullptr):
        QWidget(parent),
        xLogAxis(new QLogValueAxis),
        xLinAxis(new QValueAxis),
        yAxis(new QValueAxis)
    {
        xLogAxis->setBase(10);
        xLogAxis->setMinorTickCount(10);
        view.setChart(&chart);
        checkbox.setText("Log Axis");
        connect(&checkbox, &QCheckBox::stateChanged, this, &Widget::onStateChanged);
        QVBoxLayout *lay = new QVBoxLayout(this);
        lay->addWidget(&checkbox);
        lay->addWidget(&view);

        chart.addAxis(yAxis, Qt::AlignLeft);
        // chart.legend()->hide();

        // create series
        for(const std::pair<function, std::string> & func: functions){
            QLineSeries *serie = new QLineSeries;
            serie->setName(QString::fromStdString(func.second));
            for(int i=0; i< 1000; ++i){
                *serie << QPointF(i+1, func.first(i));
            }
            chart.addSeries(serie);
            serie->attachAxis(yAxis);
        }
        onStateChanged(checkbox.checkState());
    }
private slots:
    void onStateChanged(int state){
        QAbstractAxis *removeaxis, *insertaxis;
        if(state == Qt::Checked){
            removeaxis = xLinAxis;
            insertaxis = xLogAxis;;
        }
        else{
            removeaxis = xLogAxis;
            insertaxis = xLinAxis;
        }
        if(chart.axes(Qt::Horizontal).contains(removeaxis))
            chart.removeAxis(removeaxis);
        chart.addAxis(insertaxis, Qt::AlignBottom);

        for(auto serie: chart.series()){
            if(serie->attachedAxes().contains(removeaxis))
                serie->detachAxis(removeaxis);
            serie->attachAxis(insertaxis);
        }
    }
private:
    QCheckBox checkbox;
    QChartView view;
    QChart chart;

    QLogValueAxis *xLogAxis;
    QValueAxis *xLinAxis;

    QValueAxis *yAxis;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.resize(640, 480);
    w.show();
    return a.exec();
}
#include "main.moc"