绘制Y轴文本数据(非数字)和X轴数值数据的图

时间:2021-08-27 08:26:53

I can create a simple columnar diagram in a matplotlib according to the 'simple' dictionary:

我可以根据'simple'字典在matplotlib中创建一个简单的柱状图:

import matplotlib.pyplot as pltD = {u'Label1':26, u'Label2': 17, u'Label3':30}plt.bar(range(len(D)), D.values(), align='center')plt.xticks(range(len(D)), D.keys())plt.show()

绘制Y轴文本数据(非数字)和X轴数值数据的图But, how do I create curved line on the text and numeric data of this dictionarie, I do not know?

但是,我怎么在这个词典的文本和数字数据上创建曲线,我不知道?

Т_OLD = {'10': 'need1', '11': 'need2', '12': 'need1', '13': 'need2', '14': 'need1'}

Like the picture below绘制Y轴文本数据(非数字)和X轴数值数据的图

如下图所示

3 个解决方案

#1


3  

You may use numpy to convert the dictionary to an array with two columns, which can be plotted.

您可以使用numpy将字典转换为具有两列的数组,这些列可以绘制。

import matplotlib.pyplot as pltimport numpy as npT_OLD = {'10' : 'need1', '11':'need2', '12':'need1', '13':'need2','14':'need1'}x = list(zip(*T_OLD.items()))# sort array, since dictionary is unsortedx = np.array(x)[:,np.argsort(x[0])].T# let second column be "True" if "need2", else be "Falsex[:,1] = (x[:,1] == "need2").astype(int)# plot the two columns of the arrayplt.plot(x[:,0], x[:,1])#set the labels accordinlyplt.gca().set_yticks([0,1])plt.gca().set_yticklabels(['need1', 'need2'])plt.show()

绘制Y轴文本数据(非数字)和X轴数值数据的图

The following would be a version, which is independent on the actual content of the dictionary; only assumption is that the keys can be converted to floats.

以下是一个版本,它独立于字典的实际内容;唯一的假设是密钥可以转换为浮点数。

import matplotlib.pyplot as pltimport numpy as npT_OLD = {'10': 'run', '11': 'tea', '12': 'mathematics', '13': 'run', '14' :'chemistry'}x = np.array(list(zip(*T_OLD.items())))u, ind = np.unique(x[1,:], return_inverse=True)x[1,:] = indx = x.astype(float)[:,np.argsort(x[0])].T# plot the two columns of the arrayplt.plot(x[:,0], x[:,1])#set the labels accordinlyplt.gca().set_yticks(range(len(u)))plt.gca().set_yticklabels(u)plt.show()

绘制Y轴文本数据(非数字)和X轴数值数据的图

#2


2  

Use numeric values for your y-axis ticks, and then map them to desired strings with plt.yticks():

使用y轴刻度的数值,然后使用plt.yticks()将它们映射到所需的字符串:

import matplotlib.pyplot as pltimport pandas as pd # example datatimes = pd.date_range(start='2017-10-17 00:00', end='2017-10-17 5:00', freq='H')data = np.random.choice([0,1], size=len(times))data_labels = ['need1','need2']fig, ax = plt.subplots()ax.plot(times, data, marker='o', linestyle="None")plt.yticks(data, data_labels)plt.xlabel("time")

绘制Y轴文本数据(非数字)和X轴数值数据的图

Note: It's generally not a good idea to use a line graph to represent categorical changes in time (e.g. from need1 to need2). Doing that gives the visual impression of a continuum between time points, which may not be accurate. Here, I changed the plotting style to points instead of lines. If for some reason you need the lines, just remove linestyle="None" from the call to plt.plot().

注意:使用折线图来表示时间上的分类变化(例如从need1到need2)通常不是一个好主意。这样做会给出时间点之间连续性的视觉印象,这可能不准确。在这里,我将绘图样式更改为点而不是线。如果由于某种原因你需要这些行,只需从调用plt.plot()中删除linestyle =“None”。

UPDATE
(per comments)

更新(每条评论)

To make this work with a y-axis category set of arbitrary length, use ax.set_yticks() and ax.set_yticklabels() to map to y-axis values.

要使用任意长度的y轴类别集进行此操作,请使用ax.set_yticks()和ax.set_yticklabels()映射到y轴值。

For example, given a set of potential y-axis values labels, let N be the size of a subset of labels (here we'll set it to 4, but it could be any size).

例如,给定一组潜在的y轴值标签,让N为标签子集的大小(这里我们将其设置为4,但它可以是任何大小)。

Then draw a random sample data of y values and plot against time, labeling the y-axis ticks based on the full set labels. Note that we still use set_yticks() first with numerical markers, and then replace with our category labels with set_yticklabels().

然后绘制y值的随机样本数据并绘制时间图,根据完整集标签标记y轴刻度。请注意,我们仍然首先使用set_yticks()和数字标记,然后使用set_yticklabels()替换我们的类别标签。

labels = np.array(['A','B','C','D','E','F','G'])N = 4# example datatimes = pd.date_range(start='2017-10-17 00:00', end='2017-10-17 5:00', freq='H')data = np.random.choice(np.arange(len(labels)), size=len(times))fig, ax = plt.subplots(figsize=(15,10))ax.plot(times, data, marker='o', linestyle="None")ax.set_yticks(np.arange(len(labels)))ax.set_yticklabels(labels)plt.xlabel("time")

#3


2  

This gives the exact desired plot:

这给出了确切的期望图:

import matplotlib.pyplot as pltfrom collections import OrderedDictT_OLD = {'10' : 'need1', '11':'need2', '12':'need1', '13':'need2','14':'need1'}T_SRT = OrderedDict(sorted(T_OLD.items(), key=lambda t: t[0]))plt.plot(map(int, T_SRT.keys()), map(lambda x: int(x[-1]), T_SRT.values()),'r')plt.ylim([0.9,2.1])ax = plt.gca()ax.set_yticks([1,2])ax.set_yticklabels(['need1', 'need2'])plt.title('T_OLD')plt.xlabel('time')plt.ylabel('need')plt.show()

For Python 3.X the plotting lines needs to explicitly convert the map() output to lists:

对于Python 3.X,绘图线需要显式地将map()输出转换为列表:

plt.plot(list(map(int, T_SRT.keys())), list(map(lambda x: int(x[-1]), T_SRT.values())),'r')

as in Python 3.X map() returns an iterator as opposed to a list in Python 2.7.

与Python中一样3.X map()返回迭代器而不是Python 2.7中的列表。

The plot uses the dictionary keys converted to ints and last elements of need1 or need2, also converted to ints. This relies on the particular structure of your data, if the values where need1 and need3 it would need a couple more operations.

该图使用转换为int的字典键和need1或need2的最后元素,也转换为int。这取决于数据的特定结构,如果需要1和need3的值需要更多操作。

After plotting and changing the axes limits, the program simply modifies the tick labels at y positions 1 and 2. It then also adds the title and the x and y axis labels.

绘制和更改轴限制后,程序只需修改y位置1和2处的刻度标签。然后还会添加标题以及x和y轴标签。

Important part is that the dictionary/input data has to be sorted. One way to do it is to use OrderedDict. Here T_SRT is an OrderedDict object sorted by keys in T_OLD.

重要的是必须对字典/输入数据进行排序。一种方法是使用OrderedDict。这里T_SRT是一个OrderedDict对象,按T_OLD中的键排序。

The output is:

输出是:

绘制Y轴文本数据(非数字)和X轴数值数据的图

This is a more general case for more values/labels in T_OLD. It assumes that the label is always 'needX' where X is any number. This can readily be done for a general case of any string preceding the number though it would require more processing,

对于T_OLD中的更多值/标签,这是更一般的情况。它假设标签总是'needX',其中X是任意数字。对于数字前面的任何字符串的一般情况,这可以很容易地完成,尽管它需要更多的处理,

import matplotlib.pyplot as pltfrom collections import OrderedDictimport reT_OLD = {'10' : 'need1', '11':'need8', '12':'need11', '13':'need1','14':'need3'}T_SRT = OrderedDict(sorted(T_OLD.items(), key=lambda t: t[0]))x_val = list(map(int, T_SRT.keys()))y_val = list(map(lambda x: int(re.findall(r'\d+', x)[-1]), T_SRT.values()))plt.plot(x_val, y_val,'r')plt.ylim([0.9*min(y_val),1.1*max(y_val)])ax = plt.gca()y_axis = list(set(y_val))ax.set_yticks(y_axis)ax.set_yticklabels(['need' + str(i) for i in y_axis])plt.title('T_OLD')plt.xlabel('time')plt.ylabel('need')plt.show()

This solution finds the number at the end of the label using re.findall to accommodate for the possibility of multi-digit numbers. Previous solution just took the last component of the string because numbers were single digit. It still assumes that the number for plotting position is the last number in the string, hence the [-1]. Again for Python 3.X map output is explicitly converted to list, step not necessary in Python 2.7.

此解决方案使用re.findall查找标签末尾的数字,以适应多位数的可能性。之前的解决方案只占用字符串的最后一个部分,因为数字是单个数字。它仍假设绘制位置的数字是字符串中的最后一个数字,因此为[-1]。再次为Python 3.X映射输出显式转换为list,Python 2.7中不需要步骤。

The labels are now generated by first selecting unique y-values using set and then renaming their labels through concatenation of the strings 'need' with its corresponding integer.

现在,通过首先使用set选择唯一的y值,然后通过将字符串'need'与其对应的整数串联来重命名它们的标签来生成标签。

The limits of y-axis are set as 0.9 of the minimum value and 1.1 of the maximum value. Rest of the formatting is as before.

y轴的极限设定为最小值的0.9和最大值的1.1。其余格式与以前一样。

The result for this test case is:

此测试用例的结果是:

绘制Y轴文本数据(非数字)和X轴数值数据的图

#1


3  

You may use numpy to convert the dictionary to an array with two columns, which can be plotted.

您可以使用numpy将字典转换为具有两列的数组,这些列可以绘制。

import matplotlib.pyplot as pltimport numpy as npT_OLD = {'10' : 'need1', '11':'need2', '12':'need1', '13':'need2','14':'need1'}x = list(zip(*T_OLD.items()))# sort array, since dictionary is unsortedx = np.array(x)[:,np.argsort(x[0])].T# let second column be "True" if "need2", else be "Falsex[:,1] = (x[:,1] == "need2").astype(int)# plot the two columns of the arrayplt.plot(x[:,0], x[:,1])#set the labels accordinlyplt.gca().set_yticks([0,1])plt.gca().set_yticklabels(['need1', 'need2'])plt.show()

绘制Y轴文本数据(非数字)和X轴数值数据的图

The following would be a version, which is independent on the actual content of the dictionary; only assumption is that the keys can be converted to floats.

以下是一个版本,它独立于字典的实际内容;唯一的假设是密钥可以转换为浮点数。

import matplotlib.pyplot as pltimport numpy as npT_OLD = {'10': 'run', '11': 'tea', '12': 'mathematics', '13': 'run', '14' :'chemistry'}x = np.array(list(zip(*T_OLD.items())))u, ind = np.unique(x[1,:], return_inverse=True)x[1,:] = indx = x.astype(float)[:,np.argsort(x[0])].T# plot the two columns of the arrayplt.plot(x[:,0], x[:,1])#set the labels accordinlyplt.gca().set_yticks(range(len(u)))plt.gca().set_yticklabels(u)plt.show()

绘制Y轴文本数据(非数字)和X轴数值数据的图

#2


2  

Use numeric values for your y-axis ticks, and then map them to desired strings with plt.yticks():

使用y轴刻度的数值,然后使用plt.yticks()将它们映射到所需的字符串:

import matplotlib.pyplot as pltimport pandas as pd # example datatimes = pd.date_range(start='2017-10-17 00:00', end='2017-10-17 5:00', freq='H')data = np.random.choice([0,1], size=len(times))data_labels = ['need1','need2']fig, ax = plt.subplots()ax.plot(times, data, marker='o', linestyle="None")plt.yticks(data, data_labels)plt.xlabel("time")

绘制Y轴文本数据(非数字)和X轴数值数据的图

Note: It's generally not a good idea to use a line graph to represent categorical changes in time (e.g. from need1 to need2). Doing that gives the visual impression of a continuum between time points, which may not be accurate. Here, I changed the plotting style to points instead of lines. If for some reason you need the lines, just remove linestyle="None" from the call to plt.plot().

注意:使用折线图来表示时间上的分类变化(例如从need1到need2)通常不是一个好主意。这样做会给出时间点之间连续性的视觉印象,这可能不准确。在这里,我将绘图样式更改为点而不是线。如果由于某种原因你需要这些行,只需从调用plt.plot()中删除linestyle =“None”。

UPDATE
(per comments)

更新(每条评论)

To make this work with a y-axis category set of arbitrary length, use ax.set_yticks() and ax.set_yticklabels() to map to y-axis values.

要使用任意长度的y轴类别集进行此操作,请使用ax.set_yticks()和ax.set_yticklabels()映射到y轴值。

For example, given a set of potential y-axis values labels, let N be the size of a subset of labels (here we'll set it to 4, but it could be any size).

例如,给定一组潜在的y轴值标签,让N为标签子集的大小(这里我们将其设置为4,但它可以是任何大小)。

Then draw a random sample data of y values and plot against time, labeling the y-axis ticks based on the full set labels. Note that we still use set_yticks() first with numerical markers, and then replace with our category labels with set_yticklabels().

然后绘制y值的随机样本数据并绘制时间图,根据完整集标签标记y轴刻度。请注意,我们仍然首先使用set_yticks()和数字标记,然后使用set_yticklabels()替换我们的类别标签。

labels = np.array(['A','B','C','D','E','F','G'])N = 4# example datatimes = pd.date_range(start='2017-10-17 00:00', end='2017-10-17 5:00', freq='H')data = np.random.choice(np.arange(len(labels)), size=len(times))fig, ax = plt.subplots(figsize=(15,10))ax.plot(times, data, marker='o', linestyle="None")ax.set_yticks(np.arange(len(labels)))ax.set_yticklabels(labels)plt.xlabel("time")

#3


2  

This gives the exact desired plot:

这给出了确切的期望图:

import matplotlib.pyplot as pltfrom collections import OrderedDictT_OLD = {'10' : 'need1', '11':'need2', '12':'need1', '13':'need2','14':'need1'}T_SRT = OrderedDict(sorted(T_OLD.items(), key=lambda t: t[0]))plt.plot(map(int, T_SRT.keys()), map(lambda x: int(x[-1]), T_SRT.values()),'r')plt.ylim([0.9,2.1])ax = plt.gca()ax.set_yticks([1,2])ax.set_yticklabels(['need1', 'need2'])plt.title('T_OLD')plt.xlabel('time')plt.ylabel('need')plt.show()

For Python 3.X the plotting lines needs to explicitly convert the map() output to lists:

对于Python 3.X,绘图线需要显式地将map()输出转换为列表:

plt.plot(list(map(int, T_SRT.keys())), list(map(lambda x: int(x[-1]), T_SRT.values())),'r')

as in Python 3.X map() returns an iterator as opposed to a list in Python 2.7.

与Python中一样3.X map()返回迭代器而不是Python 2.7中的列表。

The plot uses the dictionary keys converted to ints and last elements of need1 or need2, also converted to ints. This relies on the particular structure of your data, if the values where need1 and need3 it would need a couple more operations.

该图使用转换为int的字典键和need1或need2的最后元素,也转换为int。这取决于数据的特定结构,如果需要1和need3的值需要更多操作。

After plotting and changing the axes limits, the program simply modifies the tick labels at y positions 1 and 2. It then also adds the title and the x and y axis labels.

绘制和更改轴限制后,程序只需修改y位置1和2处的刻度标签。然后还会添加标题以及x和y轴标签。

Important part is that the dictionary/input data has to be sorted. One way to do it is to use OrderedDict. Here T_SRT is an OrderedDict object sorted by keys in T_OLD.

重要的是必须对字典/输入数据进行排序。一种方法是使用OrderedDict。这里T_SRT是一个OrderedDict对象,按T_OLD中的键排序。

The output is:

输出是:

绘制Y轴文本数据(非数字)和X轴数值数据的图

This is a more general case for more values/labels in T_OLD. It assumes that the label is always 'needX' where X is any number. This can readily be done for a general case of any string preceding the number though it would require more processing,

对于T_OLD中的更多值/标签,这是更一般的情况。它假设标签总是'needX',其中X是任意数字。对于数字前面的任何字符串的一般情况,这可以很容易地完成,尽管它需要更多的处理,

import matplotlib.pyplot as pltfrom collections import OrderedDictimport reT_OLD = {'10' : 'need1', '11':'need8', '12':'need11', '13':'need1','14':'need3'}T_SRT = OrderedDict(sorted(T_OLD.items(), key=lambda t: t[0]))x_val = list(map(int, T_SRT.keys()))y_val = list(map(lambda x: int(re.findall(r'\d+', x)[-1]), T_SRT.values()))plt.plot(x_val, y_val,'r')plt.ylim([0.9*min(y_val),1.1*max(y_val)])ax = plt.gca()y_axis = list(set(y_val))ax.set_yticks(y_axis)ax.set_yticklabels(['need' + str(i) for i in y_axis])plt.title('T_OLD')plt.xlabel('time')plt.ylabel('need')plt.show()

This solution finds the number at the end of the label using re.findall to accommodate for the possibility of multi-digit numbers. Previous solution just took the last component of the string because numbers were single digit. It still assumes that the number for plotting position is the last number in the string, hence the [-1]. Again for Python 3.X map output is explicitly converted to list, step not necessary in Python 2.7.

此解决方案使用re.findall查找标签末尾的数字,以适应多位数的可能性。之前的解决方案只占用字符串的最后一个部分,因为数字是单个数字。它仍假设绘制位置的数字是字符串中的最后一个数字,因此为[-1]。再次为Python 3.X映射输出显式转换为list,Python 2.7中不需要步骤。

The labels are now generated by first selecting unique y-values using set and then renaming their labels through concatenation of the strings 'need' with its corresponding integer.

现在,通过首先使用set选择唯一的y值,然后通过将字符串'need'与其对应的整数串联来重命名它们的标签来生成标签。

The limits of y-axis are set as 0.9 of the minimum value and 1.1 of the maximum value. Rest of the formatting is as before.

y轴的极限设定为最小值的0.9和最大值的1.1。其余格式与以前一样。

The result for this test case is:

此测试用例的结果是:

绘制Y轴文本数据(非数字)和X轴数值数据的图