Linestyle graph cannot see x axis labels - python

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

Related

Custom categorized legend matplotlib

I made a mock-up version of my dataset to illustrate my problem.
I have a graph like this:
import pandas as pd
import matplotlib.pyplot as plt
data = {'x': [0, 1, 2, 3],
'y': [3, 2, 1, 0],
'cat1': ['A', 'B', 'A', 'B'],
'cat2': ['f', 'g', 'h', 'i']}
df = pd.DataFrame(data)
colors = {'A':'tab:red',
'B':'tab:blue'}
markers = {'f':"o",
'g':"v",
'h':"s",
'i':"+"}
fig, ax = plt.subplots()
for i in range(df.shape[0]):
ax.scatter(df.loc[i,'x'],
df.loc[i,'y'],
color=colors[df.loc[i,'cat1']],
marker=markers[df.loc[i,'cat2']],
label = df.loc[i, 'cat2'])
ax.legend()
But I'm looking for a legend like this:
Could anyone give me some tips on how to solve this? Also, it would be better if the legend in the final plot were in a box outside the plot, on the right side.
To add additional lines (A,B), rearrange the order and move the legend outside the graph, these are the steps you can follow after plotting.
Create a custom legend entries for the new entries and existing one using Line2D
Plot the legend and use bbox_to_anchor to move the legend to where you need it. You can adjust the coordinates within bbox if you want to move the position
Adjust the labels for A, B as these are only text (no marker) so that align horizontally to the middle (you can adjust set_position() if you want to move it further to the left/right
Code
import pandas as pd
import matplotlib.pyplot as plt
data = {'x': [0, 1, 2, 3],
'y': [3, 2, 1, 0],
'cat1': ['A', 'B', 'A', 'B'],
'cat2': ['f', 'g', 'h', 'i']}
df = pd.DataFrame(data)
colors = {'A':'tab:red',
'B':'tab:blue'}
markers = {'f':"o",
'h':"s",
'g':"v",
'i':"+"}
fig, ax = plt.subplots()
for i in range(df.shape[0]):
ax.scatter(df.loc[i,'x'], df.loc[i,'y'],
color=colors[df.loc[i,'cat1']],
marker=markers[df.loc[i,'cat2']],
label = df.loc[i, 'cat2']
## Create legend handle entries for each of the items
from matplotlib.lines import Line2D
title = Line2D([0], [0], linestyle="none", marker="")
f = Line2D([0], [0], linestyle="none", marker="o", markersize=10, markeredgecolor='tab:red', markerfacecolor="tab:red")
g = Line2D([0], [0], linestyle="none", marker="v", markersize=10, markeredgecolor='tab:blue', markerfacecolor="tab:blue")
h = Line2D([0], [0], linestyle="none", marker="s", markersize=10, markeredgecolor='tab:red', markerfacecolor="tab:red")
i = Line2D([0], [0], linestyle="none", marker="+", markersize=10, markeredgecolor='tab:blue', markerfacecolor="tab:blue")
## Plot in order you want, bbox to set legend box outside
leg=ax.legend((title, f, h, title, g, i), ('A', 'f', 'h', 'B', 'g','i'), bbox_to_anchor=(1.16, 1.03))
## Adjust position of A and B so that they are in middle
for item, label in zip(leg.legendHandles, leg.texts):
if label._text in ['A', 'B']:
width=item.get_window_extent(fig.canvas.get_renderer()).width
label.set_ha('left')
label.set_position((-width/2,0)) ## Adjust here to move left/right
Plot

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()

Set matplotlib plot characteristics as a variable and reference for each plot

I am plotting a large number of plots and am using consistent marker styles, but more than one style. I am looking for a way to define the different markers I want to use once - and then just call the relevant marker for each plot. Consider
import matplotlib.pyplot as plt
import numpy as np
a = np.random.rand(50)
b = np.random.rand(50)
c = np.random.rand(50)
x = np.random.rand(50)
plt.plot(x,a, 'o', markeredgecolor = 'b', markerfacecolor = 'b')
plt.plot(x,b, 's', markeredgecolor = 'xkcd:amber', markerfacecolor = 'xkcd:amber')
plt.plot(x,c, '<', markeredgecolor = 'r', markerfacecolor = 'r')
I would like a way to have something like
marker1 = {'o', markeredgecolor = 'b', markerfacecolor = 'b'}
marker2 = {'s', markeredgecolor = 'xkcd:amber', markerfacecolor = 'xkcd:amber'}
marker3 = {'<', markeredgecolor = 'r', markerfacecolor = 'r'}
plt.plot(x,a,marker1)
plt.plot(x,b,marker2)
plt.plot(x,c,marker3)
I want to create a series of different markers (or line styles etc.) and call them by a variable name. I do not want to change the global settings. I have more characteristics than just those in the example.
I don't know what this is called, so searching for a solution has been rather unsuccessful - apologies if this has been asked and answered already.
Put your marker options into a dictionary, and then unpack it, like that:
marker1 = {'marker': 'o', 'markeredgecolor': 'b', 'markerfacecolor': 'b'}
marker2 = {'marker': 's', 'markeredgecolor': 'xkcd:amber', 'markerfacecolor': 'xkcd:amber'}
marker3 = {'marker': '<', 'markeredgecolor': 'r', 'markerfacecolor': 'r'}
plt.plot(x, a, **marker1)
plt.plot(x, b, **marker2)
plt.plot(x, c, **marker3)

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