Superimposing plot over errorbars in matplotlib - python

I am trying to superimpose a plot over my error bars. I have searched online and this seems to be the method to do this. I am expecting the plot to look the way it does however with thin black lines running between the thick colour lines.
plt.figure(figsize=(15, 10), dpi=80)
plt.grid(True, linewidth=0.5, color='#ff0000', linestyle='-')
for i in range(len(B_arrays)):
plt.errorbar(T_arrays[i], B_arrays[i], STD_arrays[i], linestyle='None', marker='^', label = labels[i])
plt.plot(T_arrays[i], B_arrays[i], color = "k")
plt.ylabel("B")
plt.xlabel("Time")
plt.legend(loc="upper right", prop={'size': 8})
plt.show()

Use plt.plot for the black lines, but just adjust the zorder:
Either pull the black lines above with zorder > 2
for t, b, std, label in zip(T_arrays, B_arrays, STD_arrays, labels):
plt.errorbar(t, b, std, linestyle='None', marker='^', label=label)
plt.plot(t, b, color='k', zorder=3)
# ^^^^^^^^
Or push the error bars below with zorder < 2
for t, b, std, label in zip(T_arrays, B_arrays, STD_arrays, labels):
plt.errorbar(t, b, std, linestyle='None', marker='^', label=label, zorder=1)
plt.plot(t, b, color='k')
# ^^^^^^^^
The key value here is 2 because all lines (including error bars) have a default zorder of 2:
Type
Default zorder
Images
0
Patches
1
Lines
2
Major ticks
2.01
Text
3
Legend
5

I found a solution, however it is not the cleanest way. I'm open to better ways to do this if the community has other approaches.
plt.figure(figsize=(15, 10), dpi=80)
plt.grid(True, linewidth=0.5, color='#ff0000', linestyle='-')
for i in range(len(B_arrays)):
plt.errorbar(T_arrays[i], B_arrays[i], STD_arrays[i], linestyle='None', marker='^', label = labels[i])
plt.errorbar(T_arrays[i], B_arrays[i], np.zeros(len(B_arrays[i])),color = "k")
plt.ylabel("B")
plt.xlabel("Time")
plt.legend(loc="upper right", prop={'size': 8})
plt.show()

Related

For scatterplot with matplotlib how to include in the legend gradient for dot size and colour?

I create two scatterplots with matplotlib in python with this code, the data for the code is here:
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize
fig = plt.figure(figsize=(20,12))
ax1 = fig.add_subplot(111)
ax3 = ax1.twinx()
norm = Normalize(vmin=0.95*min(arr), vmax=1.05*max(arr))
ax1.scatter(x, y1, s=20, c=arr, cmap='Blues_r', norm=norm, marker='x', label='bla1')
ax3.scatter(x, y2, s=(20*(1.1-arr))**3.5, c=arr, cmap='Reds_r', norm=norm, marker='^', label='bla1')
The created fig. looks like this:
So, the dot size (in ax3) and the dot colour (in ax1 and ax3) are taken from arrays containing floats with all kinds of values in the range [0,1]. My question: How do I create a legend that displays the corresponding y-values for, let's say 5 different dot sizes and 5 different colour nuances?
I would like the legend to look like in the figure below (source here), but with the colour bar and size bar put into a single legend, if possible. Thanks for suggestions and code!
# using your data in dataframe df
# create s2
df['s2'] = (20*(1.1-df.arr))**3.5
fig = plt.figure(figsize=(20,12))
ax1 = fig.add_subplot(111)
ax3 = ax1.twinx()
norm = Normalize(vmin=0.95*min(df.arr), vmax=1.05*max(df.arr))
p1 = ax1.scatter(df.x, df.y1, s=20, c=df.arr, cmap='Blues_r', norm=norm, marker='x')
fig.colorbar(p1, label='arr')
p2 = ax3.scatter(df.x, df.y2, s=df.s2, c=df.arr, cmap='Reds_r', norm=norm, marker='^')
fig.colorbar(p2, label='arr')
# create the size legend for red
for x in [15, 80, 150]:
plt.scatter([], [], c='r', alpha=1, s=x, label=str(x), marker='^')
plt.legend(loc='upper center', bbox_to_anchor=(1.23, 1), ncol=1, fancybox=True, shadow=True, title='s2')
plt.show()
There's no legend for p1 because the size is static.
I think this would be better as two separate plots
I used Customizing Plot Legends: Legend for Size of Points
Separate
fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(20, 10))
norm = Normalize(vmin=0.95*min(df.arr), vmax=1.05*max(df.arr))
p1 = ax1.scatter(df.x, df.y1, s=20, c=df.arr, cmap='Blues_r', norm=norm, marker='x')
fig.colorbar(p1, ax=ax1, label='arr')
p2 = ax2.scatter(df.x, df.y2, s=df.s2, c=df.arr, cmap='Reds_r', norm=norm, marker='^')
fig.colorbar(p2, ax=ax2, label='arr')
# create the size legend for red
for x in [15, 80, 150]:
plt.scatter([], [], c='r', alpha=1, s=x, label=str(x), marker='^')
plt.legend(loc='upper center', bbox_to_anchor=(1.2, 1), ncol=1, fancybox=True, shadow=True, title='s2')
plt.show()

Scatter plot with markers changing size according to number of represented points

I'm plotting a simple scatter plot:
It represents my data correctly, however there is many datapoints with coordinates (1.00,1.00) and in the plot, they appear under a single marker (top right corner). I'd like to have a functionality that changes the size of every marker according to the number of points it is representing. Will appreciate any help. Here's my code:
def saveScatter(figureTitle, xFeature, yFeature, xTitle, yTitle):
''' save a scatter plot of xFeatures vs yFeatures '''
fig = plt.figure(figsize=(8, 6), dpi=300)
ax = fig.add_subplot(111)
ax.scatter(dfModuleCPositives[names[xFeature]][:], dfModuleCPositives[names[yFeature]][:], c='r', marker='x', alpha=1, label='Module C Positives')
ax.scatter(dfModuleCNegatives[names[xFeature]][:], dfModuleCNegatives[names[yFeature]][:], c='g', alpha=0.5, label='Module C Negatives')
ax.scatter(dfModuleDPositives[names[xFeature]][:], dfModuleDPositives[names[yFeature]][:], c='k', marker='x', alpha=1, label='Module D Positives')
ax.scatter(dfModuleDNegatives[names[xFeature]][:], dfModuleDNegatives[names[yFeature]][:], c='b', alpha=0.5, label='Module D Negatives')
ax.set_xlabel(xTitle, fontsize=10)
ax.set_ylabel(yTitle, fontsize=10)
ax.set_title(figureTitle)
ax.grid(True)
ax.legend(loc="lower right")
fig.tight_layout()
plt.show()
return ax

Histogram show values of vertical lines in legends

Can I show the values of vertical lines(dashed) in legends or annotate it somewhere, how?
Here is the code for dashed line
plt.hist(df['wt_avg_delay'], bins=50, color='lightblue', edgecolor='black')
plt.axvline(df['wt_avg_delay'].mean(), color='orange', linestyle='dashed', linewidth=1)
plt.axvline(-19, color='green', linestyle='dashed', linewidth=1)
plt.axvline(27 color='red', linestyle='dashed', linewidth=1)
The easiest way to annotate is probably by using plt.text():
plt.text(x, y, 'annotation')
Alternatively you can just add a label to the lines:
import matplotlib.pyplot as plt
x = [1, 1, 1, 2, 2, 3]
p = 2.5
plt.hist(x, label='data')
plt.axvline(p, color='g', label=str(p))
plt.legend()
plt.show()

Color coded plot Python

I have a color coded plot. Here is a part of the code:
fig = plt.figure(figsize=(10,10))
color_scheme = plt.get_cmap('cool')
gs = gridspec.GridSpec(1, 1)
ax1 = plt.subplot(gs[0])
gs.update(left=0.15,bottom=0.15,right=0.80,top=0.95)
cax = fig.add_axes([0.80, 0.15, 0.03, 0.80])
im = ax1.scatter(x, y, c=z, edgecolors='black', marker='.', s=40, lw=1, cmap=color_scheme, vmin=0, vmax=10)
cb = fig.colorbar(im, cax=cax)
for t in cb.ax.get_yticklabels(): t.set_fontsize(12)
The problem is that I want to connect the dots with a line, and it doesn't work to use marker='-' and it also doesn't work if I use ax1.plt. How can I do this?
What I actually need is to fit a line to some points and color it the same color as the points (the points I fit to will all have same color)
Instead of using
ax1.scatter(x, y, ...)
use
ax1.plot(x, y, 'o-', ...) # three dots meaning you can configure markers, linestyle, etc.
This works bacause of 'o-' argument, which is a line plot with markers at every data point.
Plot the same x and y-data separately with a standard ax.plot behind your scatter plot.
ax1.plot(x, y, '-')
im = ax1.scatter(x, y, c=z, edgecolors='black', marker='.', s=40, lw=1, cmap=color_scheme, vmin=0, vmax=10)
This should give you your cmapped scatter plot with the lines behind the scatter-points.

Matplotlib; Scatter plot marker, dot within circle

I'm plotting using the Matplotlib scatter plotter. For the markers I'd ideally like the outline of a circle with a dot inside (outside circle makes it clear there's something there, the dot is then more precise). I can achieve this if I simply plot it twice (once with the outline then again with the dot) but then my legend isn't correct. So my question is, is there any way to do this? Or am I looking for a solution that doesn't exist?
Example code:
import matplotlib.pyplot as plt
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
x_data = [0.5, 1, 1.5]
y_data = [0.06, 0.06, 0.01]
ax1.scatter(x_data, y_data, label= 'Example legend entry.', s=80, marker='o', facecolors='none', edgecolors='black')
ax1.scatter(x_data, y_data, label= 'Example legend entry.', s=10, marker='o', color='black')
plt.gcf().subplots_adjust(bottom=0.08, top=0.95, left=0.05, right=0.84)
ax1.legend(loc='center left', bbox_to_anchor=(1, 0.5), fancybox=True, ncol=1, fontsize=17, labelspacing=1)
mng = plt.get_current_fig_manager()
mng.window.showMaximized()
plt.show()
And the example plot:
So yeah, would like something like those markers but with the ability to have them like that on the legend (unlike how it is currently split up into the two parts).
If any further information or clarification is needed, just ask. Thanks in advance for any/all help!
Clarification: I'm not sure I explained my goal well enough. I know I can get rid of one of the legends, but what I'm trying to achieve is a single legend entry with the combined marker (i.e. a circle with a 'dot' inside it). If I can't achieve then yes I'll just disable the legend for the outer circle but would quite like to get the marker used (which is a combination of two markers) on the plot to also be used on the legend.
You can use latex marker like that :
ax1.scatter(x_data, y_data, label= 'Example legend entry.', s=80, marker=r'$\odot$', facecolors='none', edgecolors='black')
And then plot your graph only one time.
Have you tried removing the label from the circle? I used altered your code so that your first plot of the larger circles does not have a label. ax1.scatter(x_data, y_data, s=80, marker='o', facecolors='none', edgecolors='black')
This worked for me, but perhaps not for you?
You can mark your scatter plots and include only one in your legend:
Here's how :
a_ = ax1.scatter(x_data, y_data, label= 'Example legend entry.', s=80, marker='o', facecolors='none', edgecolors='black')
b_ = ax1.scatter(x_data, y_data, label= 'Example legend entry.', s=10, marker='o', color='black')
ax1.legend([a_],["Example legend entry"] , loc='center left', bbox_to_anchor=(1, 0.5), fancybox=True, ncol=1, fontsize=17, labelspacing=1)

Categories