Suggestions to plot overlapping lines in matplotlib? - python

Does anybody have a suggestion on what's the best way to present overlapping lines on a plot? I have a lot of them, and I had the idea of having full lines of different colors where they don't overlap, and having dashed lines where they do overlap so that all colors are visible and overlapping colors are seen.
But still, how do I that.

I have the same issue on a plot with a high degree of discretization.
Here the starting situation:
import matplotlib.pyplot as plt
grid=[x for x in range(10)]
graphs=[
[1,1,1,4,4,4,3,5,6,0],
[1,1,1,5,5,5,3,5,6,0],
[1,1,1,0,0,3,3,2,4,0],
[1,2,4,4,3,2,3,2,4,0],
[1,2,3,3,4,4,3,2,6,0],
[1,1,3,3,0,3,3,5,4,3],
]
for gg,graph in enumerate(graphs):
plt.plot(grid,graph,label='g'+str(gg))
plt.legend(loc=3,bbox_to_anchor=(1,0))
plt.show()
No one can say where the green and blue lines run exactly
and my "solution"
import matplotlib.pyplot as plt
grid=[x for x in range(10)]
graphs=[
[1,1,1,4,4,4,3,5,6,0],
[1,1,1,5,5,5,3,5,6,0],
[1,1,1,0,0,3,3,2,4,0],
[1,2,4,4,3,2,3,2,4,0],
[1,2,3,3,4,4,3,2,6,0],
[1,1,3,3,0,3,3,5,4,3],
]
for gg,graph in enumerate(graphs):
lw=10-8*gg/len(graphs)
ls=['-','--','-.',':'][gg%4]
plt.plot(grid,graph,label='g'+str(gg), linestyle=ls, linewidth=lw)
plt.legend(loc=3,bbox_to_anchor=(1,0))
plt.show()
I am grateful for suggestions on improvement!

Just decrease the opacity of the lines so that they are see-through. You can achieve that using the alpha variable. Example:
plt.plot(x, y, alpha=0.7)
Where alpha ranging from 0-1, with 0 being invisible.

imagine your panda data frame is called respone_times, then you can use alpha to set different opacity for your graphs. Check the picture before and after using alpha.
plt.figure(figsize=(15, 7))
plt.plot(respone_times,alpha=0.5)
plt.title('a sample title')
plt.grid(True)
plt.show()

Depending on your data and use case, it might be OK to add a bit of random jitter to artificially separate the lines.
from numpy.random import default_rng
import pandas as pd
rng = default_rng()
def jitter_df(df: pd.DataFrame, std_ratio: float) -> pd.DataFrame:
"""
Add jitter to a DataFrame.
Adds normal distributed jitter with mean 0 to each of the
DataFrame's columns. The jitter's std is the column's std times
`std_ratio`.
Returns the jittered DataFrame.
"""
std = df.std().values * std_ratio
jitter = pd.DataFrame(
std * rng.standard_normal(df.shape),
index=df.index,
columns=df.columns,
)
return df + jitter
Here's a plot of the original data from Markus Dutschke's example:
And here's the jittered version, with std_ratio set to 0.1:

Replacing solid lines by dots or dashes works too
g = sns.FacetGrid(data, col='config', row='outputs', sharex=False)
g.map_dataframe(sns.lineplot, x='lag',y='correlation',hue='card', linestyle='dotted')

Instead of random jitter, the lines can be offset just a little bit, creating a layered appearance:
import matplotlib.pyplot as plt
from matplotlib.transforms import offset_copy
grid = list(range(10))
graphs = [[1, 1, 1, 4, 4, 4, 3, 5, 6, 0],
[1, 1, 1, 5, 5, 5, 3, 5, 6, 0],
[1, 1, 1, 0, 0, 3, 3, 2, 4, 0],
[1, 2, 4, 4, 3, 2, 3, 2, 4, 0],
[1, 2, 3, 3, 4, 4, 3, 2, 6, 0],
[1, 1, 3, 3, 0, 3, 3, 5, 4, 3]]
fig, ax = plt.subplots()
lw = 1
for gg, graph in enumerate(graphs):
trans_offset = offset_copy(ax.transData, fig=fig, x=lw * gg, y=lw * gg, units='dots')
ax.plot(grid, graph, lw=lw, transform=trans_offset, label='g' + str(gg))
ax.legend(loc='upper left', bbox_to_anchor=(1.01, 1.01))
# manually set the axes limits, because the transform doesn't set them automatically
ax.set_xlim(grid[0] - .5, grid[-1] + .5)
ax.set_ylim(min([min(g) for g in graphs]) - .5, max([max(g) for g in graphs]) + .5)
plt.tight_layout()
plt.show()

Related

Supblots to include radar plot

I'm running into issues with some subplots. I've provided some sample code to generate the types of plots I would like to create. I'd like these to be the same size, side by side.
I'm am having a really hard time figuring out how to create the subplots though. I keep running into some issues with the thetagrids here. This is what i've tried. I can get these to work seprarately, but cant figure out how to combine them. Eventually I might want a third plot as well.
import numpy as np
import matplotlib.pyplot as plt
## Plot 1
x1 = np.array([0, 1, 2, 3])
y1 = np.array([7, 2, 4, 2])
plt.subplot(1, 2, 1)
plt.figure(figsize=(5, 5))
plt.scatter(x1, y1)
# plt.show()
### Plot 2
# make up data for plot
polar_list = ['a', 'b', 'c', 'd', 'a']
polar_points = [4, 3, 6, 7, 4]
# modify lists for plots
label_loc = np.linspace(start=0, stop=2 * np.pi, num=len(polar_list))
plt.figure(figsize=(5, 5))
plt.subplot(1, 2, 2, polar=True)
plt.plot(label_loc, polar_points, label='DataLable')
plt.title('DataLable comparison', size=20, y=1.05)
lines, labels = plt.thetagrids(np.degrees(label_loc), labels=polar_list)
plt.legend()
plt.show()
You are creating a new figure every time you call plt.figure(). Just place one at the very beginning and then the plt.subplot() will add subplots to the figures.
import numpy as np
import matplotlib.pyplot as plt
## Plot 1
x1 = np.array([0, 1, 2, 3])
y1 = np.array([7, 2, 4, 2])
plt.figure(figsize= (5, 5))
plt.subplot(1, 2, 1)
plt.scatter(x1, y1)
# plt.show()
### Plot 2
# make up data for plot
polar_list = ['a', 'b', 'c', 'd', 'a']
polar_points = [4, 3, 6, 7, 4]
# modify lists for plots
label_loc = np.linspace(start=0, stop=2 * np.pi, num=len(polar_list))
plt.subplot(1, 2, 2, polar=True)
plt.plot(label_loc, polar_points, label='DataLable')
plt.title('DataLable comparison', size=20, y=1.05)
lines, labels = plt.thetagrids(np.degrees(label_loc), labels=polar_list)
plt.legend()
plt.show()

Plot multiple histograms as a grid

I am trying to plot multiple histograms on the same window using a list of tuples. I have managed to get it to sketch only 1 tuple at a time and I just can't seem to get it to work with all of them.
import numpy as np
import matplotlib.pyplot as plt
a = [(1, 2, 0, 0, 0, 3, 3, 1, 2, 2), (0, 2, 3, 3, 0, 1, 1, 1, 2, 2), (1, 2, 0, 3, 0, 1, 2, 1, 2, 2),(2, 0, 0, 3, 3, 1, 2, 1, 2, 2),(3,1,2,3,0,0,1,2,3,1)] #my list of tuples
q1,q2,q3,q4,q5,q6,q7,q8,q9,q10 = zip(*a) #split into [(1,0,1,2,3) ,(2,2,2,0,1),..etc] where q1=(1,0,1,2,3)
labels, counts = np.unique(q1,return_counts=True) #labels = 0,1,2,3 and counts the occurence of 0,1,2,3
ticks = range(len(counts))
plt.bar(ticks,counts, align='center')
plt.xticks(ticks, labels)
plt.show()
As you can see from the above code, I can plot one tuple at a time say q1,q2 etc but how do I generalise it so that it plots all of them.
I've tried to mimic this python plot multiple histograms, which is exactly what I want however I had no luck.
Thank you for your time :)
You need to define a grid of axes with plt.subplots taking into account the amount of tuples in the list, and how many you want per row. Then iterate over the returned axes, and plot the histograms in the corresponding axis. You could use Axes.hist, but I've always preferred to use ax.bar, from the result of np.unique, which also can return the counts of unique values:
from matplotlib import pyplot as plt
import numpy as np
l = list(zip(*a))
n_cols = 2
fig, axes = plt.subplots(nrows=int(np.ceil(len(l)/n_cols)),
ncols=n_cols,
figsize=(15,15))
for i, (t, ax) in enumerate(zip(l, axes.flatten())):
labels, counts = np.unique(t, return_counts=True)
ax.bar(labels, counts, align='center', color='blue', alpha=.3)
ax.title.set_text(f'Tuple {i}')
plt.tight_layout()
plt.show()
You can customise the above to whatever amount of rows/cols you prefer, for 3 rows for instance:
l = list(zip(*a))
n_cols = 3
fig, axes = plt.subplots(nrows=int(np.ceil(len(l)/n_cols)),
ncols=n_cols,
figsize=(15,15))
for i, (t, ax) in enumerate(zip(l, axes.flatten())):
labels, counts = np.unique(t, return_counts=True)
ax.bar(labels, counts, align='center', color='blue', alpha=.3)
ax.title.set_text(f'Tuple {i}')
plt.tight_layout()
plt.show()

Matplotlib pyplot: Is it possible to have exponential axis?

i need "the opposite" of loglog for my pyplot chart.
How can i achive exponential axis?
Data looks like:
x = [1, 2, 4]
y = [1, 2, 4]
z = [2, 2, 2]
quadranten = plt.figure()
s = [20*4**n for n in z]
fig, ax = plt.subplots()
ax.axis([1, 5, 1, 5])
ax.loglog() <-- opposite function?
xstart, xend = ax.get_xlim()
ax.xaxis.set_ticks(np.arange(xstart, xend, 0.712123))
ax.xaxis.set_major_formatter(ticker.FormatStrFormatter('%0.1f'))
ystart, yend = ax.get_ylim()
ax.yaxis.set_ticks(np.arange(ystart, yend, 0.712123))
ax.yaxis.set_major_formatter(ticker.FormatStrFormatter('%0.1f'))
plt.xlabel('x')
plt.ylabel('y')
plt.scatter(x,y,s=s)
plt.show()
The goal is the x axis to have evenly sized steps: 0, 1, 2, 4, 8,...
Same for the y axis with evenly sized steps getting exponentially bigger by a factor (for example two): 0, 1, 2, 4, 8, ...
Is this possible?
Something like this:
loglog takes arguments basex and basey that control the base of the logarithms:
loglog(arange(1,100), arange(1,100)**2, basex=2, basey=2)

How to use matplotlib to draw 3D barplot with specific color according to the bar height

Hey guys, I am using matplotlib to draw 3D barplot. I wonder whether it is possible to give each bar (total 9) a different color according to their value (dz) and also show the corresponding level in this figure.
Many thanks in advance!!!
My code is below:
fig_stat=plt.figure(dpi=100)
ax_stat = fig_stat.add_subplot(111, projection='3d')
xpos = [1, 1, 1, 3, 3, 3, 5, 5, 5]
ypos = [1, 3, 5, 1, 3, 5, 1, 3, 5]
# initial z position (x-y plane), np.zeros(x), x
zpos = [0, 0, 0, 0, 0, 0, 0, 0, 0]
# x is the number of points you need
dx = np.ones(9)
dy = np.ones(9)
# dz = [1, 2, 3, 4, 10, 6, 7, 8, 9] # signal intensity
dz = col_stat.iloc[:, -2]
ax_stat.set_xlabel('X axis')
ax_stat.set_ylabel('Y axis')
ax_stat.set_zlabel('Signal Intensity')
ax_stat.bar3d(xpos, ypos, zpos, dx, dy, dz, color='#00ceaa')
plt.title("Position_{}".format(L))
The bar3d method allows to enter as color an array of the same length as the data arrays. Therefore, a colormap can be used to get the colors corresponding to each dz:
from matplotlib import cm
from matplotlib.colors import Normalize
cmap = cm.get_cmap('plasma')
norm = Normalize(vmin=min(dz), vmax=max(dz))
colors = cmap(norm(dz))
And use this colors as input in the bar3d color parameter instead of '#00ceaa'. Afterwards, the colorbar can be shown using this piece of code:
sc = cm.ScalarMappable(cmap=cmap,norm=norm)
sc.set_array([])
plt.colorbar(sc)
Which will generate a plot looking like this:

Shortening line segments in Matplotlib plots

Is it possible to shorten line segments in a matplotlib plot to produce an image like the one below, where the line segments do not completely reach the point markers?
I've found the following stupid way, but for me it works
import matplotlib.pyplot as plt
x = [0, 1, 2, 3, 4, 5]
y = [1, 3, 2, 5, 3, 1]
plt.figure()
plt.plot(x,y,'b-')
plt.plot(x,y,'wo', markersize=25, markeredgecolor = 'w')
plt.plot(x,y,'bo', markersize=7, markeredgecolor = 'w')
plt.show()

Categories