Using Seaborn's relplot instead of Matplotlib's plot - matplotlib

I have a line graph built using matplotlib with the following code:
f = plt.figure(figsize=(20, 7))
sns.set_style("darkgrid")
ax = plt.subplot(111)
df.plot(x='Date', y=['Burglary',
'Criminal Damage',
'Criminal Damage',
'Drugs',
'Fraud or Forgery',
'Robbery',
'Sexual Offences',
'Theft and Handling',
'Violence Against The Person',
'Other Notifiable Offences'], ax=f.gca())
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
plt.show()
It works fine. df.head() looks like:
When I try to use relplot from Seaborn, I get the following error:
ValueError: could not broadcast input array from shape (10) into shape (105)
Modified code is as follows:
f = plt.figure(figsize=(20, 7))
sns.set_style("darkgrid")
ax = plt.subplot(111)
sns.relplot(data=df, x='Date', y=['Burglary',
'Criminal Damage',
'Criminal Damage',
'Drugs',
'Fraud or Forgery',
'Robbery',
'Sexual Offences',
'Theft and Handling',
'Violence Against The Person',
'Other Notifiable Offences'], ax=f.gca())
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
plt.show()
Does the dataframe need to be in some different structure or am I missing something in the code? I want to use Seaborn so I can turn on or off the different categories so the graph is more readable when presenting.
Thanks in advance.

Related

How to align a single legend over two seaborn barplots?

I would like to have a single legend that nicely fits on top of both the subplots (doesn't necessarily need to span the entire width of the plots, but needs to be outside the plot). I know you can work with bbox_to_anchor() but somehow this doesn't seem to work nicely. It always moves one subplot away.
fig, ax = plt.subplots(1, 2)
sns.barplot(x="day", y="total_bill", hue="sex", data=tips, ax = ax[0])
ax[0].legend_.remove()
sns.barplot(x="day", y="total_bill", hue="sex", data=tips, ax = ax[1])
sns.move_legend(ax[1], loc = "center", bbox_to_anchor=(-0.5, 1.1), ncol=2, title=None, frameon=False)
fig.tight_layout()
There are a couple of ways that I would approach closing the gap.
1: Use a sns.catplot:
This potentially requires doubling your data, though if you're plotting different variables in each subplot you may be able to melt your data
import pandas as pd
import seaborn as sns
# Load the dataset twice
tips_a = sns.load_dataset("tips")
tips_b = sns.load_dataset("tips")
# Add a dummy facet variable
tips_a["col"] = "A"
tips_b["col"] = "B"
# Concat them
tips = pd.concat([tips_a, tips_b])
# Use the dummy variable for the `col` param
g = sns.catplot(x="day", y="total_bill", hue="sex", data=tips, kind="bar", col="col")
# Remove the titles and move the legend
g.set_titles("")
sns.move_legend(g, loc="upper center", ncol=2, title=None, frameon=False)
2: autoscale the axes
This still requires a little bit of bbox_to_anchor fiddling and you probably want to change the right y-axis label (and ticks/ticklabels).
import matplotlib.pyplot as plt
import seaborn as sns
fig, ax = plt.subplots(1, 2, figsize=(7, 4))
sns.barplot(x="day", y="total_bill", hue="sex", data=tips, ax=ax[0])
ax[0].legend_.remove()
sns.barplot(x="day", y="total_bill", hue="sex", data=tips, ax=ax[1])
sns.move_legend(
ax[1],
loc="upper center",
bbox_to_anchor=(-0.1, 1.1),
ncol=2,
title=None,
frameon=False,
)
ax[0].autoscale()
ax[1].autoscale()

Threshold Otsu: AttributeError: 'AxesSubplot' object has no attribute 'ravel'

I loaded nifty files(These were as well converted from .pack CT scans). My goal is to use the threashold otsu algorithm to mask it from the background and compare the two images. When I try to plot I get the error
AttributeError: 'AxesSubplot' object has no attribute 'ravel'
Below is the code and attached is a screenshot.
import SimpleITK as sitk
import matplotlib.pyplot as plt
import numpy as np
from skimage.filters import threshold_otsu
#THRESHOLD OTSU
img = sitk.GetArrayFromImage(sitk.ReadImage("\\\\x.x.x.x/users/ddff/python/nifts/prr_ipsi.nii"))
print(img.shape)
thresh = threshold_otsu(img.flatten())
#thresh = thresh.reshape(img.shape)
binary = img <= thresh
#I can plot this image slice fine
plt.imshow(img[20,:,:])
fig, axes = plt.subplots(ncols=1)
ax = axes.ravel()
ax[0] = plt.subplot(1, 3, 1)
ax[1] = plt.subplot(1, 3, 2)
ax[2] = plt.subplot(1, 3, 3, sharex=ax[0], sharey=ax[0])
ax[0].imshow(img[20,:,:], cmap=plt.cm.gray)
ax[0].set_title('Original Breast Delineation')
ax[0].axis('off')
ax[1].hist(thresh, bins=256)
ax[1].set_title('Histogram ')
ax[1].axvline(thresh, color='r')
ax[2].imshow(binary[20,:,:], cmap=plt.cm.gray)
ax[2].set_title('Thresholded')
ax[2].axis('off')
plt.show()[enter image description here][1]
axes is just a single figure with 1 column so there is nothing to ravel or flatten. It will work if you have more than one sub plot. Nevertheless, you can do the following without ravel if you have only a single row or a single column.
fig, ax = plt.subplots(ncols=3, sharex=True, sharey=True)
ax[0].imshow(img[20,:,:], cmap=plt.cm.gray)
ax[0].set_title('Original Breast Delineation')
ax[0].axis('off')
ax[1].hist(thresh, bins=256)
ax[1].set_title('Histogram ')
ax[1].axvline(thresh, color='r')
ax[2].imshow(binary[20,:,:], cmap=plt.cm.gray)
ax[2].set_title('Thresholded')
ax[2].axis('off')
In case you want a 2d matrix of subplot instances, you can use Thomas Kühn's suggestion.
fig, ax = plt.subplots(ncols=3, sharex=True, sharey=True, squeeze=False)
and then you can access the subplots as
ax[0][0].imshow()
ax[0][1].imshow()
......

Ipython - plot pie chart from series with series table next to it

I have a matplotlib pie chart in Ipython notebook with a plt.text series table posted next to it. The problem is the table is formated as series output and not as a nice table. What am I doing wrong?
sumByGroup = df['dollar charge'].groupby(df['location']).sum().astype('int')
sumByGroup.plot(kind='pie', title='DOLLARS', autopct='%1.1f%%')
plt.axis('off')
plt.text(2, -0.5, sumByGroup, size=12)
I think the problem is that you're calling groupby on df['dollar change'] rather than the df as a whole. Try this instead,
sumByGroup = df.groupby(df['location']).sum().astype('int')
sumByGroup.plot(y='dollar charge', kind='pie', title='DOLLARS', autopct='%1.1f%%')
plt.axis('off')
plt.text(2, -0.5, sumByGroup, size=12)
Full working example with made up data.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
n = 20
locations = ['MD', 'DC', 'VA', 'NC', 'NY']
df = pd.DataFrame({'dollar charge': np.random.randint(28, 53, n),
'location': np.random.choice(locations, n),
'Col A': np.random.randint(-5, 5, n),
'Col B': np.random.randint(-5, 5, n)})
sumByGroup = df.groupby(df['location']).sum()
fig, ax = plt.subplots()
sumByGroup.plot(y='dollar charge', kind='pie', title='DOLLARS',
autopct='%1.1f%%', legend=False, ax=ax)
ax.axis('off')
ax.text(2, -0.5, sumByGroup, size=12)
ax.set_aspect('equal')

Align ylabel with yticks

The code below draws a plot that looks almost exactly the way I want it to be. However, I'd like the ylabel to be horizontal and left-aligned with the yticks. Currently, the ylabel is placed left relative to the yticks which looks ugly (the image below shows the upper left corner of the plot). Does someone know how to fix this?
import matplotlib.pyplot as plt
import numpy as np
xvals = range(0,10);
yvals = lambda s: [ x*x*s for x in xvals ]
# setting the x=... option does NOT help
yprops = dict(rotation=0, y=1.05, horizontalalignment='left')
plt.subplot(111,axisbg='#BBBBBB',alpha=0.1)
plt.grid(color='white', alpha=0.5, linewidth=2, linestyle='-', axis='y')
for spine_name in ['top', 'left', 'right']:
plt.gca().spines[spine_name].set_color('none')
plt.ylabel('y label', **yprops)
plt.xlabel('x label')
plt.gca().tick_params(direction='out', length=0, color='k')
plt.plot(xvals, yvals(1), 'bo-', linewidth=2)
plt.gca().set_axisbelow(True)
plt.show()
You can adjust the coordinates using ax.yaxis.set_label_coords like in this example.
With your data:
import matplotlib.pyplot as plt
import numpy as np
xvals = range(0,10);
yvals = lambda s: [ x*x*s for x in xvals ]
yprops = dict(rotation=0, x=0, y=1.05)
fig, ax = plt.subplots(1, 1, figsize=(5,3))
ax.set_ylabel('y label', **yprops )
ax.set_xlabel('x label')
ax.plot(xvals, yvals(1), 'bo-', linewidth=2)
print(ax.get_position())
ax.yaxis.set_label_coords(-0.1,1.05)
fig.savefig('cucu.png')
plt.show()
Note that if you go further away, the label will be placed outside the figure. If that is the case, you can adjust the margins before:
fig, ax = plt.subplots(1, 1, figsize=(5,3))
ax.set_ylabel('y label', **yprops )
ax.set_xlabel('x label')
ax.plot(xvals, yvals(1), 'bo-', linewidth=2)
fig.subplots_adjust(left=0.2, bottom=0.2, right=0.8, top=0.8)
ax.yaxis.set_label_coords(-0.2,1.2)
fig.savefig('cucu2.png')
plt.show()
See also this answer

Keywords arguments in matplotlib radviz

I am trying to understand the keyword arguments that can be used in matplotlib radviz. I am using the well-known iris dataset, and the simple code below:
import pandas as pd
plt.xkcd()
iris = pd.read_csv("iris.csv")
pd.tools.plotting.radviz(iris, "name")
Generating the following chart:
How can I setup the dimensions (x, y) and the title of the chart? How can I specify the placement of the legend? What other arguments (if any) can be used with radviz?
Thank you very much for your help.
all the pandas plotting tools take an ax argument, you can make the axis and pass to the plotting function:
fig = plt.figure( )
ax = fig.add_axes( [.05, .05, .9, .9], title='whatever title' )
pd.tools.plotting.radviz( iris, 'name', ax=ax )
then if you need to change the legend, you may do:
ax.legend( loc='center right', fontsize='medium' )
or change the title:
ax.set_title( 'new title' )
alternatively, i believe the plotting tools return the axis after plotting, so you may do
ax = pd.tools.plotting.radviz( iris, 'name')
and check dir( ax ) for some of the functionality available.
with plt.xkcd( ):
ax = pd.tools.plotting.radviz(df, 'Name')
ax.legend( loc='center left', bbox_to_anchor=(0, 1),
fontsize='medium', fancybox=True, ncol=3 )
ax.set_xlim( -1.6, 1.6, emit=True, auto=False )
ax.set_title( 'iris - radviz', loc='right' )