2017-01-27 2 views
1

Я использую boxplot в matplotlib (Python), чтобы создавать полевые диаграммы, я создаю много графиков с разными датами. На оси x данные дискретны.Как я могу указать дискретные значения, которые я хочу построить на оси x (matplotlib, boxplot)?

Значения по оси x в секундах составляют 0,25, 0,5, 1, 2, 5 .... 28800. Эти значения были выбраны произвольно (это периоды выборки). На некоторых графиках отсутствуют одно или два значения, поскольку данные недоступны. На этих графиках ось x изменяет размеры для распространения других значений.

Я хотел бы все графики имеют то же значение, в том же месте на оси х (не имеет значения, если ось й показывает значение, но нет никаких данных не нанесены на графике)

Может ли кто-нибудь сказать мне, есть ли способ указать значения оси x? Или другой способ сохранить одни и те же значения в одном и том же месте.

Соответствующий раздел кода выглядит следующим образом:


для I, группы в myDataframe.groupby ("Дата"):

graphFilename = (basename+'_' + str(i) + '.png') 
    plt.figure(graphFilename) 
    group.boxplot(by=["SamplePeriod_seconds"], sym='g+') ## colour = 'blue' 
    plt.grid(True) 
    axes = plt.gca() 
    axes.set_ylim([0,30000]) 
    plt.ylabel('Average distance (m)', fontsize =8) 
    plt.xlabel('GPS sample interval (s)', fontsize=8) 
    plt.tick_params(axis='x', which='major', labelsize=8) 
    plt.tick_params(axis='y', which='major', labelsize=8) 
    plt.xticks(rotation=90) 
    plt.title(str(i) + ' - ' + 'Average distance travelled by cattle over 24 hour period', fontsize=9) 
    plt.suptitle('') 
    plt.savefig(graphFilename) 
    plt.close()  

Любая оцененная помощь, я буду продолжить googling ... .thanks :)

+0

.... p.s. причина, по которой я хочу, чтобы ось была последовательной, так что я могу прорисовывать графики и легко сравнивать их. – shara

ответ

1

По умолчанию boxplot просто отображает доступные данные в последовательные положения по осям. Отсутствующие данные не учитываются, просто потому, что boxplot не знает, что они отсутствуют. Однако позиции ящиков можно установить вручную, используя аргумент positions. В следующем примере это и, следовательно, дает графики равных экстентов, даже когда значения отсутствуют.

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


basename = __file__+"_plot" 
Nd = 4 # four different dates 
Ns = 5 # five second intervals 
N = 80 # each 80 values 
date = [] 
seconds = [] 
avgdist = [] 
# fill lists 
for i in range(Nd): 
    # for each date, select a random SamplePeriod to be not part of the dataframe 
    w = np.random.randint(0,5) 
    for j in range(Ns): 
     if j!=w: 
      av = np.random.poisson(1.36+j/10., N)*4000+1000 
      avgdist.append(av) 
      seconds.append([j]*N) 
      date.append([i]*N) 

date = np.array(date).flatten() 
seconds = np.array(seconds).flatten() 
avgdist = np.array(avgdist).flatten() 
#put data into DataFrame 
myDataframe = pd.DataFrame({"Date" : date, "SamplePeriod_seconds" : seconds, "avgdist" : avgdist}) 
# obtain a list of all possible Sampleperiods 
globalunique = np.sort(myDataframe["SamplePeriod_seconds"].unique()) 

for i, group in myDataframe.groupby("Date"): 

    graphFilename = (basename+'_' + str(i) + '.png') 
    fig = plt.figure(graphFilename, figsize=(6,3)) 
    axes = fig.add_subplot(111) 
    plt.grid(True) 

    # omit the `dates` column 
    dfgroup = group[["SamplePeriod_seconds", "avgdist"]] 
    # obtain a list of Sampleperiods for this date 
    unique = np.sort(dfgroup["SamplePeriod_seconds"].unique()) 
    # plot the boxes to the axes, one for each sample periods in dfgroup 
    # set the boxes' positions to the values in unique 
    dfgroup.boxplot(by=["SamplePeriod_seconds"], sym='g+', positions=unique, ax=axes) 

    # set xticks to the unique positions, where boxes are 
    axes.set_xticks(unique) 
    # make sure all plots share the same extent. 
    axes.set_xlim([-0.5,globalunique[-1]+0.5]) 
    axes.set_ylim([0,30000]) 

    plt.ylabel('Average distance (m)', fontsize =8) 
    plt.xlabel('GPS sample interval (s)', fontsize=8) 
    plt.tick_params(axis='x', which='major', labelsize=8) 
    plt.tick_params(axis='y', which='major', labelsize=8) 
    plt.xticks(rotation=90) 
    plt.suptitle(str(i) + ' - ' + 'Average distance travelled by cattle over 24 hour period', fontsize=9) 
    plt.title("") 
    plt.savefig(graphFilename) 
    plt.close()  

enter image description here
enter image description here

Это все равно будет работать, если значения в полях SamplePeriod_seconds columnare без равноотстоящего, но, конечно, если они очень разные, это не будет производить хорошие результаты, так как бары будут overlapp:

enter image description here

Это, однако, не является проблемой построения себя , И для дальнейшей помощи нужно знать, как вы ожидаете, что график будет выглядеть в конце.

+0

спасибо большое! Я посмотрю на это и вернусь к вам, в тот момент, когда я пытаюсь понять, как читать значения, используемые графиком на оси x, определить, какие значения он пропустил, а затем соответственно отрегулируйте расстояние. Цените помощь. – shara

+0

Я бы порекомендовал выяснить недостающие части перед графикой (как, например, в приведенном выше коде, используя 'unique'). Это позволяет использовать аргумент 'position' для использования и дает вам полный контроль. – ImportanceOfBeingErnest

+0

спасибо! :) сделаю, я поеду завтра или в воскресенье (почти в 12 утра, где я нахожусь сейчас), я думаю, что сейчас учусь. Большое спасибо за помощь! – shara

1

если вы попробуете что-то вроде:

plt.xticks(np.arange(x.min(), x.max(), 5)) 

где x - ваш массив значений x и 5 шагов, которые вы выполняете вдоль оси.

То же самое относится к оси y с yticks. Надеюсь, поможет! :)

EDIT:

я удалил экземпляры, которые у меня не было, но следующий код должен дать вам сетку, чтобы построить на:

import matplotlib.pyplot as plt 
import numpy as np 


plt.grid(True) 
axes = plt.gca() 
axes.set_ylim([0, 30000]) 
plt.ylabel('Average distance (m)', fontsize=8) 
plt.xlabel('GPS sample interval (s)', fontsize=8) 
plt.tick_params(axis='x', which='major', labelsize=8) 
plt.tick_params(axis='y', which='major', labelsize=8) 
plt.xticks(rotation=90) 
plt.suptitle('') 
my_xticks =[0.25,0.5,1,2,5,10,20,30,60,120,300,600,1200,1800,2400,3‌000,3600,7200,10800,‌​ 14400,18000,21600,25‌​200,28800] 
x = np.array(np.arange(0, len(my_xticks), 1)) 

plt.xticks(x, my_ticks) 
plt.show() 

Попробуйте подключить в ваших значений на вершине из этого:

+0

спасибо большое! Я пробовал это, у меня пока нет работы, но надеюсь, если я продолжу и попробую несколько вещей, сообщит вам об этом ... – shara

+0

Хмм, я думаю, что это не работает, потому что мои значения оси x не являются но я пытаюсь равномерно распределить их по оси. Это: (0,25,0,5,1,2,5,10,20,30,60,120,300,600,1200,1800,2400,3000,3600,7200,10800,14400,18000,21600,25200,28800). Большое спасибо за вашу помощь! Я буду продолжать попытки, мне удалось получить их по оси x, но тогда это просто построение результатов по порядку, а не соответствует значению, показанному на оси. Возможно, мне также нужно выяснить, какой тип данных он использует при построении значений, мы надеемся, что они будут плавать, но они могут быть строками или чем-то еще. – shara

+0

Что вы имеете в виду равномерно по оси? В числовом смысле это не имеет смысла, но вы можете это сделать ** см. Выше edit :) – JB1

0

Спасибо всем за помощь, используя ваши ответы. Я получил ее работу со следующим кодом. (Я понимаю, что он, вероятно, может быть улучшен, но счастлив, что он работает, я могу посмотреть на данные сейчас :))

valuesShouldPlot = ['0.25','0.5','1.0','2.0','5.0','10.0','20.0','30.0','60.0','120.0','300.0','600.0','1200.0','1800.0','2400.0','3000.0','3600.0','7200.0','10800.0','14400.0','18000.0','21600.0','25200.0','28800.0']  


for xDate, group in myDataframe.groupby("Date"):   ## for each date 

    graphFilename = (basename+'_' + str(xDate) + '.png') ## make up a suitable filename for the graph 

    plt.figure(graphFilename) 

    group.boxplot(by=["SamplePeriod_seconds"], sym='g+', return_type='both') ## create box plot, (boxplots are placed in default positions) 

    ## get information on where the boxplots were placed by looking at the values on the x-axis              
    axes = plt.gca() 
    checkXticks= axes.get_xticks() 
    numOfValuesPlotted =len(checkXticks)   ## check how many boxplots were actually plotted by counting the labels printed on the x-axis 
    lengthValuesShouldPlot = len(valuesShouldPlot) ## (check how many boxplots should have been created if no data was missing) 



    if (numOfValuesPlotted < valuesShouldPlot): ## if number of values actually plotted is less than the maximum possible it means some values are missing 
               ## if that occurs then want to move the plots across accordingly to leave gaps where the missing values should go 


     labels = [item.get_text() for item in axes.get_xticklabels()] 

     i=0     ## counter to increment through the entire list of x values that should exist if no data was missing. 
     j=0     ## counter to increment through the list of x labels that were originally plotted (some labels may be missing, want to check what's missing) 

     positionOfBoxesList =[] ## create a list which will eventually contain the positions on the x-axis where boxplots should be drawn 

     while (j < numOfValuesPlotted): ## look at each value in turn in the list of x-axis labels (on the graph plotted earlier) 

      if (labels[j] == valuesShouldPlot[i]): ## if the value on the x axis matches the value in the list of 'valuesShouldPlot' 
       positionOfBoxesList.append(i)  ## then record that position as a suitable position to put a boxplot 
       j = j+1 
       i = i+1 


      else :         ## if they don't match (there must be a value missing) skip the value and look at the next one    

       print("\n******** missing value ************") 
       print("Date:"), 
       print(xDate), 
       print(", Position:"), 
       print(i), 
       print(":"), 
       print(valuesShouldPlot[i]) 
       i=i+1    


     plt.close()  ## close the original plot (the one that didn't leave gaps for missing data) 
     group.boxplot(by=["SamplePeriod_seconds"], sym='g+', return_type='both', positions=positionOfBoxesList) ## replot with boxes in correct positions 

    ## format graph to make it look better   
    plt.ylabel('Average distance (m)', fontsize =8) 
    plt.xlabel('GPS sample interval (s)', fontsize=8) 
    plt.tick_params(axis='x', which='major', labelsize=8) 
    plt.tick_params(axis='y', which='major', labelsize=8) 
    plt.xticks(rotation=90) 
    plt.title(str(xDate) + ' - ' + 'Average distance travelled by cattle over 24 hour period', fontsize=9) ## put the title above the first subplot (ie. at the top of the page) 
    plt.suptitle('') 
    axes = plt.gca() 
    axes.set_ylim([0,30000]) 

    ## save and close 
    plt.savefig(graphFilename) 
    plt.close()   
Смежные вопросы