智能计算图表刻度位置

发布于 2024-10-16 19:02:23 字数 951 浏览 6 评论 0原文

无论我使用 matplotlib、Open-Flash-Charts 或其他图表框架,我总是需要找到一种方法来设置 x/y 比例限制和间隔,因为内置函数不够智能(或根本不......),

只需尝试一下这在 pylab (ipyhton -pylab) 中理解我的意思:

In [1]: a, b, x = np.zeros(10), np.ones(10), np.arange(10)

In [2]: plot(x, a); plot(x, b)

你会看到只是空的框架网格,隐藏了其顶部和底部边框下方的 2 条水平线。

我想知道是否有一些算法(我可以将其移植到 python)来智能地设置顶部和底部 y 限制和步骤,并计算每个显示 x 厚度的值。

例如,假设我有 475 个测量值 (datetime, temp) 作为 (x, y)

2011-01-15 10:45:00 < datetime < 2011-01-17 02:20:00

(每 5 分钟一次),

26.5 < temperature < 28.3

我对这种特殊情况的建议可以是要设置:

26.4 <= y_scale <= 28.4,每个 .2 较粗

,每 12 个项目在 x_scale 上勾勾(每小时一次)。

但是,如果我在 20 天内只有 20 个测量 -21.5 -21.5 -21.5 -21.5 温度< 38.7 等等?有没有标准化的方法?

Whatever I'm using matplotlib, Open-Flash-Charts or other charts frameworks I always end needing to find a way to set x/y scales limits and intervals since builtins are not enough smart (or not at all...)

just try this in pylab (ipyhton -pylab) to understand what I mean:

In [1]: a, b, x = np.zeros(10), np.ones(10), np.arange(10)

In [2]: plot(x, a); plot(x, b)

you'll see just and empty frame grid hiding the 2 horizontal lines under it's its top and bottom borders.

I wonder if there is some algorithm around (that I can port to python) to set smartly top and bottom y limits and steps and also calculate every how many values show the x thick.

For example, let's say I have 475 measures as (datetime, temperature) as (x, y) with

2011-01-15 10:45:00 < datetime < 2011-01-17 02:20:00

(one every 5 minutes) and

26.5 < temperature < 28.3

My suggestion for this particular case could be to set:

26.4 <= y_scale <= 28.4 with a thick every .2

and a tick on x_scale every 12 items (once per hour).

But what about if I have just 20 measures over 20 days with -21.5 < temperature < 38.7, and so on? Is there a standardized method around?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

几味少女 2024-10-23 19:02:23

以下是我多年来使用的方法,简单且效果很好。请原谅我它是 C 语言,但翻译成 Python 应该不难。

需要以下函数,该函数来自 Graphic Gems 第 1 卷。

double NiceNumber (const double Value, const int Round) {
  int    Exponent;
  double Fraction;
  double NiceFraction;

  Exponent = (int) floor(log10(Value));
  Fraction = Value/pow(10, (double)Exponent);

  if (Round) {
    if (Fraction < 1.5) 
      NiceFraction = 1.0;
    else if (Fraction < 3.0)
      NiceFraction = 2.0;
    else if (Fraction < 7.0)
      NiceFraction = 5.0;
    else
      NiceFraction = 10.0;
   }
  else {
    if (Fraction <= 1.0)
      NiceFraction = 1.0;
    else if (Fraction <= 2.0)
      NiceFraction = 2.0;
    else if (Fraction <= 5.0)
      NiceFraction = 5.0;
    else
      NiceFraction = 10.0;
   }

  return NiceFraction*pow(10, (double)Exponent);
 }

像下面的示例一样使用它,根据您希望显示的主要刻度数选择轴的“良好”起点/终点。如果您不关心刻度,您可以将其设置为常量值(例如:10)。

      //Input parameters
  double AxisStart = 26.5;
  double AxisEnd   = 28.3;
  double NumTicks  = 10;

  double AxisWidth;
  double NewAxisStart;
  double NewAxisEnd;
  double NiceRange;
  double NiceTick;

    /* Check for special cases */
  AxisWidth = AxisEnd - AxisStart;
  if (AxisWidth == 0.0) return (0.0);

    /* Compute the new nice range and ticks */
  NiceRange = NiceNumber(AxisEnd - AxisStart, 0);
  NiceTick = NiceNumber(NiceRange/(NumTicks - 1), 1);

    /* Compute the new nice start and end values */
  NewAxisStart = floor(AxisStart/NiceTick)*NiceTick;
  NewAxisEnd = ceil(AxisEnd/NiceTick)*NiceTick;

  AxisStart = NewAxisStart; //26.4
  AxisEnd = NewAxisEnd;     //28.4

The following is what I've used for years which is simple and works well enough. Forgive me for it being C but translating to Python shouldn't be difficult.

The following function is needed and is from Graphic Gems volume 1.

double NiceNumber (const double Value, const int Round) {
  int    Exponent;
  double Fraction;
  double NiceFraction;

  Exponent = (int) floor(log10(Value));
  Fraction = Value/pow(10, (double)Exponent);

  if (Round) {
    if (Fraction < 1.5) 
      NiceFraction = 1.0;
    else if (Fraction < 3.0)
      NiceFraction = 2.0;
    else if (Fraction < 7.0)
      NiceFraction = 5.0;
    else
      NiceFraction = 10.0;
   }
  else {
    if (Fraction <= 1.0)
      NiceFraction = 1.0;
    else if (Fraction <= 2.0)
      NiceFraction = 2.0;
    else if (Fraction <= 5.0)
      NiceFraction = 5.0;
    else
      NiceFraction = 10.0;
   }

  return NiceFraction*pow(10, (double)Exponent);
 }

Use it like in the following example to choose a "nice" start/end of the axis based on the number of major ticks you wish displayed. If you don't care about ticks you can just set it to a constant value (ex: 10).

      //Input parameters
  double AxisStart = 26.5;
  double AxisEnd   = 28.3;
  double NumTicks  = 10;

  double AxisWidth;
  double NewAxisStart;
  double NewAxisEnd;
  double NiceRange;
  double NiceTick;

    /* Check for special cases */
  AxisWidth = AxisEnd - AxisStart;
  if (AxisWidth == 0.0) return (0.0);

    /* Compute the new nice range and ticks */
  NiceRange = NiceNumber(AxisEnd - AxisStart, 0);
  NiceTick = NiceNumber(NiceRange/(NumTicks - 1), 1);

    /* Compute the new nice start and end values */
  NewAxisStart = floor(AxisStart/NiceTick)*NiceTick;
  NewAxisEnd = ceil(AxisEnd/NiceTick)*NiceTick;

  AxisStart = NewAxisStart; //26.4
  AxisEnd = NewAxisEnd;     //28.4
山有枢 2024-10-23 19:02:23

我在这里报告我的上述 C 代码的 python 版本,如果它可能对某人有任何帮助:

import math


def nice_number(value, round_=False):
    '''nice_number(value, round_=False) -> float'''
    exponent = math.floor(math.log(value, 10))
    fraction = value / 10 ** exponent

    if round_:
        if fraction < 1.5:
            nice_fraction = 1.
        elif fraction < 3.:
            nice_fraction = 2.
        elif fraction < 7.:
            nice_fraction = 5.
        else:
            nice_fraction = 10.
    else:
        if fraction <= 1:
            nice_fraction = 1.
        elif fraction <= 2:
            nice_fraction = 2.
        elif fraction <= 5:
            nice_fraction = 5.
        else:
            nice_fraction = 10.

    return nice_fraction * 10 ** exponent


def nice_bounds(axis_start, axis_end, num_ticks=10):
    '''
    nice_bounds(axis_start, axis_end, num_ticks=10) -> tuple
    @return: tuple as (nice_axis_start, nice_axis_end, nice_tick_width)
    '''
    axis_width = axis_end - axis_start
    if axis_width == 0:
        nice_tick = 0
    else:
        nice_range = nice_number(axis_width)
        nice_tick = nice_number(nice_range / (num_ticks - 1), round_=True)
        axis_start = math.floor(axis_start / nice_tick) * nice_tick
        axis_end = math.ceil(axis_end / nice_tick) * nice_tick

    return axis_start, axis_end, nice_tick

用作:

>>> nice_bounds(26.5, 28.3)
(26.4, 28.4, 0.2)

同时添加 javascript 移植:

function nice_number(value, round_){
    //default value for round_ is false
    round_ = round_ || false;
    // :latex: \log_y z = \frac{\log_x z}{\log_x y}
    var exponent = Math.floor(Math.log(value) / Math.log(10));
    var fraction = value / Math.pow(10, exponent);

    if (round_)
        if (fraction < 1.5)
            nice_fraction = 1.
        else if (fraction < 3.)
            nice_fraction = 2.
        else if (fraction < 7.)
            nice_fraction = 5.
        else
            nice_fraction = 10.
    else
        if (fraction <= 1)
            nice_fraction = 1.
        else if (fraction <= 2)
            nice_fraction = 2.
        else if (fraction <= 5)
            nice_fraction = 5.
        else
            nice_fraction = 10.

    return nice_fraction * Math.pow(10, exponent)
}

function nice_bounds(axis_start, axis_end, num_ticks){
    //default value is 10
    num_ticks = num_ticks || 10;
    var axis_width = axis_end - axis_start;

    if (axis_width == 0){
        axis_start -= .5
        axis_end += .5
        axis_width = axis_end - axis_start
    }

    var nice_range = nice_number(axis_width);
    var nice_tick = nice_number(nice_range / (num_ticks -1), true);
    var axis_start = Math.floor(axis_start / nice_tick) * nice_tick;
    var axis_end = Math.ceil(axis_end / nice_tick) * nice_tick;
    return {
        "min": axis_start,
        "max": axis_end,
        "steps": nice_tick
    }
}

I report here my python version of above C code if it may be of any help for someone:

import math


def nice_number(value, round_=False):
    '''nice_number(value, round_=False) -> float'''
    exponent = math.floor(math.log(value, 10))
    fraction = value / 10 ** exponent

    if round_:
        if fraction < 1.5:
            nice_fraction = 1.
        elif fraction < 3.:
            nice_fraction = 2.
        elif fraction < 7.:
            nice_fraction = 5.
        else:
            nice_fraction = 10.
    else:
        if fraction <= 1:
            nice_fraction = 1.
        elif fraction <= 2:
            nice_fraction = 2.
        elif fraction <= 5:
            nice_fraction = 5.
        else:
            nice_fraction = 10.

    return nice_fraction * 10 ** exponent


def nice_bounds(axis_start, axis_end, num_ticks=10):
    '''
    nice_bounds(axis_start, axis_end, num_ticks=10) -> tuple
    @return: tuple as (nice_axis_start, nice_axis_end, nice_tick_width)
    '''
    axis_width = axis_end - axis_start
    if axis_width == 0:
        nice_tick = 0
    else:
        nice_range = nice_number(axis_width)
        nice_tick = nice_number(nice_range / (num_ticks - 1), round_=True)
        axis_start = math.floor(axis_start / nice_tick) * nice_tick
        axis_end = math.ceil(axis_end / nice_tick) * nice_tick

    return axis_start, axis_end, nice_tick

use as:

>>> nice_bounds(26.5, 28.3)
(26.4, 28.4, 0.2)

Also add a javascript porting:

function nice_number(value, round_){
    //default value for round_ is false
    round_ = round_ || false;
    // :latex: \log_y z = \frac{\log_x z}{\log_x y}
    var exponent = Math.floor(Math.log(value) / Math.log(10));
    var fraction = value / Math.pow(10, exponent);

    if (round_)
        if (fraction < 1.5)
            nice_fraction = 1.
        else if (fraction < 3.)
            nice_fraction = 2.
        else if (fraction < 7.)
            nice_fraction = 5.
        else
            nice_fraction = 10.
    else
        if (fraction <= 1)
            nice_fraction = 1.
        else if (fraction <= 2)
            nice_fraction = 2.
        else if (fraction <= 5)
            nice_fraction = 5.
        else
            nice_fraction = 10.

    return nice_fraction * Math.pow(10, exponent)
}

function nice_bounds(axis_start, axis_end, num_ticks){
    //default value is 10
    num_ticks = num_ticks || 10;
    var axis_width = axis_end - axis_start;

    if (axis_width == 0){
        axis_start -= .5
        axis_end += .5
        axis_width = axis_end - axis_start
    }

    var nice_range = nice_number(axis_width);
    var nice_tick = nice_number(nice_range / (num_ticks -1), true);
    var axis_start = Math.floor(axis_start / nice_tick) * nice_tick;
    var axis_end = Math.ceil(axis_end / nice_tick) * nice_tick;
    return {
        "min": axis_start,
        "max": axis_end,
        "steps": nice_tick
    }
}
思慕 2024-10-23 19:02:23

下面是我的自动计算刻度的Python代码,它需要数据范围和最大刻度数。

例如:

auto_tick([-120, 580], max_tick=10, tf_inside=False)
Out[224]: array([-100.,   -0.,  100.,  200.,  300.,  400.,  500.])
auto_tick([-120, 580], max_tick=20, tf_inside=False)
Out[225]: array([-100.,  -50.,   -0.,   50.,  100.,  150.,  200.,  250.,  300., 350.,  400.,  450.,  500.,  550.])

下面是该函数的Python代码

def auto_tick(data_range, max_tick=10, tf_inside=False):
    """
    tool function that automatically calculate optimal ticks based on range and the max number of ticks
    :param data_range:   range of data, e.g. [-0.1, 0.5]
    :param max_tick:     max number of ticks, an interger, default to 10
    :param tf_inside:    True/False if only allow ticks to be inside
    :return:             list of ticks
    """
    data_span = data_range[1] - data_range[0]
    scale = 10.0**np.floor(np.log10(data_span))    # scale of data as the order of 10, e.g. 1, 10, 100, 0.1, 0.01, ...
    list_tick_size_nmlz = [5.0, 2.0, 1.0, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01]   # possible tick sizes for normalized data in range [1, 10]
    tick_size_nmlz = 1.0     # initial tick size for normalized data
    for i in range(len(list_tick_size_nmlz)):                 # every loop reduces tick size thus increases tick number
        num_tick = data_span/scale/list_tick_size_nmlz[i]     # number of ticks for the current tick size
        if num_tick > max_tick:                               # if too many ticks, break loop
            tick_size_nmlz = list_tick_size_nmlz[i-1]
            break
    tick_size = tick_size_nmlz * scale             # tick sizse for the original data
    ticks = np.unique(np.arange(data_range[0]/tick_size, data_range[1]/tick_size).round())*tick_size    # list of ticks

    if tf_inside:     # if only allow ticks within the given range
        ticks = ticks[ (ticks>=data_range[0]) * (ticks<=data_range[1])]

    return ticks

Below are my python code to automatically calculate ticks, it needs the range of data and the max number of ticks.

For example:

auto_tick([-120, 580], max_tick=10, tf_inside=False)
Out[224]: array([-100.,   -0.,  100.,  200.,  300.,  400.,  500.])
auto_tick([-120, 580], max_tick=20, tf_inside=False)
Out[225]: array([-100.,  -50.,   -0.,   50.,  100.,  150.,  200.,  250.,  300., 350.,  400.,  450.,  500.,  550.])

Below is the Python code of the function

def auto_tick(data_range, max_tick=10, tf_inside=False):
    """
    tool function that automatically calculate optimal ticks based on range and the max number of ticks
    :param data_range:   range of data, e.g. [-0.1, 0.5]
    :param max_tick:     max number of ticks, an interger, default to 10
    :param tf_inside:    True/False if only allow ticks to be inside
    :return:             list of ticks
    """
    data_span = data_range[1] - data_range[0]
    scale = 10.0**np.floor(np.log10(data_span))    # scale of data as the order of 10, e.g. 1, 10, 100, 0.1, 0.01, ...
    list_tick_size_nmlz = [5.0, 2.0, 1.0, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01]   # possible tick sizes for normalized data in range [1, 10]
    tick_size_nmlz = 1.0     # initial tick size for normalized data
    for i in range(len(list_tick_size_nmlz)):                 # every loop reduces tick size thus increases tick number
        num_tick = data_span/scale/list_tick_size_nmlz[i]     # number of ticks for the current tick size
        if num_tick > max_tick:                               # if too many ticks, break loop
            tick_size_nmlz = list_tick_size_nmlz[i-1]
            break
    tick_size = tick_size_nmlz * scale             # tick sizse for the original data
    ticks = np.unique(np.arange(data_range[0]/tick_size, data_range[1]/tick_size).round())*tick_size    # list of ticks

    if tf_inside:     # if only allow ticks within the given range
        ticks = ticks[ (ticks>=data_range[0]) * (ticks<=data_range[1])]

    return ticks
莫相离 2024-10-23 19:02:23

这是 @uesp answer

function niceNumber(value: number, round = false) {

  const exponent = Math.floor(Math.log10(value));
  const fraction = value / Math.pow(10, exponent);

  let niceFraction: number;

  if (round) {
    if (fraction < 1.5) {
      niceFraction = 1.0;
    } else if (fraction < 3.0) {
      niceFraction = 2.0;
    } else if (fraction < 7.0) {
      niceFraction = 5.0;
    } else {
      niceFraction = 10.0;
    }
  } else {
    if (fraction <= 1.0) {
      niceFraction = 1.0;
    } else if (fraction <= 2.0) {
      niceFraction = 2.0;
    } else if (fraction <= 5.0) {
      niceFraction = 5.0;
    } else {
      niceFraction = 10.0;
    }
  }

  return niceFraction * Math.pow(10, exponent);

}

export function calcTicks(minValue: number, maxValue: number, ticksCount: number) {

  const range = niceNumber(maxValue - minValue);

  const tickValue = niceNumber(range / (ticksCount - 1), true);

  const ticks: number[] = [];
  for (let i = 0; i < ticksCount; i++) {
    ticks.push(minValue + tickValue * i);
  }

  return ticks;

}

但是,这里的 calcTicks() 函数返回一个刻度数组,而不是开始和结束边界。

And here's the version of @uesp answer in TypeScript / JavaScript ES6:

function niceNumber(value: number, round = false) {

  const exponent = Math.floor(Math.log10(value));
  const fraction = value / Math.pow(10, exponent);

  let niceFraction: number;

  if (round) {
    if (fraction < 1.5) {
      niceFraction = 1.0;
    } else if (fraction < 3.0) {
      niceFraction = 2.0;
    } else if (fraction < 7.0) {
      niceFraction = 5.0;
    } else {
      niceFraction = 10.0;
    }
  } else {
    if (fraction <= 1.0) {
      niceFraction = 1.0;
    } else if (fraction <= 2.0) {
      niceFraction = 2.0;
    } else if (fraction <= 5.0) {
      niceFraction = 5.0;
    } else {
      niceFraction = 10.0;
    }
  }

  return niceFraction * Math.pow(10, exponent);

}

export function calcTicks(minValue: number, maxValue: number, ticksCount: number) {

  const range = niceNumber(maxValue - minValue);

  const tickValue = niceNumber(range / (ticksCount - 1), true);

  const ticks: number[] = [];
  for (let i = 0; i < ticksCount; i++) {
    ticks.push(minValue + tickValue * i);
  }

  return ticks;

}

However, calcTicks() function here returns an array of ticks instead of start and end bounds.

花辞树 2024-10-23 19:02:23

Perl 版本,提供处理轴起点和终点的选项(或导出此形式的数据点列表),以及生成(起点、终点、刻度大小)或刻度点列表的函数

#!/usr/bin/env perl
use strict; use warnings;

print join("--",niceTicks(minmax([34,6,-7,15]),5));


#given a list of data (as an array or arrayref, return minimum and maximum)
sub minmax{
   my @list=@_;
   @list=@{$list[0]} if (ref $list[0]);
   my $max=my $min = shift @list;;
   foreach my $v (@list){
      $max=$v if $max<$v;
      $min=$v if $min>$v;   
   }
   return ($min,$max)
}

# niceTicks
# takes minimum value, maximum value and number of desired ticks;
# returns list of ticks
sub niceTicks{
   my ($axisStart,$axisEnd,$nTicks)=@_;
   ($axisStart,$axisEnd,my $tick)=niceAxis($axisStart,$axisEnd,$nTicks);
   my @tickList=($axisStart);
   push @tickList,$tickList[-1]+$tick while ($tickList[-1]<=$axisEnd);
   return @tickList;
}

# niceAxis
# takes minimum value, maximum value and number of desired ticks;
# returns nice axis start, axis end and gap between ticks
sub niceAxis{   
   my ($axisStart,$axisEnd,$nTicks)=@_;
   $nTicks//=5;
   my $axisWidth=$axisEnd-$axisStart;
   return undef unless $axisWidth>0;  # error is start >= end 
   
   my $niceRange=niceNumber($axisWidth,0);
   my $niceTick =niceNumber($niceRange/($nTicks-1) , 1);  
   $axisStart=floor($axisStart/$niceTick)*$niceTick;
   $axisEnd = ceil($axisEnd/$niceTick)*$niceTick;
   return ($axisStart,$axisEnd,$niceTick)  
}

# uesps algorthm
sub niceNumber{
  my ($value,$round)=@_;
 
  my $exp= floor(log($value)/log(10));
  my $fraction=$value/(10**$exp);
  
    if ($round){
       for ($fraction){
         $_ < 1.5  && return  1*(10**$exp);
         $_ < 3.0  && return  2*(10**$exp);
         $_ < 7.0  && return  5*(10**$exp);
         return  10*(10**$exp);
       }
    }
    else{
       for ($fraction){
         $_ < 1  && return  1*(10**$exp);
         $_ < 2  && return  2*(10**$exp);
         $_ < 5  && return  5*(10**$exp);
         return  10*(10**$exp);
       }
    }
}


# saves having to use POSIX
sub floor{
  my $v=shift;
  return int($v)-($v<0?1:0);
}

# saves having to use POSIX
sub ceil{
  my $v=shift;
  return int($v)+ ($v==int($v)?0:1);
}

A Perl version that offers options of working on axis start and end, (or derive this form list of data points), with functions to produce (start, end, tick size) or a list of tick points

#!/usr/bin/env perl
use strict; use warnings;

print join("--",niceTicks(minmax([34,6,-7,15]),5));


#given a list of data (as an array or arrayref, return minimum and maximum)
sub minmax{
   my @list=@_;
   @list=@{$list[0]} if (ref $list[0]);
   my $max=my $min = shift @list;;
   foreach my $v (@list){
      $max=$v if $max<$v;
      $min=$v if $min>$v;   
   }
   return ($min,$max)
}

# niceTicks
# takes minimum value, maximum value and number of desired ticks;
# returns list of ticks
sub niceTicks{
   my ($axisStart,$axisEnd,$nTicks)=@_;
   ($axisStart,$axisEnd,my $tick)=niceAxis($axisStart,$axisEnd,$nTicks);
   my @tickList=($axisStart);
   push @tickList,$tickList[-1]+$tick while ($tickList[-1]<=$axisEnd);
   return @tickList;
}

# niceAxis
# takes minimum value, maximum value and number of desired ticks;
# returns nice axis start, axis end and gap between ticks
sub niceAxis{   
   my ($axisStart,$axisEnd,$nTicks)=@_;
   $nTicks//=5;
   my $axisWidth=$axisEnd-$axisStart;
   return undef unless $axisWidth>0;  # error is start >= end 
   
   my $niceRange=niceNumber($axisWidth,0);
   my $niceTick =niceNumber($niceRange/($nTicks-1) , 1);  
   $axisStart=floor($axisStart/$niceTick)*$niceTick;
   $axisEnd = ceil($axisEnd/$niceTick)*$niceTick;
   return ($axisStart,$axisEnd,$niceTick)  
}

# uesps algorthm
sub niceNumber{
  my ($value,$round)=@_;
 
  my $exp= floor(log($value)/log(10));
  my $fraction=$value/(10**$exp);
  
    if ($round){
       for ($fraction){
         $_ < 1.5  && return  1*(10**$exp);
         $_ < 3.0  && return  2*(10**$exp);
         $_ < 7.0  && return  5*(10**$exp);
         return  10*(10**$exp);
       }
    }
    else{
       for ($fraction){
         $_ < 1  && return  1*(10**$exp);
         $_ < 2  && return  2*(10**$exp);
         $_ < 5  && return  5*(10**$exp);
         return  10*(10**$exp);
       }
    }
}


# saves having to use POSIX
sub floor{
  my $v=shift;
  return int($v)-($v<0?1:0);
}

# saves having to use POSIX
sub ceil{
  my $v=shift;
  return int($v)+ ($v==int($v)?0:1);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文