Question

This is perhaps an unusual graph that I am trying to make, so I've attached an illustration. I'm not sure if it is possible in matplotlib, so I thought I'd ask here for how to do it.

https://i.stack.imgur.com/WQucW.jpg

Basically I'd like to plot a histogram (with hist()) on its side and then on top, overlay a line graph (with plot()), keeping the axis the same for the y on both sides.

Additionally I think it would only work if the histogram can have a lower opacity. Not sure if opacity can be set per plot instead of per figure.

Code so far:

import numpy as np
import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure()
ax1 = fig.add_subplot(111)
line = [0.2, 0.3, 0.37, 0.4, 0.6, 0.7, 0.72, 0.75, 0.77, 0.78, 0.79, 0.795] 
distribution = [0.2, 0.3, 0.3, 0.4, 0.7, 0.7, 0.7, 0.8]

plt.hist(distribution, orientation='horizontal')
plt.plot(range(len(line)), line, color='grey')

plt.savefig("test.png")

The histogram doesn't show up.

How can I do this?

Was it helpful?

Solution

You just need to use twinx/twiny twice to get two independent axes (there are probably ways to do this with out making a un-used middle axes, but this takes care a bunch of the behind-the-scenes details for you):

import matplotlib.pyplot as plt
import numpy as np

line = [0.2, 0.3, 0.37, 0.4, 0.6, 0.7, 0.72, 0.75, 0.77, 0.78, 0.79, 0.795]
distribution = [0.2, 0.3, 0.3, 0.4, 0.7, 0.7, 0.7, 0.8]

fig, ax = plt.subplots(1, 1)

ax2 = ax.twinx()
ax3 = ax2.twiny()

ax.plot(line)
ax.set_xlabel('line xaxis')
ax.set_ylabel('line yaxis')

ax3.hist(distribution, orientation='horizontal', alpha=.5)
ax3.invert_xaxis()
ax3.set_xlabel('hist xaxis, note where 0 is')
# note this needs to be ax2 due to subtle overlay issues....
ax2.set_ylabel('hist yaxis')
plt.draw()

You will have to play with the details of the axis (limit, labels, ticks ect), but ax and ax3 are independent and you can apply the standard tactics to each independently.

enter image description here

OTHER TIPS

I used your code, and it rendered just fine, but then I switched to plotting using the axes to be a little bit more canon and a little less surprising. When you plot using axes, you generate an Artist object, but when you plot using plt, you generate a list of Artist objects.

import numpy as np
import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure()
ax  = plt.gca()

line = [0.2, 0.3, 0.37, 0.4, 0.6, 0.7, 0.72, 0.75, 0.77, 0.78, 0.79, 0.795] 
distribution = [0.2, 0.3, 0.3, 0.4, 0.7, 0.7, 0.7, 0.8]

ax.hist(distribution, orientation='horizontal', alpha=.5)
ax.plot(np.linspace(0,4,len(line)), line, color='grey', linewidth=2)

plt.show()

enter image description here

Beyond that, it's not clear what other functionality you'd like to see! There are many great tools within matplotlib, and having an axis-centric perspective is likely to make things a little clearer.

Here is a partial solution - I used a bar chart instead of a histogram because I couldn't figure out how to do the histogram sideways and overlaid.

from pylab import figure, show
import numpy as np
import matplotlib.pyplot as plt

people = ('Tom', 'Dick', 'Harry', 'Slim', 'Jim')
y_pos_hist = np.arange(len(people))
performance = 10*np.random.rand(len(people))

x_for_line = np.linspace(0,10)
y_for_line = np.cos(x_for_line)

fig = figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()


ax1.plot(x_for_line, y_for_line)
ax2.barh(y_pos_hist, performance, alpha=0.2)
#alpha = 0.2 is what changes the opacity of the bars

plt.yticks(y_pos_hist, people)

plt.show()

enter image description here

The bar chart part is from this example

Consider this example, too

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top