4

I want to plot a map of specific sites to interpret their effects on the surrounding city environment. To do this, I would like to plot the sites as bubbles, with a decreasing gradient towards the edge of the circle, and where the gradient of the overlapping circles is the sum.

As an example I've used this:

# libraries
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns

# create data
x = np.random.rand(15)
y = x+np.random.rand(15)
z = x+np.random.rand(15)
z=z*z

# Change color with c and alpha. I map the color to the X axis value.
plt.scatter(x, y, s=1500, c=z, cmap="Blues", alpha=0.4, edgecolors="grey", linewidth=1)

# Add titles (main and on axis)
plt.xlabel("the X axis")
plt.ylabel("the Y axis")
plt.title("A colored bubble plot")

plt.show();

which produces:

enter image description here

However, the color of the circles does not decay, nor do they seem to sum the intended way.

Is there any smart way to do this, or could it possibly be easier with some kind of heatmap solution, or using grids and a decaying effect on adjacent tiles?

Tobias P. G.
  • 827
  • 8
  • 15
  • 3
    I believe there is no such functionality implemented yet. Some years ago there was a [feature request](https://github.com/matplotlib/matplotlib/issues/8926) which was never picked up. However, it seems that the accepted answer [here](https://stackoverflow.com/questions/10958835/matplotlib-color-gradient-in-patches) could be a workaround which is suitable for you. – gehbiszumeis Feb 07 '20 at 12:42
  • 1
    and here is another [example](https://matplotlib.org/devdocs/gallery/lines_bars_and_markers/gradient_bar.html) – trsvchn Feb 07 '20 at 12:46

1 Answers1

1

Here is an approach with densities placed at each x and y, enlarged by the z value. Depending on the distance to each x,y position a quantity is added.

import matplotlib.pyplot as plt
import numpy as np
from numpy.linalg import norm # calculate the length of a vector
# import seaborn as sns

# create data
x = np.random.rand(15)
y = x+np.random.rand(15)
z = x+np.random.rand(15)
z=z*z

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(12,5))
# Change color with c and alpha. I map the color to the X axis value.
ax1.scatter(x, y, s=1500, c=z, cmap="Blues", alpha=0.4, edgecolors="grey", linewidth=1)
ax1.set_xlabel("the X axis")
ax1.set_ylabel("the Y axis")
ax1.set_title("A colored bubble plot")

centers = np.dstack((x, y))[0]
xmin = min(x)-0.2
xmax = max(x)+0.2
ymin = min(y)-0.2
ymax = max(y)+0.2
zmin = min(z)
zmax = max(z)
xx, yy = np.meshgrid(np.linspace(xmin, xmax, 100),
                     np.linspace(ymin, ymax, 100))
xy = np.dstack((xx, yy))
zz = np.zeros_like(xx)
for ci, zi in zip(centers, z):
    sigma = zi / zmax * 0.3
    sigma2 = sigma ** 2
    zz += np.exp(- norm(xy - ci, axis=-1) ** 2 / sigma2 / 2)

img = ax2.imshow(zz, extent=[xmin, xmax, ymin, ymax], origin='lower', aspect='auto', cmap='Blues')
#plt.colorbar(img, ax=ax2)

ax2.set_xlabel("the X axis")
ax2.set_ylabel("the Y axis")
ax2.set_title("Density depending on z")

plt.show()

The plot compares the two approaches using the same random data.

sample plot

JohanC
  • 71,591
  • 8
  • 33
  • 66
  • Was this answer helpful? – JohanC Feb 10 '20 at 00:34
  • It's definately close, it doesn't quiet achieve what I'm looking for. In the example here: https://imgur.com/a/O6gRTcz the bubble at the top right corner should still have a high value / strong color. Maybe considering it as a matrix with a gradient function like https://imgur.com/a/iySzDlD would be more optimal? However I do not know how to apply that either. – Tobias P. G. Feb 10 '20 at 13:32