# How to plot a vector field with arrow length and background color for strength and direction

I want to visualize a 2D vector field, e.g.,

Table[Exp[-(x^2 + y^2)/4] {y, -x}, {x, -3, 3, 0.2}, {y, -3, 3, 0.2}]


in the following way:

• the arrow length denotes the vector length
• the background color indicates the local vector orientation
• the color becomes paler when the vector length decreases

Just something like the following. How can one achieve this in Mathematica?

# Edit

Using the Hue method in the answer below, I tried the following case. There looks to be some obvious mismatch: the vectors are still quite big while the colors already decay to white.

rmax = 5.0; rmesh = 0.1;
data = Table[{{x, y}, Exp[-(x^2 + y^2)/0.5] {y, -x}}, {x, -rmax, rmax,
rmesh}, {y, -rmax, rmax, rmesh}];
maxnorm = Max[Map[Norm[#[[2]]] &, data, {2}]]
data = MapAt[#/maxnorm &, data, {All, All, 2}];
vp2 = ListVectorPlot[data,
Prolog -> {Map[{If[#[[1]] == {0, 0}, Hue[0, 0, 1],
Hue[ArcTan[#[[2, 1]], #[[2, 2]]]/(2 \[Pi]), Norm[#[[2]]], 1]],
Rectangle[#[[1]] - rmesh/2, #[[1]] + rmesh/2]} &, data, {2}]},
PlotRange -> rmax {{-1, 1}, {-1, 1}}, VectorColorFunction -> None,
VectorScaling -> Automatic, VectorStyle -> Black]


If I understood the requirements correctly, two ways you might be able to do it are using RegionPlot + VectorPlot or Graphics + ListVectorPlot. The first way is nice because you can continuously increase the resolution. The second way uses pre-calculated, discrete values which more closely match the example graphic.

rp = RegionPlot[
-3 <= x <= 3 \[And] -3 <= y <= 3,
{x, -3, 3},
{y, -3, 3},
BoundaryStyle -> None,
ColorFunction -> (Hue[
ArcTan[Exp[-(#1^2 + #2^2)/
4] #2, -Exp[-(#1^2 + #2^2)/4] #1]/(2 \[Pi]),
Norm[Exp[-(#1^2 + #2^2)/4]], 1] &),
ColorFunctionScaling -> False,
PlotPoints -> 200,
PlotRange -> {{-3, 3}, {-3, 3}}
];
vp = VectorPlot[
Exp[-(x^2 + y^2)/4] {y, -x},
{x, -3, 3},
{y, -3, 3},
VectorColorFunction -> None,
VectorScaling -> Automatic,
VectorStyle -> Black
];
Show[
rp,
vp
]


The vectors go slightly outside of the plot, but the vectors could probably be adjusted to avoid that without too much difficulty. Here, the colourful background is provided by RegionPlot, and the the specific hue is controlled by the angle of the vector at a given point with the saturation controlled by the length of the vector. The brightness is 1 in all cases. As far as I can tell, that's how it worked in the example image so I tried to replicate that here. I think the ArcTan for the hue should be fine, but I'm not sure how robust using the Norm for the saturation will be. If the length of your vectors is greater than 1, the values for saturation will be clipped to 1, so keep that in mind.

We can also create a little colour wheel. This wheel can be added to either version, but here I've only added it to the discretized version of the plot.

wheel = RegionPlot[
x^2 + y^2 <= 1,
{x, -1, 1},
{y, -1, 1},
BoundaryStyle -> None,
ColorFunction -> (Hue[ArcTan[#1, #2]/(2 \[Pi]), Sqrt[#1^2 + #2^2],
1] &),
ColorFunctionScaling -> False,
Frame -> False,
Epilog -> {
Line[{{0, 0}, {0, 1}}],
Line[{{0, #}, {0.05, #}}] & /@ {0, 0.5, 1},
Text[Style[ToString[#], 16], {0.1, #}, {-1, 0}] & /@ {0, 0.5, 1}
}
]


Then create our data points, make the plots, and add the wheel:

data = Table[
{{x, y}, Exp[-(x^2 + y^2)/4] {y, -x}},
{x, -3, 3, 0.2},
{y, -3, 3, 0.2}
];
vp2 = ListVectorPlot[
data,
Prolog -> {
Map[
{
If[
#[[1]] == {0, 0},
Hue[0, 0, 1],
Hue[ArcTan[#[[2, 1]], #[[2, 2]]]/(2 \[Pi]), Norm[#[[2]]], 1]
],
Rectangle[#[[1]] - 0.1, #[[1]] + 0.1]
} &,
data,
{2}
]
},
PlotRange -> {{-3, 3}, {-3, 3}},
VectorColorFunction -> None,
VectorScaling -> Automatic,
VectorStyle -> Black,
Epilog -> {
Inset[
wheel,
{3, 3},
{1.12, 1.12},
Scaled[0.3]
]
}
]


In this one, I'm creating the background by using Prolog in the ListVectorPlot and creating a bunch of rectangles of the correct hue and saturation. Prolog plots things before the rest of the plot and Epilog plots things after everything is said and done.

EDIT:

I just realized that my ListVectorPlot wasn't actually plotting every vector. This is because Mathematica thinks that it's too crowded (it's probably not wrong). If you would like every point to plot, add VectorPoints -> All as an option in ListVectorPlot to get:

EDIT 2:

rmax = 5.0;
rmesh = 0.1;
data = Table[
{{x, y}, Exp[-(x^2 + y^2)/1] {y, -x}},
{x, -rmax, rmax, rmesh},
{y, -rmax, rmax, rmesh}
];
maxnorm = Max[Map[Norm[#[[2]]] &, data, {2}]];
data = MapAt[#/maxnorm &, data, {All, All, 2}];
vp2 = ListVectorPlot[
data,
Prolog -> {Map[{If[#[[1]] == {0, 0}, Hue[0, 0, 1],
Hue[ArcTan[#[[2, 1]], #[[2, 2]]]/(2 \[Pi]), Norm[#[[2]]], 1]],
Rectangle[#[[1]] - rmesh/2, #[[1]] + rmesh/2]} &, data, {2}]},
PlotRange -> rmax {{-1, 1}, {-1, 1}},
VectorColorFunction -> None,
VectorScaling -> Automatic,
VectorSizes -> {0, 1},
VectorStyle -> Black
]


And with the option VectorPoints -> All added to the above code:

EDIT 3:

Adding in VectorRange:

rmax = 5.0;
rmesh = 0.1;
data = Table[
{{x, y}, Exp[-(x^2 + y^2)/1] {y, -x}},
{x, -rmax, rmax, rmesh},
{y, -rmax, rmax, rmesh}
];
maxnorm = Max[Map[Norm[#[[2]]] &, data, {2}]];
data = MapAt[#/maxnorm &, data, {All, All, 2}];
vp2 = ListVectorPlot[
data,
Prolog -> {Map[{If[#[[1]] == {0, 0}, Hue[0, 0, 1],
Hue[ArcTan[#[[2, 1]], #[[2, 2]]]/(2 \[Pi]), Norm[#[[2]]], 1]],
Rectangle[#[[1]] - rmesh/2, #[[1]] + rmesh/2]} &, data, {2}]},
PlotRange -> rmax {{-1, 1}, {-1, 1}},
VectorColorFunction -> None,
VectorRange -> {0, 1},
VectorScaling -> "Linear",
VectorSizes -> {0, 1},
VectorStyle -> Black
]


• Thanks your code to show how to use Hue! Commented Jan 22, 2021 at 10:08
• @cvgmt No problem! Commented Jan 22, 2021 at 10:18
• Thank you! This is an almost perfect answer. Commented Jan 28, 2021 at 7:23
• Could you please help look at the following code piece using your method? It looks weird that the arrows are still very big although the color almost disappears. I add a normalization of the vector length, by the way. rmax = 5.0; rmesh = 0.1; data = Table[{{x, y}, Exp[-(x^2 + y^2)/1] {y, -x}}, {x, -rmax, rmax, rmesh}, {y, -rmax, rmax, rmesh}]; maxnorm = Max[Map[Norm[#[[2]]] &, data, {2}]] data = MapAt[#/maxnorm &, data, {All, All, 2}]; Commented Jan 28, 2021 at 14:23
• vp2 = ListVectorPlot[data, Prolog -> {Map[{If[#[[1]] == {0, 0}, Hue[0, 0, 1], Hue[ArcTan[#[[2, 1]], #[[2, 2]]]/(2 \[Pi]), Norm[#[[2]]], 1]], Rectangle[#[[1]] - rmesh/2, #[[1]] + rmesh/2]} &, data, {2}]}, PlotRange -> rmax {{-1, 1}, {-1, 1}}, VectorColorFunction -> None, VectorScaling -> Automatic, VectorStyle -> Black] Commented Jan 28, 2021 at 14:25

Maybe like this.

ListVectorDensityPlot[
Table[{y, -x}, {x, -3, 3, 0.2}, {y, -3, 3, 0.2}],
ColorFunctionScaling -> False, VectorScaling -> True,
ColorFunction ->
Function[{x, y, vx, vy, n},
Hue[If[vx == vy == 0, 0, ArcTan[vx, vy]/(2 π)]]],
VectorStyle -> Black, VectorColorFunction -> None]


• Hue[Arg[vx + I*vy] Commented Jan 22, 2021 at 9:31
• Thanks for the nice answer. I eventually also found this method very useful since it generates smooth colors in the background. But I notice a weird issue recently. Commented Mar 16, 2021 at 5:06