15

I'm using a seaborn jointplot for scatterplotting purposes, but I can't seem to get a simple diagonal line going across... I'm getting a AttributeError: 'JointGrid' object has no attribute 'get_xlim'. Does anyone know a workaround using Seaborn?

Here's my code (also the title doesn't show up! what gives):

ax = sns.jointplot(x="Av Tomato-meter", y="Av Audience Score", data=director_combined_ratings, stat_func = None, 
                   size = 8, xlim=(0,100), ylim=(0,100))

ax.plot(ax.get_xlim(), ax.get_ylim(), ls="--", c=".3") #this is the error line.

ax.title = "Average Tomato-meter vs Audience Score for Directors with over 10 Movies"

thanks in advance everyone.

SpicyClubSauce
  • 4,076
  • 13
  • 37
  • 62

1 Answers1

28

The error was a useful hint: a JointGrid organizes several subplots, you have to find the specific ax to plot onto. :

import numpy as np
import pandas as pd
import seaborn as sns
from matplotlib.pyplot import show
sns.set_style('darkgrid')

# Generate a random correlated bivariate dataset
# https://stackoverflow.com/questions/16024677/generate-correlated-data-in-python-3-3

rs = np.random.RandomState(5)
mean = [0, 0]
cov = [[2, .1],
       [.5, 3]]  # make it asymmetric as a better test of x=y line
y = np.random.multivariate_normal(mean, cov, 500, tol=1e-4)

# Show the joint distribution using kernel density estimation
g = sns.jointplot(x=y[:,0], y=y[:,1],
                  kind="kde",
                  fill="true", height=5, space=0, levels=7)

# Draw a line of x=y 
x0, x1 = g.ax_joint.get_xlim()
y0, y1 = g.ax_joint.get_ylim()
lims = [max(x0, y0), min(x1, y1)]
g.ax_joint.plot(lims, lims, '-r')
show()

A jointplot shows the density view of a "mountain", with the projections along the X and Y axes plotted above and to the right. The x=y line is plotted in red.

I figured this out in an interpreter: dir(g), then g.plot?, g.plot_joint? -- those are plotting functions specific to the jointplot -- what else was there? -- dir(g.ax_joint); aha, there's set_ylim, etc.

The diagonal line is the x=y line, but note that it isn't the 45deg diagonal of the pixels of the central plot. The seaborn jointplot function always draws a square central plot. When the data is asymmetric the X and Y axes of the plot will change to fit into the square. The variable lims holds the edges of the display in data coordinates.

There's a comment suggesting a diagonal plotted that will always be the diagonal of the display, but it isn't the line of equality of the data. Here are a few lines to add to test this and figure out which you want:

# This will always go from corner to corner of the displayed plot
g.ax_joint.plot([0,1], [0,1], ':y', transform=g.ax_joint.transAxes)

# This is the x=y line using transforms
g.ax_joint.plot(lims, lims, 'w', linestyle='dashdot', transform=g.ax_joint.transData)

# This is a simple way of checking which is x=y
g.ax_joint.scatter(x=[0, 2],y=[0,2], s=30,c= 'w',marker='o')
show()

The previous plot, with two more lines plotted, one the 45deg diagonal of the center plot, the other x=y. Also (0,0) and (2,2) have been plotted as points to verify x=y.

cphlewis
  • 15,759
  • 4
  • 46
  • 55
  • I'm trying to do this almost verbatim and the line won't display. Anything else I need to do to make this work in 2019? – Sledge Jun 27 '19 at 18:14
  • Your jointplot is fine, but the additional line won't display? I just reran this a couple times in ipython and it worked (with one parameter name update). We maybe need to compare library/language version numbers. Or are you getting any error messages? – cphlewis Jun 27 '19 at 19:33
  • Thats because last code block used to draw diagonal is wrong. From [this SO answer](https://stackoverflow.com/questions/22104256/does-matplotlib-have-a-function-for-drawing-diagonal-lines-in-axis-coordinates), you might rather use: `g.ax_joint.plot([0, 1], [0, 1], ':k', transform=g.ax_joint.transAxes)` – H4dr1en Mar 18 '20 at 13:34