4

Hi i'm having a problem where I have a dataset which ranges between -10^3 to 10^3

I need to be able to plot this as with a log scale but semilogy cannot plot negative values

Say for example my data is:

x = [-3,-2,-1,0,1,2,3];
y = [-1000,-100,-10,1,10,100,1000];

(or in general y=sign(x).*10.^abs(x);)

How can I plot this in MATLAB with a log scale? If possible It would be great if the log scale ticks could be on the Y-axis too

Eduardo
  • 6,900
  • 17
  • 77
  • 121
  • for log(x), x cannot be less than 0. – NKN Jan 09 '14 at 19:22
  • @NKN Im well aware, but im calculating the log of the difference between two variables that can range between 0 and 1000. In general the difference is positive but I need to be able to plot the times it is isnt. – Eduardo Jan 09 '14 at 19:46
  • if they are two positive variables then why you just don't plot them on top of each other? – NKN Jan 09 '14 at 19:54
  • 2
    You have to decide what to do to your values to make them all positive (add 10^3 to them?). Otherwise forget about log – Luis Mendo Jan 09 '14 at 19:54

4 Answers4

4

Use your actual data as labels, but scale the plotted data with log10.

% data
x = -3:0.1:3;
y = sign(x).*10.^abs(x);

% scaling function
scale = @(x) sign(x).*log10(abs(x));

N = 7;    % number of ticks desired

% picking of adequate values for the labels
TickMask = linspace(1,numel(y),N);
YTickLabels = y(TickMask);

% scale labels and plotdata, remove NaN ->inconsistency, do you really want that?
YTick = scale( YTickLabels );
Y = scale(y);

YTick(isnan(YTick)) = 0;
Y(isnan(Y)) = 0;

% plot
plot(x,Y)
set(gca,'YTick',YTick,'YTickLabels',YTickLabels)
grid on

For N = 7:

enter image description here

For N = 11

enter image description here


How to find a valid value for N?

The following function (thanks to gnovice) will return all possible values you could choose for N:

n = numel(x);
N = find(rem(n./(1:n), 1) == 0) + 1;

about the semilogy-style labels: by adding the following line before the plot:

YTickLabels = cellfun(@(x) ['10^' num2str(x)], num2cell(YTick),'UniformOutput',false)

you could at least achieve something like this: enter image description here not beautiful and not generic, but a good point to start for you.

Community
  • 1
  • 1
Robert Seifert
  • 25,078
  • 11
  • 68
  • 113
  • It there anyway to get the log scale markers that are shown by semilogy? – Eduardo Jan 09 '14 at 18:06
  • 1
    no, because that is not what semilogy does. A logarithm for negative values is not defined (for real numbers). What you want is mathematically not consistent, that is why `YTick(isnan(YTick)) = 0;` is required. – Robert Seifert Jan 09 '14 at 18:09
  • actually, it is somehow possible. A first idea you can find my last edit. – Robert Seifert Jan 09 '14 at 20:08
1

The reason you can't make a logarithmic axis that crosses zero, is that it doesn't make sense! Since a logarithmic scale is generally displayed as eg. 100 - 10 - 1 - 1/10 - 1/100 - ..., you would need an infinite amount of space to make the axis cross zero.

0

How about this:

x=logspace(-3,3);
y=sign(x).*10.^abs(x);
loglog(x,y)

enter image description here

NKN
  • 6,482
  • 6
  • 36
  • 55
0

@thewaywewalk has already given a beautiful solution to it. The one I'm suggesting is an epsilon improvement on it. If you make two changes (a) Define a new MATLAB function signia that basically extracts the sign before a number.

function value = signia(x)
if(x>=0)
    value = '';
else
    value = '-';
end

and (b) make this little change that instead of

YTickLabels = cellfun(@(x) ['10^' num2str(x)], num2cell(YTick),'UniformOutput',false)

you use

YTickLabels = cellfun(@(x) [signia(x) '10^{' num2str(x) '}'], num2cell(YTick),'UniformOutput',false);

(notice the presence of curly braces), you'll get an improvement in the Y ticks display. I got the following. enter image description here

Ramanuja
  • 1
  • 1