1

I have a pair of lists of numbers representing points in a 2-D space, and I want to represent the y/x ratios for these points as a 1-dimensional heatmap, with a diverging color map centered around 1, or the logs of my ratios, with a diverging color map centered around 0.

How do I do that?

My current attempt (borrowing somewhat from Heatmap in matplotlib with pcolor?):

from matplotlib import numpy as np
import matplotlib.pyplot as plt
# There must be a better way to generate arrays of random values
x_values = [np.random.random() for _ in range(10)]
y_values = [np.random.random() for _ in range(10)]
labels = list("abcdefghij")
ratios = np.asarray(y_values) / np.asarray(x_values)
axis = plt.gca()
# I transpose the array to get the points arranged vertically
heatmap = axis.pcolor(np.log2([ratios]).T, cmap=plt.cm.PuOr)
# Put labels left of the colour cells
axis.set_yticks(np.arange(len(labels)) + 0.5, minor=False)
# (Not sure I get the label order correct...)
axis.set_yticklabels(labels)
# I don't want ticks on the x-axis: this has no meaning here
axis.set_xticks([])
plt.show()

Some points I'm not satisfied with:

  • The coloured cells I obtain are horizontally-elongated rectangles. I would like to control the width of these cells and obtain a column of cells.
  • I would like to add a legend for the color map. heatmap.colorbar = plt.colorbar() fails with RuntimeError: No mappable was found to use for colorbar creation. First define a mappable such as an image (with imshow) or a contour set (with contourf).

One important point:

  • matplotlib/pyplot always leaves me confused: there seems to be a lot of ways to do things and I get lost in the documentation. I never know what would be the "clean" way to do what I want: I welcome suggestions of reading material that would help me clarify my very approximative understanding of these things.
Community
  • 1
  • 1
bli
  • 7,549
  • 7
  • 48
  • 94
  • 1
    I felt the same way when I first started using matplotlib. I found looking at [examples](http://matplotlib.org/examples/) very helpful. Also, I know that you didn't ask this in your question, but to answer the question in the comment in your code, yes, there's a simpler way: np.random.random() takes a size argument and can return an array of random numbers: `x_values, y_values = np.random.random((2, 10))` – Amy Teegarden Aug 27 '15 at 18:23

1 Answers1

3

Just 2 more lines:

axis.set_aspect('equal') # X scale matches Y scale
plt.colorbar(mappable=heatmap) # Tells plt where it should find the color info.

Can't answer your final question very well. Part of it is due to we have two branches of doing things in matplotlib: the axis way (axis.do_something...) and the MATLAB clone way plt.some_plot_method. Unfortunately we can't change that, and it is a good feature for people to migrate into matplotlib. As far as the "Clean way" is concerned, I prefer to use whatever produces the shorter code. I guess that is inline with Python motto: Simple is better than complex and Readability counts.

enter image description here

CT Zhu
  • 52,648
  • 17
  • 120
  • 133
  • In my test code, the `axis.set_aspect('equal')` worked. But in my real code, I had a `plt.axis("tight")` that seemed to force the cells to fill the available width on the figure. When I remove it, I obtain a thin column of coloured cells, but the column is topped by extra white cells, and there is a lot of white space at the left of the figure. – bli Aug 28 '15 at 15:27
  • `axis.set_ylim((0, len(labels)))` solves the problem of the white cells topping the column. I still can't find how to get the figure not to have a lot of blank space on the left. – bli Aug 28 '15 at 16:50
  • Using `bbox_inches='tight'`in the `savefig` options instead of `plt.axis("tight")` solves the other problem. – bli Aug 28 '15 at 16:57