{"id":8269,"date":"2022-06-08T11:07:11","date_gmt":"2022-06-08T10:07:11","guid":{"rendered":"https:\/\/www.blopig.com\/blog\/?p=8269"},"modified":"2022-06-14T17:36:56","modified_gmt":"2022-06-14T16:36:56","slug":"making-better-plots-with-matplotlib-pyplot-in-python3","status":"publish","type":"post","link":"https:\/\/www.blopig.com\/blog\/2022\/06\/making-better-plots-with-matplotlib-pyplot-in-python3\/","title":{"rendered":"Making better plots with matplotlib.pyplot in Python3"},"content":{"rendered":"\n<p>The default plots made by Python&#8217;s matplotlib.pyplot module are almost always insufficient for publication. With a ~20 extra lines of code, however, you can generate high-quality plots suitable for inclusion in your next article. <\/p>\n\n\n\n<p>Let&#8217;s start with code for a very default plot:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import matplotlib.pyplot as plt\nimport numpy as np\n\nnp.random.seed(1)\nd1 = np.random.normal(1.0, 0.1, 1000)\nd2 = np.random.normal(3.0, 0.1, 1000)\nxvals = np.arange(1, 1000+1, 1)\n\nplt.plot(xvals, d1, label='data1')\nplt.plot(xvals, d2, label='data2')\nplt.legend(loc='best')\nplt.xlabel('Time, ns')\nplt.ylabel('RMSD, Angstroms')\nplt.savefig('bad.png', dpi=300)<\/pre>\n\n\n\n<p> The result of this will be:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/bad.png?ssl=1\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"625\" height=\"417\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/bad.png?resize=625%2C417&#038;ssl=1\" alt=\"\" class=\"wp-image-8270\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/bad.png?resize=1024%2C683&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/bad.png?resize=300%2C200&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/bad.png?resize=768%2C512&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/bad.png?resize=1536%2C1024&amp;ssl=1 1536w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/bad.png?resize=624%2C416&amp;ssl=1 624w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/bad.png?w=1800&amp;ssl=1 1800w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/bad.png?w=1250&amp;ssl=1 1250w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><figcaption>Plot generated with matplotlib.pyplot defaults<\/figcaption><\/figure>\n\n\n\n<p>The fake data I generated for the plot look something like Root Mean Square Deviation (RMSD) versus time for a converged molecular dynamics simulation, so let&#8217;s pretend they are. There are a number of problems with this plot: it&#8217;s overall ugly, the color scheme is not very attractive and may not be color-blind friendly, the y-axis range of the data extends outside the range of the tick labels, etc. <\/p>\n\n\n\n<p>We can easily convert this to a much better plot:<\/p>\n\n\n\n<!--more-->\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/better.png?ssl=1\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"625\" height=\"417\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/better.png?resize=625%2C417&#038;ssl=1\" alt=\"\" class=\"wp-image-8271\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/better.png?resize=1024%2C683&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/better.png?resize=300%2C200&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/better.png?resize=768%2C512&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/better.png?resize=1536%2C1024&amp;ssl=1 1536w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/better.png?resize=624%2C416&amp;ssl=1 624w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/better.png?w=1800&amp;ssl=1 1800w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/06\/better.png?w=1250&amp;ssl=1 1250w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><figcaption>Updated plot with better color scheme, more legible labels, and better use of white space<\/figcaption><\/figure>\n\n\n\n<p>We just need to add some extra lines to the code as follows:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import matplotlib.pyplot as plt\nimport numpy as np#np.random.seed(1)\n\nd1 = np.random.normal(1.0, 0.1, 1000)\nd2 = np.random.normal(3.0, 0.1, 1000)xvals = np.arange(1, 1000+1, 1)\n\nfontsize = 12 # set variable for fontsize\nlinewidth = 2 # set variable for line width\ncolors = ['#4477AA', '#AA3377'] # from \"bright\" color-blind friendly colors from Paul Tol\"s notes\n\nax = plt.subplot(111) # get axes object for subplot\nax.spines['right'].set_visible(False) # remove right plot boundary\nax.spines['top'].set_visible(False) # remove top plot boundary\nax.spines['left'].set_linewidth(linewidth) # make left axis thicker\nax.spines['bottom'].set_linewidth(linewidth) # make bottom axis thicker\nax.xaxis.set_tick_params(width=linewidth) # make x-axis tick marks thicker\nax.yaxis.set_tick_params(width=linewidth) # make y-axis tick marks thicker\n\nplt.plot(xvals, d1, label='data1', color=colors[0]) # use better colors\nplt.plot(xvals, d2, label='data2', color=colors[1]) # use better colors\n\nplt.xlabel('Time, ns', fontsize=fontsize+2) # update fontsize\nplt.ylabel('RMSD, '+r'$\\AA$', fontsize=fontsize+2) # use Angstrom symbol in axis label, update fontsize\nplt.yticks([0.0, 1.0, 2.0, 3.0, 4.0], fontsize=fontsize) # make sure tick labels span the y range; update fontsize\nplt.xticks(fontsize=fontsize) # update xtick fontsize\n\nplt.legend(loc='upper center', ncol=2, fancybox=True, framealpha=1.0) # put legend in convenient location and make 2 columns\n\nplt.savefig('better.png', dpi=300)<\/pre>\n\n\n\n<p>And that&#8217;s it &#8211; you can read through the comments to see what each line of code is doing. One last thing: take a look at Paul Tol&#8217;s <a href=\"https:\/\/personal.sron.nl\/~pault\/\" data-type=\"URL\" data-id=\"https:\/\/personal.sron.nl\/~pault\/\">excellent notes<\/a> on color theory and how to choose colors that are maximally distinct from one another and work for the color blind as well. <\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The default plots made by Python&#8217;s matplotlib.pyplot module are almost always insufficient for publication. With a ~20 extra lines of code, however, you can generate high-quality plots suitable for inclusion in your next article. Let&#8217;s start with code for a very default plot: The result of this will be: The fake data I generated for [&hellip;]<\/p>\n","protected":false},"author":69,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"nf_dc_page":"","wikipediapreview_detectlinks":true,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"ngg_post_thumbnail":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[361,621,227],"tags":[614,623,63,624,613,256,152],"ppma_author":[542],"class_list":["post-8269","post","type-post","status-publish","format-standard","hentry","category-data-science","category-data-visualization","category-python-code","tag-color-blind","tag-colors","tag-colour-blind","tag-colours","tag-matplotlib","tag-plotting","tag-python"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"authors":[{"term_id":542,"user_id":69,"is_guest":0,"slug":"dan","display_name":"Daniel Nissley","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/fd064a72579f11063ca36621317b744b6bc9df79116bc01af9b57f531bf10662?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts\/8269","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/users\/69"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/comments?post=8269"}],"version-history":[{"count":5,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts\/8269\/revisions"}],"predecessor-version":[{"id":8322,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts\/8269\/revisions\/8322"}],"wp:attachment":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/media?parent=8269"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/categories?post=8269"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/tags?post=8269"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=8269"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}