1

I want to draw rectangles along with the x-axis categorical values of the data.

Some posts similar but not the one I look for.

matplotlib: how to draw a rectangle on image

Plotting shapes in Matplotlib through a loop

Weird behavior of matplotlib plt.Rectangle

These are the expected outputs; enter image description here

I'd like to move the rectangle to each subsequent x-value. And save all images separately.

enter image description here

The code for the plots above (with preliminary code for the rectangles):

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

data = pd.DataFrame(raw_data, columns = ['first_name', 'pre_score'])

order = np.sort(data['first_name'].unique())

save_images = r'D:\test'

for x_names in order:

    print(x_names)

    sns.set_style("ticks")
    ax = sns.stripplot(x='first_name', y='pre_score', hue='first_name',order=order, jitter=True, dodge=False, size=6, zorder=0, alpha=0.5, linewidth =1, data=data)
    ax = sns.boxplot(x='first_name', y='pre_score', hue='first_name',order=order, dodge=False, showfliers=True, linewidth=0.8, showmeans=True, width=0.28, data=data)
    ax = sns.pointplot(x='first_name', y='pre_score', order=order, data=data, ci=None, color='black')
    fig_size = [18.0, 10.0]
    plt.rcParams["figure.figsize"] = fig_size
    ax.yaxis.set_tick_params(labelsize=14)
    ax.xaxis.set_tick_params(labelsize=14)

    plt.Rectangle((0, 0), 0.28, max(data['pre_score']), color="red");

    # ax.add_patch(plt.Rectangle(x_names, fill=False, linewidth=2.0))

    plt.savefig(save_images +x_names+'.png', dpi=150,bbox_inches="tight")

Got this after @JohanC enter image description here

Alexander
  • 4,527
  • 5
  • 51
  • 98
  • What are you getting currently? Without `raw_data` info, I could not generate current plots. – SKPS Jan 28 '20 at 06:40
  • @SathishSanjeevi raw data is at the bottom! – Alexander Jan 28 '20 at 06:42
  • What is the additional difficulty compared to this? https://stackoverflow.com/questions/37435369/matplotlib-how-to-draw-a-rectangle-on-image?rq=1 – SKPS Jan 28 '20 at 06:43

1 Answers1

3

The principal question seems to be how to calculate the coordinates of a rectangle surrounding each column.

The parameters of Rectangle are Rectangle((x, y), width, height, ...

When working with categorical data, the x-position of each name is an index 0, 1, 2, .... The x-distance between two successive names is 1.0, so a number a bit smaller can be used as width of the rectangle. The x-position for the name is just in the center of its box. To get a centered rectangle, we can position it at x minus half the width.

For the y-position and height, we can take the axes limits, and subtract some padding.

In the code below some random data is generated. Also, the figsize is set before calling the plots.

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

N = 100
raw_names = np.random.choice(['Amy', 'Jake', 'Jason', 'Molly', 'Tina'], N)
raw_scores = np.random.uniform(0, 95, N)

data = pd.DataFrame({'first_name':raw_names, 'pre_score': raw_scores})
order = np.sort(data['first_name'].unique())
save_images = r'D:\test'

plt.rcParams["figure.figsize"] = [18.0, 10.0]

for name_ind, x_names in enumerate(order):
    np.random.seed(123456) # to get the same random stripplot everytime
    sns.set_style("ticks")
    ax = sns.stripplot(x='first_name', y='pre_score', hue='first_name', order=order, jitter=True, dodge=False, size=6, zorder=0, alpha=0.5, linewidth=1, data=data)
    ax = sns.boxplot(x='first_name', y='pre_score', hue='first_name', order=order, dodge=False, showfliers=True, linewidth=0.8, showmeans=True,width=0.28, data=data)
    ax = sns.pointplot(x='first_name', y='pre_score', order=order, data=data, ci=None, color='black')
    ax.yaxis.set_tick_params(labelsize=14)
    ax.xaxis.set_tick_params(labelsize=14)

    ymin, ymax = plt.ylim()
    height = ymax - ymin
    width = 0.7
    ax.add_patch(plt.Rectangle((name_ind - width / 2, ymin + height * 0.02), width, height * 0.96,
                               edgecolor='crimson', fill=False))

    plt.legend(loc='upper left', title='', bbox_to_anchor=[1.01, 0, 1, 1])

    plt.savefig(save_images+x_names+'.png', dpi=150, bbox_inches="tight")
    plt.clf()
    # plt.tight_layout(pad=2)
    # plt.show()

sample plot

JohanC
  • 71,591
  • 8
  • 33
  • 66
  • thanks a lot. I can have the rectangles along the x_axis values. OTH, In my case I got all of rectangles drawn for each axis at the end. What I need to have is remove the previous rectangle as x value goes along. how did you get the image in your solution ? – Alexander Jan 28 '20 at 15:19
  • This is fantastic. Thanks a lot for you to putting an effor to explain details. One more small issue, I realized that for every plot the points in the box plot little bit changing. They are in the same y-axis though but some may complain about it:) what is the reason of it ? – Alexander Jan 28 '20 at 15:57
  • The stripplot is generated 5 times randomly, once for every pass of the for loop. By explicitly initializing the random seed at the start of the loop, we'll get the same random points. – JohanC Jan 28 '20 at 16:20
  • Ok I got it. Thanks! – Alexander Jan 28 '20 at 16:36