@@ -1000,80 +1000,90 @@ run_example("streamplot")
10001000## Theme
10011001$(ATTRIBUTES)
10021002"""
1003- @recipe (StreamPlot, f, xrange, yrange ) do scene
1003+ @recipe (StreamPlot, f, limits ) do scene
10041004 Theme (
10051005 stepsize = 0.01 ,
1006- resolution = (32 , 32 ),
1006+ gridsize = (32 , 32 , 32 ),
10071007 colormap = theme (scene, :colormap ),
10081008 arrow_size = 0.03
10091009 )
10101010end
10111011
1012- function convert_arguments (:: Type{<: StreamPlot} , f:: Function , x, y)
1013- (f, x, y)
1012+ function convert_arguments (:: Type{<: StreamPlot} , f:: Function , xrange, yrange)
1013+ xmin, xmax = extrema (xrange)
1014+ ymin, ymax = extrema (yrange)
1015+ return (f, Rect (xmin, ymin, xmax - xmin, ymax - ymin))
1016+ end
1017+ function convert_arguments (:: Type{<: StreamPlot} , f:: Function , xrange, yrange, zrange)
1018+ xmin, xmax = extrema (xrange)
1019+ ymin, ymax = extrema (yrange)
1020+ zmin, zmax = extrema (yrange)
1021+ mini = Vec3f0 (xmin, ymin, zmin)
1022+ maxi = Vec3f0 (xmax, ymax, zmax)
1023+ return (f, Rect (mini, maxi .- mini))
1024+ end
1025+
1026+ function convert_arguments (:: Type{<: StreamPlot} , f:: Function , limits:: Rect )
1027+ return (f, limits)
10141028end
10151029
10161030"""
10171031Code adapted from an example implementation by Moritz Schauer (@mschauer)
10181032from https://github.com/JuliaPlots/Makie.jl/issues/355#issuecomment-504449775
10191033"""
1020- function streamplot_impl (CallType, f, xrange, yrange, resolution, stepsize)
1021- mask = trues (resolution)
1022- arrow_pos = Point2f0[]
1023- arrow_dir = Vec2f0[]
1024- line_points = Point2f0[]
1034+ function streamplot_impl (CallType, f, limits:: Rect{N, T} , resolutionND, stepsize) where {N, T}
1035+ resolution = to_ndim (Vec{N, Int}, resolutionND, last (resolutionND))
1036+ mask = trues (resolution... )
1037+ arrow_pos = Point{N, Float32}[]
1038+ arrow_dir = Vec{N, Float32}[]
1039+ line_points = Point{N, Float32}[]
10251040 colors = Float64[]
10261041 line_colors = Float64[]
1027- xmin, xmax = extrema (xrange)
1028- ymin, ymax = extrema (yrange)
1029- limits = Rect (xmin, ymin, xmax - xmin, ymax - ymin)
1030- dt = Point2f0 (to2tuple (stepsize))
1031- r = (
1032- LinRange (xmin, xmax, resolution[1 ] + 1 ),
1033- LinRange (ymin, ymax, resolution[2 ] + 1 )
1034- )
1042+ dt = Point {N, Float32} (stepsize)
1043+ mini, maxi = minimum (limits), maximum (limits)
1044+ r = ntuple (N) do i
1045+ LinRange (mini[i], maxi[i], resolution[i] + 1 )
1046+ end
10351047 apply_f (x0, P) = if P <: Point
10361048 f (x0)
10371049 else
1038- f (x0[ 1 ], x0[ 2 ] )
1050+ f (x0... )
10391051 end
10401052 for c in CartesianIndices (mask)
1041- i0, j0 = Tuple (c)
1042- x0 = Point2 (
1043- first (r[1 ]) + (i0 - 0.5 ) * step (r[1 ]),
1044- first (r[2 ]) + (j0 - 0.5 ) * step (r[1 ])
1045- )
1053+ x0 = Point (ntuple (N) do i
1054+ first (r[i]) + (c[i] - 0.5 ) * step (r[i])
1055+ end )
10461056 if mask[c]
10471057 point = apply_f (x0, CallType)
1048- if ! (point isa Point2)
1049- error (" Function passed to streamplot must return Point2" )
1058+ if ! (point isa Point2 || point isa Point3 )
1059+ error (" Function passed to streamplot must return Point2 or Point3 " )
10501060 end
10511061 pnorm = norm (point)
10521062 push! (arrow_pos, x0)
1053- push! (arrow_dir, point / pnorm)
1063+ push! (arrow_dir, point . / pnorm)
10541064 push! (colors, pnorm)
10551065 mask[c] == false
10561066 for d in (- 1 , 1 )
10571067 n_linepoints = 1
10581068 x = x0
1059- push! (line_points, Point2f0 (NaN ), x)
1069+ push! (line_points, Point {N, Float32} (NaN ), x)
10601070 push! (line_colors, 0.0 , pnorm)
1061- i0, j0 = Tuple (c)
10621071 while x in limits && n_linepoints < 500
10631072 point = apply_f (x, CallType)
10641073 pnorm = norm (point)
10651074 x = x .+ d .* dt .* point ./ pnorm
10661075 if ! (x in limits)
10671076 break
10681077 end
1069- i = searchsortedlast (r[1 ], x[1 ])
1070- j = searchsortedlast (r[2 ], x[2 ])
1071- if (i, j) != (i0, j0)
1072- if ! mask[i,j]
1078+ # WHAT? Why does point behave different from tuple in this
1079+ # broadcast
1080+ idx = CartesianIndex (searchsortedlast .(r, Tuple (x)))
1081+ if idx != c
1082+ if ! mask[idx]
10731083 break
10741084 end
1075- mask[i, j ] = false
1076- i0, j0 = i, j
1085+ mask[idx ] = false
1086+ c = idx
10771087 end
10781088 push! (line_points, x)
10791089 push! (line_colors, pnorm)
@@ -1092,21 +1102,22 @@ function streamplot_impl(CallType, f, xrange, yrange, resolution, stepsize)
10921102end
10931103
10941104function plot! (p:: StreamPlot )
1095- data = lift (p. f, p. xrange , p. yrange , p. resolution, p . stepsize) do f, xrange, yrange , resolution, stepsize
1096- P = if applicable (f, Point2f0 (0 ))
1105+ data = lift (p. f, p. limits , p. gridsize , p. stepsize) do f, limits , resolution, stepsize
1106+ P = if applicable (f, Point2f0 (0 )) || applicable (f, Point3f0 ( 0 ))
10971107 Point
10981108 else
10991109 Number
11001110 end
1101- streamplot_impl (P, f, xrange, yrange , resolution, stepsize)
1111+ streamplot_impl (P, f, limits , resolution, stepsize)
11021112 end
11031113 lines! (
11041114 p,
11051115 lift (x-> x[3 ], data), color = lift (last, data), colormap = p. colormap
11061116 )
1107- scatter! (
1117+ N = ndims (p. limits[])
1118+ scatterfun (N)(
11081119 p,
1109- lift (first, data), markersize = p. arrow_size, marker = ' ▲ ' ,
1120+ lift (first, data), markersize = p. arrow_size, marker = arrow_head (N, automatic) ,
11101121 color = lift (x-> x[4 ], data), rotations = lift (x-> x[2 ], data),
11111122 colormap = p. colormap,
11121123 )
0 commit comments