add 2D streamplot function in 3D axes

This commit is contained in:
wyq 2023-06-15 23:29:04 +08:00
parent ead8103231
commit eecbd206bf
8 changed files with 260 additions and 27 deletions

View File

@ -6992,26 +6992,158 @@ public class GraphicFactory {
}
/**
* Create stream line
* Create streamline
*
* @param xdata X data array
* @param ydata Y data array
* @param udata U/WindDirection data array
* @param vdata V/WindSpeed data array
* @param cdata Color value data array
* @param density Streamline density
* @param slb Streamline break
* @param ls Legend scheme
* @param isUV Is U/V or not
* @return GraphicCollection
* @param offset Offset in z direction
* @param zdir Z direction - x, y or z
* @return GraphicCollection3D
*/
public static GraphicCollection createStreamlines(Array xdata, Array ydata, Array udata, Array vdata,
int density, StreamlineBreak slb, boolean isUV) {
GraphicCollection gc = new GraphicCollection();
public static GraphicCollection3D createStreamlines(Array xdata, Array ydata, Array udata, Array vdata,
Array cdata, int density, LegendScheme ls, boolean isUV, double offset, String zdir) {
GraphicCollection3D graphics = new GraphicCollection3D();
if (!isUV) {
Array[] uvData = MeteoMath.ds2uv(udata, vdata);
udata = uvData[0];
vdata = uvData[1];
}
double[][] u = (double[][])ArrayUtil.copyToNDJavaArray_Double(udata);
double[][] v = (double[][])ArrayUtil.copyToNDJavaArray_Double(vdata);
double[] x = (double[]) ArrayUtil.copyToNDJavaArray_Double(xdata);
double[] y = (double[]) ArrayUtil.copyToNDJavaArray_Double(ydata);
List<PolyLine> streamlines = Contour.tracingStreamline(u, v,
x, y, density);
int ny = u.length;
int nx = u[0].length;
ColorBreak cb = ls.getLegendBreak(0);
if (cdata == null) {
for (PolyLine line : streamlines) {
PolylineZShape shape = new PolylineZShape();
List<PointZ> points = new ArrayList<>();
PointZ p;
if (zdir.equals("x")) {
for (int j = 0; j < line.PointList.size(); j++) {
p = new PointZ();
p.Y = (line.PointList.get(j)).X;
p.Z = (line.PointList.get(j)).Y;
p.X = offset;
points.add(p);
}
} else if (zdir.equals("y")) {
for (int j = 0; j < line.PointList.size(); j++) {
p = new PointZ();
p.X = (line.PointList.get(j)).X;
p.Z = (line.PointList.get(j)).Y;
p.Y = offset;
points.add(p);
}
} else {
for (int j = 0; j < line.PointList.size(); j++) {
p = new PointZ();
p.X = (line.PointList.get(j)).X;
p.Y = (line.PointList.get(j)).Y;
p.Z = offset;
points.add(p);
}
}
shape.setPoints(points);
graphics.add(new Graphic(shape, cb));
}
} else {
cdata = cdata.copyIfView();
for (PolyLine line : streamlines) {
PolylineZShape shape = new PolylineZShape();
List<PointZ> points = new ArrayList<>();
PointZ p;
ColorBreakCollection cbs = new ColorBreakCollection();
if (zdir.equals("x")) {
for (int j = 0; j < line.PointList.size(); j++) {
p = new PointZ();
p.Y = (line.PointList.get(j)).X;
p.Z = (line.PointList.get(j)).Y;
p.X = offset;
int[] idx = ArrayUtil.gridIndex(xdata, ydata, p.Y, p.Z);
if (idx != null) {
int yi = idx[0];
int xi = idx[1];
p.M = cdata.getDouble(yi * nx + xi);
}
cb = ls.findLegendBreak(p.M);
cbs.add(cb);
points.add(p);
}
} else if (zdir.equals("y")) {
for (int j = 0; j < line.PointList.size(); j++) {
p = new PointZ();
p.X = (line.PointList.get(j)).X;
p.Z = (line.PointList.get(j)).Y;
p.Y = offset;
int[] idx = ArrayUtil.gridIndex(xdata, ydata, p.X, p.Z);
if (idx != null) {
int yi = idx[0];
int xi = idx[1];
p.M = cdata.getDouble(yi * nx + xi);
}
cb = ls.findLegendBreak(p.M);
cbs.add(cb);
points.add(p);
}
} else {
for (int j = 0; j < line.PointList.size(); j++) {
p = new PointZ();
p.X = (line.PointList.get(j)).X;
p.Y = (line.PointList.get(j)).Y;
p.Z = offset;
int[] idx = ArrayUtil.gridIndex(xdata, ydata, p.X, p.Y);
if (idx != null) {
int yi = idx[0];
int xi = idx[1];
p.M = cdata.getDouble(yi * nx + xi);
}
cb = ls.findLegendBreak(p.M);
cbs.add(cb);
points.add(p);
}
}
shape.setPoints(points);
graphics.add(new Graphic(shape, cbs));
}
}
graphics.setLegendScheme(ls);
return graphics;
}
/**
* Create streamline
*
* @param xdata X data array
* @param ydata Y data array
* @param udata U/WindDirection data array
* @param vdata V/WindSpeed data array
* @param density Streamline density
* @param slb Streamline break
* @param isUV Is U/V or not
* @return GraphicCollection
*/
public static GraphicCollection createStreamlines(Array xdata, Array ydata, Array udata, Array vdata,
int density, StreamlineBreak slb, boolean isUV) {
GraphicCollection gc = new GraphicCollection();
if (!isUV) {
Array[] uvData = MeteoMath.ds2uv(udata, vdata);
udata = uvData[0];
vdata = uvData[1];
}
double[][] u = (double[][])ArrayUtil.copyToNDJavaArray_Double(udata);
double[][] v = (double[][])ArrayUtil.copyToNDJavaArray_Double(vdata);
double[] x = (double[]) ArrayUtil.copyToNDJavaArray_Double(xdata);
@ -7019,7 +7151,7 @@ public class GraphicFactory {
List<PolyLine> streamlines = Contour.tracingStreamline(u, v,
x, y, density);
PolyLine line;
for (int i = 0; i < streamlines.size() - 1; i++) {
for (int i = 0; i < streamlines.size(); i++) {
line = streamlines.get(i);
PolylineShape aPolyline = new PolylineShape();
PointD aPoint;
@ -7039,7 +7171,7 @@ public class GraphicFactory {
}
/**
* Trace streamlines
* Trace 3D streamlines
* @param xa X coordinate array
* @param ya Y coordinate array
* @param z Z value
@ -7174,7 +7306,7 @@ public class GraphicFactory {
}
/**
* Trace streamlines
* Trace 3D streamlines
* @param xa X coordinate array
* @param ya Y coordinate array
* @param xySlice XY slice value - [x1,y1,x2,y2]

View File

@ -1,14 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<MeteoInfo File="milconfig.xml" Type="configurefile">
<Path OpenPath="D:\Working\MIScript\Jython\mis\dataframe">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\contour"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\slice"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\funny"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types"/>
<Path OpenPath="D:\Working\MIScript\Jython\mis\plot_types\wind">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\contour"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\array"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\meteo"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\meteo\calc"/>
@ -16,21 +10,27 @@
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io\savefig"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\dataframe"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\contour"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\contour"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\streamplot"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\wind"/>
</Path>
<File>
<OpenedFiles>
<OpenedFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\meteoview3d\_reload.py"/>
<OpenedFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\meteoview3d\mainGUI.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\dataframe\loc_2.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\dataframe\compare_2.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\dataframe\compare_1.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\contour\contour3_1.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\streamplot\streamplot_3.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\streamplot\streamplot_2d_1.py"/>
</OpenedFiles>
<RecentFiles>
<RecentFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\meteoview3d\_reload.py"/>
<RecentFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\meteoview3d\mainGUI.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\dataframe\loc_2.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\dataframe\compare_2.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\dataframe\compare_1.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\contour\contour3_1.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\streamplot\streamplot_3.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\streamplot\streamplot_2d_1.py"/>
</RecentFiles>
</File>
<Font>
@ -38,5 +38,5 @@
</Font>
<LookFeel DockWindowDecorated="true" LafDecorated="true" Name="FlatDarkLaf"/>
<Figure DoubleBuffering="true"/>
<Startup MainFormLocation="-7,0" MainFormSize="1421,827"/>
<Startup MainFormLocation="-7,-7" MainFormSize="1293,685"/>
</MeteoInfo>

View File

@ -3703,7 +3703,7 @@ class Axes(object):
def streamplot(self, *args, **kwargs):
"""
Plot 3D streamline.
Plot 2D streamline.
:param x: (*array_like*) Optional. X coordinate array.
:param y: (*array_like*) Optional. Y coordinate array.
@ -3716,7 +3716,7 @@ class Axes(object):
:param density: (*int*) Streamline density. Default is 4.
:param zorder: (*int*) Z-order of streamline graphic for display.
:returns: (*graphics*) 3D streamline graphics.
:returns: (*graphics*) 2D streamline graphics.
"""
isuv = kwargs.pop('isuv', True)
density = kwargs.pop('density', 4)

View File

@ -502,6 +502,107 @@ class Axes3DGL(Axes3D):
return barbreaks
def streamplot(self, *args, **kwargs):
"""
Plot 2D streamline.
:param x: (*array_like*) Optional. X coordinate array.
:param y: (*array_like*) Optional. Y coordinate array.
:param u: (*array_like*) U component of the arrow vectors (wind field) or wind direction.
:param v: (*array_like*) V component of the arrow vectors (wind field) or wind speed.
:param z: (*array_like*) Optional, 2-D z value array.
:param color: (*Color*) Streamline color.
:param fill_value: (*float*) Fill_value. Default is ``-9999.0``.
:param isuv: (*boolean*) Is U/V or direction/speed data array pairs. Default is True.
:param density: (*int*) Streamline density. Default is 4.
:param offset: (*float*) Z direction offset. Default is 0.
:param zdir: (*int*) Z direction ['x'|'y'|'z']. Default is `z`.
:returns: (*graphics*) 2D streamline graphics.
"""
ls = kwargs.pop('symbolspec', None)
cmap = plotutil.getcolormap(**kwargs)
density = kwargs.pop('density', 4)
iscolor = False
cdata = None
if len(args) < 4:
u = args[0]
v = args[1]
u = np.asarray(u)
nz, ny, nx = u.shape
x = np.arange(nx)
y = np.arange(ny)
args = args[2:]
else:
x = args[0]
y = args[1]
u = args[2]
v = args[3]
args = args[4:]
if len(args) > 0:
cdata = args[0]
iscolor = True
args = args[1:]
x = plotutil.getplotdata(x)
y = plotutil.getplotdata(y)
u = plotutil.getplotdata(u)
v = plotutil.getplotdata(v)
if ls is None:
if iscolor:
if len(args) > 0:
cn = args[0]
if isinstance(cn, NDArray):
cn = cn.aslist()
ls = LegendManage.createLegendScheme(cdata.min(), cdata.max(), cn, cmap)
else:
levs = kwargs.pop('levels', None)
if levs is None:
ls = LegendManage.createLegendScheme(cdata.min(), cdata.max(), cmap)
else:
if isinstance(levs, NDArray):
levs = levs.tolist()
ls = LegendManage.createLegendScheme(cdata.min(), cdata.max(), levs, cmap)
else:
if cmap.getColorCount() == 1:
c = cmap.getColor(0)
else:
c = Color.black
ls = LegendManage.createSingleSymbolLegendScheme(ShapeTypes.POLYLINE, c, 1)
ls = plotutil.setlegendscheme_line(ls, **kwargs)
if not kwargs.has_key('headwidth'):
kwargs['headwidth'] = 1
if not kwargs.has_key('headlength'):
kwargs['headlength'] = 2.5 * kwargs['headwidth']
for i in range(ls.getBreakNum()):
lb = plotutil.line2stream(ls.getLegendBreak(i), **kwargs)
ls.setLegendBreak(i, lb)
if not cdata is None:
cdata = plotutil.getplotdata(cdata)
isuv = kwargs.pop('isuv', True)
offset = kwargs.pop('offset', 0)
zdir = kwargs.pop('zdir', 'z')
graphics = GraphicFactory.createStreamlines(x, y, u, v, cdata, density, ls, isuv,
offset, zdir)
lighting = kwargs.pop('lighting', None)
if not lighting is None:
graphics.setUsingLight(lighting)
# Pipe
pipe = kwargs.pop('pipe', False)
if pipe:
radius = kwargs.pop('radius', 0.02)
steps = kwargs.pop('steps', 48)
graphics = GraphicFactory.lineString3DToPipe(graphics, radius, steps)
self.add_graphic(graphics)
return graphics
def streamplot3(self, *args, **kwargs):
"""
Plot streamlines in 3D axes.

View File

@ -1670,7 +1670,7 @@ def scatterm(*args, **kwargs):
return r
@_copy_docstring_and_deprecators(Axes3D.streamplot)
@_copy_docstring_and_deprecators(Axes3DGL.streamplot3)
def streamplot3(*args, **kwargs):
global g_axes
if g_axes is None:
@ -1679,7 +1679,7 @@ def streamplot3(*args, **kwargs):
if not isinstance(g_axes, Axes3DGL):
g_axes = axes3dgl()
r = g_axes.streamplot(*args, **kwargs)
r = g_axes.streamplot3(*args, **kwargs)
draw_if_interactive()
return r