【问题标题】:Line chart in matplotlib with a double axis(strings on the axis)matplotlib 中带有双轴的折线图(轴上的字符串)
【发布时间】:2017-05-04 16:24:15
【问题描述】:

我正在尝试使用 python 从 Excel 工作表中的数据创建图表。数据是这样的

       Location Values
Trial 1 Edge    12
         M-2    13
       Center   14
         M-4    15
         M-5    12
         Top    13
Trial 2 Edge    10
        N-2     11
      Center    11
        N-4     12
        N-5     13
        Top     14
Trial 3 Edge    15
        R-2     13
     Center     12
       R-4      11
       R-5      10
       Top       3

我希望我的图表如下所示: Chart-1 . 图表应将 Location 列的值作为 X 轴,即字符串对象。这可以很容易地完成(通过使用/创建位置作为数组),

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
datalink=('/Users/Maxwell/Desktop/W1.xlsx')
df=pd.read_excel(datalink,skiprows=2)
x1=df.loc[:,['Location']]
x2=df.loc[:,['Values']]
x3=np.linspace(1,len(x2),num=len(x2),endpoint=True)
vals=['Location','Edge','M-2','Center','M-4','M-5','Top','Edge','N-2','Center','N-4','N-5','Top','Edge','R-2']
plt.figure(figsize=(12,8),dpi=300)
plt.subplot(1,1,1)
plt.xticks(x3,vals)
plt.plot(x3,x2)
plt.show()

但是,我还想在 X 轴上显示 Trial-1、Trial-2 ..。到目前为止,我一直在使用 Excel 生成图表,但是我有很多类似的数据,并且想使用 python 来自动完成任务。

【问题讨论】:

  • 如果你可以分享一个minimal reproducible example 生成你称之为“这很容易做到”的情节的代码,它将帮助人们真正为你提供问题的解决方案。
  • 我想你误解了我。情节是在 Excel 中创建的。我正在寻找在 python 中生成类似图表的代码。
  • 那么“这可以很容易地完成”是什么意思呢?我的评论旨在帮助您提出一个问题,可以在此问答网站的范围内回答。您当然可能会问是否有人可以为您编写完整的代码 - 但是我怀疑是否有人真的会这样做;但你仍然可以尝试。您可能还想了解this question 及其答案对您有多大帮助。
  • @ImportanceOfBeingErnest :对不起,所有的混乱/滋扰。我已经编辑了我的问题,并且包括了到目前为止我所做的事情。我希望现在对阅读问题/帖子的任何人都有意义。我试图通过this question。我没有看到对代码的任何评论,我对 python 很陌生,很难理解哪个代码在做什么。

标签: python excel string matplotlib charts


【解决方案1】:

使用具有以下数据的 excel 表,

,

你可以使用 matplotlib 来创建你想要的情节。这并不简单,但可以做到。见下文:

编辑:之前我建议使用 factorplot,但它不适用,因为每个试验的 location 值不是恒定的。

df = pd.read_excel(r'test_data.xlsx', header = 1, parse_cols = "D:F",
                  names = ['Trial', 'Location', 'Values'])
'''
  Trial Location  Values
0   Trial 1     Edge      12
1       NaN      M-2      13
2       NaN   Center      14
3       NaN      M-4      15
4       NaN      M-5      12
5       NaN      Top      13
6   Trial 2     Edge      10
7       NaN      N-2      11
8       NaN   Center      11
9       NaN      N-4      12
10      NaN      N-5      13
11      NaN      Top      14
12  Trial 3     Edge      15
13      NaN      R-2      13
14      NaN   Center      12
15      NaN      R-4      11
16      NaN      R-5      10
17      NaN      Top       3
'''


# this will replace the nan with corresponding trial number for each set of trials
df = df.fillna(method = 'ffill')
'''
 Trial Location  Values
0   Trial 1     Edge      12
1   Trial 1      M-2      13
2   Trial 1   Center      14
3   Trial 1      M-4      15
4   Trial 1      M-5      12
5   Trial 1      Top      13
6   Trial 2     Edge      10
7   Trial 2      N-2      11
8   Trial 2   Center      11
9   Trial 2      N-4      12
10  Trial 2      N-5      13
11  Trial 2      Top      14
12  Trial 3     Edge      15
13  Trial 3      R-2      13
14  Trial 3   Center      12
15  Trial 3      R-4      11
16  Trial 3      R-5      10
17  Trial 3      Top       3
'''

from matplotlib import rcParams
from matplotlib import pyplot as plt
import matplotlib.ticker as ticker

rcParams.update({'font.size': 10})
fig1 = plt.figure()
f, ax1 = plt.subplots(1, figsize = (10,3))

ax1.plot(list(df.Location.index), df['Values'],'o-')
ax1.set_xticks(list(df.Location.index))
ax1.set_xticklabels(df.Location, rotation=90 )
ax1.yaxis.set_label_text("Values")

# create a secondary axis
ax2 = ax1.twiny()
# hide all the spines that we dont need
ax2.spines['top'].set_visible(False)
ax2.spines['bottom'].set_visible(False)
ax2.spines['right'].set_visible(False)
ax2.spines['left'].set_visible(False)

pos1 = ax2.get_position() # get the original position 
pos2 = [pos1.x0 + 0, pos1.y0 -0.2,  pos1.width , pos1.height ] # create a new position by offseting it
ax2.xaxis.set_ticks_position('bottom')
ax2.set_position(pos2) # set a new position


trials_ticks = 1.0 * df.Trial.value_counts().cumsum()/ (len(df.Trial)) # create a series object for ticks for each trial group
trials_ticks_positions = [0]+list(trials_ticks) # add a additional zero. this will make tick at zero.
trials_labels_offset = 0.5 * df.Trial.value_counts()/ (len(df.Trial)) # create an offset for the tick label, we want the tick label to between ticks
trials_label_positions = trials_ticks - trials_labels_offset # create the position of tick labels

# set the ticks and ticks labels
ax2.set_xticks(trials_ticks_positions)
ax2.xaxis.set_major_formatter(ticker.NullFormatter())
ax2.xaxis.set_minor_locator(ticker.FixedLocator(trials))
ax2.xaxis.set_minor_formatter(ticker.FixedFormatter(list(trials_label_positions.index)))
ax2.tick_params(axis='x', length = 10,width = 1)

plt.show()

导致

【讨论】:

  • 非常感谢您的帮助。我在执行您提供的代码时遇到问题。 'df['Trial'] = [u for u in df['Trial'].dropna().unique() for l in range(len(df['Location'].unique()))]' 给出 值的长度与索引的长度不匹配错误。我试图弄清楚出了什么问题。另外,我试图将整个情节合二为一,而不是分成三部分。你的代码帮助我学习了更多的python。
  • 您在 excel 文件中的数据是否像我在答案中发布的方式一样。如果您可以上传包含部分数据的 excel 文件,将会有所帮助。
  • 我创建了一个github目录。文件名为 W1.xlsx.link
  • 我已经更新了代码。此代码使用 matplotlib 而不是 seaborn。如果代码有帮助,请投票或/并接受答案。
  • 非常感谢您更新代码。我能够(几乎)复制与您相同的结果。 (我得到的图表上的顺序是 Trial2、Trial1 和 Trial3)。请原谅我,如果我打扰您,但我无法理解您分配刻度和刻度标签的方式。另外,我认为代码ax2.xaxis.set_minor_locator 缺少一些东西!
猜你喜欢
  • 2014-07-06
  • 1970-01-01
  • 1970-01-01
  • 2017-05-17
  • 1970-01-01
  • 1970-01-01
  • 2013-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多