plotting with pcolormesh, changing axis - python

Supppose I am plotting a assymetric matrix with pcolormesh:
import prettyplotlib as ppl
import matplotlib.pyplot as plt
import numpy as np
plt.figure()
fig, ax = plt.subplots(1)
ppl.pcolormesh(fig, ax, np.random.randn(10,80))
plt.show()
Now I want to change the x-axis such that its extents are for example -500 to 500 without changing the plot, only the labels of the x-axis, the same for y-axis. How can I accomplish that?

After the ppl.pcolormesh command you can define the ticklables directly using
ax.set_xticks(xticks)
ax.set_xticklabels(xticklabels)
where xticklabels is an array of your desired labels and xticks are the values at which the labels should apply.

Related

Aligning y-axis label with middle of subplot?

I'm working with Matplotlib and have a large number of 1D heatmaps, each with their own label. However, the labels are misaligned with the plots and I cannot figure out to get this to work automatically.
Here's an MWE
import numpy as np
import matplotlib.pyplot as plt
data = np.random.rand(10, 1000)
dogs = ["woof", "bark", "bowwow"]
fig, axs = plt.subplots(10)
for i in range(10):
axs[i].scatter(np.linspace(0, 1, 1000), np.linspace(0,1,1000)*0, 2000,
c=data[i, :], marker="|", cmap='inferno')
axs[i].set_frame_on(False)
axs[i].set_yticklabels([])
axs[i].set_xticklabels([])
axs[i].set_xticks([])
axs[i].set_yticks([])
axs[i].set_ylabel(dogs[i%3], rotation='horizontal')
plt.show()
I experimented with
axs[i].yaxis.set_label_coords(x, y)
for various values of x and y, and nothing seems to work. I would prefer to have it align automatically, with the bottom of the text corresponding to the bottom of the individual plot.
Attached is an image showcasing the alignment issue.
Example
You could create your heatmaps via seaborn, and use yticklabels=[label_name] to set the labels. Rotating the labels to 0 degrees should have them nicely aligned. Note that the data is expected to have a shape of 1xN.
from matplotlib import pyplot as plt
import seaborn as sns
import numpy as np
labels = ['Alkaid', 'Mizar', 'Alioth', 'Megrez', 'Phecda', 'Merak', 'Dubhe']
nrows = len(labels)
fig, axs = plt.subplots(nrows=nrows, figsize=(10, 5))
for ax_i, data_i, label_i in zip(axs, np.random.randn(nrows, 1, 100).cumsum(axis=2), labels):
sns.heatmap(data=data_i, xticklabels=[], yticklabels=[label_i], cmap='inferno', cbar=False, ax=ax_i)
ax_i.tick_params(axis='y', rotation=0, labelsize=22, length=0) # length means length of the tick mark
plt.tight_layout()
plt.show()
After a bit of playing around, I found that
axs[0].set_ylabel("Pseudotime", fontsize=12, rotation='horizontal', ha='right', va='center')
is sufficient for aligning the y-labels.

fixing the y scale in python matplotlib

I want to draw multiple bar plots with the same y-scale, and so I need the y-scale to be consistent.
For this, I tried using ylim() after yscale()
plt.yscale("log")
plt.ylim(top=2000)
plt.show()
However, python keeps autoscaling the intermittent values depending on my data.
Is there a way to fix this?
overlayed graphs
import numpy as np
import matplotlib.pyplot as plt
xaxis = np.arange(10)
yaxis = np.random.rand(10)*100
fig = plt.subplots(figsize =(10, 7))
plt.bar(xaxis, yaxis, width=0.8, align='center', color='y')
# show graph
plt.yscale("log")
plt.ylim(top=2000)
plt.show()
You can set the y-axis tick labels manually. See yticks for an example. In your case, you will have to do this for each plot to have consistent axes.

How to have the axis ticks in both top and bottom, left and right of a heatmap

I am trying to draw a big heatmap with sns.heatmap function. However, since the map is too big, it's a little hard to find the xtick label or ytick label with corresponding rows and columns. Can I add the xtick and xlabels also on the top and ytick and ylabels also on the right??
I have tried many different ways. But they all didn't work.
The usual way would be via tick_params, which has the labelrotation parameter, and accepts rotation:
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(0)
import seaborn as sns
uniform_data = np.random.rand(10, 12)
ax = sns.heatmap(uniform_data)
ax.tick_params(right=True, top=True, labelright=True, labeltop=True, labelrotation=0)
plt.show()
Without labelrotation=0 or rotation=0
Axis ticks for all sides can be placed using tick_params from matplotlib
#Get sample correlation data to plot something. 'data' is a dataframe
corr=data.corr()
#Create Heatmap
axr = sns.heatmap(corr,cmap="coolwarm", annot=True, linewidths=.5,cbar=False)
#Set all sides
axr.tick_params(right=True, top=True, labelright=True, labeltop=True,rotation=0)
#Rotate X ticks
plt.xticks(rotation='vertical')

Histogram at specific coordinates inside axes

What I want to achieve with Python 3.6 is something like this :
Obviously made in paint and missing some ticks on the xAxis. Is something like this possible? Essentially, can I control exactly where to plot a histogram (and with what orientation)?
I specifically want them to be on the same axes just like the figure above and not on separate axes or subplots.
fig = plt.figure()
ax2Handler = fig.gca()
ax2Handler.scatter(np.array(np.arange(0,len(xData),1)), xData)
ax2Handler.hist(xData,bins=60,orientation='horizontal',normed=True)
This and other approaches (of inverting the axes) gave me no results. xData is loaded from a panda dataframe.
# This also doesn't work as intended
fig = plt.figure()
axHistHandler = fig.gca()
axScatterHandler = fig.gca()
axHistHandler.invert_xaxis()
axHistHandler.hist(xData,orientation='horizontal')
axScatterHandler.scatter(np.array(np.arange(0,len(xData),1)), xData)
A. using two axes
There is simply no reason not to use two different axes. The plot from the question can easily be reproduced with two different axes:
import numpy as np
import matplotlib.pyplot as plt
plt.style.use("ggplot")
xData = np.random.rand(1000)
fig,(ax,ax2)= plt.subplots(ncols=2, sharey=True)
fig.subplots_adjust(wspace=0)
ax2.scatter(np.linspace(0,1,len(xData)), xData, s=9)
ax.hist(xData,bins=60,orientation='horizontal',normed=True)
ax.invert_xaxis()
ax.spines['right'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax2.tick_params(axis="y", left=0)
plt.show()
B. using a single axes
Just for the sake of answering the question: In order to plot both in the same axes, one can shift the bars by their length towards the left, effectively giving a mirrored histogram.
import numpy as np
import matplotlib.pyplot as plt
plt.style.use("ggplot")
xData = np.random.rand(1000)
fig,ax= plt.subplots(ncols=1)
fig.subplots_adjust(wspace=0)
ax.scatter(np.linspace(0,1,len(xData)), xData, s=9)
xlim1 = ax.get_xlim()
_,__,bars = ax.hist(xData,bins=60,orientation='horizontal',normed=True)
for bar in bars:
bar.set_x(-bar.get_width())
xlim2 = ax.get_xlim()
ax.set_xlim(-xlim2[1],xlim1[1])
plt.show()
You might be interested in seaborn jointplots:
# Import and fake data
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
data = np.random.randn(2,1000)
# actual plot
jg = sns.jointplot(data[0], data[1], marginal_kws={"bins":100})
jg.ax_marg_x.set_visible(False) # remove the top axis
plt.subplots_adjust(top=1.15) # fill the empty space
produces this:
See more examples of bivariate distribution representations, available in Seaborn.

Matplotlib - imshow twiny() problems

I am trying to have two inter-depedent x-axis in a matplotlib imshow() plot. I have bottom x-axis as the radius squared and I want the top as just the radius. I have tried so far:
ax8 = ax7.twiny()
ax8._sharex = ax7
fmtr = FuncFormatter(lambda x,pos: np.sqrt(x) )
ax8.xaxis.set_major_formatter(fmtr)
ax8.set_xlabel("Radius [m]")
where ax7 is the y-axis and the bottom x-axis (or radius squared). Instead of getting the sqrt (x_bottom) as the ticks at the top I just get a range from 0 to 1. How can I fix this?
Thanks a lot in advance.
You're misunderstanding what twiny does. It makes a completely independent x-axis with a shared y-axis.
What you want to do is have a different formatter with a linked axis (i.e. sharing the axis limits but nothing else).
The simple way to do this is to manually set the axis limits for the twinned axis:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
fig, ax1 = plt.subplots()
ax1.plot(range(10))
ax2 = ax1.twiny()
formatter = FuncFormatter(lambda x, pos: '{:0.2f}'.format(np.sqrt(x)))
ax2.xaxis.set_major_formatter(formatter)
ax2.set_xlim(ax1.get_xlim())
plt.show()
However, as soon as you zoom or interact with the plot, you'll notice that the axes are unlinked.
You could add an axes in the same position with both shared x and y axes, but then the tick formatters are shared, as well.
Therefore, the easiest way to do this is using a parasite axes.
As a quick example:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
from mpl_toolkits.axes_grid1.parasite_axes import SubplotHost
fig = plt.figure()
ax1 = SubplotHost(fig, 1,1,1)
fig.add_subplot(ax1)
ax2 = ax1.twin()
ax1.plot(range(10))
formatter = FuncFormatter(lambda x, pos: '{:0.2f}'.format(np.sqrt(x)))
ax2.xaxis.set_major_formatter(formatter)
plt.show()
Both this and the previous plot will look identical at first. The difference will become apparent when you interact (e.g. zoom/pan) with the plot.

Categories