Как получить логарифмические оси для графика плотности с помощью matplotlib?

#python #matplotlib

#python #matplotlib

Вопрос:

Я пытаюсь создать график плотности 2D (из некоторых данных моделирования) с помощью matplotlib. Мои данные x и y определяются как log10 некоторых величин. Как я могу получить логарифмические оси (с небольшими отметками в журнале)?

Вот пример моего кода:

 import numpy as np
import matplotlib.pyplot as plt

Data = np.genfromtxt("data") # A 2-column data file
x = np.log10(Data[:,0])
y = np.log10(Data[:,1])

xmin = x.min()
xmax = x.max()
ymin = y.min()
ymax = y.max()

fig = plt.figure()
ax = fig.add_subplot(111)

hist = ax.hexbin(x,y,bins='log', gridsize=(30,30), cmap=cm.Reds)
ax.axis([xmin, xmax, ymin, ymax])

plt.savefig('plot.pdf')
  

Ответ №1:

Из строки документации matplotlib.pyplot.hist похоже, что есть аргумент ‘log’, для которого нужно установить значение ‘True’, если вы хотите масштаб журнала по оси.

 hist(x, bins=10, range=None, normed=False, cumulative=False,
     bottom=None, histtype='bar', align='mid',
     orientation='vertical', rwidth=None, log=False, **kwargs)

log:
If True, the histogram axis will be set to a log scale. If log is True and x is a 1D
array, empty bins will be filtered out and only the non-empty (n, bins, patches) will be
returned.
  

Существует также функция pyplot.loglog для построения графика с логарифмическим масштабированием по осям x и y.

Ответ №2:

Большое вам спасибо за предложения.

Ниже я присоединяюсь к своему собственному решению. Вряд ли это «минимальный рабочий пример», но я уже довольно сильно урезал свой скрипт!

В двух словах, я использовал imshow для построения «изображения» (2D-гистограммы с ячейками журнала) и удаляю оси. Затем я рисую второй, пустой (и прозрачный) график, точно поверх первого графика, чтобы получить логарифмические оси, поскольку imshow, похоже, этого не позволяет. Довольно сложно, если вы спросите меня!

Мой код, вероятно, далек от оптимального, поскольку я новичок в python и matplotlib…

Кстати, я не использую hexbin по двум причинам: 1) Он слишком медленный для работы с очень большими файлами данных, такими как у меня. 2) В версии, которую я использую, шестиугольники немного слишком велики, т. Е. Они перекрываются, что приводит к «пикселям» неправильных форм и размеров. Кроме того, я хочу иметь возможность записывать данные гистограммы в файл в текстовом формате.

 #!/usr/bin/python

# How to get log axis with a 2D colormap (i.e. an "image") ??
#############################################################
#############################################################

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

# Data file containing 2D data in log-log coordinates.
# The format of the file is 3 columns : x y v
# where v is the value to plotted for coordinate (x,y)
# x and y are already log values
# For instance, this can be a 2D histogram with log bins.
input_file="histo2d.dat"

# Parameters to set space for the plot ("bounding box")
x1_bb, y1_bb, x2_bb, y2_bb = 0.125, 0.12, 0.8, 0.925

# Parameters to set space for colorbar
cb_fraction=0.15
cb_pad=0.05

# Return unique values from a sorted list, will be required later
def uniq(seq, idfun=None): 
    # order preserving
    if idfun is None:
        def idfun(x): return x
    seen = {}
    result = []
    for item in seq:
        marker = idfun(item)
        # in old Python versions:
        # if seen.has_key(marker)
        # but in new ones:
        if marker in seen: continue
        seen[marker] = 1
        result.append(item)
    return result

# Read data from file. The format of the file is 3 columns : x y v
# where v is the value to plotted for coordinate (x,y)

Data = np.genfromtxt(input_file)
x = Data[:,0]
y = Data[:,1]
v = Data[:,2]

# Determine x and y limits and resolution of data

x_uniq = np.array(uniq(np.sort(x)))
y_uniq = np.array(uniq(np.sort(y)))

x_resolution = x_uniq.size
y_resolution = y_uniq.size

x_interval_length = x_uniq[1]-x_uniq[0]
y_interval_length = y_uniq[1]-y_uniq[0]

xmin = x.min()
xmax = x.max() 0.5*x_interval_length
ymin = y.min()
ymax = y.max() 0.5*y_interval_length

# Reshape 1D data to turn it into a 2D "image"

v = v.reshape([x_resolution, y_resolution])
v = v[:,range(y_resolution-1,-1,-1)].transpose()

# Plot 2D "image" 
# ---------------

# I use imshow which only work with linear axes.
# We will have to change the axes later...

axis_lim=[xmin, xmax, ymin, ymax]

fig = plt.figure()
ax = fig.add_subplot(111)
extent = [xmin, xmax, ymin, ymax]
img = plt.imshow(v, extent=extent, interpolation='nearest', cmap=cm.Reds, aspect='auto')
ax.axis(axis_lim)

# Make space for the colorbar
x2_bb_eff = (x2_bb-(cb_fraction cb_pad)*x1_bb)/(1.0-(cb_fraction cb_pad))
ax.set_position([x1_bb, y1_bb, x2_bb_eff-x1_bb, y2_bb-y1_bb])
position = ax.get_position()

# Remove axis ticks so that we can put log ticks on top
ax.set_xticks([])
ax.set_yticks([])

# Add colorbar
cb = fig.colorbar(img,fraction=cb_fraction,pad=cb_pad)
cb.set_label('Value [unit]')

# Add logarithmic axes
# --------------------

# Empty plot on top of previous one. Only used to add log axes.
ax = fig.add_subplot(111,frameon=False)
ax.set_xscale('log')
ax.set_yscale('log')
plt.plot([])
ax.set_position([x1_bb, y1_bb, x2_bb-x1_bb, y2_bb-y1_bb])

axis_lim_log=map(lambda x: 10.**x, axis_lim)
ax.axis(axis_lim_log)

plt.grid(b=True, which='major', linewidth=1)
plt.ylabel('Some quantity [unit]')
plt.xlabel('Another quantity [unit]')

plt.show()
  

Ответ №3:

Ответ от @gcalmettes относится к pyplot.hist . Подпись для pyplot.hexbin немного отличается:

 hexbin(x, y, C = None, gridsize = 100, bins = None,
             xscale = 'linear', yscale = 'linear',
             cmap=None, norm=None, vmin=None, vmax=None, alpha=None, linewidths=None,
             edgecolors='none', reduce_C_function = np.mean, mincnt=None, marginals=True,
             **kwargs)
  

Вас интересует xscale параметр:

 *xscale*: [ 'linear' | 'log' ]
    Use a linear or log10 scale on the horizontal axis.