[PYTHON] I want to create a graph with wavy lines omitted in the middle with matplotlib (I want to manipulate the impression)

Overview

Due to various adult circumstances, you may want to ** omit the middle of the graph with a wavy line **. This is an explanation of how to create such a graph using matplotlib.

f.png

Execution environment

We have confirmed the execution and operation with Python 3.6.9 (Google Colab. Environment).

Execution environment


japanize-matplotlib      1.0.5          
matplotlib               3.1.3          
matplotlib-venn          0.11.5         

Preparation for using Japanese in graphs

In order to make matplotlib ** Japanese compatible ** in Google Colab. Environment, do as follows.

Preparation for using Japanese in the graph


!pip install japanize-matplotlib
import japanize_matplotlib

Create a bar chart normally

First, let's draw a bar graph normally.

Create a bar chart normally


left   = np.array(['Fukushima', 'Aichi', 'Kanagawa', 'Osaka', 'Tokyo'])
height = np.array([160, 220, 280, 360, 1820])

plt.figure(figsize=(3,4), dpi=160)
plt.bar(left,height) #bar graph
plt.yticks(np.arange(0,1800+1,200))    #X-axis scale from 0 to 1900 in 200 increments
plt.gcf().patch.set_facecolor('white') #Set the background color to "white"

The execution result is as follows. The protrusion of Tokyo is very noticeable.

f1.png

Create a bar graph with wavy lines omitted in the middle

Step 1 Arrange the same bar charts up and down in the subplot

Step.1


import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.path import Path

left   = np.array(['Fukushima', 'Aichi', 'Kanagawa', 'Osaka', 'Tokyo'])
height = np.array([160, 220, 280, 360, 1820])

#Subplot Prepare a 2-by-1 subplot
fig, ax = plt.subplots(nrows=2, figsize=(3,4), dpi=160, sharex='col',
                       gridspec_kw={'height_ratios': (1,2)} )

fig.patch.set_facecolor('white') #Set the background color to "white"

ax[0].bar(left,height) #Upper row
ax[1].bar(left,height) #Lower row

gridspec_kw = {'height_ratios': (1,2)} is set so that the height ratio of the top and bottom is $ 1: 2 $. The execution result is as follows.

f2.png

Step 2 Stick the upper and lower graphs together

There is a gap between the upper and lower subplots, so I will erase it.

Step.2


#Set the vertical spacing between subplots to zero
fig.subplots_adjust(hspace=0.0)  

The execution result is as follows.

f3.png

Step 3 Erase the border and set the Y-axis range individually at the top and bottom

Hides the borders of the upper and lower graphs (= the bottom of the upper subplot, the top of the lower subplot). It also sets the Y-axis display range and scale for each subplot. At this time, make sure that the ** Y-axis display range ratio ** between the subplots is the same as the 'height_ratios': (1,2) specified in Step.1.

Step.3


#Lower subplot
ax[1].set_ylim(0,400)  #Section width 400
ax[1].set_yticks(np.arange(0,300+1,100))

#Upper subplot
ax[0].set_ylim(1750,1950)  #Section width 200
ax[0].set_yticks((1800,1900))

#Hide the top edge of the lower plot area
ax[1].spines['top'].set_visible(False)

#Hide the bottom of the upper plot area, hide the X-axis scale and labels
ax[0].spines['bottom'].set_visible(False)
ax[0].tick_params(axis='x', which='both', bottom=False, labelbottom=False) 

The execution result is as follows. f4.png

Step 4 Draw a Nyoro line

I will draw a nyoro (wavy line) indicating that the middle section is omitted.

Step.4


d1 = 0.02 #X-axis protrusion amount
d2 = 0.03 #Nyoro wave height
wn = 21   #Number of Nyoro waves (specify an odd value)

pp = (0,d2,0,-d2)
px = np.linspace(-d1,1+d1,wn)
py = np.array([1+pp[i%4] for i in range(0,wn)])
p = Path(list(zip(px,py)), [Path.MOVETO]+[Path.CURVE3]*(wn-1))

line1 = mpatches.PathPatch(p, lw=4, edgecolor='black',
                          facecolor='None', clip_on=False,
                          transform=ax[1].transAxes, zorder=10)

line2 = mpatches.PathPatch(p,lw=3, edgecolor='white',
                           facecolor='None', clip_on=False,
                           transform=ax[1].transAxes, zorder=10,
                           capstyle='round')

a = ax[1].add_patch(line1)
a = ax[1].add_patch(line2)

The execution result is as follows.

f5.png

Setting the drawing parameters as d1 = 0.1, wn = 41 gives:

f6.png

Whole code

Whole code


%reset -f
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.path import Path

left   = np.array(['Fukushima', 'Aichi', 'Kanagawa', 'Osaka', 'Tokyo'])
height = np.array([160, 220, 280, 360, 1820])

#Subplot Prepare a 2-by-1 subplot
fig, ax = plt.subplots(nrows=2, figsize=(3,4), dpi=160, sharex='col',
                       gridspec_kw={'height_ratios': (1,2)} )

fig.patch.set_facecolor('white') #Set the background color to "white"

ax[0].bar(left,height) #Upper row
ax[1].bar(left,height) #Lower row

#Set the vertical spacing between subplots to zero
fig.subplots_adjust(hspace=0.0)  

#Lower subplot
ax[1].set_ylim(0,400)  #Section width 400
ax[1].set_yticks(np.arange(0,300+1,100))

#Upper subplot
ax[0].set_ylim(1750,1950)  #Section width 200
ax[0].set_yticks((1800,1900))

#Hide the top edge of the lower plot area
ax[1].spines['top'].set_visible(False)

#Hide the bottom of the upper plot area, hide the X-axis scale and labels
ax[0].spines['bottom'].set_visible(False)
ax[0].tick_params(axis='x', which='both', bottom=False, labelbottom=False) 

##Nyoro line drawing
d1 = 0.02 #X-axis protrusion amount
d2 = 0.03 #Nyoro wave height
wn = 21   #Number of Nyoro waves (specify an odd value)

pp = (0,d2,0,-d2)
px = np.linspace(-d1,1+d1,wn)
py = np.array([1+pp[i%4] for i in range(0,wn)])
p = Path(list(zip(px,py)), [Path.MOVETO]+[Path.CURVE3]*(wn-1))

line1 = mpatches.PathPatch(p, lw=4, edgecolor='black',
                          facecolor='None', clip_on=False,
                          transform=ax[1].transAxes, zorder=10)

line2 = mpatches.PathPatch(p,lw=3, edgecolor='white',
                           facecolor='None', clip_on=False,
                           transform=ax[1].transAxes, zorder=10,
                           capstyle='round')

a = ax[1].add_patch(line1)
a = ax[1].add_patch(line2)

Recommended Posts

I want to create a graph with wavy lines omitted in the middle with matplotlib (I want to manipulate the impression)
I want to manually create a legend with matplotlib
I want to transition with a button in flask
I want to work with a robot in python.
I want to create an API that returns a model with a recursive relationship in the Django REST Framework
[Visualization] I want to draw a beautiful graph with Plotly
I want to create a Dockerfile for the time being.
[Python] I want to make a 3D scatter plot of the epicenter with Cartopy + Matplotlib!
I want to see the graph in 3D! I can make such a dream come true.
I want to create a system to prevent forgetting to tighten the key 1
I want to create a pipfile and reflect it in docker
I want to create a histogram and overlay the normal distribution curve on it. matplotlib edition
I want to print in a comprehension
I want to embed Matplotlib in PySimpleGUI
Create a graph with borders removed with matplotlib
When generating a large number of graphs with matplotlib, I do not want to display the graph on the screen (jupyter environment)
I want to change the color by clicking the scatter point in matplotlib
I want to sort a list in the order of other lists
I tried to display the altitude value of DTM in a graph
I want to solve the problem of memory leak when outputting a large number of images with Matplotlib
I want to make matplotlib a dark theme
I want to easily create a Noise Model
I want to display multiple images with matplotlib.
I want to create a plug-in type implementation
I want to write to a file with Python
I want to display the progress in Python!
I want to display only different lines of a text file with diff
I want to create a priority queue that can be updated in Python (2.7)
To output a value even in the middle of a cell with Jupyter Notebook
Create a stacked graph corresponding to both positive and negative directions with matplotlib
I want to set a life cycle in the task definition of ECS
I want to see a list of WebDAV files in the Requests module
Create a filter to get an Access Token in the Graph API (Flask)
I tried to create a model with the sample of Amazon SageMaker Autopilot
I wanted to know the number of lines in multiple files, so I tried to get it with a command
I tried to graph the packages installed in Python
I want to embed a variable in a Python string
I want to easily implement a timeout in python
[Python] How to draw a line graph with Matplotlib
Try to create a battle record table with matplotlib from the data of "Schedule-kun"
I want to climb a mountain with reinforcement learning
I want to write in Python! (2) Let's write a test
I created a stacked bar graph with matplotlib in Python and added a data label
I want to randomly sample a file in Python
I want to save a file with "Do not compress images in file" set in OpenPyXL
I want to inherit to the back with python dataclass
I want to split a character string with hiragana
I want to create a lunch database [EP1] Django study for the first time
I want to create a lunch database [EP1-4] Django study for the first time
I want to write in Python! (3) Utilize the mock
I can't manipulate iframes in a page with Selenium
[Python] How to create a 2D histogram with Matplotlib
I want to extract only pods with the specified label using Label Selector in Client-go
I tried to create a class to search files with Python's Glob method in VBA
I want to use the R dataset in python
I want to run a quantum computer with Python
I want to manipulate strings in Kotlin like Python!
I want to bind a local variable with lambda
Make a note of what you want to do in the future with Raspberry Pi
I made a class to get the analysis result by MeCab in ndarray with python
I tried to create a Python script to get the value of a cell in Microsoft Excel