Errorbars are over scatter plot points matplotlib - matplotlib

I have some issues using plt.errorbar and plt.scatter. I want to create a plot with points with their own error bars where both of them follow a certain color scale.
The problem is that to create this I have to use plt.errorbar and plt.scatter at the same time to report the points in the same color scale, but doing this the errorbar are above my points and overlap onto other points and I don't want this. Someone can help?
I add an image of what is happening at the moment and the code.
import matplotlib.pyplot as plt
import IPython
from astropy.cosmology import FlatLambdaCDM
import numpy as np
import math as ma
import matplotlib
import matplotlib.cm as cm
from matplotlib.colors import Normalize
cosmo = FlatLambdaCDM(H0=70, Om0=0.3)
Fu20_beam_814=np.array([0.91, 0.65, 0.58, 0.47, 0.64, 0.59, 0.77, 0.57, 0.59, 1.63])
err_Fu20_beam_814=np.array([0.13, 0.20, 0.14, 0.32, 0.17, 0.17, 0.16, 0.24, 0.15, 0.35])
Gav_beam_814=np.array([0.45, 0.41, 0.44, 0.55, 0.45, 0.47, 0.50, 0.56, 0.44, 0.45])
Z_beam_814=np.array([ 4.4105, 5.6700, 4.4381, 5.6704, 4.5134, 5.5448, 5.1818, 5.5420, 4.5785, 4.5802 ])
fake_814=np.array([0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2])*(-1/2)
M_beam_814=np.array([ 9.7, 9.8, 9.9, 10.2, 9.6, 10.2, 9.4, 10.2, 10.0, 9.7])
def f(Re,z):
return Re/(cosmo.arcsec_per_kpc_proper(z).value)
ReG_beam_814 = f(Gav_beam_814, Z_beam_814)
col='jet'
size=150
cap=1
norm = matplotlib.colors.Normalize(vmin=min(M_beam_814), vmax=max(M_beam_814), clip=True)
mapper = cm.ScalarMappable(norm=norm, cmap='jet')
M_color = np.array([(mapper.to_rgba(v)) for v in M_beam_814])
for x, y, ye, xe, color in zip(Fu20_beam_814, ReG_beam_814, fake_814, err_Fu20_beam_814, M_color):
plt.errorbar(x, y, ye, xe, c=color)
Beam_814 = plt.scatter(Fu20_beam_814, ReG_beam_814, s=size, marker='s', c=M_beam_814, cmap=col, edgecolors='#000000', linewidths=0.7)
plt.colorbar()
[1]: https://i.stack.imgur.com/EmkNT.png

Related

annotations in annotated_heatmap plotly lost when adding a subplot

I'm trying to subplot annotated_heatmap instance with go table , when Im subploting both the annotations on the heatmap are gone and I can't reproduce it .
[I want my heatmap will be as this on ][1]
[but this is what I get][2]
[1]: https://i.stack.imgur.com/V8aEc.png
[2]: https://i.stack.imgur.com/wP9cp.png
here is my code-
#here I create the subplots
fig = make_subplots(
rows=2, cols=1,
shared_xaxes=False,
vertical_spacing=0.05,
specs=[[{"type": "table"}],
[{"type": "scatter"}]],
subplot_titles=("AA table","AA heatmap")
)
#here i add go table
fig.add_trace(fig1.data[0],
row=1, col=1)
#here i add the heatmap
fig.add_trace(fig2.data[0],row=2,col=1)
fig.update_yaxes(title_text="Wild Type amino acid", row=2, col=1)
fig.update_xaxes(title_text="New amino acid", row=2, col=1)
fig.update_layout(
height=800,
showlegend=False,
title_text="Amino acids changes",
)
fig.show()
you have not provided sample data or how fig1 and fig2 are created. So have used https://plotly.com/python/annotated-heatmap/
as stated annotated_heatmap() is deprecated and it's now recommended to use px.imshow()
using this approach it works (have not focused on table rows/cols being correct)
import plotly.express as px
from plotly.subplots import make_subplots
import plotly.graph_objects as go
z = [
[0.1, 0.3, 0.5, 0.7, 0.9],
[1, 0.8, 0.6, 0.4, 0.2],
[0.2, 0, 0.5, 0.7, 0.9],
[0.9, 0.8, 0.4, 0.2, 0],
[0.3, 0.4, 0.5, 0.7, 1],
]
fig1 = go.Figure(go.Table(cells={"values": z}))
# annotated heatmap
fig2 = px.imshow(z, text_auto=True)
fig = make_subplots(
rows=2,
cols=1,
shared_xaxes=False,
vertical_spacing=0.05,
specs=[[{"type": "table"}], [{"type": "scatter"}]],
subplot_titles=("AA table", "AA heatmap"),
)
# here i add go table
fig.add_trace(fig1.data[0], row=1, col=1)
# here i add the heatmap
fig.add_trace(fig2.data[0], row=2, col=1)
fig.update_yaxes(title_text="Wild Type amino acid", row=2, col=1)
fig.update_xaxes(title_text="New amino acid", row=2, col=1)
fig.update_layout(
height=800,
showlegend=False,
title_text="Amino acids changes",
)
fig

Align bar and line plot on x axis without the use of rank and pointplot

Please note, I've looked at other questions like question and my problem is different and not a duplicate!
I would like to have two plots, with the same x axis in matplotlib. I thought this should be achieved via constrained_layout, but apparently this is not the case. Here is an example code.
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.gridspec as grd
x = np.arange(0, 30, 0.001)
df_line = pd.DataFrame({"x": x, "y": np.sin(x)})
df_bar = pd.DataFrame({
"x_bar": [1, 7, 10, 20, 30],
"y_bar": [0.0, 0.3, 0.4, 0.1, 0.2]
})
fig = plt.subplots(constrained_layout=True)
gs = grd.GridSpec(2, 1, height_ratios=[3, 2], wspace=0.1)
ax1 = plt.subplot(gs[0])
sns.lineplot(data=df_line, x=df_line["x"], y=df_line["y"], ax=ax1)
ax1.set_xlabel("time", fontsize="22")
ax1.set_ylabel("y values", fontsize="22")
plt.yticks(fontsize=16)
plt.xticks(fontsize=16)
plt.setp(ax1.get_legend().get_texts(), fontsize="22")
ax2 = plt.subplot(gs[1])
sns.barplot(data=df_bar, x="x_bar", y="y_bar", ax=ax2)
ax2.set_xlabel("time", fontsize="22")
ax2.set_ylabel("y values", fontsize="22")
plt.yticks(fontsize=16)
plt.xticks(fontsize=16)
this leads to the following figure.
However, I would like to see the corresponding x values of both plot aligned. How can I achieve this? Note, I've tried to use the following related question. However, this doesn't fully apply to my situation. First with the high number of x points (which I need in reality) point plots is make the picture to big and slow for loading. On top, I can't use the rank method as my categories for the barplot are not evenly distributed. They are specific points on the x axis which should be aligned with the corresponding point on the lineplot
x = np.arange(0, 30, 0.001)
df_line = pd.DataFrame({"x": x, "y": np.sin(x)})
df_bar = pd.DataFrame({
"x_bar": [1, 7, 10, 20, 30],
"y_bar": [0.0, 0.3, 0.4, 0.1, 0.2]
})
fig, (ax1, ax2) = plt.subplots(2,1)
ax1.plot(df_line['x'], df_line['y'])
for i in range(len(df_bar['x_bar'])):
ax2.axvline(x=df_bar['x_bar'][i], ymin=0, ymax=df_bar['y_bar'][i])
Output:
---edit---
I incorporated #mozway advice for linewidth:
lw = (300/ax1.get_xlim()[1])
ax2.axvline(x=df_bar['x_bar'][i], ymin=0, ymax=df_bar['y_bar'][i], solid_capstyle='butt', lw=lw)
Output:
or:

How to avoid overlapping bars in plt.bar when x-values aren't spaced evenly?

I have
x = array([0., 0.08, 0.12, 0.18, 0.27, 0.42, 0.65])
y = array([0., 0.03758546, 0.06577713, 0.48786205, 0.28553257, 0.09909356, 0.02414922])
I then write
plt.ticklabel_format(useOffset=False)
plt.figure(figsize=(20,10))
plt.xlabel('D/Dmax')
plt.bar(x, y), align = 'edge', tick_label = x, color = 'red', edgecolor = "black")
And I get the following chart. Why is it like this, and how can I make the bars not overlap and distinct like every other bar chart?
As your bars don't have a constant width, you can calculate these widths as the difference between the x-values: np.diff(x). Note that there is one less difference than there are elements in x. To get a width for the last bar (which in theory could be infinite), you can either repeat the next-to-last width, or add an extra x-value to set the rightmost boundary.
from matplotlib import pyplot as plt
import numpy as np
x = np.array([0., 0.08, 0.12, 0.18, 0.27, 0.42, 0.65])
y = np.array([0., 0.03758546, 0.06577713, 0.48786205, 0.28553257, 0.09909356, 0.02414922])
widths = np.pad(np.diff(x), (0, 1), 'edge')
plt.figure(figsize=(20, 10))
plt.xlabel('D/Dmax')
plt.bar(x, y, width=widths, align='edge', tick_label=x, color='red', edgecolor="black")
plt.show()
In this case, a logical extension for x could be to include 1:
from matplotlib import pyplot as plt
import numpy as np
x = np.array([0., 0.08, 0.12, 0.18, 0.27, 0.42, 0.65])
x = np.concatenate([x, [1]])
y = np.array([0., 0.03758546, 0.06577713, 0.48786205, 0.28553257, 0.09909356, 0.02414922])
widths = np.diff(x)
plt.figure(figsize=(20, 10))
plt.xlabel('D/Dmax')
plt.bar(x[:-1], y, width=widths, align='edge', color='red', edgecolor="black")
plt.xticks(x)
plt.show()
Your real x-values are much smaller than the default bar width which makes the bars overlap. You need to use a smaller bar width, for ex. 0.02 which is of the order of your smaller x-value.
plt.bar(x, y, align='edge', tick_label=x, color='red', edgecolor="black",
width=0.02)

Matplotlib: setting x-limits also forces tick labels?

I just upgraded to matplotlib 2.0, and I feel like I'm on crazy pills. I'm trying to make a log-linear plot, with the y-axis on a linear scale and the x-axis on a log10 scale. Previously, the following code would have allowed me to specify exactly where I want my ticks, and what I want their labels to be:
import matplotlib.pyplot as plt
plt.plot([0.0,5.0], [1.0, 1.0], '--', color='k', zorder=1, lw=2)
plt.xlim(0.4,2.0)
plt.ylim(0.0,2.0)
plt.xscale('log')
plt.tick_params(axis='x',which='minor',bottom='off',top='off')
xticks = [0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0]
ticklabels = ['0.4', '0.6', '0.8', '1.0', '1.2', '1.4', '1.6', '1.8', '2.0']
plt.xticks(xticks, ticklabels)
plt.show()
But in matplotlib 2.0, this now causes me to get a set of overlapping tick labels where matplotlib apparently wants to auto-create ticks:
But if I comment out the "plt.xlim(0.4,2.0)" line and let it automatically determine the axis limits, there are no overlapping tick labels and I just get the ones I want:
But that doesn't work because I now have useless x-axis limits.
Any ideas?
Edit: for people searching the internet in the future, I'm becoming more convinced that this is actually a bug in matplotlib itself. I reverted back to v. 1.5.3. to just avoid the issue.
The additional ticklabels that overlap originate from some minor ticklabels, which are present in the plot. To get rid of them, one can set the minor formatter to the NullFormatter:
plt.gca().xaxis.set_minor_formatter(matplotlib.ticker.NullFormatter())
The complete code from the question might then look like
import matplotlib.pyplot as plt
import matplotlib.ticker
import numpy as np
x = np.linspace(0,2.5)
y = np.sin(x*6)
plt.plot(x,y, '--', color='k', zorder=1, lw=2)
plt.xlim(0.4,2.0)
plt.xscale('log')
xticks = [0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0]
ticklabels = ['0.4', '0.6', '0.8', '1.0', '1.2', '1.4', '1.6', '1.8', '2.0']
plt.xticks(xticks, ticklabels)
plt.gca().xaxis.set_minor_formatter(matplotlib.ticker.NullFormatter())
plt.show()
A code that may be more intuitive as it is not setting the xticklabels as strings would be the following, where we use a FixedLocator and a ScalarFormatter.
This code produces the identical plot as the above.
import matplotlib.pyplot as plt
import matplotlib.ticker
import numpy as np
x = np.linspace(0,2.5)
y = np.sin(x*6)
plt.plot(x,y, '--', color='k', zorder=1, lw=2)
plt.xlim(0.4,2.0)
plt.xscale('log')
xticks = [0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0]
xmajorLocator = matplotlib.ticker.FixedLocator(locs=xticks)
xmajorFormatter = matplotlib.ticker.ScalarFormatter()
plt.gca().xaxis.set_major_locator( xmajorLocator )
plt.gca().xaxis.set_major_formatter( xmajorFormatter )
plt.gca().xaxis.set_minor_formatter(matplotlib.ticker.NullFormatter())
plt.show()

Compact horizontal guage Matplotlib

How to create a compact horizontal gauge like for example a thermometer for temperature, barometer for pressure using Matplotlib. The scale of the gauge will be split into ranges; each range denoting high-high, high. low and low-low and a pointer reading the value? Is it possible to create such a gauge in matplotlib?
You could use a colorbar.
For example:
import matplotlib.pyplot as plt
import matplotlib as mpl
fig = plt.figure(figsize=(8, 2))
ax = fig.add_axes([0.1, 0.4, 0.8, 0.2])
bounds = [-20, -10, 0, 10, 20]
labels = ('low-low', 'low', 'high', 'high-high')
cmap = mpl.cm.coolwarm
norm = mpl.colors.Normalize(vmin=bounds[0], vmax=bounds[-1])
cb = mpl.colorbar.ColorbarBase(
ax,
cmap=cmap,
norm=norm,
orientation='horizontal',
boundaries=bounds,
label='temperature (degrees celcius)',
)
for i, label in enumerate(labels):
xpos = float((2*i + 1))/(2*len(labels))
ax.annotate(label, xy=(xpos, 0.5), xycoords='axes fraction', ha='center', va='center')
plt.show()
Which produces something like this:
For more info see these examples in the matplotlib docs.