Create an account


Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tut] Matplotlib Legend – A Helpful Illustrated Guide

#1
Matplotlib Legend – A Helpful Illustrated Guide

<div><p>You’ve plotted some data in <a rel="noreferrer noopener" href="https://matplotlib.org/" target="_blank">Matplotlib </a>but you don’t know which data shows what? It’s time for a legend!</p>
<p><strong>How to add a legend in Python’s Matplotlib library?</strong></p>
<ul>
<li><strong>Label it with the <code>label</code> keyword argument in your plot method. </strong></li>
<li><strong>Before <code>plt.show()</code>, call <code>plt.legend()</code> your plot will be displayed with a legend. </strong></li>
</ul>
<p>Here’s the minimal example:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import matplotlib.pyplot as plt plt.plot([1, 2, 3], [1, 4, 9], label='squares')
plt.plot([1, 2, 3], [1, 8, 27], label='cubes') plt.legend()
plt.show()</pre>
<p>In the following video, I’ll lead you through the article, step by step.</p>
<figure class="wp-block-embed-youtube wp-block-embed is-type-rich is-provider-embed-handler wp-embed-aspect-4-3 wp-has-aspect-ratio">
<div class="wp-block-embed__wrapper">
<div class="ast-oembed-container"><iframe title="matplotlib legend video" width="1333" height="1000" src="https://www.youtube.com/embed/lbRSzL7Gg_M?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
</p></div>
</figure>
<h2>Prettier Example</h2>
<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 necessary modules
import matplotlib.pyplot as plt
import numpy as np # Optional: Use seaborn style as it looks nicer than matplotlib's default
import seaborn as sns; sns.set() # Generate data
vals = np.array([0, 1, 2, 3, 4]) # Plot and label
plt.plot(vals, label='vals') plt.legend()
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img0.png" alt=""/></figure>
<p>If you plot and label multiple lines, the legend will contain multiple entries. </p>
<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="">plt.plot(vals, label='Linear')
plt.plot(vals**2, label='Squared')
plt.plot(vals**0.5, label='Square Root') plt.legend()
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img1.png" alt=""/></figure>
<p>You can combine different types of plot – <a href="https://blog.finxter.com/matplotlib-scatter-plot/">scatter</a>, <a href="https://blog.finxter.com/matplotlib-line-plot/">line</a>, <a href="https://blog.finxter.com/matplotlib-histogram/">histogram</a> etc. – but you may have to specify the colors manually if you do. </p>
<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 random # Set seed to reproduce results
random.seed(1) # Generate random data
x = [random.random() for _ in range(100)]
y = [random.random() for _ in range(100)] # Scatter plot
plt.scatter(x, y, label='Data') # Red line plot acting as the 'line of best fit'
plt.plot([0, 1], label='Best Fit', c='r')
plt.legend()
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img2.png" alt=""/></figure>
<p>In this example, I first <a href="https://blog.finxter.com/python-random-module/">generated some random data</a> before making a scatter plot from it. Then, I drew a line plot on top of it to act as the line of best fit (note that this is just an example and isn’t actually the line of best fit for this dataset!). Unfortunately, matplotlib does not automatically change the color of each plot if you plot a line and a scatter plot on top of each other. So, I manually changed it to red with the <code>c</code> keyword argument.</p>
<p>To learn more about <a href="https://blog.finxter.com/python-random-module/">Python’s random module</a>, check out my article. </p>
<p>Let’s dive into a more detailed example of how legends work in matplotlib.</p>
<h2>Matplotlib Legend Example</h2>
<p>To display a legend on any plot, you must call <code>plt.legend()</code> at some point in your code – usually, just before <code>plt.show()</code> is a good place.</p>
<p>There are 3 ways you can call it:</p>
<ol>
<li><code>plt.legend()</code></li>
<li><code>plt.legend(labels)</code></li>
<li><code>plt.legend(handles, labels)</code></li>
</ol>
<p>The first option – <code>plt.legend()</code> – automatically detects which elements to show. It does this by displaying all plots that have been labeled with the <code>label</code> keyword argument. The order of the lines in the legend are the same as the order you plot them. </p>
<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="">vals = np.array([0, 1, 2, 3, 4]) # Plot vals first
plt.plot(vals, label='vals') # Plot vals/2 second
plt.plot(vals/2, label='vals/2') # Call plt.legend() without arguments
plt.legend()
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img3.png" alt=""/></figure>
<p>First I plotted <code>vals</code> and then plotted <code>vals/2</code>. You can see that <code>vals</code> is displayed first in the legend and is a blue line. Now let’s swap the order. </p>
<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=""># Plot vals/2 first
plt.plot(vals/2, label='vals/2') # Plot vals second
plt.plot(vals, label='vals') # Call plt.legend() without arguments
plt.legend()
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img4.png" alt=""/></figure>
<p>Now <code>vals/2</code> is displayed first in the legend and is colored blue. By changing the order of the plots, you change not only the order in the legend but also the colors of the lines.</p>
<p>Note: you can manually control the colors using the <code>c</code> keyword argument if you want to.</p>
<p>The second option –<code>plt.legend(labels)</code> – is rarely used but I’ll show you what it does just for completeness.</p>
<p>The argument <code>labels</code> must be an iterable – most likely a list or tuple – containing the labels you want to display in the legend. Instead of explicitly labeling each line you draw like so:</p>
<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="">plt.plot(x_1, label='plot_1')
plt.plot(x_2, label='plot_2')
plt.legend()
plt.show()
</pre>
<p>You do not label any of the lines explicitly and instead label them based on the order they appear:</p>
<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="">plt.plot(x_1)
plt.plot(x_2)
plt.legend(['plot_1', 'plot_2'])
plt.show()
</pre>
<p>This method does work but can cause you a lot of headaches. For example, the iterable <code>labels</code> must be exactly the same length as the number of lines you draw. Moreover, if you change the order of any of your plots, you must also change the order of the elements in <code>labels</code>. Lastly, it violates The Zen of Python <em>Explicit is better than implicit</em> because you implicitly label each plot based on its order.</p>
<p>It is much easier for everyone if you explicitly label each of the plots rather than implicitly doing so like this. Thus, both the <a href="https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.legend.html">matplotlib docs</a> and I do not recommend you use this method.</p>
<p>The final method – <code>plt.legend(handles, labels)</code> – provides you with the most flexibility but takes slightly longer to write.</p>
<p>Both <code>handles</code> and <code>labels</code> are iterables – usually lists or tuples. The <code>handles</code> are the lines you wish to appear on the legend and the <code>labels</code> are, as I hope you know by now, the word(s) you want to appear in the legend next to each line. </p>
<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=""># Save plots with descriptive variable names
linear, = plt.plot(vals)
sqrt, = plt.plot(vals**0.5) # Create iterables handles and labels
handles = [linear, sqrt]
labels = ['Linear', 'Square Root'] # Pass handles and lables to plt.legend()
plt.legend(handles, labels)
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img5.png" alt=""/></figure>
<p>First, you must save the output of each line in a variable. The function <code>plt.plot()</code> returns a <code>list</code> of length 1, so you must unpack it by putting a comma after your variable name to get the value inside the list. The value is a <code>matplotlib.lines.Line2D</code> object which is how matplotlib stores lines.</p>
<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=""># linear_wrong is a list of length 1
linear_wrong = plt.plot(val) # linear_correct is a Line2D object - what you want
linear_correct, = plt.plot(val)
</pre>
<p>For ease of reading, I created the lists <code>handles</code> and <code>labels</code> which I then passed to <code>plt.legend()</code>. You can skip this intermediate step if you wish.</p>
<p>The biggest advantage of this method is that you have total control of the order in which the legend’s items appear: the order you pass <code>handles</code> is the order they will appear. This means you can plot them in any order you want and still control the order of the legend entries. This is in contract to method 1 where the order you plot your lines is the order they appear in the legend.</p>
<p>So, to make <code>Square Root</code> appear as the first entry in the legend, do the following.</p>
<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="">linear, = plt.plot(vals)
sqrt, = plt.plot(vals**0.5) # Swap order of sqrt and linear
handles_ = [sqrt, linear]
labels_ = ['Square Root', 'Linear'] plt.legend(handles_, labels_)
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img6.png" alt=""/></figure>
<p>In this plot, the color of the lines has not changed but the order in the legend has changed because I changed the lists <code>handles</code> and <code>labels</code>.</p>
<p>Finally, one thing many Python programmers don’t know is that if your label starts with an underscore, it will not be displayed in the legend. This may be useful if you have many plots and want to be able to easily scan the code but not display the names in the plots. </p>
<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=""># No legend displayed because of underscore
plt.plot(vals, label='_I will not be displayed')
plt.legend()
plt.show()
</pre>
<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="">No handles with labels found to put in legend.
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img7.png" alt=""/></figure>
<h2>Matplotlib Legend Location</h2>
<p>To change the location of a legend in matplotlib, use the <code>loc</code> keyword argument in <code>plt.legend()</code>.</p>
<p>By default, matplotlib draws the legend in the ‘best’ location i.e. the place that overlaps the least with the lines drawn. This can be slow if you plot a lot of data, so manually setting a location can speed up the process.</p>
<p>To manually set it, use the <code>loc</code> keyword and one of these 10, self-explanatory, strings:</p>
<ul>
<li><code>‘upper right’</code>, <code>‘upper left’</code>, <code>‘upper center’</code></li>
<li><code>‘lower right’</code>, <code>‘lower left’</code>, <code>‘lower center’</code></li>
<li><code>‘center right’</code> or <code>‘center left’</code></li>
<li><code>‘right’</code> or <code>‘center’</code> (for some reason, <code>‘left’</code> is not an option)</li>
</ul>
<p>Here are some examples of putting the legend in different locations. If you are unsure how to <a href="https://blog.finxter.com/matplotlib-subplots/">plot subplots in matplotlib</a>, check out my article. </p>
<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="">fig, axes = plt.subplots(nrows=1, ncols=3, figsize=plt.figaspect(1/3)) # Differnet legend locations
locations = ['best', 'upper center', 'lower left'] for ax, loc in zip(axes.flat, locations): ax.plot(vals, label='vals') ax.set_title(f"Legend loc='{loc}") # Set legend location ax.legend(loc=loc)
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img8.png" alt=""/></figure>
<p>You can change the default location for all plots by setting <code>plt.rcParams['legend.loc']</code> to the <code>loc</code> value of your choice.</p>
<p>Finally, you can choose any coordinate points by passing a 2-tuple to <code>loc</code> instead of a string. This will specify the location of the lower-left corner of the legend as a <em>fraction of the axes</em>. So setting <code>loc=(0.5, 0.5)</code> will place the bottom left corner half way along the x-axis and half way along the y-axis. </p>
<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="">plt.plot(vals, label='vals') # Set location of legend
plt.legend(loc=(0.5, 0.5)) plt.title('Legend loc=(0.5, 0.5)')
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img9.png" alt=""/></figure>
<p>If you input <code>loc=(2, 2)</code> you get a very stange looking graph because matplotlib places the legend at double the length and double the height of the axes. </p>
<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="">plt.plot(vals, label='vals') # Set location of legend
plt.legend(loc=(2, 2)) plt.title('Legend loc=(2, 2)')
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img10.png" alt=""/></figure>
<p>Of course, it is possible to place the legend at any coordinate point you want. Just remember to scale it by the maximum x- and y-axis values (both <code>4</code> in this example). So, to place the legend at the coordinate points <code>(2, 3)</code>, pass <code>loc=(2/4, 3/4)</code>.</p>
<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="">plt.plot(vals, label='vals') # Set location of legend
plt.legend(loc=(2/4, 3/4)) plt.title('Legend at coordiante points (2, 3)')
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img11.png" alt=""/></figure>
<h2>Matplotlib Legend Font Size</h2>
<p>To change the fontsize of a legend, use the <code>fontsize</code> keyword argument. It can take any int or float – the absolute size in points. Try lots of different sizes to get a feel for it.</p>
<p>You can also pass one of several strings:</p>
<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="">['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large']
</pre>
<p>These are all relative to the current default font size. Let’s look at some examples. </p>
<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="">fig, axes = plt.subplots(nrows=1, ncols=3, figsize=plt.figaspect(1/3)) # Different font sizes to try
fonts = ['xx-small', 'medium', 'x-large'] for ax, font in zip(axes.flat, fonts): ax.plot(vals, label='vals') ax.set_title(f"Legend fontsize='{font}'") # Set fontsize in legend ax.legend(fontsize=font) plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img12.png" alt=""/></figure>
<h2>Matplotlib Legend Title</h2>
<p>To add a title to a legend use the <code>title</code> keyword argument.</p>
<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="">plt.plot(vals, label='vals') # Add title to legend
plt.legend(title='My Awesome Legend')
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img13.png" alt=""/></figure>
<h2>Matplotlib Legend Title Font Size</h2>
<p>To change the font size of the title for a legend in matplotlib use the <code>title_fontsize</code> keyword argument. Like the <code>fontsize</code> keyword argument, it accepts any int or float – the absolute size in points – or one of the fontsize strings.</p>
<p>The <a href="https://matplotlib.org/api/_as_gen/matplotlib.pyplot.legend.html#matplotlib.pyplot.legend">matplotlib docs</a> are actually incorrect because they say that <code>title_fontsize</code> only accepts a string or <code>None</code>. </p>
<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="">fig, axes = plt.subplots(nrows=1, ncols=3, figsize=plt.figaspect(1/3)) # Differnet fontsizes to try
title_size = ['large', 5, None] for ax, size in zip(axes.flat, title_size): ax.plot(vals, label='vals') ax.set_title(f"Legend title_fontsize={size}") # Set title_fontsize of the legend ax.legend(title='My Awesome Legend', title_fontsize=size)
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img14.png" alt=""/></figure>
<h2>Matplotlib Legend Color</h2>
<p>You can change both the <code>facecolor</code> and <code>edgecolor</code> of a legend using those keyword arguments in the function call.</p>
<p>The <code>facecolor</code> is the main color and the <code>edgecolor</code> is, you guessed it, the color around the edge of the box. </p>
<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="">fig, axes = plt.subplots(nrows=2, ncols=2) # facecolors to choose
colors = ['red', 'blue', 'green', 'yellow'] for ax, color in zip(axes.flat, colors): ax.plot(vals, label=color) # Set facecolor of the legend ax.legend(facecolor=color)
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img15.png" alt=""/></figure>
<p>Let’s do the same now but just change the edge color. </p>
<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="">fig, axes = plt.subplots(nrows=2, ncols=2) # Edgecolors to choose
colors = ['red', 'blue', 'green', 'yellow'] for ax, color in zip(axes.flat, colors): ax.plot(vals, label=color) # Choose edgecolor of legend ax.legend(edgecolor=color)
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img16.png" alt=""/></figure>
<p>Of course, you can mix and match the face and edge colors to your heart’s content.</p>
<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="">fig, axes = plt.subplots(nrows=2, ncols=2) # Colors to use
colors = ['red', 'blue', 'green', 'yellow'] # Same as colors but reversed
edges = colors[::-1] for ax, color, edge in zip(axes.flat, colors, edges): ax.plot([0, 1, 2, 3, 4], label=color) # Choose both the facecolor and edgecolor ax.legend(facecolor=color, edgecolor=edge)
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/legend/final_html/img/img17.png" alt=""/></figure>
<h2>Matplotlib Legend Order</h2>
<p>To learn how to order elements in a legend, check out the Matplotlib Legend Example section.</p>
<h2>Matplotlib Legend Background Color</h2>
<p>To learn how to change the background color of a legend, check out the Matplotlib Legend Color section.</p>
<h2>Conclusion</h2>
<p>That’s it, you now know all the basics of working with legends in matplotlib.</p>
<p>You know the three different ways to call the function – <code>plt.legend()</code>, <code>plt.legend(labels)</code> and <code>plt.legend(handles, labels)</code> – you know how to set its location with both strings and coordinate points. Plus you can change the font size, set a title and even change the font size of the title. Lastly, you can jazz up your legends by setting the facecolor or edgecolor to anything you want.</p>
<h2>Where To Go From Here?</h2>
<p>Do you wish you could be a programmer full-time but don’t know how to start?</p>
<p>Check out the pure value-packed webinar where Chris – creator of Finxter.com – teaches you to become a Python freelancer in 60 days or your money back!</p>
<p><a href="https://tinyurl.com/become-a-python-freelancer">https://tinyurl.com/become-a-python-freelancer</a></p>
<p>It doesn’t matter if you’re a Python novice or Python pro. If you are not making six figures/year with Python right now, you will learn something from this webinar.</p>
<p>These are proven, no-BS methods that get you results fast.</p>
<p>This webinar won’t be online forever. Click the link below before the seats fill up and learn how to become a Python freelancer, guaranteed.</p>
<p><a href="https://tinyurl.com/become-a-python-freelancer">https://tinyurl.com/become-a-python-freelancer</a></p>
</div>


https://www.sickgaming.net/blog/2020/03/...ted-guide/
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

Forum software by © MyBB Theme © iAndrew 2016