Updating aesthetics of matplotlib heatmap - python

import matplotlib.pyplot as plt
import numpy as np
column_labels = list('ABCD')
row_labels = list('WXYZ')
data = np.random.rand(4,4)
fig, ax = plt.subplots()
heatmap = ax.pcolor(data, cmap=plt.cm.Blues)
# put the major ticks at the middle of each cell
ax.set_xticks(np.arange(data.shape[0])+0.5, minor=False)
ax.set_yticks(np.arange(data.shape[1])+0.5, minor=False)
# want a more natural, table-like display
ax.invert_yaxis()
ax.xaxis.set_label_position('top') # <-- This doesn't work!
ax.set_xticklabels(row_labels, minor=False)
ax.set_yticklabels(column_labels, minor=False)
plt.show()
Above code is from: Moving x-axis to the top of a plot in matplotlib
How can I change output from this script so that it looks aesthetically more like this picture:
Any solution using python matplotlib or seaborn works. I want to insert white between the cells, have the cells be square and also control their size

I think you need 2 tricks. First, add the line
ax.set_aspect('equal')
to make the cells appear as squares (assuming that you have an equal number on the x- and y-axes, as in your example). If you have x squares on the x-axis and y squares on the y-axis, I suspect that you could instead do,
ax.set_aspect(float(y) / float(x))
Second, you need to add edgecolor to the cells and make the edges thick, so modify your line to e.g.,
heatmap = ax.pcolor(data, cmap=plt.cm.Blues, edgecolor='white', linewidths=10)
The result is

Related

python code to place x and y label in the middle of tick positions in matplotlib.pyplot

I am trying to create a heatmap by putting gridlines to some particular positions which I have done. Suppose, I tried to make gridlines in positions 358 and 589 in a matrix of length 640,640. After that, I wanted to change the label from 358 to a defined value of 999 and 589 to a specified value of 1023. However, I cannot change the x and y labels in the center position of two gridlines. For example, I have tried the following:
data = np.random.rand(640, 640)
fig, ax = plt.subplots()
im = ax.imshow(data,cmap='coolwarm')
ax.set_xticks([358,589])
ax.set_yticks([358,589])
ax.set_xticklabels([999,1023])
ax.set_yticklabels([999,1023])
ax.grid(which='major',color='black',linestyle='--',linewidth=1,alpha=0.5)
plt.show()
That create a image as follows:
Heatmap with customized labelling
But I want the labeling in the middle of two gridlines instead of the gridline positions. How can that be done?
By default, both the tick labels and the grid lines are decided via the major ticks. To change this, you could use the minor ticks to position the grid lines and the major ticks for the tick labels:
from matplotlib import pyplot as plt
import numpy as np
data = np.random.randn(640, 640).cumsum(axis=0).cumsum(axis=1)
fig, ax = plt.subplots()
im = ax.imshow(data, cmap='coolwarm')
positions = np.array([358, 589])
ax.set_xticks(positions, minor=True)
ax.set_yticks(positions, minor=True)
borders = np.append(0, positions)
mids = (borders[:-1] + borders[1:]) / 2
ax.set_xticks(mids, [999, 1023], minor=False)
ax.set_yticks(mids, [999, 1023], minor=False)
ax.grid(which='minor', color='black', linestyle='--', linewidth=1, alpha=0.9)
plt.show()

Removing legend from mpl parallel coordinates plot?

I have a parallel coordinates plot with lots of data points so I'm trying to use a continuous colour bar to represent that, which I think I have worked out. However, I haven't been able to remove the default key that is put in when creating the plot, which is very long and hinders readability. Is there a way to remove this table to make the graph much easier to read?
This is the code I'm currently using to generate the parallel coordinates plot:
parallel_coordinates(data[[' male_le','
female_le','diet','activity','obese_perc','median_income']],'median_income',colormap = 'rainbow',
alpha = 0.5)
fig, ax = plt.subplots(figsize=(6, 1))
fig.subplots_adjust(bottom=0.5)
cmap = mpl.cm.rainbow
bounds = [0.00,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]
norm = mpl.colors.BoundaryNorm(bounds, cmap.N,)
plt.colorbar(mpl.cm.ScalarMappable(norm = norm, cmap=cmap),cax = ax, orientation = 'horizontal',
label = 'normalised median income', alpha = 0.5)
plt.show()
Current Output:
I want my legend to be represented as a color bar, like this:
Any help would be greatly appreciated. Thanks.
You can use ax.legend_.remove() to remove the legend.
The cax parameter of plt.colorbar indicates the subplot where to put the colorbar. If you leave it out, matplotlib will create a new subplot, "stealing" space from the current subplot (subplots are often referenced to by ax in matplotlib). So, here leaving out cax (adding ax=ax isn't necessary, as here ax is the current subplot) will create the desired colorbar.
The code below uses seaborn's penguin dataset to create a standalone example.
import matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn as sns
import numpy as np
from pandas.plotting import parallel_coordinates
penguins = sns.load_dataset('penguins')
fig, ax = plt.subplots(figsize=(10, 4))
cmap = plt.get_cmap('rainbow')
bounds = np.arange(penguins['body_mass_g'].min(), penguins['body_mass_g'].max() + 200, 200)
norm = mpl.colors.BoundaryNorm(bounds, 256)
penguins = penguins.dropna(subset=['body_mass_g'])
parallel_coordinates(penguins[['bill_length_mm', 'bill_depth_mm', 'flipper_length_mm', 'body_mass_g']],
'body_mass_g', colormap=cmap, alpha=0.5, ax=ax)
ax.legend_.remove()
plt.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=cmap),
ax=ax, orientation='horizontal', label='body mass', alpha=0.5)
plt.show()

Configuring grid-lines in matplotlib plot

Consider the figure below.
This image has been set up with the following code.
plt.rc('text', usetex=True)
plt.rc('font', family='serif')
fig, ax = plt.subplots()
ax.set_xlabel("Run Number", fontsize=25)
plt.grid(True, linestyle='--')
plt.tick_params(labelsize=20)
ax.set_xticklabels(map(str,range(number_of_runs)))
ax.minorticks_on()
ax.set_ylim([0.75,1.75])
I have not included the code that actually generates the data for plotting for the sake of clarity.
Unlike the diagram above, I would like to draw grid-lines perpendicular to the X-axis through each orange (and hence blue) dot. How do I do this?
The x-coordinates of the successive orange and blue dots form the same arithmetic progression in my code.
Also I notice that the tick numbers numbered 1,2,... are wrong for my application. Instead, I would like each successive grid-line, which I ask for as perpendicular to the X-axis in the previous step, to be numbered sequentially from 1 along the X-axis. How do I configure the Xtick marks for this?
The grid lines cross the xticks (or yticks).
You need to define xticks properly so that the grid lines cross your data points (the dots)
example below:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
number_of_runs = range(1,10) # use your actual number_of_runs
ax.set_xticks(number_of_runs, minor=False)
ax.xaxis.grid(True, which='major')
In case you want to have only vertical lines, add this:
ax.yaxis.grid(False, which='major')
Similar question here.
You should specify the exact places where you want the grids using a call to ax.set_xticks and then specify the exact numbers you want on the axis using a call to ax.set_xticklabels.
I am plotting some two random arrays in the example below:
plt.rc('text', usetex=True)
plt.rc('font', family='serif')
y1 = np.random.random(10)
y2 = np.random.random(10)
fig, ax = plt.subplots(ncols=2, figsize=(8, 3))
# equivalent to your figure
ax[0].plot(y1, 'o-')
ax[0].plot(y2, 'o-')
ax[0].grid(True, linestyle='--')
ax[0].set_title('Before')
# hopefully what you want
ax[1].plot(y1, 'o-')
ax[1].plot(y2, 'o-')
ax[1].set_title('After')
ax[1].set_xticks(range(0, len(y1)))
ax[1].set_xticklabels(range(1, len(y1)+1))
ax[1].grid(True, linestyle='--')
plt.show()
This is the output:
A note: Looking at your plot, it seems that the actual x-axis is not integers, but you want integers starting from 1, Probably the best way to do this is to just pass in the y axis data array as an argument for the plot command (plt.plot(y) instead of plt.plot(x, y), like what I have done above. You should decide if this is appropriate for your case.

Plot over subplot

I have a subplot inside an existing axes frame, and in the subplot there are some lines or filled contourf plot. What I want to do is to plot some lines in the existing bigger frame, and these lines must be on top of the lines/contourf in the subfigure. The following is a small example. Basically I want the blue and/or green lines to be on top of the red line. It seems setting the zorder has no effect for lines belonging to different sub-axes.
import matplotlib.pyplot as plt
fig = plt.figure()
plt.plot([0,2], color='blue', zorder=300)
ax0 = gca()
ax = fig.add_axes([0.3,0.3,0.3,0.3], zorder=0, axisbg='none')
ax.plot([0,1],[1,0], linewidth=40, color='red', zorder=-100)
ax0.plot([0.55,0.55],[0,2], linewidth=20, color='green', zorder=200)
I kind of find a solution, which may not be perfect but works for my needs. The trick is to set the big axes frame to a high zorder, and set its background color to transparent, so that the small axes frame in the background can be seen, and in this way the lines in the main frame will naturally be on top of the lines in the small frame.
import matplotlib.pyplot as plt
fig = plt.figure()
plt.plot([0,2], color='blue')
ax0 = gca()
ax0.set_zorder(100)
ax0.set_axis_bgcolor('none')
ax = fig.add_axes([0.3,0.3,0.3,0.3], zorder=0, axisbg='none')
ax.plot([0,1],[1,0], linewidth=40, color='red')
ax0.plot([0.55,0.55],[0,2], linewidth=20, color='green')

Tick properties for scatterplot matrices with Matplotlib

I am trying to plot a scatterplot matrix based on the code written by Joe Kington: Is there a function to make scatterplot matrices in matplotlib?
Some people already helped me: Thank you again (especially J.K.).
I am having a last problem: I cannot rotate the ticks of some axis for which numbers overlap (bottom left):
I would like to try to have them vertical but I cannot do it.... Here is my code:
import itertools
import numpy as np
import pylab as plot
import scipy
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import axis
import math
from matplotlib import rc
import os
import platform
def main():
FigSize=8.89
FontSize=8
np.random.seed(1977)
numvars, numdata = 4, 10
data = 10 * np.random.random((numvars, numdata))
fig = scatterplot_matrix(data, ['mpg', 'disp', 'drat', 'wt'], FigSize, FontSize,
linestyle='none', marker='o', color='black', mfc='none', markersize=3,)
fig.suptitle('Simple Scatterplot Matrix')
plt.savefig('Plots/ScatterplotMatrix/ScatterplotMatrix2.pdf',format='pdf', dpi=1000, transparent=True, bbox_inches='tight')
plt.show()
def scatterplot_matrix(data, names, FigSize, FontSize, **kwargs):
"""Plots a scatterplot matrix of subplots. Each row of "data" is plotted
against other rows, resulting in a nrows by nrows grid of subplots with the
diagonal subplots labeled with "names". Additional keyword arguments are
passed on to matplotlib's "plot" command. Returns the matplotlib figure
object containg the subplot grid."""
legend=['(kPa)','\%','\%','\%']
numvars, numdata = data.shape
fig, axes = plt.subplots(nrows=numvars, ncols=numvars, figsize=(FigSize/2.54,FigSize/2.54))
fig.subplots_adjust(hspace=0.05, wspace=0.05)
sub_labelx_top=[2,4]
sub_labelx_bottom=[13,15]
sub_labely_left=[5,13]
sub_labely_right=[4,12]
for i, ax in enumerate(axes.flat, start=1):
# Hide all ticks and labels
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
ax.xaxis.set_major_locator(MaxNLocator(prune='both',nbins=4))
ax.yaxis.set_major_locator(MaxNLocator(prune='both',nbins=4)) #http://matplotlib.org/api/ticker_api.html#matplotlib.ticker.MaxNLocator
# Set up ticks only on one side for the "edge" subplots...
if ax.is_first_col():
ax.yaxis.set_ticks_position('left')
ax.tick_params(direction='out')
ax.yaxis.set_tick_params(labelsize=0.75*FontSize)
if i in sub_labely_left:
ax.yaxis.set_label_position('left')
ax.set_ylabel('(\%)',fontsize=0.75*FontSize)
if ax.is_last_col():
ax.yaxis.set_ticks_position('right')
ax.tick_params(direction='out')
ax.yaxis.set_tick_params(labelsize=0.75*FontSize)
if i in sub_labely_right:
ax.yaxis.set_label_position('right')
if i==4:
ax.set_ylabel('(kPa)',fontsize=0.75*FontSize)
else:
ax.set_ylabel('(\%)',fontsize=0.75*FontSize)
if ax.is_first_row():
ax.xaxis.set_ticks_position('top')
ax.tick_params(direction='out')
ax.xaxis.set_tick_params(labelsize=0.75*FontSize)
if i in sub_labelx_top:
ax.xaxis.set_label_position('top')
ax.set_xlabel('(\%)',fontsize=0.75*FontSize)
if ax.is_last_row():
ax.xaxis.set_ticks_position('bottom')
ax.tick_params(direction='out')
ax.xaxis.set_tick_params(labelsize=0.75*FontSize)
if i in sub_labelx_bottom:
ax.xaxis.set_label_position('bottom')
if i==13:
ax.set_xlabel('(kPa)',fontsize=0.75*FontSize)
else:
ax.set_xlabel('(\%)',fontsize=0.75*FontSize)
# Plot the data.
for i, j in zip(*np.triu_indices_from(axes, k=1)):
for x, y in [(i,j), (j,i)]:
axes[x,y].plot(data[y], data[x], **kwargs)
# Label the diagonal subplots...
for i, label in enumerate(names):
axes[i,i].annotate(label, (0.5, 0.5), xycoords='axes fraction',
ha='center', va='center',fontsize=FontSize)
# Turn on the proper x or y axes ticks.
for i, j in zip(range(numvars), itertools.cycle((-1, 0))):
axes[j,i].xaxis.set_visible(True)
axes[i,j].yaxis.set_visible(True)
return fig
main()
My second question is more for the 'fun': how can I make the subplots perfectly squares?
I apologize to Joe Kington; I know my code is way less elegant than his... I just started few weeks ago. If you have any suggestions to improve mine, for example to make it more dynamic, I am very interesting.
You can rotate the xtick labels using setp.
from matplotlib.artist import setp
Then after you set the x tick positions for the top row and left column of subplot call:
setp(ax.get_xticklabels(), rotation=90)
To make the size of the subplots equal, you can fig.subplots_adjust to set the area of all the subplots to a square. Something like this:
gridSize = 0.6
leftBound = 0.5 - gridSize/2
bottomBound = 0.1
rightBound = leftBound + gridSize
topBound = bottomBound + gridSize
fig.subplots_adjust(hspace=0.05, wspace=0.05, left=leftBound,
bottom=bottomBound, right=rightBound, top=topBound)
If the figure size isn't square, you'll need to change the shape of the grid accordingly. Alternately, you could add each subplot axes individually with fig.add_axes. That will allow you to set the size directly but you'll also have to set the location.
Don't use bbox_inches='tight' to save the figure or you'll lose the title with these setting. You can save like this:
plt.savefig('ScatterplotMatrix.pdf',format='pdf', dpi=1000, transparent=True)
The resulting graph looks like this:

Categories

Resources