File indexing completed on 2024-04-28 11:20:36

0001 /*
0002     SPDX-License-Identifier: GPL-2.0-or-later
0003     SPDX-FileCopyrightText: 2013 Filipe Saraiva <filipe@kde.org>
0004 */
0005 
0006 #include "pythonextensions.h"
0007 
0008 #include <QDebug>
0009 
0010 #include <KLocalizedString>
0011 
0012 #include "pythonutils.h"
0013 
0014 #include "settings.h"
0015 
0016 #define PYTHON_EXT_CDTOR(name) Python##name##Extension::Python##name##Extension(QObject* parent) : name##Extension(parent) {} \
0017                                      Python##name##Extension::~Python##name##Extension() {}
0018 
0019 PYTHON_EXT_CDTOR(LinearAlgebra)
0020 
0021 QString PythonLinearAlgebraExtension::createVector(const QStringList& entries, Cantor::LinearAlgebraExtension::VectorType type)
0022 {
0023     Q_UNUSED(type);
0024 
0025     QString command;
0026     command += QLatin1String("numpy.matrix([");
0027 
0028     foreach (const QString& entry, entries)
0029     {
0030         command += entry + QLatin1String(", ");
0031     }
0032 
0033     command.chop(2);
0034     command += QLatin1String("])\n");
0035 
0036     return command;
0037 }
0038 
0039 QString PythonLinearAlgebraExtension::createMatrix(const Cantor::LinearAlgebraExtension::Matrix& matrix)
0040 {
0041     QString command;
0042     command += QLatin1String("numpy.matrix([[");
0043 
0044     foreach (const QStringList row, matrix)
0045     {
0046         foreach (const QString entry, row)
0047         {
0048             command += entry;
0049             command += QLatin1String(", ");
0050         }
0051         command.chop(2);
0052         command += QLatin1String("], [");
0053     }
0054 
0055     command.chop(3);
0056     command += QLatin1String("])");
0057 
0058     return command;
0059 }
0060 
0061 QString PythonLinearAlgebraExtension::eigenValues(const QString& matrix)
0062 {
0063     return QString::fromLatin1("numpy.linalg.eigvals(%1)").arg(matrix);
0064 }
0065 
0066 QString PythonLinearAlgebraExtension::eigenVectors(const QString& matrix)
0067 {
0068     return QString::fromLatin1("numpy.linalg.eig(%1)").arg(matrix);
0069 }
0070 
0071 QString PythonLinearAlgebraExtension::identityMatrix(int size)
0072 {
0073     return QString::fromLatin1("numpy.identity(%1)").arg(size);
0074 }
0075 
0076 QString PythonLinearAlgebraExtension::invertMatrix(const QString& matrix)
0077 {
0078     return QString::fromLatin1("numpy.linalg.inv(%1)").arg(matrix);
0079 }
0080 
0081 QString PythonLinearAlgebraExtension::nullMatrix(int rows, int columns)
0082 {
0083     return QString::fromLatin1("numpy.zeros(%1, %2)").arg(rows).arg(columns);
0084 }
0085 
0086 QString PythonLinearAlgebraExtension::nullVector(int size, Cantor::LinearAlgebraExtension::VectorType type)
0087 {
0088     QString command = QLatin1String("numpy.zeros(%1, %2)");
0089     switch (type)
0090     {
0091         case ColumnVector:
0092             return command.arg(size).arg(1);
0093         case RowVector:
0094             return command.arg(1).arg(size);
0095         default:
0096             return Cantor::LinearAlgebraExtension::nullVector(size, type);
0097     }
0098 }
0099 
0100 QString PythonLinearAlgebraExtension::rank(const QString& matrix)
0101 {
0102     return QString::fromLatin1("numpy.linalg.matrix_rank(%1)").arg(matrix);
0103 }
0104 
0105 QString PythonLinearAlgebraExtension::charPoly(const QString& matrix)
0106 {
0107     return QString::fromLatin1("numpy.poly(%1)").arg(matrix);
0108 }
0109 
0110 PYTHON_EXT_CDTOR(Packaging)
0111 
0112 QString PythonPackagingExtension::importPackage(const QString& package)
0113 {
0114     return QString::fromLatin1("import %1").arg(package);
0115 }
0116 
0117 PYTHON_EXT_CDTOR(Plot)
0118 
0119 QString PythonPlotExtension::plotFunction2d(const QString& function, const QString& variable, const QString& left, const QString& right)
0120 {
0121     QString command;
0122     QString limits;
0123 
0124     int val = PythonSettings::plotExtenstionGraphicPackage();
0125     switch (val)
0126     {
0127         case PythonSettings::EnumPlotExtenstionGraphicPackage::matplotlib:
0128             if (!left.isEmpty() && !right.isEmpty())
0129                 limits = QString::fromLatin1("plt.xlim(%1, %2)\n").arg(left, right);
0130             command = QString::fromLatin1(
0131                 "import matplotlib.pyplot as plt\n"
0132                 "\n"
0133                 "plt.plot(%1, %2)\n"
0134                 "%3"
0135                 "plt.show()"
0136             ).arg(variable, function, limits);
0137             break;
0138 
0139         case PythonSettings::EnumPlotExtenstionGraphicPackage::pylab:
0140             if (!left.isEmpty() && !right.isEmpty())
0141                 limits = QString::fromLatin1("pylab.xlim(%1, %2)\n").arg(left, right);
0142             command = QString::fromLatin1(
0143                 "import pylab\n"
0144                 "\n"
0145                 "pylab.clf()\n"
0146                 "pylab.plot(%1, %2)\n"
0147                 "%3"
0148                 "pylab.show()"
0149             ).arg(variable, function, limits);
0150             break;
0151 
0152         case PythonSettings::EnumPlotExtenstionGraphicPackage::plotly:
0153             if (!left.isEmpty() && !right.isEmpty())
0154                 limits = QString::fromLatin1("fig.update_layout(xaxis=dict(range=[%1, %2]))\n").arg(left, right);
0155             command = QString::fromLatin1(
0156                 "import plotly.graph_objects as go\n"
0157                 "\n"
0158                 "fig = go.Figure(data=go.Scatter(x=%1, y=%2))\n"
0159                 "%3"
0160                 "fig.show()"
0161             ).arg(variable, function, limits);
0162             break;
0163 
0164         case PythonSettings::EnumPlotExtenstionGraphicPackage::gr:
0165             if (!left.isEmpty() && !right.isEmpty())
0166                 limits = QString::fromLatin1("\nmlab.xlim(%1, %2)").arg(left, right);
0167             command = QString::fromLatin1(
0168                 "from gr.pygr import mlab\n"
0169                 "\n"
0170                 "mlab.plot(%1, %2)"
0171                 "%3"
0172             ).arg(variable, function, limits);
0173             break;
0174 
0175         case PythonSettings::EnumPlotExtenstionGraphicPackage::bokeh:
0176             if (!left.isEmpty() && !right.isEmpty())
0177                 limits = QString::fromLatin1("x_range=(%1, %2)").arg(left, right);
0178             command = QString::fromLatin1(
0179                 "from bokeh.plotting import figure, show\n"
0180                 "\n"
0181                 "fig = figure(%3)\n"
0182                 "fig.line(%1, %2)\n"
0183                 "show(fig)"
0184             ).arg(variable, function, limits);
0185             break;
0186     };
0187 
0188     return command;
0189 }
0190 
0191 QString PythonPlotExtension::plotFunction3d(const QString& function, const VariableParameter& var1, const VariableParameter& var2)
0192 {
0193     QString command;
0194 
0195     const Interval& interval1 = var1.second;
0196     const Interval& interval2 = var2.second;
0197 
0198     QString interval1Limits;
0199     QString interval2Limits;
0200 
0201     int val = PythonSettings::plotExtenstionGraphicPackage();
0202     switch (val)
0203     {
0204         case PythonSettings::EnumPlotExtenstionGraphicPackage::matplotlib:
0205                         if(!interval1.first.isEmpty() && !interval1.second.isEmpty()){
0206                 interval1Limits = QString::fromLatin1("ax3D.set_xlim3d(%1, %2)\n").arg(interval1.first, interval1.second);
0207             }
0208 
0209             if(!interval2.first.isEmpty() && !interval2.second.isEmpty()){
0210                 interval2Limits = QString::fromLatin1("ax3D.set_ylim3d(%1, %2)\n").arg(interval2.first, interval2.second);
0211             }
0212 
0213             command = QString::fromLatin1(
0214                 "import matplotlib.pyplot as plt\n"
0215                 "from mpl_toolkits.mplot3d import Axes3D\n\n"
0216                 "fig3D = plt.figure()\n"
0217                 "ax3D = fig3D.gca(projection='3d')\n"
0218                 "ax3D.plot_surface(%1, %2, %3)\n"    \
0219                 "%4%5"                                                             \
0220                 "plt.show()"
0221             ).arg(var1.first, var2.first, function, interval1Limits, interval2Limits);
0222             break;
0223 
0224         case PythonSettings::EnumPlotExtenstionGraphicPackage::pylab:
0225             if(!interval1.first.isEmpty() && !interval1.second.isEmpty()){
0226                 interval1Limits = QString::fromLatin1("ax3D.set_xlim3d(%1, %2)\n").arg(interval1.first, interval1.second);
0227             }
0228 
0229             if(!interval2.first.isEmpty() && !interval2.second.isEmpty()){
0230                 interval2Limits = QString::fromLatin1("ax3D.set_ylim3d(%1, %2)\n").arg(interval2.first, interval2.second);
0231             }
0232 
0233             command = QString::fromLatin1(
0234                 "import pylab\n"
0235                 "from mpl_toolkits.mplot3d import Axes3D\n\n"
0236                 "fig3D = pylab.figure()\n"
0237                 "ax3D = fig3D.gca(projection='3d')\n"
0238                 "ax3D.plot_surface(%1, %2, %3)\n"    \
0239                 "%4%5"                                                             \
0240                 "pylab.show()"
0241             ).arg(var1.first, var2.first, function, interval1Limits, interval2Limits);
0242             break;
0243 
0244         case PythonSettings::EnumPlotExtenstionGraphicPackage::plotly:
0245             if(!interval1.first.isEmpty() && !interval1.second.isEmpty()){
0246                 interval1Limits = QString::fromLatin1("fig.update_layout(xaxis=dict(range=[%1, %2]))\n").arg(interval1.first, interval1.second);
0247             }
0248 
0249             if(!interval2.first.isEmpty() && !interval2.second.isEmpty()){
0250                 interval2Limits = QString::fromLatin1("fig.update_layout(yaxis=dict(range=[%1, %2]))\n").arg(interval2.first, interval2.second);
0251             }
0252 
0253             command = QString::fromLatin1(
0254                 "import plotly.graph_objects as go\n"
0255                 "\n"
0256                 "fig = go.Figure(data=go.Scatter3d(x=%1, y=%2, z=%3))\n"
0257                 "%4%5"
0258                 "fig.show()"
0259             ).arg(var1.first, var2.first, function, interval1Limits, interval2Limits);
0260             break;
0261 
0262         case PythonSettings::EnumPlotExtenstionGraphicPackage::gr:
0263             {
0264             if(!interval1.first.isEmpty() && !interval1.second.isEmpty()){
0265                 interval1Limits = QString::fromLatin1("mlab.xlim(%1, %2)\n").arg(interval1.first, interval1.second);
0266             }
0267 
0268             if(!interval2.first.isEmpty() && !interval2.second.isEmpty()){
0269                 interval2Limits = QString::fromLatin1("mlab.ylim(%1, %2)").arg(interval2.first, interval2.second);
0270             }
0271             QString newLinePlacement;
0272             if(!interval1Limits.isEmpty() || !interval2Limits.isEmpty())
0273                 newLinePlacement = QLatin1String("\n");
0274 
0275             command = QString::fromLatin1(
0276                 "from gr.pygr import mlab\n"
0277                 "\n"
0278                 "mlab.plot3(%1, %2, %3)%6"
0279                 "%4%5"
0280             ).arg(var1.first, var2.first, function, interval1Limits, interval2Limits, newLinePlacement);
0281             }
0282             break;
0283 
0284         case PythonSettings::EnumPlotExtenstionGraphicPackage::bokeh:
0285             command = i18n("# Sorry, but Bokeh doesn't support 3d plotting");
0286             break;
0287     };
0288 
0289     return command;
0290 }
0291 
0292 PYTHON_EXT_CDTOR(Script)
0293 
0294 QString PythonScriptExtension::runExternalScript(const QString& path)
0295 {
0296     return QString::fromLatin1("exec(open(\"%1\").read())").arg(path);
0297 }
0298 
0299 QString PythonScriptExtension::scriptFileFilter()
0300 {
0301     return i18n("Python script file (*.py)");
0302 }
0303 
0304 QString PythonScriptExtension::highlightingMode()
0305 {
0306     return QLatin1String("python");
0307 }
0308 
0309 PYTHON_EXT_CDTOR(VariableManagement)
0310 
0311 QString PythonVariableManagementExtension::addVariable(const QString& name, const QString& value)
0312 {
0313     return setValue(name, value);
0314 }
0315 
0316 QString PythonVariableManagementExtension::setValue(const QString& name, const QString& value)
0317 {
0318     return QString::fromLatin1("%1 = %2").arg(name, value);
0319 }
0320 
0321 QString PythonVariableManagementExtension::removeVariable(const QString& name)
0322 {
0323     return QString::fromLatin1("del(%1)").arg(name);
0324 }
0325 
0326 QString PythonVariableManagementExtension::clearVariables()
0327 {
0328     return fromSource(QLatin1String(":/py/variables_cleaner.py"));
0329 }
0330 
0331 QString PythonVariableManagementExtension::saveVariables(const QString& fileName)
0332 {
0333     return fromSource(QLatin1String(":/py/variables_saver.py")).arg(fileName);
0334 }
0335 
0336 QString PythonVariableManagementExtension::loadVariables(const QString& fileName)
0337 {
0338     return fromSource(QLatin1String(":/py/variables_loader.py")).arg(fileName);
0339 }