diff --git a/pub/lib/commands.cpp b/pub/lib/commands.cpp
index c29c2ef0de8553ffd9720f7f0573478575bf32b5..2e9c15ca77fd3214c5d8d61acc3932681d335e3b 100644
--- a/pub/lib/commands.cpp
+++ b/pub/lib/commands.cpp
@@ -639,6 +639,9 @@ bool frida_command(string cmd)
     } else if (cmd == "_t") {
         NSpecial::Test();
 
+    } else if (cmd == "p2d") { // new after 2.3.6b, undocumented
+        NSpecial::export_p2d(SMem::instance()->overwrite);
+
     } else if (cmd == "qui" || cmd == "quit") {
         exit(0);
 
diff --git a/pub/lib/file_out.cpp b/pub/lib/file_out.cpp
index ecc0a6c1907f6f7c9c0d2961da4a6db9816ab6e0..74d74cecf748b11ad1b122496f1e9480dda2df5b 100644
--- a/pub/lib/file_out.cpp
+++ b/pub/lib/file_out.cpp
@@ -13,6 +13,7 @@
 #include <yaml-cpp/yaml.h>
 
 #include "../readplus/ask.hpp"
+#include "../trivia/file_ops.hpp"
 #include "../trivia/yaml_out.hpp"
 
 #include "file_out.hpp"
@@ -47,13 +48,8 @@ void NFileOut::save(string fmt, bool allow_overwrite)
         // document file save
         f->log_action("fs " + outfnam + " # " + triv::time2strg(time(0)));
         // prevent unintended overwriting
-        if (!allow_overwrite) {
-            FILE* file;
-            if ((file = fopen(outfnam.c_str(), "r"))) {
-                fclose(file);
-                throw "file " + outfnam + " exists, use fso to overwrite";
-            }
-        }
+        if (!allow_overwrite && triv::file_exists(outfnam))
+            throw "file " + outfnam + " exists, use command modifier '!' to overwrite";
         // save file
         if (fmt == "yda") {
             std::ofstream ofs;
diff --git a/pub/lib/obj.cpp b/pub/lib/obj.cpp
index 8849ff28ec9274a04deaf2086e5b1415a7d4bfa6..8ede1c5f3f634f15792d11692a74281974badfd2 100644
--- a/pub/lib/obj.cpp
+++ b/pub/lib/obj.cpp
@@ -158,6 +158,14 @@ string CObjVecObj::to_s(int maxlen, int minlen, int prec) const
     return ret;
 }
 
+vector<double> CObjVecObj::to_rvec() const
+{
+    vector<double> ret(size());
+    for (int i = 0; i < v.size(); ++i)
+        ret[i] = v[i]->to_r();
+    return ret;
+}
+
 //**************************************************************************************************
 //  CObjVecInt
 //**************************************************************************************************
diff --git a/pub/lib/obj.hpp b/pub/lib/obj.hpp
index 9a8e6f1abcb29067dbdb3947326e58cd602365b3..63eb78f2208cae3d167dae855a55780f51b9f9e3 100644
--- a/pub/lib/obj.hpp
+++ b/pub/lib/obj.hpp
@@ -153,6 +153,7 @@ public:
     inline string result_info() const { return to_s(); }
     inline RObj to_obj(int i) const { return v[i]; }
     string to_s(int maxlen = 12, int minlen = 1, int prec = 6) const;
+    vector<double> to_rvec() const;
     RObj to_vecnum() const;
 };
 
diff --git a/pub/lib/olf.cpp b/pub/lib/olf.cpp
index 91d4aab2538262633e13451c086cc3202de2d303..fbff309b4efb3db1c3cc95925a64a17b20955474 100644
--- a/pub/lib/olf.cpp
+++ b/pub/lib/olf.cpp
@@ -102,6 +102,14 @@ void COlo::check_integrity() const
 
 RObj COlo::z(int j, int iz) const { return V[j]->z[iz]; }
 
+//! Return vector of iz-th z-variables.
+
+RObjVecObj COlo::zvec(int iz) const {
+    PObjVecObj ret(new CObjVecObj(nJ()));
+    for (size_t j=0; j<nJ(); ++j)
+        ret->v[j] = V[j]->z[iz];
+    return ret;
+}
 
 //**************************************************************************************************
 //*  COld/COlc (member functions that are similar for both classes)
diff --git a/pub/lib/olf.hpp b/pub/lib/olf.hpp
index a311cc29c3c9c113eaf93fd909df150ed66556b7..493d0acca7d002b393d0a29a041dc9d6557025e3 100644
--- a/pub/lib/olf.hpp
+++ b/pub/lib/olf.hpp
@@ -47,6 +47,7 @@ public:
     int nJ() const { return V.size(); }
     int nZ() const { return ZCo.size(); }
     RObj z(int j, int iz) const;
+    RObjVecObj zvec(int iz) const;
     virtual PSlice copy_slice(int j) const = 0;
     virtual POlo new_POlo() const = 0;
     virtual CCoord coord(const CGenus& genus) const = 0;
diff --git a/pub/lib/special.cpp b/pub/lib/special.cpp
index cf8eba150c371b191203fbd038e3c0f6e71ebde9..70b3708453079ff12757131bdd43cbad27df79ef 100644
--- a/pub/lib/special.cpp
+++ b/pub/lib/special.cpp
@@ -9,10 +9,14 @@
 
 #include "defs.hpp"
 
-
+#include <fstream>
+#include <vector>
 #include <fftw3.h>
+#include <boost/format.hpp>
 
-
+#include "../trivia/file_ops.hpp"
+#include "../trivia/vector_ops.hpp"
+#include "../readplus/ask.hpp"
 #include "fsel.hpp"
 #include "loop.hpp"
 #include "mem.hpp"
@@ -21,6 +25,9 @@
 #include "slice.hpp"
 #include "special.hpp"
 
+using boost::format;
+using std::vector;
+
 namespace NSpecial
 {
 void q_eval(double* par, int m_dat, double* fvec, void* data, int* info);
@@ -97,3 +104,38 @@ void NSpecial::Test()
     }
     SMem::instance()->mem_store(move(fout));
 }
+
+//! Experimental 2d plot
+
+void NSpecial::export_p2d(bool allow_overwrite)
+{ // EMBEDDED_DIALOG
+    string outfnam;
+    FileIterator fiter(SFSel::instance()->selD());
+    while (COld* f = fiter.nextD()) {
+        size_t m = f->nJ();
+        if (m<2)
+            throw "2d plot requires at least 2 slices";
+        // query output file name
+        outfnam = wask("Export to (.p2d)", f->name);
+        if (outfnam == "")
+            return;
+        f->name = outfnam;
+        outfnam += ".p2d";
+        // document file save
+        if (!allow_overwrite && triv::file_exists(outfnam))
+            throw "file " + outfnam + " exists, use flag ! to overwrite";
+        std::ofstream ofs;
+        ofs.open(outfnam, std::ofstream::out);
+        vector<double> zval = f->zvec(0)->to_rvec();
+        vector<double> zlim = triv::histogram_limits(zval);
+        for (size_t j=0; j<m; ++j) {
+            const CSpec* s = f->VS(j);
+            vector<double> xlim = triv::histogram_limits(s->x);
+            for (size_t i=0; i<s->size(); ++i)
+                ofs << ( format("%13.7g wx %13.7g wx  %13.7g wz %13.7g wz  %13.7g wy p2d\n")
+                         % xlim[i] % xlim[i+1] % zlim[j] % zlim[j+1] % s->y[i] );
+            ofs << "\n";
+        }
+        ofs.close();
+    }
+}
diff --git a/pub/lib/special.hpp b/pub/lib/special.hpp
index 192da96e96e61e33c10b400f7ed7f1e9b12195c7..1bd69fe62126dbd21227779260d71c16befc7779 100644
--- a/pub/lib/special.hpp
+++ b/pub/lib/special.hpp
@@ -20,6 +20,7 @@ namespace NSpecial
 {
 void FourierCosine();
 void Test();
+void export_p2d(bool allow_overwrite);
 
 template <typename T> complex<T> pssc(T z)
 {