Matplotlib - piechart - ValueError: 'label' must be of length 'x' - python

I want to make a pie chart using matplotlib. I am using python 2.7. I am trying to recreate the example given here with inputs from this stackoverflow post. But, I keep running into errors.
This is my code:
import matplotlib.pyplot as plt
topic = ['A', 'B', 'C', 'D', \
'E', 'F', 'G', 'H', 'I' \
'J']
labels = list(topic)
sizes = [18.7, 18.4, 12.7, 8.5, 3.4, 2.4, 1.8, 1.7, 1.5, 30.9]
explode = (0, 0.1, 0, 0, 0, 0, 0, 0, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs')
fig1, ax1 = plt.subplots()
ax1.pie(sizes, explode=explode, labels=labels,
autopct='%1.1f%%',
shadow=True, startangle=90)
ax1.axis('equal')
plt.show()
This is the error that I am getting:
Traceback (most recent call last):
File "occupation_pie.py", line 13, in <module>
shadow=True, startangle=90)
File "/anaconda2/lib/python2.7/site-packages/matplotlib/__init__.py", line 1867, in inner
return func(ax, *args, **kwargs)
File "/anaconda2/lib/python2.7/site-packages/matplotlib/axes/_axes.py", line 2867, in pie
raise ValueError("'label' must be of length 'x'")
ValueError: 'label' must be of length 'x'
How can I make my code work?

Is it on purpose that you are missing a , in topics?
Try changing topic = ['A', 'B', 'C', 'D', \
'E', 'F', 'G', 'H', 'I' \
'J']
to
topic = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']

Related

How to generate proper legends for scatter plot in python

I am trying to prepare a box and scatter plot for 8 data points in python. I use the following code:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
x = [24.4, 6.7, 19.7, 16.0, 25.1, 19.5, 10, 22.1]
f, ax = plt.subplots()
ax.boxplot(x, vert=False, showmeans=True, showfliers=False)
x0 = np.random.normal(1, 0.05, len(x))
c = ['r', 'b', 'c', 'm', 'y', 'g', 'm', 'k']
lab = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
ax.scatter(x, x0, c=c, s=60, alpha=0.2)
ax.legend(labels=lab, loc="upper left", ncol=8)
It generate a image like the following:
It looks that the legend doesn't have the proper sphere symbols with different colors, which I expected. Beside the colors for the symbols are shallow and light.
So how to generate proper legends with correct symbols and how to make the colors of the symbols brighter and sharper?
I will deeply appreciate it if anyone can help.
Best regards
To make the colours brighter, just raise the alpha value.
For the legend, the order of the plotting matters here, it is better that the boxplot is plotted after the scatter plots. Also, to get for each point a place in the legend, it should b considered as a different graph, for that I used a loop to loop over the values of x, x0 and c. Here's the outcome:
import numpy as np
import matplotlib.pyplot as plt
# init figure
f, ax = plt.subplots()
# values
x = [24.4, 6.7, 19.7, 16.0, 25.1, 19.5, 10, 22.1]
x0 = np.random.normal(1, 0.05, len(x))
# labels and colours
c = ['r', 'b', 'c', 'm', 'y', 'g', 'm', 'k']
lab = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
# put the plots into a list
plots = []
for i in range(len(x)):
p = ax.scatter(x[i], x0[i], c=c[i], s=60, alpha=0.5) # raised the alpha to get sharper colors
plots.append(p)
# plot legends
plt.legend(plots,
labels=lab,
scatterpoints=1,
loc='upper left',
ncol=8,
fontsize=8)
# plot the box plot (the order here matters!)
ax.boxplot(x, vert=False, showmeans=True, showfliers=False)
# save the desired figure
plt.savefig('tt.png')
Output:

`matplotlib` colored output for graphs

How to output colored graph (each vertex has its own color) using matplotlib library for python? Is there any method to adjust specific color to each vertex?
Code example without using colors:
import networkx as nx
import matplotlib.pyplot as plt
class Graph:
def __init__(self, edges):
self._edges = edges
def visualize(self):
vg = nx.Graph()
vg.add_edges_from(self._edges)
nx.draw_networkx(vg)
plt.show()
nodes = [['A', 'B'], ['A', 'C'], ['B', 'D'], ['C', 'D'],
['C', 'E'], ['D', 'F'], ['E', 'F']]
G = Graph(nodes)
G.visualize()
That's how i want to see it:
I'm not sure if you want to change colors only for this case or make it more flexible - using list comprehension, but AFAIK draw_networkx has a parameter which takes a list of strings or for RGB tuple of floats, so only what you can do is prepare a list of colors:
import networkx as nx
import matplotlib.pyplot as plt
class Graph:
def __init__(self, edges, colors):
self._edges = edges
self._colors = colors
def visualize(self):
vg = nx.Graph()
vg.add_edges_from(self._edges)
nx.draw_networkx(vg, node_color=self._colors)
plt.show()
nodes = [['A', 'B'], ['A', 'C'], ['B', 'D'], ['C', 'D'],
['C', 'E'], ['D', 'F'], ['E', 'F']]
colors = ['green', 'red', 'red', 'green', 'green', 'red']
G = Graph(nodes, colors)
G.visualize()

How to add labels to the axes of subplots

I am plotting 8 subplots into a figure as follows:
import matplotlib.pyplot as plt
fig, axs = plt.subplots(8)
label = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
data = [0.6, 0.4, 1.3, 0.8, 0.9, 1.0, 1.6, 0.2]
plt.xlim(0,2)
for i in range(8):
axs[i].get_yaxis().set_visible(False)
axs[i].get_xaxis().set_visible(False)
axs[i].set_xlim([0, 2])
axs[i].axvline(data[i],linestyle='--')
axs[i].get_yaxis().set_visible(False)
axs[7].get_xaxis().set_visible(True)
plt.show()
This looks like:
In order to label the subplots I would like to write label[i] (see code above) to the left of subplot i. How can you do that?
(As a quick fix), you might just be able to use Axes.text, for example:
axs[i].text(-0.1,0.2,label[i])
Adjust the x and y arguments as needed depending on the length of the labels.
As mentioned in the comments, another (much better) option is to keep the y-axis visible, but then set the ticks to nothing:
axs[i].set_yticks(())
axs[i].set_ylabel(label[i], rotation=0, ha='right', va='center')
As I mentioned in the comments, the proper approach would be to not set the y axis off, and remove the ticks.
The trick is to remove the two lines with axs[i].get_yaxis().set_visible(False) and add the following two lines:
axs[i].tick_params(left=False, labelleft=False)
axs[i].set_ylabel(label[i])
Please, consider the following code as a full answer (edited to include bnaecker's suggestion):
import matplotlib.pyplot as plt
plt.close('all')
fig, axs = plt.subplots(8, sharex="col")
label = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
data = [0.6, 0.4, 1.3, 0.8, 0.9, 1.0, 1.6, 0.2]
plt.xlim(0, 2)
for i in range(8):
axs[i].set_xlim([0, 2])
axs[i].tick_params(left=False, labelleft=False)
axs[i].axvline(data[i], linestyle='--')
axs[i].set_ylabel(label[i])
plt.show()
The figure should look like this:

Linestyle graph cannot see x axis labels

I am testing a very simple exercise just plot the code below:
t = pd.Series([1,2,5,1,8], index=['a', 's', 'l', 'f', 'd' ])
t.plot(linestyle = '-', color = 'b', sharex = True)
but I cannot see the letters a, s, l, f, and d.
Any suggestions?
You can go like:
import pandas as pd
from matplotlib import pyplot as plt
t = pd.Series([1,2,5,1,8], index=['a', 's', 'l', 'f', 'd' ])
plt.plot(t.index, t.values,linestyle = '-', color = 'b')
plt.show()
Image is in the following link
Adapted from here

How can I get annotations (neatly) outside the convex hull?

I have developed a bit of code to automatically generate an equilateral n-dimensional polygon:
# Create equilateral n-dimensional polygon
def polygon(side, radius=1, rotation=0, translation=None):
import math
vertex = 2 * math.pi / side
points = [
(math.sin(vertex * i + rotation) * radius,
math.cos(vertex * i + rotation) * radius)
for i in range(side)]
if translation:
points = [[sum(pair) for pair in zip(point, translation)]
for point in points]
return np.array(points)
Now, I want to put labels neatly to the outside corners of this n-dimensional polygon. In the following example I have created a hexagon with radius 10, centered around (3,3).
import matplotlib.pyplot as plt
pol = polygon(7, 10, 0, [3,3])
hull = ConvexHull(pol)
labels = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', "L", 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
fig = plt.figure(figsize=(4, 4), dpi=100)
for simplex in hull.simplices:
plt.plot(pol[simplex,0], pol[simplex,1], 'k-')
plt.plot(pol[:,0], pol[:,1], 'gs', ms=10)
if labels is not None:
for i, label in enumerate(labels):
if i <= len(pol)-1:
plt.annotate(label, xy=(pol[:,0][i],pol[:,1][i]), xytext=(0, 8),
textcoords='offset points', ha="center", va="bottom")
plt.axis('off')
plt.show()
Unfortunately, as the figure shows, only point A, B, and F lay neatly outside the hexagon. Is there a systematic way to annotate the labels to the outside corner of the polygon (hexagon in this case), no matter the dimension n? Thanks in advance!
Plot of hexagon with wrongly placed annotations
First, let's look at the special case of a n-dimensional regular polygon.
For this, you can just put the annotations on the vertices of a slightly larger polygon (I used 1.2 times the original radius).
Below is the full code and result.
import matplotlib.pyplot as plt
from scipy.spatial import ConvexHull
r = 10 # radius
center = [3, 3]
pol = polygon(7, r, 0, center)
pol2 = polygon(7, 1.2*r, 0, center) # for annotations
hull = ConvexHull(pol)
labels = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', "L", 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
fig = plt.figure(figsize=(4, 4), dpi=100)
for simplex in hull.simplices:
plt.plot(pol[simplex,0], pol[simplex,1], 'k-')
plt.plot(pol[:,0], pol[:,1], 'gs', ms=10)
if labels is not None:
for i, label in enumerate(labels):
if i <= len(pol)-1:
plt.annotate(label, xy=(pol2[i,0], pol2[i,1]), xytext=(0, 0),
textcoords='offset points', ha="center", va="center")
plt.xlim(center[0] - 1.5*r, center[0] + 1.5*r)
plt.ylim(center[1] - 1.5*r, center[1] + 1.5*r)
plt.axis('off')
plt.show()
Now, let's look at a general convex hull. An easy solution would be the following:
For each simplex S, calculate the mid point M of its neighbouring two simplices (called N_1 and N_2). We know this midpoint must be in the interior of the convex hull.
(N_1, N_2) = hull.neighbors(S)
M = (pol[N_1] + pol[N_2]) / 2
Draw the line from M to S, and take the new point M_ext which is on the line, so that S is equidistant to M and M_ext, but with M_ext being on the other side. We know that M_ext is definitely, in that case.
M_ext = pol[S] + (pol[S] - M)
You could potentially normalize it, so that the annotations are the same distance to the simplex (e.g. using numpy.linalg.norm). In my code I also multiplied by a constant factor, so that the text does not overlap with the vertices.
M_ext = pol[S] + (pol[S] - M) / np.linalg.norm(pol[S]-M)
Again full code & result below:
import matplotlib.pyplot as plt
import numpy as np
from scipy.spatial import ConvexHull
r = 10 # radius
center = [3, 3]
pol = polygon(7, r, 0, center)
pol2 = polygon(7, 1.2*r, 0, center) # for annotations
hull = ConvexHull(pol)
labels = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', "L", 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
fig = plt.figure(figsize=(4, 4), dpi=100)
for simplex in hull.simplices:
plt.plot(pol[simplex,0], pol[simplex,1], 'k-')
plt.plot(pol[:,0], pol[:,1], 'gs', ms=10)
if labels is not None:
for i, label in enumerate(labels):
if i <= len(pol)-1:
S = i
(N_1, N_2) = hull.neighbors[S]
M = (pol[N_1] + pol[N_2]) / 2
M_ext = pol[S] + (pol[S] - M) / np.linalg.norm(pol[S] - M) * 0.2*r
plt.annotate(label, xy=M_ext, xytext=(0, 0),
textcoords='offset points', ha="center", va="center")
plt.xlim(center[0] - 1.5*r, center[0] + 1.5*r)
plt.ylim(center[1] - 1.5*r, center[1] + 1.5*r)
plt.axis('off')
plt.show()

Categories

Resources