Matplotlib: How to combine scatter and line plot to one legend entry - python

I draw my data points with ax.scatter() and connect the data points with a fit using ax.plot().
How do I create a common entry in the legend that combines the marker for the data point with the line of the fit? I want to get a legend entry as I would get it for ax.plot(x, y, '-o', label = 'abc').
I have created the following minimal example:
import matplotlib.pyplot as plt
import numpy as np
x_scatter = np.linspace(0,10,10)
x_line = np.linspace(0,10,100)
fig, ax = plt.subplots()
for i in range(5):
ax.scatter(x_scatter, np.sin(x_scatter) + i, label = i)
ax.plot(x_line, np.sin(x_line)+i)
plt.legend(loc='best')
plt.show()

This 'hack' should work:
import matplotlib.pyplot as plt
import numpy as np
x_scatter = np.linspace(0,10,10)
x_line = np.linspace(0,10,100)
fig, ax = plt.subplots()
prop = ax._get_lines.prop_cycler
for i in range(5):
color = next(prop)['color']
ax.scatter(x_scatter, np.sin(x_scatter) + i, color=color)
ax.plot(x_line, np.sin(x_line)+i, color=color)
ax.plot([], [], '-o', color=color, label = i)
plt.legend(loc='best')
plt.show()

Related

Adding one colorbar to multiple plots in one graph

I'm trying to attach the colorbar to my MatplotLib plot which plots several plots in one graph (I'm not looking for a single colorbar to multiple subplots).
In my script I load files and plot runs of variables, however I'd like to colorize them regarding to the third variable.
I found a way to do it, however it plots colorbar to each plot, and it looks like: 1
I'd like it to look like: 2, except every path should be colorized.
Here is my block of code generating the plots:
import os
import glob
import mesa_reader as mesa
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Rectangle
fig, ax = plt.subplots(1, 1, sharex=True, sharey=True, figsize=(10,5), dpi=100)
counter = 0
for fname in glob.glob('LOGS_P_*'):
a = mesa.MesaData(fname+'/LOGS1/history.data')
counter = counter + 1
if counter == 1:
plt.plot(a.log_Teff, a.log_L, color='black', linestyle='solid', linewidth=0.8)
points = np.array([a.log_Teff, a.log_L]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
# Create a continuous norm to map from data points to colors
norm = plt.Normalize(-20, a.lg_mtransfer_rate.max())
lc = LineCollection(segments, cmap='viridis', norm=norm)
# Set the values used for colormapping
lc.set_array(a.lg_mtransfer_rate)
lc.set_linewidth(2)
fig.colorbar(ax.add_collection(lc), ax=ax)
else:
plt.plot(a.log_Teff, a.log_L, color='black', linestyle='solid', linewidth=0.8)
points = np.array([a.log_Teff, a.log_L]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
# Create a continuous norm to map from data points to colors
norm = plt.Normalize(-20, a.lg_mtransfer_rate.max())
lc = LineCollection(segments, cmap='viridis', norm=norm)
# Set the values used for colormapping
lc.set_array(a.lg_mtransfer_rate)
lc.set_linewidth(2)
fig.colorbar(ax.add_collection(lc), ax=ax)
This figure
was produced running the following script
from numpy import array, concatenate, linspace, cos, pi, sin
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from matplotlib.colors import Normalize
from matplotlib.cm import ScalarMappable
def segments_from(x, y):
tmp = array((x, y)).T.reshape(-1,1,2)
return concatenate([tmp[:-1], tmp[1:]], axis=1)
t = linspace(0, 3, 301)
w1, w2 = 2*pi, 3*pi
s1, s2 = sin(w1*t), sin(w2*t)
c1, c2 = cos(w1*t), cos(w2*t)
norm = Normalize(-2, +2)
cmap = plt.get_cmap('inferno')
fig, ax = plt.subplots()
ax.set_xlim(0, 3)
ax.set_ylim(-2, 2)
for y, v in ((1.6*c1, c2), (0.9*s1, s2)):
lc = LineCollection(segments_from(t, y),
linewidths=4,
norm=norm, cmap=cmap)
lc.set_array(v)
ax.add_collection(lc)
fig.colorbar(ScalarMappable(norm=norm, cmap=cmap))
plt.show()

How to set title position inside graph in scatter plot?

MWE:
I would like the title position same as in the graph :
Here is my code :
import matplotlib.pyplot as plt
import numpy as np
import random
fig, ax = plt.subplots()
x = random.sample(range(256),200)
y = random.sample(range(256),200)
cor=np.corrcoef(x,y)
plt.scatter(x,y, color='b', s=5, marker=".")
#plt.scatter(x,y, label='skitscat', color='b', s=5, marker=".")
ax.set_xlim(0,300)
ax.set_ylim(0,300)
plt.xlabel('x')
plt.ylabel('y')
plt.title('Correlation Coefficient: %f'%cor[0][1])
#plt.legend()
fig.savefig('plot.png', dpi=fig.dpi)
#plt.show()
But this gives :
How do I fix this title position?
assign two corresponded value to X and Y axis. notice! to have title inside graph, values should be in (0,1) interval. you can see a sample code here:
import matplotlib. pyplot as plt
A= [2,1,4,5]; B = [3,2,-2,1]
plt.scatter(A,B)
plt.title("title", x=0.9, y=0.9)
plt.xlabel("x-axis")
plt.ylabel("y-axis")
plt.show()
It will be unnecessarily complicated to move the title at some arbitrary position inside the axes.
Instead one would rather create a text at the desired position.
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
x = np.random.randint(256,size=200)
y = np.random.randint(256,size=200)
cor=np.corrcoef(x,y)
ax.scatter(x,y, color='b', s=5, marker=".")
ax.set_xlim(0,300)
ax.set_ylim(0,300)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.text(0.9, 0.9, 'Correlation Coefficient: %f'%cor[0][1],
transform=ax.transAxes, ha="right")
plt.show()

how to get color from a line plot

I want to plot several normal distributions, and add labels to each one in its line color. However the color does not seem to update.
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import scipy.stats as stats
def single_plot(mu, sigma, ax, label=None):
x = np.linspace(mu - 4*sigma, mu + 4*sigma, 1000)
ax = sns.lineplot(x, stats.norm.pdf(x, mu, sigma), ax=ax, label=label, zorder=2)
#my code to get color
color = ax.get_lines()[0].get_c() #fetch color of line
ax.text(mu, max(stats.norm.pdf(x, mu, sigma)), label, fontsize=16, color=color)
When put to use, however, this does not update the color with each line. If I try:
fig, ax = plt.subplots()
ax = single_plot(mu=1000, sigma=100, ax=ax, label='test1')
ax = single_plot(mu=1500, sigma=200, ax=ax, label='test2')
fig.show()
I am getting this figure. The label for "test2" was not updated.
I am wondering where I was wrong and how to fix this problem.

Remove annotation while keeping plot matplotlib

I'm producing a series of scatterplots, where I keep most of the plot (besides the scatter plot) between each plot. This is done like so: Keeping map overlay between plots in matplotlib
Now I want to add annotation to the plot:
for j in range(len(n)):
plt.annotate(n[j], xy = (x[j],y[j]), color = "#ecf0f1", fontsize = 4)
However, this annotation stays on the plot between plots. How can I clear the annotation after each figure is saved?
You can remove an artist using remove().
ann = plt.annotate (...)
ann.remove()
After removal it may be necessary to redraw the canvas.
Here is a complete example, removing several annotations within an animation:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation
fig, ax = plt.subplots()
x = np.arange(0, 2*np.pi, 0.01)
f = lambda x: np.sin(x)
line, = ax.plot(x, f(x))
scat = plt.scatter([], [], s=20, alpha=1, color="purple", edgecolors='none')
ann_list = []
def animate(j):
for i, a in enumerate(ann_list):
a.remove()
ann_list[:] = []
n = np.random.rand(5)*6
scat.set_offsets([(r, f(r)) for r in n])
for j in range(len(n)):
ann = plt.annotate("{:.2f}".format(n[j]), xy = (n[j],f(n[j])), color = "purple", fontsize = 12)
ann_list.append(ann)
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=20, interval=360)
ani.save(__file__+".gif",writer='imagemagick', fps=3)
plt.show()

How to plot with x-axis at the top of the figure?

I would like to ask how to produce a plot similar to that in the figure below? Basically, how to have x-axis at the top of the figure. Thanks
Image from: http://oceanographyclay1987.blogspot.com/2010/10/light-attenuation-in-ocean.html
Use
ax.xaxis.set_ticks_position("top")
For example,
import numpy as np
import matplotlib.pyplot as plt
numdata = 100
t = np.linspace(0, 100, numdata)
y = 1/t**(1/2.0)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.xaxis.set_ticks_position('top')
ax.yaxis.grid(linestyle = '-', color = 'gray')
ax.invert_yaxis()
ax.plot(t, y, 'g-', linewidth = 1.5)
plt.show()

Categories