Logit scale in Plotly Express - matplotlib

My goal is to get a probability plot with the logit scale using Plotly Express (px).
In Matplotlib (plt) this is possible:
x, y = ([1, 2, 3], [1, 3, 2])
fig, ax = plt.subplots()
ax.scatter(x, y)
ax.set_yscale("logit")
Is there any comparable functionality in px?
The workaround I am trying currently is to get these ticks from plt and give them as parameters to px. That does work, but only changes the tick labels, not the actual scale of the y axis:
ytickvals = ax.get_yticks()
fig = px.scatter(x, y)
layout = dict(
yaxis=dict(
tickmode="array",
tickvals=ytickvals
)
)
fig.update_layout(layout)
How can I set the scale of the Plotly plot to be like the logit scale of Matplotlib?
Plotly API documentation doesn't know the term "logit" and plotly.graph_objects.layout.YAxis seems to not have a way of setting the scale.
PS, bonus question: why do my ticks not get displayed with the suffix using ticksuffix=" %" and showticksuffix="all"?

Related

Apply `ListedColormap` on bar chart [duplicate]

I have a df with two columns:
y: different numeric values for the y axis
days: the names of four different days (Monday, Tuesday, Wednesday, Thursday)
I also have a colormap with four different colors that I made myself and it's a ListedColorMap object.
I want to create a bar chart with the four categories (days of the week) in the x axis and their corresponding values in the y axis. At the same time, I want each bar to have a different color using my colormap.
This is the code I used to build my bar chart:
def my_barchart(my_df, my_cmap):
fig = plt.figure()
ax = fig.add_axes([0,0,1,1])
ax.bar(my_df['days'], my_df['y'], color=my_cmap)
return fig
However, I get the following error: "object of type 'ListedColormap' has no len()", so it seems that I'm not using my_cmap correctly.
If I remove that from the function and run it, my bar chart looks ok, except that all bars have the same color. So my question is: what is the right way to use a colormap with a bar chart?
The color argument wants either a string or an RGB[A] value (it can be a single colour, or a sequence of colours with one for each data point you are plotting). Colour maps are typically callable with floats in the range [0, 1].
So what you want to do is take the values you want for the colours for each bar, scale them to the range [0, 1], and then call my_cmap with those rescaled values.
So, say for example you wanted the colours to correspond to the y values (heights of the bars), then you should modify your code like this (assumes you have called import numpy as np earlier on):
def my_barchart(my_df, my_cmap):
rescale = lambda y: (y - np.min(y)) / (np.max(y) - np.min(y))
fig = plt.figure()
ax = fig.add_axes([0,0,1,1])
ax.bar(my_df['days'], my_df['y'], color=my_cmap(rescale(my_df['y'])))
return fig
Here is a self-contained minimal example of using the color argument with the output from a cmap:
import matplotlib.pyplot as plt
import numpy as np
x = np.array([1, 2, 3])
y = np.array([4, 5, 6])
my_cmap = plt.get_cmap("viridis")
rescale = lambda y: (y - np.min(y)) / (np.max(y) - np.min(y))
plt.bar(x, y, color=my_cmap(rescale(y)))
plt.savefig("temp")
Output:
Okay, I found a way to do this without having to scale my values:
def my_barchart(my_df, my_cmap):
fig = plt.figure()
ax = fig.add_axes([0,0,1,1])
ax.bar(my_df['days'], my_df['y'], color=my_cmap.colors)
return fig
Simply adding .colors after my_cmap works!

How do I plot a continuous color bar instead of discrete?

I am contouring some 2D data but want to have a continuous color bar instead of a discrete. How do I get this? Check out my code and output.
I have tried plotting without providing color levels, different color maps but does not help.
ylim = [0, 8]
xlim = [starttime, endtime]
fig = plt.figure(figsize=(10,7))
ax = plt.subplot()
levels1 = np.arange(5,61,5)
cmap=plt.get_cmap('jet')
Zplot=ax.contourf(timesNew, hgtNew, ZNew, levels1, cmap=cmap,
vmin=min(levels1), vmax=max(levels1), extend='both')
cbZ=plt.colorbar(Zplot, ticks=levels1)
niceDates = []
for timestamp in np.arange(ax.get_xlim()[0],ax.get_xlim()[1]+sec,sec):
niceDates.append(str(datetime.datetime.utcfromtimestamp(timestamp).strftime("%H")))
ax.set_ylim(ylim)
ax.set_xlim(xlim)
ax.set_xticks(np.arange(ax.get_xlim()[0],ax.get_xlim()[1]+sec,sec))
ax.set_xticklabels([])
ax.set_xticklabels(niceDates) #plot nice dates
ax.set_ylabel('Height (km)', fontsize=labelsize)
ax.set_xlabel('Time (UTC)', fontsize=labelsize)
The code works and plots nicely but the color bar is discrete and I want it to be continuous. What am I doing wrong? The data is in 2D numpy arrays. I have done some extensive processing to the data so not showing the full code other than the plotting.
As far as I know there is no way to get a real continuous colorbar. Try adding a lot more levels. This way it will look more like a continuous colorbar.
ylim = [0, 8]
xlim = [starttime, endtime]
fig = plt.figure(figsize=(10,7))
ax = plt.subplot()
levels1 = np.linspace(5,61,500)
level_ticks = np.arange(5, 61, 5)
cmap=plt.get_cmap('jet')
Zplot=ax.contourf(timesNew, hgtNew, ZNew, levels1, cmap=cmap,
vmin=min(levels1), vmax=max(levels1), extend='both')
cbZ=plt.colorbar(Zplot, ticks=level_ticks)
niceDates = []
for timestamp in np.arange(ax.get_xlim()[0],ax.get_xlim()[1]+sec,sec):
niceDates.append(str(datetime.datetime.utcfromtimestamp(timestamp).strftime("%H")))
ax.set_ylim(ylim)
ax.set_xlim(xlim)
ax.set_xticks(np.arange(ax.get_xlim()[0],ax.get_xlim()[1]+sec,sec))
ax.set_xticklabels([])
ax.set_xticklabels(niceDates) #plot nice dates
ax.set_ylabel('Height (km)', fontsize=labelsize)
ax.set_xlabel('Time (UTC)', fontsize=labelsize)

How to stack the graphs in such a way that the share a common scale along x-axis

The following code is for generating the 3 subplots. And on all the 3 subplots scale is mentioned. I want to stack them in such a way that x-axis and y-axis scale appear once like this. Can I get this plot with plt.subplot() or fig.add_axes is compulsory for this? I actually want to do this with subplots because in fig.add_subplot I havve to specify the width and height of each plot that I don't want.
`fig,axes = plt.figure(nrow=3, ncolmn=1)
ax1 = fig.add_subplot(311)
ax2 = fig.add_subplot(312)
ax3 = fig.add_subplot(313)
ind1 =[1,2,3]
ind2 = [4,5,6]
for i in range(len(3)):
data1=np.load(..)
data2=np.load(..)
axes[i].plot(data1, data2)`
Here is one solution using subplots_adjust where you put the space between two plots to 0 using hspace. Also, use sharex=True to have a shared x-axis
fig, axes = plt.subplots(nrows=3, ncols=1,sharex=True)
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
for i, ax in enumerate(axes.ravel()): # or axes.flatten() or axes.flat
ax.plot(x, y, label='File %d' %i)
ax.legend()
fig.text(0.5, 0.01, 'X-label', ha='center')
fig.text(0.01, 0.5, 'Y-label', va='center', rotation='vertical')
plt.tight_layout() # To get a better spacing between the subplots
plt.subplots_adjust(hspace=.0)

how to add variable error bars to scatter plot points with shared axes in python matplotlib

I have generated a plot that shows a topographic profile with points along the profile that represent dated points. However, these dated points also have symmetric uncertainty values/error bars (that typically vary for each point).
In this example, I treat non-dated locations as 'np.nan'. I would like to add uncertainty values to the y2 axis (Mean Age) with defined uncertainty values as y2err.
Everytime I use the ax2.errorbar( ... ) line, my graph is squeezed and distorted.
import numpy as np
import matplotlib.pyplot as plt
fig, ax1 = plt.subplots()
#Longitude = x; Elevation = y
x = (-110.75696,-110.75668,-110.75640,-110.75612,-110.75584,-110.75556,-110.75528)
y = (877,879,878,873,871,872,872)
ax1.plot(x, y)
ax1.set_xlabel('Longitude')
# Make the y-axis label, ticks and tick labels match the line color.
ax1.set_ylabel('Elevation', color='b')
ax1.tick_params('y', colors='b')
ax2 = ax1.twinx()
# Mean Age, np.nan = 0.0
y2 = (np.nan,20,np.nan,np.nan,np.nan,np.nan,np.nan)
y2err = (np.nan,5,np.nan,np.nan,np.nan,np.nan,np.nan)
ax2.scatter(x, y2, color='r')
#add error bars to scatter plot points
# (??????) ax2.errorbar(x, y, y2, y2err, capsize = 0, color='black')
ax2.set_ylim(10,30)
ax2.set_ylabel('Mean Age', color='r')
ax2.tick_params('y', colors='r')
fig.tight_layout()
plt.show()
If I do not apply the ax2.errorbar... line my plot looks like the first image, which is what I want but with the points showing uncertainty values (+/- equal on both side of point in the y-axis direction).
Plot of Elevation vs Age without error bars
When I use the ax2.errorbar line it looks like the second image:
Plot when using ax2.errorbar line
Thanks!

How to force a graph within a grid in matplotlib?

I have a grid that looks like this
fig = plt.figure()
ax = fig.gca()
ax.set_xticks(numpy.arange(-5,6,1))
ax.set_yticks(numpy.arange(-5,6,1))
plt.grid(True)
When plotting an exponential function, obviously the function's values grow larger than the grid very quickly, and my grid ticks get distorted. I want the grid to be fixed, and only that part of the function to be graphed which fits inside of the grid. Is this possible?
Thanks in advance.
You can set the limits of the axes:
fig = plt.figure()
ax = fig.gca()
# Exponential plot:
x = linspace(-5, 5, 100)
y = power(2, x)
ax.plot(x, y)
ax.set_xticks(numpy.arange(-5,6,1))
ax.set_yticks(numpy.arange(-5,6,1))
ax.set_xlim(-5, 6)
ax.set_ylim(-5, 6)
plt.grid(True)