Laurinda Souza
Laurinda Souza

Reputation: 1337

logarithmic scale in Python

I am Trying to plot a graphic in logarithmic scale (Y axis) but I need to show in the Y axis all the original values.

I used the code:

# -*- coding: utf-8 -*-

import math
import matplotlib.pyplot as plt
import matplotlib.dates as dates
from datetime import datetime, timedelta
import numpy as np 

x = []
y = []
with open("dataset.csv") as f:
    for l in f:
        X,Y = l.split(",") #separador eh a virgula
        x.append(float(X))
        y.append( float (Y))
        #y.append( math.log (float (Y)))

#x1 = [datetime.fromtimestamp(int(d)) for d in x]
x1 = [str(datetime.fromtimestamp(int(d)))[-8:] for d in x]
y_pos = [idx for idx, i in enumerate(y)]

plt.figure(figsize=(17,9))
plt.gca().xaxis.set_major_formatter(dates.DateFormatter('%m/%d/%Y %H:%M:%S'))

plt.bar(y_pos, y, align='edge', color="blue", alpha=0.5, width=0.5) # <--- EDICAO PRINCIPAL
plt.title("Values X Time")
plt.ylabel("Values")
plt.xlabel('Time')
plt.xticks(y_pos, x1, size='small',rotation=35, ha="right")
#plt.yticks(y)
#plt.yticks(np.arange(0,max(y),0.3))
#plt.yticks(np.arange(0,max(y)+5,1))
plt.yscale('log')
plt.ylim(ymax=sorted(y)[-1]+1) # valor maximo do eixo y
#plt.ylim(ymin=sorted(y)[0]-1) # valor minimo do eixo y

plt.show()

Where dataset is:

     1491828000,3
    1491828060,195
    1491828120,220
    1491828180,240  
    1491828240,230  
    1491828300,238
    1491828360,310
    1491828420,280
    1491828480,263
    1491828540,271
    1491828600,282
    1491828660,302
    1491828720,298
    1491828780,257
    1491828840,245
    1491828900,200
    1491828960,170
    1491829020,138
    1491829080,59
    1491829140,39
    1491829200,48
    1491829260,95
    1491829320,151
    1491829380,155
    1491829440,175
    1491829500,93
    1491829560,25
    1491829620,3
    1491829680,185
    1491829740,233
    1491829800,210
    1491829860,86
    1491829920,32
    1491829980,46
    1491830040,51
    1491830100,201
    1491830160,129
    1491830220,116
    1491830280,105
    1491830340,200
    1491830400,203

But the result is:

I need the orignal values in Y axis

How could I show the original values in Y axis (logarithmic scale ), instead of 10, 10², etc? I tried hard but I only could show 10, 10² in Y axis!

I need to show in the Y axis all the original values. Any idea?

Upvotes: 0

Views: 28729

Answers (4)

Guto
Guto

Reputation: 541

Funny, I solved exactly this problem in the SO in portuguese.

In addition to the answer of ImportanceOfBeingErnest, you can add

plt.gca().minorticks_off()

to remove the minor ticks of the log scale, as they are overlapping. As i believe that this remove all minor ticks, you can use another approach:

matplotlib.rcParams['xtick.minor.size'] = 0
matplotlib.rcParams['xtick.minor.width'] = 0

Or any of the other solutions mentioned in this question.

Upvotes: 2

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339102

The question seems to be how to show all y values which are present as bars on the y axis, given the y axis being a logarithmic scale.

While this may not make too much sense, because of overlapping labels, here is the answer:

You may use a FixedLocator to set the positions of the labels and a ScalarFormatter to set the format to normal decimal numbers (instead of powers of 10).

plt.gca().yaxis.set_major_locator(matplotlib.ticker.FixedLocator(np.unique(y)))
plt.gca().yaxis.set_major_formatter(matplotlib.ticker.ScalarFormatter())

Complete code:

import matplotlib.pyplot as plt
import matplotlib.dates as dates
import matplotlib.ticker
from datetime import datetime, timedelta
import numpy as np 

x,y = np.loadtxt(io.StringIO(u), delimiter=",", unpack=True)

x1 = [str(datetime.fromtimestamp(int(d)))[-8:] for d in x]
y_pos = [idx for idx, i in enumerate(y)]

plt.figure(figsize=(17,9))
plt.gca().xaxis.set_major_formatter(dates.DateFormatter('%m/%d/%Y %H:%M:%S'))

plt.bar(y_pos, y, align='edge', color="blue", alpha=0.5, width=0.5) 
plt.title("Values X Time")
plt.ylabel("Values")
plt.xlabel('Time')
plt.xticks(y_pos, x1, size='small',rotation=35, ha="right")

plt.yscale('log')
plt.ylim(ymax=sorted(y)[-1]+1) # valor maximo do eixo y

plt.gca().yaxis.set_major_locator(matplotlib.ticker.FixedLocator(np.unique(y)))
plt.gca().yaxis.set_major_formatter(matplotlib.ticker.ScalarFormatter())

plt.show()

enter image description here

Upvotes: 4

wwii
wwii

Reputation: 23743

You can specify ether the x or y tick locations. To add the maximum value to the y axis use .yticks().

plt.yscale('log')
plt.yticks([1,10,100] + [max(y)])
plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.d'))

To determine the major ticks for a log scale at runtime; find the maximum power of ten in the data, then make all the powers of ten below it.:

import math
...
exp = int(math.log10(max(y)))
majors = [10**x for x in range(exp+1)]
#majors = [10**n for n in range(len(str(max(y))))]
plt.yticks(majors + [max(y)])

Upvotes: 2

Oli
Oli

Reputation: 167

Matplotlib ticker formatting is what you're looking for:

from matplotlib.ticker import FormatStrFormatter

...

plt.yscale('log')
plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.d')) #Here!
plt.ylim(ymax=sorted(y)[-1]+1) # valor maximo do eixo y

plt.show()

Though there may be a simpler way. Found using matplotlibs tick formatting documentation

Upvotes: 4

Related Questions