I have some data where i have languages and relative unit size. I want to produce a bubble plot and then export it to PGF. I got most of my code from this answer Making a non-overlapping bubble chart in Matplotlib (circle packing) but I am having the problem that my text exits the circle boundary:
How can I either, increase the scale of everything (much easier I assume), or make sure that the bubble size is always greater than the text inside (and the bubbles are still proportional to each other according to the data series). I assume this is much more difficult to do but I don't really need that.
Relevant code:
#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
# create 10 circles with different radii
r = np.random.randint(5,15, size=10)
mapping = [("English", 25),
("French", 13),
("Spanish", 32),
("Thai", 10),
("Vientamese", 13),
("Chinese", 20),
("Jamaican", 8),
("Scottish", 3),
("Irish", 12),
("American", 5),
("Romanian", 3),
("Dutch", 2)]
class C():
def __init__(self,r):
self.colors = list(mcolors.XKCD_COLORS)
self.N = len(r)
self.labels = [item[0] for item in r]
self.x = np.ones((self.N,3))
self.x[:,2] = [item[1] for item in r]
maxstep = 2*self.x[:,2].max()
length = np.ceil(np.sqrt(self.N))
grid = np.arange(0,length*maxstep,maxstep)
gx,gy = np.meshgrid(grid,grid)
self.x[:,0] = gx.flatten()[:self.N]
self.x[:,1] = gy.flatten()[:self.N]
self.x[:,:2] = self.x[:,:2] - np.mean(self.x[:,:2], axis=0)
self.step = self.x[:,2].min()
self.p = lambda x,y: np.sum((x**2+y**2)**2)
self.E = self.energy()
self.iter = 1.
def minimize(self):
while self.iter < 1000*self.N:
for i in range(self.N):
rand = np.random.randn(2)*self.step/self.iter
self.x[i,:2] += rand
e = self.energy()
if (e < self.E and self.isvalid(i)):
self.E = e
self.iter = 1.
else:
self.x[i,:2] -= rand
self.iter += 1.
def energy(self):
return self.p(self.x[:,0], self.x[:,1])
def distance(self,x1,x2):
return np.sqrt((x1[0]-x2[0])**2+(x1[1]-x2[1])**2)-x1[2]-x2[2]
def isvalid(self, i):
for j in range(self.N):
if i!=j:
if self.distance(self.x[i,:], self.x[j,:]) < 0:
return False
return True
def scale(self, size):
"""Scales up the plot"""
self.x = self.x*size
def plot(self, ax):
for i in range(self.N):
circ = plt.Circle(self.x[i,:2],self.x[i,2], color=mcolors.XKCD_COLORS[self.colors[i]])
ax.add_patch(circ)
ax.text(self.x[i][0],self.x[i][1], self.labels[i], horizontalalignment='center', size='medium', color='black', weight='semibold')
c = C(mapping)
fig, ax = plt.subplots(subplot_kw=dict(aspect="equal"))
ax.axis("off")
c.minimize()
c.plot(ax)
ax.relim()
ax.autoscale_view()
plt.show()