How to make a centered bubble chart in python/matplot lib - python

I'm trying to make a centered bubble chart in matplotlib / python similar to this.
Some people have called it a "bottom aligned bubble chart", So far, I've basically found a way to do a concentric circle scatter plot.
%matplotlib inline
import matplotlib.pyplot as plt
s = [ 50000.,10478.2, 4733.4,3185.3,2484.7,2310.9]
x = [1]*len(s)
y = [0]*len(s);
plt.scatter(x,y,s=s);
plt.show()
Any ideas on how to line up the bottom edges of these concentric cirlces?

I would interact with matplotlib artists directly. I would also set the radius -- and therefore center -- of each circle the square root of the populations.
This is because, for a circle, A ~ r^2, so you'll heavily distort the size differences if r ~ population.
So all that said:
%matplotlib inline
import numpy
import matplotlib.colors as mcolors
import matplotlib.pyplot as plt
import seaborn
seaborn.set(style='white')
populations = numpy.sqrt([50000., 10478.2, 4733.4, 3185.3, 2484.7, 2310.9])
cp = seaborn.color_palette('Blues_r', n_colors=len(populations))
fig, ax = plt.subplots()
for n, p in enumerate(populations):
circle = plt.Circle((1, p), radius=p, facecolor=cp[n])
ax.add_artist(circle)
ax.set_xlim(-max(populations), max(populations))
ax.set_ylim(0, 2 * max(populations))
ax.set_aspect('equal')
plt.show()
Gives me this:

Related

How to do a 3D circle in Matplotlib

I am a beginner in Python. I'm trying to plot a circle using matplotlib that has tangent to Z axis. I know how to draw a sphere in 3D but don't know how to draw a circle/ring in 3D plot. Can someone help me with the code? Thanks in advance!
You need the usual imports, plus the 3D toolkit
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
You need a 3D enabled axes object
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
You need a circle, contained in the plane y-z
theta = np.linspace(0, 2 * np.pi, 201)
y = 10*np.cos(theta)
z = 10*np.sin(theta)
now we can plot the original circle and, as an example, a number of circles rotated about the z-axis and whose centers are also placed at a fixed distance (equal to the c ircles'radius) from the z-axis, so that they are tangent to it
for i in range(18):
phi = i*np.pi/9
ax.plot(y*np.sin(phi)+10*np.sin(phi),
y*np.cos(phi)+10*np.cos(phi), z)
eventually we place a vertical axis and a legend
ax.plot((0,0),(0,0), (-10,10), '-k', label='z-axis')
ax.legend()
It's time to see what we got
plt.show()
mpl_toolkits.mplot3d.art3d
https://matplotlib.org/3.2.1/gallery/mplot3d/pathpatch3d.html was mentioned
in a comment, the example can be minimized to:
#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
import mpl_toolkits.mplot3d.art3d as art3d
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# Draw a circle on the x=0 'wall'
p = Circle((5, 5), 3)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=0, zdir="x")
ax.set_xlim(0, 10)
ax.set_ylim(0, 10)
ax.set_zlim(0, 10)
plt.show()
which gives:
This is a bit nicer than https://stackoverflow.com/a/56871467/895245 as it uses a higher level Circle object directly, instead of requiring you to explicitly plot the lines.
Unfortunately, 3D support in matplotlib is a bit limited as mentioned in the documentation itself, and you have to do some extra work to plot on planes not parallel to the main coordinate plane: How can matplotlib 2D patches be transformed to 3D with arbitrary normals?
Tested on matplotlib==3.2.2.

Plotting a circle in leaflet using .add_artist()

Starting from here and the first example from here, I'm trying to use pyplot and mplleaflet to plot a fixed-size circle on a map.
(By "fixed-size", I mean that this circle is not a marker, it shouldn't adapt to the zoom level, but should stay of, say, 25m diameter whatever the zoom level).
Here is what I got :
import mplleaflet
import matplotlib.pyplot as plt
import matplotlib as mpl
fig, ax = plt.subplots()
x = 2.363561
y = 48.951918
r = 20
circle1 = mpl.patches.Circle((x,y), radius=r)
circle2= plt.Circle((x, y), r, color='r')
ax.add_artist(circle1)
ax.add_artist(circle2)
mplleaflet.show(fig=ax.figure)
Code runs fine, but when the new leaflet tab opens, I got nothing :

The plot3d figure in matplotlib is somewhat canted

I am using matplotlib to get a water fall figure, but the results look very strange. Anyone have any idea what could be wrong with it?
Here I attached the figures. The second one is the same data but in an ordinary plot. In the waterfall figure, why the color is not fully filled?
Here is the code:
def water_fall_1(x,y,Z):
#x=[...]
#y=[...]
#Z=[[z1],[z2],...z[ny]]
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection
from matplotlib.colors import colorConverter
from mpl_toolkits.mplot3d import Axes3D
figs=[]
for jc in range(len(y)):
figs.append(list(zip(x,Z[jc])))
x=np.array(x)
y=np.array(y)
Z=np.array(Z)
xmin=np.floor(np.min((x.astype(np.float))))
xmax=np.ceil(np.max((x.astype(np.float))))
ymin=np.min((y.astype(np.float)))
ymax=np.max((y.astype(np.float)))
zmin=(np.min((Z.astype(np.float))))
zmax=np.max((Z.astype(np.float)))
fig=plt.figure()
ax = Axes3D(fig)
poly = PolyCollection(figs, facecolors=colorConverter.to_rgba("r", alpha=0.5))
ax.add_collection3d(poly, zs=y.astype(np.float), zdir='y')
ax.set_xlim(xmin,xmax)
ax.set_ylim(ymin,ymax)
ax.set_zlim(zmin,zmax)
ax.set_xlabel('$\omega$')
ax.set_ylabel('$T$')
#ax.set_zlabel('$\\frac{1}{2}$')
plt.show()
The curve is fully filled. I.e. the surface in between the points of the curve is red.
Consider the following example:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection
from mpl_toolkits.mplot3d import Axes3D
bottom=-0.3
x = np.linspace(0,6, num=50)
z = np.sinc(x-4)
verts = zip(x,z)
#verts=verts + [(x.max(),bottom),(x.min(),bottom)]
fig=plt.figure()
ax = Axes3D(fig)
poly = PolyCollection([verts], facecolors="r", alpha=0.5)
ax.add_collection3d(poly, zs=1, zdir='y')
ax.set_xlim(x.min(),x.max())
ax.set_ylim(0,2)
ax.set_zlim(bottom,z.max())
plt.show()
which produces the following plot, where everything between the points of the curve is filled as expected.
If we now want to have the area between the curve and some bottom line filled, we would need to add some points,
verts=verts + [(x.max(),bottom),(x.min(),bottom)]
such that the bottom line is part of the curve and can thus be filled as well.

mplot3D fill_between extends over axis limits

I have questions related to creating a simple lineplot in Python with mplot3D where the area under the plot is filled. I am using Python 2.7.5 on RedHatEnterprise 7.2, matplotlib 1.2.0 and numpy 1.7.2.
Using the code below, I am able to generate a line plot. This is displayed as expected with the beginning / end of the plot set by the limits of the imported data set.
I am then trying to fill the area between the line plot and -0.1 using the answer given by Bart from Plotting a series of 2D plots projected in 3D in a perspectival way. This works, however, the filled area is continued beyond the limits of the data set. This is also the case when running the example from the link.
This screen shot shows the plot generated with filled area extending beyond the set axis limits.
How do I achieve that the filled area is only the range of the data set or the axis limits whichever is smaller?
How do I add a legend for those plots onto the figure?
Code as follows:
from numpy import *
import matplotlib.pylab as plt
from mpl_toolkits.mplot3d import Axes3D
x,y = genfromtxt("data.dat",unpack=True)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.add_collection3d(plt.fill_between(x,y,-0.1, color='orange', alpha=0.3,label="filled plot"),1, zdir='y')
ax.plot(x,y,1,zdir="y",label="line plot")
ax.legend()
ax.set_xlim3d(852.353,852.359)
ax.set_zlim3d(-0.1,5)
ax.set_ylim3d(0,2)
ax.get_xaxis().get_major_formatter().set_useOffset(False)
plt.show()
I don't know how to put fill_between working the way you want it to, but I can provide an alternative using a 3D polygon:
from numpy import *
import matplotlib.pylab as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection # New import
#x,y = genfromtxt("data.dat",unpack=True)
# Generated some random data
w = 3
x,y = np.arange(100), np.random.randint(0,100+w,100)
y = np.array([y[i-w:i+w].mean() for i in range(3,100+w)])
z = np.zeros(x.shape)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#ax.add_collection3d(plt.fill_between(x,y,-0.1, color='orange', alpha=0.3,label="filled plot"),1, zdir='y')
verts = [(x[i],z[i],y[i]) for i in range(len(x))] + [(x.max(),0,0),(x.min(),0,0)]
ax.add_collection3d(Poly3DCollection([verts],color='orange')) # Add a polygon instead of fill_between
ax.plot(x,z,y,label="line plot")
ax.legend()
ax.set_ylim(-1,1)
plt.show()
The code above generates some random data. Builds vertices from it and plots a polygon with those vertices. This will give you the plot you wish (but does not use fill_between). The result is:

making ellipse markers with error bars matplotlib

I need to make a plot (with errorbars) with ellipses as markers. After some searching I came up with Ellipse in matplotlib.patches. Then I could draw the error bars with plt.errorbar. But the problem is that even though I give the error bar command first, the error bars are always drawn in the foreground and the ellipses are drawn on the background, no matter what order I give in the program.
Does any one know of a better way to create an ellipse as a marker (each point will have a different eccentricity) with error bars? Or at least guide me in how to put the error bars in the background?
Here is a minimal example of what I have so far:
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
from matplotlib.patches import Ellipse
PlotFileName="test.pdf"
pdf = PdfPages(PlotFileName)
fig=plt.figure(1)
ax1=fig.add_subplot(111)
plt.xlim([1,4])
plt.ylim([2,8])
ax1.errorbar([2.5], [5], yerr=[1], fmt="o", color="black", ms=0.1)
ax1.add_artist(Ellipse((2.5, 5), 1, 1, facecolor="green", edgecolor="black"))
pdf.savefig(fig)
pdf.close()
plt.close()
and here is how it looks:
I want the error bar to go in the background of the ellipse.
Thanks in advance...
Use the zorder specifier for both your plot commands.
From the documentation: "Set the zorder for the artist. Artists with lower zorder values are drawn first."
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
fig=plt.figure(1)
ax1=fig.add_subplot(111)
plt.xlim([0,5])
plt.ylim([0,10])
ax1.errorbar([2.5], [5], yerr=[1], fmt="o", color="black", ms=0.1, zorder=1)
ax1.add_artist(Ellipse((2.5, 5), 1, 1, facecolor="green", edgecolor="black",zorder=2))
plt.show()
exit(0)
It seems to me using Path is a more straightforward approach: the Path instance is treated exactly as a normal marker, hence just use the very same interface. Please have a look at the example below, but also reference matplotlib documentation on this topic.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.path as mpath
# Create mock data.
theta = np.linspace(0, 2.*np.pi, 30)
signa = np.sin(theta)
u_theta = np.random.normal(0., scale=0.15, size=signa.size)
u_signa = np.random.normal(0., scale=0.15, size=signa.size)
theta += u_theta
signa += u_signa
# Define the ellipse marker.
circle = mpath.Path.unit_circle()
verts = np.copy(circle.vertices)
verts[:, 0] *= 1.618
ellipt_marker = mpath.Path(verts, circle.codes)
# Done, basically.[![Plotting example][1]][1]
plt.errorbar(theta, signa, xerr=u_theta, yerr=u_signa,
marker=ellipt_marker, linestyle='', capsize=5,
ms=20, mfc='w', c='r', mec='g')
plt.xlabel('Autology', fontsize=35)
plt.ylabel('Eterology', fontsize=35)
plt.show()

Categories