Изменение порядка вывода категорий, значений или рядов данных
Excel для Microsoft 365 Word для Microsoft 365 Outlook для Microsoft 365 PowerPoint для Microsoft 365 PowerPoint 2021 Excel 2019 PowerPoint 2019 Excel 2016 Word 2016 Outlook 2016 PowerPoint 2016 Excel 2013 Word 2013 Outlook 2013 PowerPoint 2013 Excel 2010 Word 2010 Outlook 2010 PowerPoint 2010 Excel 2007 Word 2007 Outlook 2007 PowerPoint 2007 Еще. Меньше
Если на диаграмме, для которой требуется изменить порядок построения, отображаются оси, можно быстро изменить порядок, в котором категории или значения отображаются вдоль этих осей. Кроме того, на трехмерных диаграммах с осью глубины можно изменить порядок построения рядов данных, чтобы крупные трехмерные маркеры данных не блокировали более мелкие.
Вы также можете изменить порядок, в котором отдельные ряды данных отображаются на диаграмме.
В этой статье
- Обратный порядок отображения категорий или значений на диаграмме
- Изменение порядка построения рядов данных на трехмерной диаграмме
- Изменение порядка построения рядов данных на диаграмме
Обратный порядок отображения категорий или значений на диаграмме
- На диаграмме выполните одно из указанных ниже действий.
- Чтобы изменить порядок отображения категорий, щелкните горизонтальную (категорию) ось.
- Чтобы изменить порядок отображения значений, щелкните вертикальную ось (значение).
Вы также можете сделать следующее, чтобы выбрать нужную ось из списка элементов диаграммы:
- Щелкните диаграмму. Откроется вкладка Работа с диаграммами.
- В разделе Работа с диаграммами на вкладке Формат в группе Текущий выбор щелкните стрелку рядом с полем Элементы диаграммы , а затем выберите элемент диаграммы, который вы хотите использовать.
- Для категорий установите флажок Категории в обратном порядке .
- Для значений установите флажок Значения в обратном порядке .
Примечание: Вы не можете изменить порядок построения значений на радиолокационной диаграмме.
Изменение порядка построения рядов данных на трехмерной диаграмме
Вы можете изменить порядок построения рядов данных, чтобы крупные трехмерные маркеры данных не блокируют более мелкие.
Рисунок: трехмерные диаграммы с рядами данных, отображаемыми в обратном порядке
На диаграмме щелкните ось глубины или сделайте следующее, чтобы выбрать ее из списка элементов диаграммы:
- Щелкните диаграмму. Откроется вкладка Работа с диаграммами.
- В разделе Работа с диаграммами на вкладке Формат в группе Текущий выбор щелкните стрелку рядом с полем Элементы диаграммы , а затем выберите элемент диаграммы, который вы хотите использовать.
Изменение порядка построения рядов данных на диаграмме
- Щелкните диаграмму, для которой требуется изменить порядок построения рядов данных. Откроется окно Инструменты для диаграмм.
- В разделе Работа с диаграммами на вкладке Конструктор в группе Данные нажмите кнопку Выбрать данные.
- В диалоговом окне Выбор источника данных в поле Записи условных обозначений (ряды) выберите ряд данных, порядок которого требуется изменить.
- Щелкните стрелки Вверх или Вниз , чтобы переместить ряд данных в нужное положение.
Описание алгоритмов сортировки и сравнение их производительности
На эту тему написано уже немало статей. Однако я еще не видел статьи, в которой сравниваются все основные сортировки на большом числе тестов разного типа и размера. Кроме того, далеко не везде выложены реализации и описание набора тестов. Это приводит к тому, что могут возникнуть сомнения в правильности исследования. Однако цель моей работы состоит не только в том, чтобы определить, какие сортировки работают быстрее всего (в целом это и так известно). В первую очередь мне было интересно исследовать алгоритмы, оптимизировать их, чтобы они работали как можно быстрее. Работая над этим, мне удалось придумать эффективную формулу для сортировки Шелла.
Во многом статья посвящена тому, как написать все алгоритмы и протестировать их. Если говорить о самом программировании, то иногда могут возникнуть совершенно неожиданные трудности (во многом благодаря оптимизатору C++). Однако не менее трудно решить, какие именно тесты и в каких количествах нужно сделать. Коды всех алгоритмов, которые выложены в данной статье, написаны мной. Доступны и результаты запусков на всех тестах. Единственное, что я не могу показать — это сами тесты, поскольку они весят почти 140 ГБ. При малейшем подозрении я проверял и код, соответствующий тесту, и сам тест. Надеюсь, что статья Вам понравится.
Описание основных сортировок и их реализация
Я постараюсь кратко и понятно описать сортировки и указать асимптотику, хотя последнее в рамках данной статьи не очень важно (интересно же узнать реальное время работы). О потреблении памяти в дальнейшем ничего писать не буду, замечу только, что сортировки, использующие непростые структуры данных (как, например, сортировка деревом), обычно потребляют ее в больших количествах, а остальные сортировки в худшем случае только создают вспомогательный массив. Также существует понятие стабильности (устойчивости) сортировки. Это значит, что относительный порядок элементов при их равенстве не меняется. Это тоже в рамках данной статьи неважно (в конце концов, можно просто прицепить к элементу его индекс), однако в одном месте пригодится.
Сортировка пузырьком / Bubble sort
Будем идти по массиву слева направо. Если текущий элемент больше следующего, меняем их местами. Делаем так, пока массив не будет отсортирован. Заметим, что после первой итерации самый большой элемент будет находиться в конце массива, на правильном месте. После двух итераций на правильном месте будут стоять два наибольших элемента, и так далее. Очевидно, не более чем после n итераций массив будет отсортирован. Таким образом, асимптотика в худшем и среднем случае – O(n 2 ), в лучшем случае – O(n).
Реализация:
void bubblesort(int* l, int* r) < int sz = r - l; if (sz *(i + 1)) < swap(*i, *(i + 1)); b = true; >> r--; > >
Шейкерная сортировка / Shaker sort
(также известна как сортировка перемешиванием и коктейльная сортировка). Заметим, что сортировка пузырьком работает медленно на тестах, в которых маленькие элементы стоят в конце (их еще называют «черепахами»). Такой элемент на каждом шаге алгоритма будет сдвигаться всего на одну позицию влево. Поэтому будем идти не только слева направо, но и справа налево. Будем поддерживать два указателя begin и end, обозначающих, какой отрезок массива еще не отсортирован. На очередной итерации при достижении end вычитаем из него единицу и движемся справа налево, аналогично, при достижении begin прибавляем единицу и двигаемся слева направо. Асимптотика у алгоритма такая же, как и у сортировки пузырьком, однако реальное время работы лучше.
Реализация:
void shakersort(int* l, int* r) < int sz = r - l; if (sz *(i + 1)) < swap(*i, *(i + 1)); b = true; >> if (!b) break; end--; for (int* i = end; i > beg; i--) < if (*i < *(i - 1)) < swap(*i, *(i - 1)); b = true; >> > >
Сортировка расческой / Comb sort
Еще одна модификация сортировки пузырьком. Для того, чтобы избавиться от «черепах», будем переставлять элементы, стоящие на расстоянии. Зафиксируем его и будем идти слева направо, сравнивая элементы, стоящие на этом расстоянии, переставляя их, если необходимо. Очевидно, это позволит «черепахам» быстро добраться в начало массива. Оптимально изначально взять расстояние равным длине массива, а далее делить его на некоторый коэффициент, равный примерно 1.247. Когда расстояние станет равно единице, выполняется сортировка пузырьком. В лучшем случае асимптотика равна O(nlogn), в худшем – O(n 2 ). Какая асимптотика в среднем мне не очень понятно, на практике похоже на O(nlogn).
Реализация:
void combsort(int* l, int* r) < int sz = r - l; if (sz 1) < for (int* i = l; i + step < r; i++) < if (*i >*(i + step)) swap(*i, *(i + step)); > step /= k; > bool b = true; while (b) < b = false; for (int* i = l; i + 1 < r; i++) < if (*i >*(i + 1)) < swap(*i, *(i + 1)); b = true; >> > >
Об этих сортировках (пузырьком, шейкерной и расческой) также можно почитать здесь.
Сортировка вставками / Insertion sort
Создадим массив, в котором после завершения алгоритма будет лежать ответ. Будем поочередно вставлять элементы из исходного массива так, чтобы элементы в массиве-ответе всегда были отсортированы. Асимптотика в среднем и худшем случае – O(n 2 ), в лучшем – O(n). Реализовывать алгоритм удобнее по-другому (создавать новый массив и реально что-то вставлять в него относительно сложно): просто сделаем так, чтобы отсортирован был некоторый префикс исходного массива, вместо вставки будем менять текущий элемент с предыдущим, пока они стоят в неправильном порядке.
Реализация:
void insertionsort(int* l, int* r) < for (int *i = l + 1; i < r; i++) < int* j = i; while (j >l && *(j - 1) > *j) < swap(*(j - 1), *j); j--; >> >
Сортировка Шелла / Shellsort
Используем ту же идею, что и сортировка с расческой, и применим к сортировке вставками. Зафиксируем некоторое расстояние. Тогда элементы массива разобьются на классы – в один класс попадают элементы, расстояние между которыми кратно зафиксированному расстоянию. Отсортируем сортировкой вставками каждый класс. В отличие от сортировки расческой, неизвестен оптимальный набор расстояний. Существует довольно много последовательностей с разными оценками. Последовательность Шелла – первый элемент равен длине массива, каждый следующий вдвое меньше предыдущего. Асимптотика в худшем случае – O(n 2 ). Последовательность Хиббарда – 2 n — 1, асимптотика в худшем случае – O(n 1,5 ), последовательность Седжвика (формула нетривиальна, можете ее посмотреть по ссылке ниже) — O(n 4/3 ), Пратта (все произведения степеней двойки и тройки) — O(nlog 2 n). Отмечу, что все эти последовательности нужно рассчитать только до размера массива и запускать от большего от меньшему (иначе получится просто сортировка вставками). Также я провел дополнительное исследование и протестировал разные последовательности вида si = a * si — 1 + k * si — 1 (отчасти это было навеяно эмпирической последовательностью Циура – одной из лучших последовательностей расстояний для небольшого количества элементов). Наилучшими оказались последовательности с коэффициентами a = 3, k = 1/3; a = 4, k = 1/4 и a = 4, k = -1/5.
Несколько полезных ссылок:
Реализации:
void shellsort(int* l, int* r) < int sz = r - l; int step = sz / 2; while (step >= 1) < for (int *i = l + step; i < r; i++) < int *j = i; int *diff = j - step; while (diff >= l && *diff > *j) < swap(*diff, *j); j = diff; diff = j - step; >> step /= 2; > > void shellsorthib(int* l, int* r) < int sz = r - l; if (sz >= 1; step--; while (step >= 1) < for (int *i = l + step; i < r; i++) < int *j = i; int *diff = j - step; while (diff >= l && *diff > *j) < swap(*diff, *j); j = diff; diff = j - step; >> step /= 2; > > int steps[100]; void shellsortsedgwick(int* l, int* r) < int sz = r - l; steps[0] = 1; int q = 1; while (steps[q - 1] * 3 < sz) < if (q % 2 == 0) steps[q] = 9 * (1 q--; for (; q >= 0; q--) < int step = steps[q]; for (int *i = l + step; i < r; i++) < int *j = i; int *diff = j - step; while (diff >= l && *diff > *j) < swap(*diff, *j); j = diff; diff = j - step; >> > > void shellsortpratt(int* l, int* r) < int sz = r - l; steps[0] = 1; int cur = 1, q = 1; for (int i = 1; i < sz; i++) < int cur = 1 sz / 2) break; for (int j = 1; j < sz; j++) < cur *= 3; if (cur >sz / 2) break; steps[q++] = cur; > > insertionsort(steps, steps + q); q--; for (; q >= 0; q--) < int step = steps[q]; for (int *i = l + step; i < r; i++) < int *j = i; int *diff = j - step; while (diff >= l && *diff > *j) < swap(*diff, *j); j = diff; diff = j - step; >> > > void myshell1(int* l, int* r) < int sz = r - l, q = 1; steps[0] = 1; while (steps[q - 1] < sz) < int s = steps[q - 1]; steps[q++] = s * 4 + s / 4; >q--; for (; q >= 0; q--) < int step = steps[q]; for (int *i = l + step; i < r; i++) < int *j = i; int *diff = j - step; while (diff >= l && *diff > *j) < swap(*diff, *j); j = diff; diff = j - step; >> > > void myshell2(int* l, int* r) < int sz = r - l, q = 1; steps[0] = 1; while (steps[q - 1] < sz) < int s = steps[q - 1]; steps[q++] = s * 3 + s / 3; >q--; for (; q >= 0; q--) < int step = steps[q]; for (int *i = l + step; i < r; i++) < int *j = i; int *diff = j - step; while (diff >= l && *diff > *j) < swap(*diff, *j); j = diff; diff = j - step; >> > > void myshell3(int* l, int* r) < int sz = r - l, q = 1; steps[0] = 1; while (steps[q - 1] < sz) < int s = steps[q - 1]; steps[q++] = s * 4 - s / 5; >q--; for (; q >= 0; q--) < int step = steps[q]; for (int *i = l + step; i < r; i++) < int *j = i; int *diff = j - step; while (diff >= l && *diff > *j) < swap(*diff, *j); j = diff; diff = j - step; >> > >
Сортировка деревом / Tree sort
Будем вставлять элементы в двоичное дерево поиска. После того, как все элементы вставлены достаточно обойти дерево в глубину и получить отсортированный массив. Если использовать сбалансированное дерево, например красно-черное, асимптотика будет равна O(nlogn) в худшем, среднем и лучшем случае. В реализации использован контейнер multiset.
Здесь можно почитать про деревья поиска:
Реализация:
void treesort(int* l, int* r) < multisetm; for (int *i = l; i
Гномья сортировка / Gnome sort
Алгоритм похож на сортировку вставками. Поддерживаем указатель на текущий элемент, если он больше предыдущего или он первый — смещаем указатель на позицию вправо, иначе меняем текущий и предыдущий элементы местами и смещаемся влево.
Реализация:
void gnomesort(int* l, int* r) < int *i = l; while (i < r) < if (i == l || *(i - 1) >
Сортировка выбором / Selection sort
На очередной итерации будем находить минимум в массиве после текущего элемента и менять его с ним, если надо. Таким образом, после i-ой итерации первые i элементов будут стоять на своих местах. Асимптотика: O(n 2 ) в лучшем, среднем и худшем случае. Нужно отметить, что эту сортировку можно реализовать двумя способами – сохраняя минимум и его индекс или просто переставляя текущий элемент с рассматриваемым, если они стоят в неправильном порядке. Первый способ оказался немного быстрее, поэтому он и реализован.
Реализация:
void selectionsort(int* l, int* r) < for (int *i = l; i < r; i++) < int minz = *i, *ind = i; for (int *j = i + 1; j < r; j++) < if (*j < minz) minz = *j, ind = j; >swap(*i, *ind); > >
Пирамидальная сортировка / Heapsort
Развитие идеи сортировки выбором. Воспользуемся структурой данных «куча» (или «пирамида», откуда и название алгоритма). Она позволяет получать минимум за O(1), добавляя элементы и извлекая минимум за O(logn). Таким образом, асимптотика O(nlogn) в худшем, среднем и лучшем случае. Реализовывал кучу я сам, хотя в С++ и есть контейнер priority_queue, поскольку этот контейнер довольно медленный.
Почитать про кучу можно здесь:
Реализация:
template class heap < public: int size() < return n; >int top() < return h[0]; >bool empty() < return n == 0; >void push(T a) < h.push_back(a); SiftUp(n); n++; >void pop() < n--; swap(h[n], h[0]); h.pop_back(); SiftDown(0); >void clear() < h.clear(); n = 0; >T operator [] (int a) < return h[a]; >private: vector h; int n = 0; void SiftUp(int a) < while (a) < int p = (a - 1) / 2; if (h[p] >h[a]) swap(h[p], h[a]); else break; a--; a /= 2; > > void SiftDown(int a) < while (2 * a + 1 < n) < int l = 2 * a + 1, r = 2 * a + 2; if (r == n) < if (h[l] < h[a]) swap(h[l], h[a]); break; >else if (h[l] else break; > else if (h[r] < h[a]) < swap(h[r], h[a]); a = r; >else break; > > >; void heapsort(int* l, int* r) < heaph; for (int *i = l; i < r; i++) h.push(*i); for (int *i = l; i < r; i++) < *i = h.top(); h.pop(); >>
Быстрая сортировка / Quicksort
Выберем некоторый опорный элемент. После этого перекинем все элементы, меньшие его, налево, а большие – направо. Рекурсивно вызовемся от каждой из частей. В итоге получим отсортированный массив, так как каждый элемент меньше опорного стоял раньше каждого большего опорного. Асимптотика: O(nlogn) в среднем и лучшем случае, O(n 2 ). Наихудшая оценка достигается при неудачном выборе опорного элемента. Моя реализация этого алгоритма совершенно стандартна, идем одновременно слева и справа, находим пару элементов, таких, что левый элемент больше опорного, а правый меньше, и меняем их местами. Помимо чистой быстрой сортировки, участвовала в сравнении и сортировка, переходящая при малом количестве элементов на сортировку вставками. Константа подобрана тестированием, а сортировка вставками — наилучшая сортировка, подходящая для этой задачи (хотя не стоит из-за этого думать, что она самая быстрая из квадратичных).
Реализация:
void quicksort(int* l, int* r) < if (r - l z) rr--; if (ll > if (l < rr) quicksort(l, rr + 1); if (ll < r) quicksort(ll, r); >void quickinssort(int* l, int* r) < if (r - l int z = *(l + (r - l) / 2); int* ll = l, *rr = r - 1; while (ll z) rr--; if (ll > if (l
Сортировка слиянием / Merge sort
Сортировка, основанная на парадигме «разделяй и властвуй». Разделим массив пополам, рекурсивно отсортируем части, после чего выполним процедуру слияния: поддерживаем два указателя, один на текущий элемент первой части, второй – на текущий элемент второй части. Из этих двух элементов выбираем минимальный, вставляем в ответ и сдвигаем указатель, соответствующий минимуму. Слияние работает за O(n), уровней всего logn, поэтому асимптотика O(nlogn). Эффективно заранее создать временный массив и передать его в качестве аргумента функции. Эта сортировка рекурсивна, как и быстрая, а потому возможен переход на квадратичную при небольшом числе элементов.
Реализация:
void merge(int* l, int* m, int* r, int* temp) < int *cl = l, *cr = m, cur = 0; while (cl < m && cr < r) < if (*cl < *cr) temp[cur++] = *cl, cl++; else temp[cur++] = *cr, cr++; >while (cl < m) temp[cur++] = *cl, cl++; while (cr < r) temp[cur++] = *cr, cr++; cur = 0; for (int* i = l; i < r; i++) *i = temp[cur++]; >void _mergesort(int* l, int* r, int* temp) < if (r - l void mergesort(int* l, int* r) < int* temp = new int[r - l]; _mergesort(l, r, temp); delete temp; >void _mergeinssort(int* l, int* r, int* temp) < if (r - l int *m = l + (r - l) / 2; _mergeinssort(l, m, temp); _mergeinssort(m, r, temp); merge(l, m, r, temp); > void mergeinssort(int* l, int* r)
Сортировка подсчетом / Counting sort
Создадим массив размера r – l, где l – минимальный, а r – максимальный элемент массива. После этого пройдем по массиву и подсчитаем количество вхождений каждого элемента. Теперь можно пройти по массиву значений и выписать каждое число столько раз, сколько нужно. Асимптотика – O(n + r — l). Можно модифицировать этот алгоритм, чтобы он стал стабильным: для этого определим место, где должно стоять очередное число (это просто префиксные суммы в массиве значений) и будем идти по исходному массиву слева направо, ставя элемент на правильное место и увеличивая позицию на 1. Эта сортировка не тестировалась, поскольку большинство тестов содержало достаточно большие числа, не позволяющие создать массив требуемого размера. Однако она, тем не менее, пригодилась.
Блочная сортировка / Bucket sort
(также известна как корзинная и карманная сортировка). Пусть l – минимальный, а r – максимальный элемент массива. Разобьем элементы на блоки, в первом будут элементы от l до l + k, во втором – от l + k до l + 2k и т.д., где k = (r – l) / количество блоков. В общем-то, если количество блоков равно двум, то данный алгоритм превращается в разновидность быстрой сортировки. Асимптотика этого алгоритма неясна, время работы зависит и от входных данных, и от количества блоков. Утверждается, что на удачных данных время работы линейно. Реализация этого алгоритма оказалась одной из самых трудных задач. Можно сделать это так: просто создавать новые массивы, рекурсивно их сортировать и склеивать. Однако такой подход все же довольно медленный и меня не устроил. В эффективной реализации используется несколько идей:
1) Не будем создавать новых массивов. Для этого воспользуемся техникой сортировки подсчетом – подсчитаем количество элементов в каждом блоке, префиксные суммы и, таким образом, позицию каждого элемента в массиве.
2) Не будем запускаться из пустых блоков. Занесем индексы непустых блоков в отдельный массив и запустимся только от них.
3) Проверим, отсортирован ли массив. Это не ухудшит время работы, так как все равно нужно сделать проход с целью нахождения минимума и максимума, однако позволит алгоритму ускориться на частично отсортированных данных, ведь элементы вставляются в новые блоки в том же порядке, что и в исходном массиве.
4) Поскольку алгоритм получился довольно громоздким, при небольшом количестве элементов он крайне неэффективен. До такой степени, что переход на сортировку вставками ускоряет работу примерно в 10 раз.
Осталось только понять, какое количество блоков нужно выбрать. На рандомизированных тестах мне удалось получить следующую оценку: 1500 блоков для 10 7 элементов и 3000 для 10 8 . Подобрать формулу не удалось – время работы ухудшалось в несколько раз.
Реализация:
void _newbucketsort(int* l, int* r, int* temp) < if (r - l int minz = *l, maxz = *l; bool is_sorted = true; for (int *i = l + 1; i < r; i++) < minz = min(minz, *i); maxz = max(maxz, *i); if (*i < *(i - 1)) is_sorted = false; >if (is_sorted) return; int diff = maxz - minz + 1; int numbuckets; if (r - l int sz = 0; for (int i = 1; i for (int i = 0; i < sz; i++) < int r = run[i]; if (r != 0) _newbucketsort(l + cnt[r - 1], l + cnt[r], temp); else _newbucketsort(l, l + cnt[r], temp); >delete run; delete cnt; > void newbucketsort(int* l, int* r)
Поразрядная сортировка / Radix sort
(также известна как цифровая сортировка). Существует две версии этой сортировки, в которых, на мой взгляд, мало общего, кроме идеи воспользоваться представлением числа в какой-либо системе счисления (например, двоичной).
LSD (least significant digit):
Представим каждое число в двоичном виде. На каждом шаге алгоритма будем сортировать числа таким образом, чтобы они были отсортированы по первым k * i битам, где k – некоторая константа. Из данного определения следует, что на каждом шаге достаточно стабильно сортировать элементы по новым k битам. Для этого идеально подходит сортировка подсчетом (необходимо 2 k памяти и времени, что немного при удачном выборе константы). Асимптотика: O(n), если считать, что числа фиксированного размера (а в противном случае нельзя было бы считать, что сравнение двух чисел выполняется за единицу времени). Реализация довольно проста.
Реализация:
int digit(int n, int k, int N, int M) < return (n >> (N * k) & (M - 1)); > void _radixsort(int* l, int* r, int N) < int k = (32 + N - 1) / N; int M = 1 = l; j--) b[--c[digit(*j, i, N, M)]] = *j; int cur = 0; for (int* j = l; j < r; j++) *j = b[cur++]; >delete b; delete c; > void radixsort(int* l, int* r)
MSD (most significant digit):
На самом деле, некоторая разновидность блочной сортировки. В один блок будут попадать числа с равными k битами. Асимптотика такая же, как и у LSD версии. Реализация очень похожа на блочную сортировку, но проще. В ней используется функция digit, определенная в реализации LSD версии.
Реализация:
void _radixsortmsd(int* l, int* r, int N, int d, int* temp) < if (d == -1) return; if (r - l int M = 1 int sz = 0; for (int i = 1; i for (int i = 0; i < sz; i++) < int r = run[i]; if (r != 0) _radixsortmsd(l + cnt[r - 1], l + cnt[r], N, d - 1, temp); else _radixsortmsd(l, l + cnt[r], N, d - 1, temp); >delete run; delete cnt; > void radixsortmsd(int* l, int* r)
Битонная сортировка / Bitonic sort:
Идея данного алгоритма заключается в том, что исходный массив преобразуется в битонную последовательность – последовательность, которая сначала возрастает, а потом убывает. Ее можно эффективно отсортировать следующим образом: разобьем массив на две части, создадим два массива, в первый добавим все элементы, равные минимуму из соответственных элементов каждой из двух частей, а во второй – равные максимуму. Утверждается, что получатся две битонные последовательности, каждую из которых можно рекурсивно отсортировать тем же образом, после чего можно склеить два массива (так как любой элемент первого меньше или равен любого элемента второго). Для того, чтобы преобразовать исходный массив в битонную последовательность, сделаем следующее: если массив состоит из двух элементов, можно просто завершиться, иначе разделим массив пополам, рекурсивно вызовем от половинок алгоритм, после чего отсортируем первую часть по порядку, вторую в обратном порядке и склеим. Очевидно, получится битонная последовательность. Асимптотика: O(nlog 2 n), поскольку при построении битонной последовательности мы использовали сортировку, работающую за O(nlogn), а всего уровней было logn. Также заметим, что размер массива должен быть равен степени двойки, так что, возможно, придется его дополнять фиктивными элементами (что не влияет на асимптотику).
Реализация:
void bitseqsort(int* l, int* r, bool inv) < if (r - l *j)) swap(*i, *j); > bitseqsort(l, m, inv); bitseqsort(m, r, inv); > void makebitonic(int* l, int* r) < if (r - l void bitonicsort(int* l, int* r)
Timsort
Гибридная сортировка, совмещающая сортировку вставками и сортировку слиянием. Разобьем элементы массива на несколько подмассивов небольшого размера, при этом будем расширять подмассив, пока элементы в нем отсортированы. Отсортируем подмассивы сортировкой вставками, пользуясь тем, что она эффективно работает на отсортированных массивах. Далее будем сливать подмассивы как в сортировке слиянием, беря их примерно равного размера (иначе время работы приблизится к квадратичному). Для этого удобного хранить подмассивы в стеке, поддерживая инвариант — чем дальше от вершины, тем больше размер, и сливать подмассивы на верхушке только тогда, когда размер третьего по отдаленности от вершины подмассива больше или равен сумме их размеров. Асимптотика: O(n) в лучшем случае и O(nlogn) в среднем и худшем случае. Реализация нетривиальна, твердой уверенности в ней у меня нет, однако время работы она показала довольно неплохое и согласующееся с моими представлениями о том, как должна работать эта сортировка.
Подробнее timsort описан здесь:
Реализация:
void _timsort(int* l, int* r, int* temp) < int sz = r - l; if (sz int minrun = sz, f = 0; while (minrun >= 64) < f |= minrun & 1; minrun >>= 1; > minrun += f; int* cur = l; stack> s; while (cur < r) < int* c1 = cur; while (c1 < r - 1 && *c1 = *(c2 + 1)) c2++; if (c1 >= c2) < c1 = max(c1, cur + minrun - 1); c1 = min(c1, r - 1); insertionsort(cur, c1 + 1); s.push(< c1 - cur + 1, cur >); cur = c1 + 1; > else < c2 = max(c2, cur + minrun - 1); c2 = min(c2, r - 1); reverse(cur, c2 + 1); insertionsort(cur, c2 + 1); s.push(< c2 - cur + 1, cur >); cur = c2 + 1; > while (s.size() >= 3) < pairx = s.top(); s.pop(); pair y = s.top(); s.pop(); pair z = s.top(); s.pop(); if (z.first >= x.first + y.first && y.first >= x.first) < s.push(z); s.push(y); s.push(x); break; >else if (z.first >= x.first + y.first) < merge(y.second, x.second, x.second + x.first, temp); s.push(z); s.push(< x.first + y.first, y.second >); > else < merge(z.second, y.second, y.second + y.first, temp); s.push(< z.first + y.first, z.second >); s.push(x); > > > while (s.size() != 1) < pairx = s.top(); s.pop(); pair y = s.top(); s.pop(); if (x.second < y.second) swap(x, y); merge(y.second, x.second, x.second + x.first, temp); s.push(< y.first + x.first, y.second >); > > void timsort(int* l, int* r)
Тестирование
Железо и система
Процессор: Intel Core i7-3770 CPU 3.40 GHz
ОЗУ: 8 ГБ
Тестирование проводилось на почти чистой системе Windows 10 x64, установленной за несколько дней до запуска. Использованная IDE – Microsoft Visual Studio 2015.
Тесты
Все тесты поделены на четыре группы. Первая группа – массив случайных чисел по разным модулям (10, 1000, 10 5 , 10 7 и 10 9 ). Вторая группа – массив, разбивающийся на несколько отсортированных подмассивов. Фактически брался массив случайных чисел по модулю 10 9 , а далее отсортировывались подмассивы размера, равного минимуму из длины оставшегося суффикса и случайного числа по модулю некоторой константы. Последовательность констант – 10, 100, 1000 и т.д. вплоть до размера массива. Третья группа – изначально отсортированный массив случайных чисел с некоторым числом «свопов» — перестановок двух случайных элементов. Последовательность количеств свопов такая же, как и в предыдущей группе. Наконец, последняя группа состоит из нескольких тестов с полностью отсортированным массивом (в прямом и обратном порядке), нескольких тестов с исходным массивом натуральных чисел от 1 до n, в котором несколько чисел заменены на случайное, и тестов с большим количеством повторений одного элемента (10%, 25%, 50%, 75% и 90%). Таким образом, тесты позволяют посмотреть, как сортировки работают на случайных и частично отсортированных массивах, что выглядит наиболее существенным. Четвертая группа во многом направлена против сортировок с линейным временем работы, которые любят последовательности случайных чисел. В конце статьи есть ссылка на файл, в котором подробно описаны все тесты.
Размер входных данных
Было бы довольно глупо сравнивать, например, сортировку с линейным временем работы и квадратичную, и запускать их на тестах одного размера. Поэтому каждая из групп тестов делится еще на четыре группы, размера 10 5 , 10 6 , 10 7 и 10 8 элементов. Сортировки были разбиты на три группы, в первой – квадратичные (сортировка пузырьком, вставками, выбором, шейкерная и гномья), во второй – нечто среднее между логарифмическим временем и квадратом, (битонная, несколько видов сортировки Шелла и сортировка деревом), в третьей все остальные. Кого-то, возможно, удивит, что сортировка деревом попала не в третью группу, хотя ее асимптотика и O(nlogn), но, к сожалению, ее константа очень велика. Сортировки первой группы тестировались на тестах с 10 5 элементов, второй группы – на тестах с 10 6 и 10 7 , третьей – на тестах с 10 7 и 10 8 . Именно такие размеры данных позволяют как-то увидеть рост времени работы, при меньших размерах слишком велика погрешность, при больших алгоритм работает слишком долго (или же недостаток оперативной памяти). С первой группой я не стал заморачиваться, чтобы не нарушать десятикратное увеличение (10 4 элементов для квадратичных сортировок слишком мало), в конце концов, сами по себе они представляют мало интереса.
Как проводилось тестирование
На каждом тесте было производилось 20 запусков, итоговое время работы – среднее по получившимся значениям. Почти все результаты были получены после одного запуска программы, однако из-за нескольких ошибок в коде и системных глюков (все же тестирование продолжалось почти неделю чистого времени) некоторые сортировки и тесты пришлось впоследствии перетестировать.
Тонкости реализации
Возможно, кого-то удивит, что в реализации самого процесса тестирования я не использовал указатели на функции, что сильно сократило бы код. Оказалось, что это заметно замедляет работу алгоритма (примерно на 5-10%). Поэтому я использовал отдельный вызов каждой функции (это, конечно, не отразилось бы на относительной скорости, но… все же хочется улучшить и абсолютную). По той же причине были заменены векторы на обычные массивы, не были использованы шаблоны и функции-компараторы. Все это более актуально для промышленного использования алгоритма, нежели его тестирования.
Результаты
Все результаты доступны в нескольких видах – три диаграммы (гистограмма, на которой видно изменение скорости при переходе к следующему ограничению на одном типе тестов, график, изображающий то же самое, но иногда более наглядно, и гистограмма, на которой видно, какая сортировка лучше всего работает на каком-то типе тестов) и таблицы, на которых они основаны. Третья группа была разделена еще на три части, а то мало что было бы понятно. Впрочем, и так далеко не все диаграммы удачны (в полезности третьего типа диаграмм я вообще сильно сомневаюсь), но, надеюсь, каждый сможет найти наиболее подходящую для понимания.
Поскольку картинок очень много, они скрыты спойлерами. Немного комментариев по поводу обозначений. Сортировки названы так, как выше, если это сортировка Шелла, то в скобочках указан автор последовательности, к названиям сортировок, переходящих на сортировку вставками, приписано Ins (для компактности). В диаграммах у второй группы тестов обозначена возможная длина отсортированных подмассивов, у третьей группы — количество свопов, у четвертой — количество замен. Общий результат рассчитывался как среднее по четырем группам.
Первая группа сортировок
Массив случайных чисел
Таблицы
Совсем скучные результаты, даже частичная отсортированность при небольшом модуле почти незаметна.
Частично отсортированный массив
Таблицы

Уже гораздо интереснее. Обменные сортировки наиболее бурно отреагировали, шейкерная даже обогнала гномью. Сортировка вставками ускорилась только под самый конец. Сортировка выбором, конечно, работает совершенно также.
Свопы
Таблицы
Здесь наконец-то проявила себя сортировка вставками, хотя рост скорости у шейкерной примерно такой же. Здесь проявилась слабость сортировки пузырьком — достаточно одного свопа, перемещающего маленький элемент в конец, и она уже работает медленно. Сортировка выбором оказалась почти в конце.
Изменения в перестановке
Таблицы

Группа почти ничем не отличается от предыдущей, поэтому результаты похожи. Однако сортировка пузырьком вырывается вперед, так как случайный элемент, вставленный в массив, скорее всего будет больше всех остальных, то есть за одну итерацию переместится в конец. Сортировка выбором стала аутсайдером.
Повторы
Таблицы

Здесь все сортировки (кроме, конечно, сортировки выбором) работали почти одинаково, ускоряясь по мере увеличении количества повторов.
Итоговые результаты

За счет своего абсолютного безразличия к массиву, сортировка выбором, работавшая быстрее всех на случайных данных, все же проиграла сортировке вставками. Гномья сортировка оказалась заметно хуже последней, из-за чего ее практическое применение сомнительно. Шейкерная и пузырьковая сортировки оказались медленнее всех.
Вторая группа сортировок
Массив случайных чисел
Таблицы, 1е6 элементов
Сортировка Шелла с последовательностью Пратта ведет себя совсем странно, остальные более менее ясно. Сортировка деревом любит частично отсортированные массивы, но не любит повторов, возможно, поэтому самое худшее время работы именно посередине.
Таблицы, 1е7 элементов
Все как прежде, только Шелл с Праттом усилился на второй группе из-за отсортированности. Также становится заметным влияние асимптотики — сортировка деревом оказывается на втором месте, в отличие от группы с меньшим числом элементов.
Частично отсортированный массив
Таблицы, 1е6 элементов

Здесь понятным образом ведут себя все сортировки, кроме Шелла с Хиббардом, который почему-то не сразу начинает ускоряться.
Таблицы, 1е7 элементов
Здесь все, в общем, как и прежде. Даже асимптотика сортировки деревом не помогла ей вырваться с последнего места.
Свопы
Таблицы, 1е6 элементов
Таблицы, 1е7 элементов
Здесь заметно, что у сортировок Шелла большая зависимость от частичной отсортированности, так как они ведут себя практически линейно, а остальные две только сильно падают на последних группах.
Изменения в перестановке
Таблицы, 1е6 элементов
Таблицы, 1е7 элементов
Здесь все похоже на предыдущую группу.
Повторы
Таблицы, 1е6 элементов
Опять все сортировки продемонстрировали удивительную сбалансированность, даже битонная, которая, казалось бы, почти не зависит от массива.
Таблицы, 1е7 элементов
Итоговые результаты


Убедительное первое место заняла сортировка Шелла по Хиббарду, не уступив ни в одной промежуточной группе. Возможно, стоило ее отправить в первую группу сортировок, но… она слишком слаба для этого, да и тогда почти никого не было бы в группе. Битонная сортировка довольно уверенно заняла второе место. Третье место при миллионе элементах заняла другая сортировка Шелла, а при десяти миллионах сортировка деревом (асимптотика сказалась). Стоит обратить внимание, что при десятикратном увеличении размера входных данных все алгоритмы, кроме древесной сортировки, замедлились почти в 20 раз, а последняя всего лишь в 13.
Третья группа сортировок
Массив случайных чисел
Таблицы, 1е7 элементов
Таблицы, 1е8 элементов









Почти все сортировки этой группы имеют почти одинаковую динамику. Почему же почти все сортировки ускоряются, когда массив частично отсортирован? Обменные сортировки работают быстрее потому, что надо делать меньше обменов, в сортировке Шелла выполняется сортировка вставками, которая сильно ускоряется на таких массивах, в пирамидальной сортировке при вставке элементов сразу завершается просеивание, в сортировке слиянием выполняется в лучшем случае вдвое меньше сравнений. Блочная сортировка работает тем лучше, чем меньше разность между минимальным и максимальным элементом. Принципиально отличается только поразрядная сортировка, которой все это безразлично. LSD-версия работает тем лучше, чем больший модуль. Динамика MSD-версия мне не ясна, то, что она сработала быстрее чем LSD удивило.
Частично отсортированный массив
Таблицы, 1е7 элементов










Таблицы, 1е8 элементов










Здесь все тоже довольно понятно. Стало заметен алгоритм Timsort, на него отсортированность действует сильнее, чем на остальные. Это позволило этому алгоритму почти сравняться с оптимизированной версией быстрой сортировки. Блочная сортировка, несмотря на улучшение времени работы при частичной отсортированности, не смогла обогнать поразрядную сортировку.
Свопы
Таблицы, 1е7 элементов










Таблицы, 1е8 элементов










Здесь очень хорошо сработали быстрые сортировки. Это, скорее всего, объясняется удачным выбором опорного элемента. Все остальное почти также, как и в предыдущей группе.
Изменения в перестановке
Таблицы, 1е7 элементов










Таблицы, 1е8 элементов










Мне удалось достичь желаемой цели — поразрядная сортировка упала даже ниже адаптированной быстрой. Блочная сортировка оказалась лучше остальных. Еще почему-то timsort обогнал встроенную сортировку C++, хотя в предыдущей группе был ниже.
Повторы
Таблицы, 1е7 элементов










Таблицы, 1е8 элементов










Здесь все довольно тоскливо, все сортировки работают с одинаковой динамикой (кроме линейных). Из необычного можно заметить, что сортировка слиянием упала ниже сортировки Шелла.
Итоговые результаты


Несмотря на мои старания, LSD-версия поразрядной сортировки все-таки заняла первое место и при 10 7 , и при 10 8 элементов. Также она продемонстрировала почти линейный рост времени. Единственная ее замеченная мной слабость — плохая работа с перестановками. MSD-версия сработала немного хуже, в первую очередь из-за большого количества тестов, состоящих из случайных чисел по модулю 10 9 . Реализацией блочной сортировки я остался доволен, несмотря на громоздкость, она показало неплохой результат. Кстати, я слишком поздно это заметил, она не до конца соптимизирована, можно еще отдельно создавать массивы run и cnt, чтобы не тратить время на их удаление. Далее уверенно заняли места различные версии быстрой сортировки. Timsort-у не удалось, на мой взгляд, оказать им серьезную конкуренцию, хотя он не сильно отстал. Далее по скорости идут сортировки слиянием, после них — мои версии сортировки Шелла. Лучше всего оказалась последовательность s * 3 + s / 3, где s — предыдущий элемент последовательности. Далее идет единственное расхождение в двух таблицах — сортировка расческой оказалась лучше при большем числе элементов, чем сортировка Шелла с последовательностью Седжвика. И за последнее место боролись пирамидальная сортировка и оригинальная сортировка Шелла.
Выиграла последняя. Кстати, сортировка Шелла, как я потом проверил, очень плохо работает на тестах размера 2 n , так что ей просто повезло, что она попала в первую группу.
Если говорить о практическом применении, то хороша поразрядная сортировка (особенно lsd-версия), она стабильна, проста в реализации и очень быстра, однако не основана на сравнениях. Из основанных на сравнениях сортировок лучше всего смотрится быстрая сортировка. Ее недостатки — неустойчивость и квадратичное время работы на неудачных входных данных (пусть они и могут встретиться только при намеренном создании теста). Но с этим можно бороться, например, выбирая опорный элемент по какому-нибудь другому принципу, или же переходя на другую сортировку при неудаче (например, introsort, который, если не ошибаюсь, и реализован в С++). Timsort лишен этих недостатков, лучше работает на сильно отсортированных данных, но все же медленнее в целом и гораздо сложнее пишется. Остальные сортировки на данный момент, пожалуй, не очень практичны. Кроме, конечно, сортировки вставками, которую весьма удачно иногда можно вставить в алгоритм.
Заключение
Должен отметить, что не все известные сортировки приняли участие в тестировании, например, была пропущена плавная сортировка (мне просто не удалось ее адекватно реализовать). Впрочем, не думаю, что это большая потеря, эта сортировка очень громоздкая и медленная, как можно видеть, например, из этой статьи: habrahabr.ru/post/133996 Еще можно исследовать сортировки на распараллеливание, но, во-первых, у меня нет опыта, во-вторых, результаты, которые получались, крайне нестабильны, очень велико влияние системы.
Здесь можно посмотреть результаты всех запусков, а также некоторые вспомогательные тестирования: ссылка на документ.
Реализации алгоритмов с векторами остались, но их корректность и хорошую работу не гарантирую. Проще взять коды функций из статьи и переделать. Генераторы тестов тоже могут не соответствовать действительности, на самом деле такой вид они приняли уже после создания тестов, когда нужно было сделать программу более компактной.
В общем, я доволен проделанной работой, надеюсь, что Вам было интересно.
- тестирование производительности
- алгоритмы сортировки
- сортировка пузырьком
- шейкерная сортировка
- сортировка выбором
- сортировка вставками
- гномья сортировка
- битонная сортировка
- сортировка деревом
- сортировка шелла
- поразрядная сортировка
- блочная сортировка
- быстрая сортировка
- timsort
- сортировка слиянием
- сортировка расчёской
- пирамидальная сортировка
Несколько советов по выбору диаграммы
В этой статье мы поговорим о том, какого вида диаграммы стоит использовать в том или ином случае, но прежде всего ответим на важный вопрос:
Зачем вообще нужны диаграммы? Почему нельзя обойтись, например, просто таблицами?
Для ответа на этот вопрос обратимся к одному из самых авторитетных источников информации, а именно, к Википедии:
Диаграмма — графическое представление данных линейными отрезками или геометрическими фигурами, позволяющее быстро оценить соотношение нескольких величин.
Вот и ответ: диаграммы нужны, чтобы быстро оценить соотношение нескольких величин.
И действительно, если вы попытаетесь ответить на вопрос «Курсы каких валют имели наиболее близкую друг к другу динамику по отношению к рублю на протяжении 2017 года?», глядя на таблицу ниже, вам понадобится от 10 до 60 секунд:

А глядя на эту диаграмму, вы ответите за пару секунд:

Однако, если вам показать такую диаграмму, то для ответа на вопрос вам придется подумать, возможно, даже больше, чем над таблицей:

Таким образом, правильно подобранная диаграмма в том или ином случае может значительно ускорить и упростить процесс анализа и восприятия информации, а неправильно выбранная, наоборот, может усложнить и замедлить этот процесс.
В настоящее время существует множество различных типов диаграмм (например, в Excel 15 только основных типов, которые делятся еще на подтипы), но наиболее популярных и часто используемых всего несколько (гистограмма, график или линейная, круговая). Однако, даже в них очень часто умудряются запутаться и выбрать неверный вариант.
Рассмотрим некоторые ошибки и примеры использования самых популярных типов диаграмм.
Одна из наиболее часто встречающихся проблем – это вот такие 3D диаграммы:

В чем же здесь проблема – спросите вы? 3D – это красиво. Но дело в том, что так как сами данные не трехмерные, то и объемное изображение в данном случае не несет никакого смысла, а наоборот мешает восприятию и даже искажает его. На этой 3D диаграмме, при первом взгляде, создается впечатление, что «Плюнет» и «Поцелует» имеют большее значение, чем, скажем, «К сердцу прижмет» и «Не любит». Однако, на самом деле, они равны.
Также восприятие усложняет легенда (это относится к любым диаграммам, не только к круговым). Нужно потратить время, чтобы соотнести значения в легенде с цветами на диаграмме, поэтому, если у вас есть возможность, то лучше подписать ряды прямо на диаграмме.
Вот в таком виде анализировать гораздо проще:

Таким образом, делаем первые выводы:
- Если вам не нужно визуализировать трехмерные данные – не используйте трехмерные диаграммы.
- Если есть возможность подписать названия рядов на самой диаграмме – сделайте это и уберите легенду.
Многие знают, что круговая диаграмма плохо подходит для анализа большого количества рядов (много секторов заводят в тупик), а если поразмыслить дальше, то, вообще говоря, круговая диаграмма также плохо подходит для анализа близких по значению показателей, даже если их немного. Например, если вы думали, что на диаграммах выше все сектора равны, то вы ошибались. На самом деле сектор «Любит» чуть больше остальных. Можно, конечно, вывести в подписи значения и анализировать по ним, но это мало чем будет отличаться от анализа таблицы:

Поэтому для визуального сравнения близких по значению показателей лучше использовать гистограмму:

Здесь сразу вино, что «Любит» чаще остальных.
Также не забывайте на подобных диаграммах сортировать значения, например, по убыванию значений, чтобы ускорить и упростить процесс анализа.
Итак, еще пара выводов:
- Если вам нужно провести визуальный сравнительный анализ близких по значению величин, то лучше подойдет гистограмма, чем круговая диаграмма.
- Если какая-либо сортировка рядов на диаграмме упростит анализ – отсортируйте их.
Обычно круговая диаграмма хорошо показывает структуру чего-либо, однако, если требуется отследить структуру в динамике или сравнить структуру нескольких объектов, то сделать это с помощью круговых диаграмм будет затруднительно.
Например, попробуйте сравнить распределение использования социальных сетей в зависимости от размера населенных пунктов:

Приходится бегать глазами от одного сектора к другому и пытаться соотнести их величину, или же, опять-таки смотреть на цифры с процентами, что не очень-то ускоряет и упрощает процесс.
В данном случае лучше использовать подобные диаграммы:

Здесь взгляду проще сравнивать высоту столбцов.
Это лишь несколько примеров, которые позволяют понять, что в каждом отдельном случае нужно хорошо подумать над тем, какую диаграмму использовать. Чтобы облегчить раздумья, многие современные программные продукты для анализа данных используют передовые технологии для упрощения процессов построения диаграмм. В частности, применяют интеллектуальные технологии для автоматического определения наилучшего типа диаграммы по данным и дают рекомендации пользователям.
Например, я часто использую для анализа данных российскую платформу класса бизнес-аналитики «Форсайт. Аналитическую платформу». В последней версии этой платформы также появилась опция рекомендуемых типов диаграмм, что значительно упрощает работу и позволяет не допустить грубых ошибок.
Вот пара вариантов того, как работают интеллектуальные системы подбора диаграмм, на примере «Форсайт. Аналитической платформы».
При выборе в таблице нескольких рядов в динамике, система в первую очередь предлагает график, который позволяет наиболее удачно визуализировать изменения:

При выборе одного периода по нескольким рядам, система предлагает уже круговую диаграмму:

Таким образом, современные технологии могут подсказать вам, как наиболее корректно визуализировать данные. Однако окончательный выбор за вами. Главное, чтобы выбранная вами диаграмма ускоряла и упрощала восприятие информации, а не наоборот.
В любом случае, правильного выбора в реальности не существует — есть только сделанный выбор и его последствия. Желаю вам, чтобы, сделанный вами выбор диаграммы всегда имел только благоприятные последствия!
Зачем нужна сортировка при построении диаграмм
В статье рассматриваются простые способы придать диаграммам более презентабельный вид.
По крайней мере, вы узнаете как избежать распространённых ошибок при их оформлении.
1. Удалите «шумы» с фона графики
Когда вы представляете данные, очень важно, говоря техническим языком, «уменьшить шум и выделить несущий сигнал». Начнем с негативного отношения к сеткам в таблицах. Даже в прекрасных презентациях, где поначалу на них не обращаешь внимания, со временем они начинают раздражать. И это основная проблема шума: он отвлекает от действительно важного.
От сетки на графике избавиться элементарно. Если необходимо применить формат к чему-либо в Excel (на диаграмме или в таблице), то просто выделите это и нажмите кнопки Ctrl+1 (для Mac: Command+1) – откроется диалоговое окно форматирования выбранных объектов.
В нашем случае щёлкаете одну из линий сетки на диаграмме (любую, но верхняя выделит всю область графика) и открываете диалоговое окно форматирования. Дальше выбираемЦвет линии > Нет линий (для Mac: Линия > Сплошная > Цвет: Без линии ).


2. Переместите легенду
По неизвестной причине Excel по умолчанию размещает легенду справа от графика (легенда – пояснительная информация к графику). В большинстве случаев это жутко неудобно. Предпочтительно размещать легенду над или под графиком. Чаще её логичнее оставить сверху, но если информации много или это круговая диаграмма, то опускаем легенду вниз.
Для этого вызываем окошко с настройками форматирования (вы уже должны знать как!) и выбираем нужную позицию в пункте Параметры легенды, у Mac соответственно Размещение > нужный пункт.
Не снимая выделения с легенды, сразу увеличиваем размер шрифта до 12. Выделять сам текст не надо, достаточно выделенного прямоугольника. Оцените сами, что лучше смотрится…


3. Удалите легенду с единственным рядом
Если на графике отражён только один показатель, нет смысла сохранять легенду, которую Excel вставляет автоматически. Достаточно включить название показателя в заголовок.

4. Добавьте описание в название диаграммы
Распространённая ошибка, встречающаяся на диаграммах маркетологов – отсутствие понятного названия. Пока вы единственный, кто сводит данные вместе, всё, что вы пытаетесь показать, совершенно понятно. Но для остальных это не так очевидно.
Например, для диаграммы приведённой ниже, было бы малоинформативно написать в заголовке только лишь «Показы»:

Чтобы добавить название к выделенному графику выберите Работа с диаграммами > Макет > Название диаграммы > нужный пункт. Для Mac соответственно: Диаграммы > Макет диаграммы > Название диаграммы > нужный пункт. Обычно разумнее выбрать Над диаграммой (Mac: Название над диаграммой).
5. Отсортируйте данные перед созданием диаграмм
Считаем данный пункт достойным особого внимания. Диаграммы, которые создаются из несортированных данных, гораздо труднее читать и интерпретировать.
При показе чего-либо последовательного, такого как количество посещений по дням в течение месяца, или помесячных доходов за год, наиболее логично располагать данные в хронологическом порядке. В отсутствие преобладающего параметра сортировки, принимаем, что данные следует упорядочить по значению.
Взгляните на диаграмму ниже. Согласитесь, что для сортировки доходов по категориям придётся бегать глазами взад вперёд.

А вот на следующей диаграмме провести сортировку и интерпретацию гораздо легче, так как это уже фактически сделано за вас.

Еще одно преимущество форматирования данных как таблицы перед созданием диаграммы это – возможность сортировки, встроенная в фильтры, добавляемые в заголовок каждого столбца. После сортировки данных, диаграмма обновляется автоматически.
6. Не заставляйте людей наклонять голову
Видели ли вы диаграммы подобные этой?

Или ещё хуже?

Работать с такими данными тяжело, и велик риск ошибки. Если имеются длинные подписи, растяните диаграмму так, чтобы метки могли отобразиться горизонтально. А лучше вместо столбчатой диаграммы используйте линейчатую, например, такую:

Совет: Если вы хотите разместить на линейчатой диаграмме наибольшие величины вверху, расположите данные соответствующего столбца (в данном случае столбец Показы) в порядке возрастания.
Такой порядок кажется нелогичным, но если этого не сделать, то в верхней части окажутся наименьшие значения. А люди, разумеется, читают таблицы сверху вниз, поэтому предпочтительно располагать важные данные сверху.
7. Приведите в порядок оси
Диаграмма ниже это – сплошной кошмар. В ней присутствует все «неправильности», которые наиболее заметны в осях графиков.

Перед тем как приступим к действиям с ними, уберём линии сетки и легенду. Потом сосредоточимся на пяти распространённых ошибках, встречающихся на осях диаграмм.
Отсутствуют разделители групп разрядов
Если в данных присутствуют числа больше чем 999, необходимо включить разделитель групп разрядов. Лучше всего отформатировать данные прямо в таблице. После этого диаграмма обновится автоматически. В противном случае необходимо снять флажок Связь с источником в окне настроек Формат оси.
Для включения разделителя групп выделите столбец с данными и нажмите кнопку 000 в группе Число. Появится разделитель, и Excel по умолчанию добавит два знака после запятой.
Или же можно открыть диалоговое окно форматирования, нажав стрелочку справа внизу у группы Число.
Загромождённость осей
Вертикальная ось на верхней диаграмме загромождена лишними подписями. Для исправления этого выделите ось и вызовите диалоговое окно. В Параметрах осиустановите переключатель цена основных делений на фиксированный (для Mac_: Формат осей > Масштаб > цена основных делений_). На нижней диаграмме этот параметр изменён с 20 000 на 40 000.
Если нужно более детальное разбиение, подберите шаг любым удобным способом.

Ненужные десятичные знаки
Никогда не включайте десятичные дроби, если все числа – целые (иными словами отсутствуют дробные части). Наиболее часто такое можно увидеть при использовании формата _Денежный, _где встречаются подобные подписи: $20 000.00, $30 000.00, и т.д. Это совершенно бесполезно и только мешает.
Десятичные дроби вместо процентов
Если на оси показаны проценты, форматируйте данные как проценты, не выводите их десятичными дробями. Чем меньше времени придётся тратить на интерпретацию данных, тем более привлекательной будет графика. И даже с процентами не забывайте убрать ненужные дроби. Иначе говоря, не делайте так: 10,00%, 20,00%… Преобразуйте к такому виду: 10%, 20%…
Жуткое форматирование ноля
Последнее неудобство – вывод дефиса вместо 0 в начале вертикальной оси. Это очень распространено. В Интернете можно найти, как работать с пользовательским числовым форматом. Там рассматриваются некоторые любопытные настройки, например, возможность добавлять текст к форматированию с сохранением числовых значений ячейки.
В данном случае нам достаточно изменить формат для 0. Для этого выделяем столбец, из которого берутся данные, потом вызываем диалоговое окно и на вкладке Число, в пункте(все форматы) находим строку «своего», в ней заменяем дефис на 0.